From 546a5cc2ae51bde0ecab26f724613006f74624c9 Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Fri, 9 Jul 2021 15:48:57 -0400 Subject: [PATCH 1/6] cli: add selection args for source freshness command --- core/dbt/contracts/rpc.py | 2 ++ core/dbt/main.py | 18 ++++++++---------- core/dbt/task/freshness.py | 14 +++++++------- core/dbt/task/rpc/project_commands.py | 4 +++- test/rpc/test_source_freshness.py | 8 ++++---- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/core/dbt/contracts/rpc.py b/core/dbt/contracts/rpc.py index 02198630e00..16beffae23b 100644 --- a/core/dbt/contracts/rpc.py +++ b/core/dbt/contracts/rpc.py @@ -186,6 +186,8 @@ class RPCRunOperationParameters(RPCParameters): class RPCSourceFreshnessParameters(RPCParameters): threads: Optional[int] = None select: Union[None, str, List[str]] = None + exclude: Union[None, str, List[str]] = None + selector: Optional[str] = None @dataclass diff --git a/core/dbt/main.py b/core/dbt/main.py index 09a5cc33ff4..f6631ed1e96 100644 --- a/core/dbt/main.py +++ b/core/dbt/main.py @@ -41,6 +41,7 @@ class DBTVersion(argparse.Action): """This is very very similar to the builtin argparse._Version action, except it just calls dbt.version.get_version_information(). """ + def __init__(self, option_strings, version=None, @@ -763,16 +764,6 @@ def _build_source_snapshot_freshness_subparser(subparsers, base_subparser): Snapshots the current freshness of the project's sources ''', ) - sub.add_argument( - '-s', - '--select', - required=False, - nargs='+', - help=''' - Specify the sources to snapshot freshness - ''', - dest='selected' - ) sub.add_argument( '-o', '--output', @@ -795,6 +786,13 @@ def _build_source_snapshot_freshness_subparser(subparsers, base_subparser): which='snapshot-freshness', rpc_method='snapshot-freshness', ) + _add_select_argument( + sub, + dest='select', + metavar='SELECTOR', + required=False, + ) + _add_common_selector_arguments(sub) return sub diff --git a/core/dbt/task/freshness.py b/core/dbt/task/freshness.py index d1a8fb9ac61..4ca7175ca30 100644 --- a/core/dbt/task/freshness.py +++ b/core/dbt/task/freshness.py @@ -19,7 +19,7 @@ from dbt.logger import print_timestamped_line from dbt.node_types import NodeType -from dbt.graph import NodeSelector, SelectionSpec, parse_difference +from dbt.graph import ResourceTypeSelector, SelectionSpec, parse_difference from dbt.contracts.graph.parsed import ParsedSourceDefinition @@ -117,7 +117,7 @@ def compile(self, manifest): return self.node -class FreshnessSelector(NodeSelector): +class FreshnessSelector(ResourceTypeSelector): def node_is_match(self, node): if not super().node_is_match(node): return False @@ -137,11 +137,10 @@ def raise_on_first_error(self): return False def get_selection_spec(self) -> SelectionSpec: - include = [ - 'source:{}'.format(s) - for s in (self.args.selected or ['*']) - ] - spec = parse_difference(include, None) + if self.args.selector_name: + spec = self.config.get_selector(self.args.selector_name) + else: + spec = parse_difference(self.args.select, self.args.exclude) return spec def get_node_selector(self): @@ -153,6 +152,7 @@ def get_node_selector(self): graph=self.graph, manifest=self.manifest, previous_state=self.previous_state, + resource_types=[NodeType.Source] ) def get_runner_type(self, _): diff --git a/core/dbt/task/rpc/project_commands.py b/core/dbt/task/rpc/project_commands.py index a4952cc87fb..f6545b4f227 100644 --- a/core/dbt/task/rpc/project_commands.py +++ b/core/dbt/task/rpc/project_commands.py @@ -231,7 +231,9 @@ class RemoteSourceFreshnessTask( METHOD_NAME = 'snapshot-freshness' def set_args(self, params: RPCSourceFreshnessParameters) -> None: - self.args.selected = self._listify(params.select) + self.args.select = self._listify(params.select) + self.args.exclude = self._listify(params.exclude) + self.args.selector_name = params.selector if params.threads is not None: self.args.threads = params.threads self.args.output = None diff --git a/test/rpc/test_source_freshness.py b/test/rpc/test_source_freshness.py index beced003d35..69c8620940c 100644 --- a/test/rpc/test_source_freshness.py +++ b/test/rpc/test_source_freshness.py @@ -65,10 +65,10 @@ def test_source_freshness( project.write_seeds(project_root, remove=True) querier.async_wait_for_result(querier.seed()) # should warn - warn_results = querier.async_wait_for_result(querier.snapshot_freshness(select='test_source.test_table')) + warn_results = querier.async_wait_for_result(querier.snapshot_freshness(select='source:test_source.test_table')) assert len(warn_results['results']) == 1 assert warn_results['results'][0]['status'] == 'warn' - warn_results = querier.async_wait_for_result(querier.cli_args('source snapshot-freshness -s test_source.test_table')) + warn_results = querier.async_wait_for_result(querier.cli_args('source snapshot-freshness -s source:test_source.test_table')) assert len(warn_results['results']) == 1 assert warn_results['results'][0]['status'] == 'warn' @@ -76,9 +76,9 @@ def test_source_freshness( project.write_seeds(project_root, remove=True) querier.async_wait_for_result(querier.seed()) # should pass! - pass_results = querier.async_wait_for_result(querier.snapshot_freshness(select=['test_source.test_table'])) + pass_results = querier.async_wait_for_result(querier.snapshot_freshness(select=['source:test_source.test_table'])) assert len(pass_results['results']) == 1 assert pass_results['results'][0]['status'] == 'pass' - pass_results = querier.async_wait_for_result(querier.cli_args('source snapshot-freshness --select test_source.test_table')) + pass_results = querier.async_wait_for_result(querier.cli_args('source snapshot-freshness --select source:test_source.test_table')) assert len(pass_results['results']) == 1 assert pass_results['results'][0]['status'] == 'pass' From 9df1383cfa2e9947e710ee853fd40a236157ed03 Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Mon, 12 Jul 2021 10:36:03 -0400 Subject: [PATCH 2/6] rename command to `source freshness` and maintain alias to old command --- core/dbt/main.py | 11 ++++++----- core/dbt/task/rpc/project_commands.py | 9 ++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/dbt/main.py b/core/dbt/main.py index f6631ed1e96..cd0957a1b2f 100644 --- a/core/dbt/main.py +++ b/core/dbt/main.py @@ -756,13 +756,14 @@ def _build_test_subparser(subparsers, base_subparser): return sub -def _build_source_snapshot_freshness_subparser(subparsers, base_subparser): +def _build_source_freshness_subparser(subparsers, base_subparser): sub = subparsers.add_parser( - 'snapshot-freshness', + 'freshness', parents=[base_subparser], help=''' Snapshots the current freshness of the project's sources ''', + aliases=['snapshot-freshness'], ) sub.add_argument( '-o', @@ -783,8 +784,8 @@ def _build_source_snapshot_freshness_subparser(subparsers, base_subparser): ) sub.set_defaults( cls=freshness_task.FreshnessTask, - which='snapshot-freshness', - rpc_method='snapshot-freshness', + which='source-freshness', + rpc_method='source-freshness', ) _add_select_argument( sub, @@ -1082,7 +1083,7 @@ def parse_args(args, cls=DBTArgumentParser): _add_table_mutability_arguments(run_sub, compile_sub) _build_docs_serve_subparser(docs_subs, base_subparser) - _build_source_snapshot_freshness_subparser(source_subs, base_subparser) + _build_source_freshness_subparser(source_subs, base_subparser) _build_run_operation_subparser(subs, base_subparser) if len(args) == 0: diff --git a/core/dbt/task/rpc/project_commands.py b/core/dbt/task/rpc/project_commands.py index f6545b4f227..d1c3342f6f1 100644 --- a/core/dbt/task/rpc/project_commands.py +++ b/core/dbt/task/rpc/project_commands.py @@ -228,7 +228,7 @@ class RemoteSourceFreshnessTask( RPCCommandTask[RPCSourceFreshnessParameters], FreshnessTask ): - METHOD_NAME = 'snapshot-freshness' + METHOD_NAME = 'source-freshness' def set_args(self, params: RPCSourceFreshnessParameters) -> None: self.args.select = self._listify(params.select) @@ -239,6 +239,13 @@ def set_args(self, params: RPCSourceFreshnessParameters) -> None: self.args.output = None +class RemoteSourceSnapshotFreshnessTask( + RemoteSourceFreshnessTask +): + """ Deprecated task method name, aliases to `source-freshness` """ + METHOD_NAME = 'snapshot-freshness' + + # this is a weird and special method. class GetManifest( RemoteManifestMethod[GetManifestParameters, GetManifestResult] From 8d41475ffb5afca6f2ef7ad9a8cc01d8abc3b4f5 Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Tue, 13 Jul 2021 11:08:43 -0400 Subject: [PATCH 3/6] update and add tests for source freshness command and node selection --- .../042_sources_test/test_sources.py | 82 +++++++++++++++++-- test/rpc/test_source_freshness.py | 64 ++++++++++++++- test/rpc/util.py | 22 +++++ 3 files changed, 159 insertions(+), 9 deletions(-) diff --git a/test/integration/042_sources_test/test_sources.py b/test/integration/042_sources_test/test_sources.py index dd3aac9d45f..d6320428f94 100644 --- a/test/integration/042_sources_test/test_sources.py +++ b/test/integration/042_sources_test/test_sources.py @@ -282,7 +282,7 @@ def _run_source_freshness(self): # by default, our data set is way out of date! self.freshness_start_time = datetime.utcnow() results = self.run_dbt_with_vars( - ['source', 'snapshot-freshness', '-o', 'target/error_source.json'], + ['source', 'freshness', '-o', 'target/error_source.json'], expect_pass=False ) self.assertEqual(len(results), 1) @@ -292,7 +292,7 @@ def _run_source_freshness(self): self._set_updated_at_to(timedelta(hours=-12)) self.freshness_start_time = datetime.utcnow() results = self.run_dbt_with_vars( - ['source', 'snapshot-freshness', '-o', 'target/warn_source.json'], + ['source', 'freshness', '-o', 'target/warn_source.json'], ) self.assertEqual(len(results), 1) self.assertEqual(results[0].status, 'warn') @@ -301,7 +301,7 @@ def _run_source_freshness(self): self._set_updated_at_to(timedelta(hours=-2)) self.freshness_start_time = datetime.utcnow() results = self.run_dbt_with_vars( - ['source', 'snapshot-freshness', '-o', 'target/pass_source.json'], + ['source', 'freshness', '-o', 'target/pass_source.json'], ) self.assertEqual(len(results), 1) self.assertEqual(results[0].status, 'pass') @@ -311,6 +311,37 @@ def _run_source_freshness(self): def test_postgres_source_freshness(self): self._run_source_freshness() + @use_profile('postgres') + def test_postgres_source_snapshot_freshness(self): + """ Ensures that the deprecated command `source snapshot-freshness` + aliases to `source freshness` command """ + self.freshness_start_time = datetime.utcnow() + results = self.run_dbt_with_vars( + ['source', 'snapshot-freshness', '-o', 'target/error_source.json'], + expect_pass=False + ) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].status, 'error') + self._assert_freshness_results('target/error_source.json', 'error') + + self._set_updated_at_to(timedelta(hours=-12)) + self.freshness_start_time = datetime.utcnow() + results = self.run_dbt_with_vars( + ['source', 'snapshot-freshness', '-o', 'target/warn_source.json'], + ) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].status, 'warn') + self._assert_freshness_results('target/warn_source.json', 'warn') + + self._set_updated_at_to(timedelta(hours=-2)) + self.freshness_start_time = datetime.utcnow() + results = self.run_dbt_with_vars( + ['source', 'snapshot-freshness', '-o', 'target/pass_source.json'], + ) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].status, 'pass') + self._assert_freshness_results('target/pass_source.json', 'pass') + @use_profile('snowflake') def test_snowflake_source_freshness(self): self._run_source_freshness() @@ -323,6 +354,43 @@ def test_redshift_source_freshness(self): def test_bigquery_source_freshness(self): self._run_source_freshness() + @use_profile('postgres') + def test_postgres_source_freshness_selection_select(self): + self._set_updated_at_to(timedelta(hours=-2)) + self.freshness_start_time = datetime.utcnow() + # select source directly + results = self.run_dbt_with_vars( + ['source', 'freshness', '--select', + 'source:test_source.test_table', '-o', 'target/pass_source.json'], + ) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].status, 'pass') + self._assert_freshness_results('target/pass_source.json', 'pass') + + @use_profile('postgres') + def test_postgres_source_freshness_selection_exclude(self): + self._set_updated_at_to(timedelta(hours=-2)) + self.freshness_start_time = datetime.utcnow() + # exclude source directly + results = self.run_dbt_with_vars( + ['source', 'freshness', '--exclude', + 'source:test_source.test_table', '-o', 'target/exclude_source.json'], + ) + self.assertEqual(len(results), 0) + + @use_profile('postgres') + def test_postgres_source_freshness_selection_graph_operation(self): + self._set_updated_at_to(timedelta(hours=-2)) + self.freshness_start_time = datetime.utcnow() + # select model ancestors + results = self.run_dbt_with_vars( + ['source', 'freshness', '--select', + '+descendant_model', '-o', 'target/ancestor_source.json'] + ) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].status, 'pass') + self._assert_freshness_results('target/ancestor_source.json', 'pass') + class TestSourceFreshnessErrors(SuccessfulSourcesTest): @property @@ -332,7 +400,7 @@ def models(self): @use_profile('postgres') def test_postgres_error(self): results = self.run_dbt_with_vars( - ['source', 'snapshot-freshness'], + ['source', 'freshness'], expect_pass=False ) self.assertEqual(len(results), 1) @@ -348,18 +416,18 @@ def models(self): def test_postgres_all_records(self): # all records are filtered out self.run_dbt_with_vars( - ['source', 'snapshot-freshness'], expect_pass=False) + ['source', 'freshness'], expect_pass=False) # we should insert a record with #101 that's fresh, but will still fail # because the filter excludes it self._set_updated_at_to(timedelta(hours=-2)) self.run_dbt_with_vars( - ['source', 'snapshot-freshness'], expect_pass=False) + ['source', 'freshness'], expect_pass=False) # we should now insert a record with #102 that's fresh, and the filter # includes it self._set_updated_at_to(timedelta(hours=-2)) results = self.run_dbt_with_vars( - ['source', 'snapshot-freshness'], expect_pass=True) + ['source', 'freshness'], expect_pass=True) class TestMalformedSources(BaseSourcesTest): diff --git a/test/rpc/test_source_freshness.py b/test/rpc/test_source_freshness.py index 69c8620940c..6f3c51e8f62 100644 --- a/test/rpc/test_source_freshness.py +++ b/test/rpc/test_source_freshness.py @@ -21,9 +21,8 @@ identifier: other_source ''' - @pytest.mark.supported('postgres') -def test_source_freshness( +def test_source_snapshot_freshness( project_root, profiles_root, dbt_profile, unique_schema ): start_time = datetime.utcnow() @@ -82,3 +81,64 @@ def test_source_freshness( pass_results = querier.async_wait_for_result(querier.cli_args('source snapshot-freshness --select source:test_source.test_table')) assert len(pass_results['results']) == 1 assert pass_results['results'][0]['status'] == 'pass' + +@pytest.mark.supported('postgres') +def test_source_freshness( + project_root, profiles_root, dbt_profile, unique_schema +): + start_time = datetime.utcnow() + warn_me = start_time - timedelta(hours=18) + error_me = start_time - timedelta(days=2) + # this should trigger a 'warn' + project = ProjectDefinition( + project_data={'seeds': {'config': {'quote_columns': False}}}, + seeds={ + 'source.csv': 'a,b\n1,{}\n'.format(error_me.strftime('%Y-%m-%d %H:%M:%S')), + 'other_source.csv': 'a,b\n1,{}\n'.format(error_me.strftime('%Y-%m-%d %H:%M:%S')) + }, + models={ + 'sources.yml': source_freshness_schema_yml.format(schema=unique_schema), + }, + ) + querier_ctx = get_querier( + project_def=project, + project_dir=project_root, + profiles_dir=profiles_root, + schema=unique_schema, + test_kwargs={}, + ) + + with querier_ctx as querier: + seeds = querier.async_wait_for_result(querier.seed()) + assert len(seeds['results']) == 2 + # should error + error_results = querier.async_wait_for_result(querier.source_freshness(), state='failed') + assert len(error_results['results']) == 2 + for result in error_results['results']: + assert result['status'] == 'error' + error_results = querier.async_wait_for_result(querier.cli_args('source freshness'), state='failed') + assert len(error_results['results']) == 2 + for result in error_results['results']: + assert result['status'] == 'error' + + project.seeds['source.csv'] += '2,{}\n'.format(warn_me.strftime('%Y-%m-%d %H:%M:%S')) + project.write_seeds(project_root, remove=True) + querier.async_wait_for_result(querier.seed()) + # should warn + warn_results = querier.async_wait_for_result(querier.source_freshness(select='source:test_source.test_table')) + assert len(warn_results['results']) == 1 + assert warn_results['results'][0]['status'] == 'warn' + warn_results = querier.async_wait_for_result(querier.cli_args('source freshness -s source:test_source.test_table')) + assert len(warn_results['results']) == 1 + assert warn_results['results'][0]['status'] == 'warn' + + project.seeds['source.csv'] += '3,{}\n'.format(start_time.strftime('%Y-%m-%d %H:%M:%S')) + project.write_seeds(project_root, remove=True) + querier.async_wait_for_result(querier.seed()) + # should pass! + pass_results = querier.async_wait_for_result(querier.source_freshness(select=['source:test_source.test_table'])) + assert len(pass_results['results']) == 1 + assert pass_results['results'][0]['status'] == 'pass' + pass_results = querier.async_wait_for_result(querier.cli_args('source freshness --select source:test_source.test_table')) + assert len(pass_results['results']) == 1 + assert pass_results['results'][0]['status'] == 'pass' diff --git a/test/rpc/util.py b/test/rpc/util.py index 2492d193ad2..64a043ec1d1 100644 --- a/test/rpc/util.py +++ b/test/rpc/util.py @@ -318,6 +318,7 @@ def snapshot_freshness( threads: Optional[int] = None, request_id: int = 1, ): + """ Deprecated rpc command `snapshot-freshness` -> `source-freshness` """ params = {} if select is not None: params['select'] = select @@ -327,6 +328,27 @@ def snapshot_freshness( method='snapshot-freshness', params=params, request_id=request_id ) + def source_freshness( + self, + select: Optional[Union[str, List[str]]] = None, + exclude: Optional[Union[str, List[str]]] = None, + threads: Optional[int] = None, + request_id: int = 1, + state: Optional[bool] = None, + ): + params = {} + if select is not None: + params['select'] = select + if exclude is not None: + params['exclude'] = exclude + if threads is not None: + params['threads'] = threads + if state is not None: + params['state'] = state + return self.request( + method='source-freshness', params=params, request_id=request_id + ) + def test( self, models: Optional[Union[str, List[str]]] = None, From ab3c7cccb3ea3a148c9094e8f369f7cc9d8b05d6 Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Tue, 13 Jul 2021 13:14:17 -0400 Subject: [PATCH 4/6] update changelog, add comments --- CHANGELOG.md | 1 + core/dbt/task/freshness.py | 6 ++++++ test/integration/042_sources_test/test_sources.py | 12 ++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7159b16983..36bd2711647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features - Add `dbt build` command to run models, tests, seeds, and snapshots in DAG order. ([#2743] (https://github.com/dbt-labs/dbt/issues/2743), [#3490] (https://github.com/dbt-labs/dbt/issues/3490)) +- Add full node selection to source freshness command and align syntax with other tasks, rename `source snapshot-freshness` -> `source freshness` ([#2987](https://github.com/dbt-labs/dbt/issues/2987), [#3554](https://github.com/dbt-labs/dbt/pull/3554)) ### Fixes - Fix docs generation for cross-db sources in REDSHIFT RA3 node ([#3236](https://github.com/fishtown-analytics/dbt/issues/3236), [#3408](https://github.com/fishtown-analytics/dbt/pull/3408)) diff --git a/core/dbt/task/freshness.py b/core/dbt/task/freshness.py index 4ca7175ca30..2450332a7a5 100644 --- a/core/dbt/task/freshness.py +++ b/core/dbt/task/freshness.py @@ -137,9 +137,15 @@ def raise_on_first_error(self): return False def get_selection_spec(self) -> SelectionSpec: + """Generates a selection spec from task arguments to use when processing + graph. A SelectionSpec describes what nodes to select when creating + queue from graph of nodes. + """ if self.args.selector_name: + # use pre-defined selector (--selector) to create selection spec spec = self.config.get_selector(self.args.selector_name) else: + # use --select and --exclude args to create selection spec spec = parse_difference(self.args.select, self.args.exclude) return spec diff --git a/test/integration/042_sources_test/test_sources.py b/test/integration/042_sources_test/test_sources.py index d6320428f94..c9633e86e41 100644 --- a/test/integration/042_sources_test/test_sources.py +++ b/test/integration/042_sources_test/test_sources.py @@ -313,8 +313,9 @@ def test_postgres_source_freshness(self): @use_profile('postgres') def test_postgres_source_snapshot_freshness(self): - """ Ensures that the deprecated command `source snapshot-freshness` - aliases to `source freshness` command """ + """Ensures that the deprecated command `source snapshot-freshness` + aliases to `source freshness` command. + """ self.freshness_start_time = datetime.utcnow() results = self.run_dbt_with_vars( ['source', 'snapshot-freshness', '-o', 'target/error_source.json'], @@ -356,6 +357,7 @@ def test_bigquery_source_freshness(self): @use_profile('postgres') def test_postgres_source_freshness_selection_select(self): + """Tests node selection using the --select argument.""" self._set_updated_at_to(timedelta(hours=-2)) self.freshness_start_time = datetime.utcnow() # select source directly @@ -369,6 +371,8 @@ def test_postgres_source_freshness_selection_select(self): @use_profile('postgres') def test_postgres_source_freshness_selection_exclude(self): + """Tests node selection using the --select argument. It 'excludes' the + only source in the project so it should return no results.""" self._set_updated_at_to(timedelta(hours=-2)) self.freshness_start_time = datetime.utcnow() # exclude source directly @@ -380,6 +384,10 @@ def test_postgres_source_freshness_selection_exclude(self): @use_profile('postgres') def test_postgres_source_freshness_selection_graph_operation(self): + """Tests node selection using the --select argument with graph + operations. `+descendant_model` == select all nodes `descendant_model` + depends on. + """ self._set_updated_at_to(timedelta(hours=-2)) self.freshness_start_time = datetime.utcnow() # select model ancestors From 7be2803de6d63c539f06a598420ed22039f4afa3 Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Tue, 13 Jul 2021 16:07:58 -0400 Subject: [PATCH 5/6] fix formatting --- core/dbt/task/freshness.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/dbt/task/freshness.py b/core/dbt/task/freshness.py index 2450332a7a5..b649ca7800d 100644 --- a/core/dbt/task/freshness.py +++ b/core/dbt/task/freshness.py @@ -137,9 +137,9 @@ def raise_on_first_error(self): return False def get_selection_spec(self) -> SelectionSpec: - """Generates a selection spec from task arguments to use when processing - graph. A SelectionSpec describes what nodes to select when creating - queue from graph of nodes. + """Generates a selection spec from task arguments to use when + processing graph. A SelectionSpec describes what nodes to select + when creating queue from graph of nodes. """ if self.args.selector_name: # use pre-defined selector (--selector) to create selection spec From 56b1436ea38cb9660fa99442d8f3b57dd080491c Mon Sep 17 00:00:00 2001 From: Kyle Wigley Date: Wed, 14 Jul 2021 16:37:42 -0400 Subject: [PATCH 6/6] update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36bd2711647..7b77d42b2fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ### Features - Add `dbt build` command to run models, tests, seeds, and snapshots in DAG order. ([#2743] (https://github.com/dbt-labs/dbt/issues/2743), [#3490] (https://github.com/dbt-labs/dbt/issues/3490)) -- Add full node selection to source freshness command and align syntax with other tasks, rename `source snapshot-freshness` -> `source freshness` ([#2987](https://github.com/dbt-labs/dbt/issues/2987), [#3554](https://github.com/dbt-labs/dbt/pull/3554)) + +### Breaking changes +- Add full node selection to source freshness command and align selection syntax with other tasks (`dbt source freshness --select source_name` --> `dbt source freshness --select source:souce_name`) and rename `dbt source snapshot-freshness` -> `dbt source freshness`. ([#2987](https://github.com/dbt-labs/dbt/issues/2987), [#3554](https://github.com/dbt-labs/dbt/pull/3554)) ### Fixes - Fix docs generation for cross-db sources in REDSHIFT RA3 node ([#3236](https://github.com/fishtown-analytics/dbt/issues/3236), [#3408](https://github.com/fishtown-analytics/dbt/pull/3408))