diff --git a/dvc/commands/data_sync.py b/dvc/commands/data_sync.py index fa05cf7aa..a8cae64bf 100644 --- a/dvc/commands/data_sync.py +++ b/dvc/commands/data_sync.py @@ -429,5 +429,11 @@ def add_parser(subparsers, _parent_parser): default=False, help="Show status in JSON format.", ) + status_parser.add_argument( + "--no-updates", + dest="check_updates", + action="store_false", + help="Ignore updates to imported data.", + ) status_parser.set_defaults(func=CmdDataStatus) diff --git a/dvc/commands/status.py b/dvc/commands/status.py index 93a9b0327..ae90bb955 100644 --- a/dvc/commands/status.py +++ b/dvc/commands/status.py @@ -60,6 +60,7 @@ class CmdDataStatus(CmdDataBase): all_commits=self.args.all_commits, with_deps=self.args.with_deps, recursive=self.args.recursive, + check_updates=self.args.check_updates, ) except DvcException: logger.exception("") diff --git a/dvc/repo/status.py b/dvc/repo/status.py index 1aab0a466..f0620adf8 100644 --- a/dvc/repo/status.py +++ b/dvc/repo/status.py @@ -8,7 +8,7 @@ from . import locked logger = logger.getChild(__name__) -def _joint_status(pairs): +def _joint_status(pairs, check_updates=True): status_info = {} for stage, filter_info in pairs: @@ -20,19 +20,23 @@ def _joint_status(pairs): ), stage, ) - status_info.update(stage.status(check_updates=True, filter_info=filter_info)) + status_info.update( + stage.status(check_updates=check_updates, filter_info=filter_info) + ) return status_info -def _local_status(self, targets=None, with_deps=False, recursive=False): +def _local_status( + self, targets=None, with_deps=False, recursive=False, check_updates=True +): targets = targets or [None] pairs = chain.from_iterable( self.stage.collect_granular(t, with_deps=with_deps, recursive=recursive) for t in targets ) - return _joint_status(pairs) + return _joint_status(pairs, check_updates=check_updates) def _cloud_status( @@ -100,7 +104,7 @@ def _cloud_status( @locked -def status( +def status( # noqa: PLR0913 self, targets=None, jobs=None, @@ -111,6 +115,7 @@ def status( all_tags=False, all_commits=False, recursive=False, + check_updates=True, ): if isinstance(targets, str): targets = [targets] @@ -138,4 +143,10 @@ def status( msg = "The following options are meaningless for local status: {}" raise InvalidArgumentError(msg.format(", ".join(ignored))) - return _local_status(self, targets, with_deps=with_deps, recursive=recursive) + return _local_status( + self, + targets, + with_deps=with_deps, + recursive=recursive, + check_updates=check_updates, + ) diff --git a/tests/func/test_status.py b/tests/func/test_status.py index e624a9924..84964d6bf 100644 --- a/tests/func/test_status.py +++ b/tests/func/test_status.py @@ -1,5 +1,7 @@ import os +import pytest + from dvc.cli import main from dvc.fs import localfs @@ -30,19 +32,25 @@ def test_implied_cloud(dvc, mocker): assert mock_status.called -def test_status_non_dvc_repo_import(tmp_dir, dvc, git_dir): +@pytest.mark.parametrize("check_updates", [True, False]) +def test_status_non_dvc_repo_import(tmp_dir, dvc, git_dir, check_updates): with git_dir.branch("branch", new=True): git_dir.scm_gen("file", "first version", commit="first version") dvc.imp(os.fspath(git_dir), "file", "file", rev="branch") - assert dvc.status(["file.dvc"]) == {} + assert dvc.status(["file.dvc"], check_updates=check_updates) == {} with git_dir.branch("branch", new=False): git_dir.scm_gen("file", "second version", commit="update file") - (status,) = dvc.status(["file.dvc"])["file.dvc"] - assert status == {"changed deps": {f"file ({git_dir})": "update available"}} + status = dvc.status(["file.dvc"], check_updates=check_updates) + if check_updates: + assert status == { + "file.dvc": [{"changed deps": {f"file ({git_dir})": "update available"}}] + } + else: + assert status == {} def test_status_before_and_after_dvc_init(tmp_dir, dvc, git_dir): diff --git a/tests/unit/command/test_status.py b/tests/unit/command/test_status.py index 9634e0081..3802972aa 100644 --- a/tests/unit/command/test_status.py +++ b/tests/unit/command/test_status.py @@ -41,6 +41,7 @@ def test_cloud_status(tmp_dir, dvc, mocker): all_commits=True, with_deps=True, recursive=True, + check_updates=True, ) @@ -117,3 +118,26 @@ def test_status_up_to_date(dvc, mocker, capsys, cloud_opts, expected_message): assert cmd.run() == 0 captured = capsys.readouterr() assert expected_message in captured.out + + +def test_status_check_updates(dvc, mocker, capsys): + cli_args = parse_args(["status", "--no-updates"]) + assert cli_args.func == CmdDataStatus + + cmd = cli_args.func(cli_args) + m = mocker.patch.object(cmd.repo, "status", autospec=True, return_value={}) + + assert cmd.run() == 0 + + m.assert_called_once_with( + cloud=False, + targets=[], + jobs=None, + remote=None, + all_branches=False, + all_tags=False, + all_commits=False, + with_deps=False, + recursive=False, + check_updates=False, + )