Skip to content

Commit

Permalink
update: support specifying revision when updating (iterative#3337)
Browse files Browse the repository at this point in the history
* update: work with rev

* completion: update --rev completion scripts

* test: fix unit test assumption

* test: use fspath_py35
  • Loading branch information
skshetry authored Feb 15, 2020
1 parent 4087b02 commit 46e5053
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 12 deletions.
5 changes: 4 additions & 1 deletion dvc/command/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def run(self):
ret = 0
for target in self.args.targets:
try:
self.repo.update(target)
self.repo.update(target, self.args.rev)
except DvcException:
logger.exception("failed to update '{}'.".format(target))
ret = 1
Expand All @@ -33,4 +33,7 @@ def add_parser(subparsers, parent_parser):
update_parser.add_argument(
"targets", nargs="+", help="DVC-files to update."
)
update_parser.add_argument(
"--rev", nargs="?", help="Git revision (e.g. SHA, branch, tag)"
)
update_parser.set_defaults(func=CmdUpdate)
2 changes: 1 addition & 1 deletion dvc/dependency/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ class DependencyBase(object):
IsNotFileOrDirError = DependencyIsNotFileOrDirError
IsStageFileError = DependencyIsStageFileError

def update(self):
def update(self, rev=None):
pass
5 changes: 4 additions & 1 deletion dvc/dependency/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def download(self, to):

repo.pull_to(self.def_path, to.path_info)

def update(self):
def update(self, rev=None):
if rev:
self.def_repo[self.PARAM_REV] = rev

with self._make_repo(locked=False) as repo:
self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()
6 changes: 4 additions & 2 deletions dvc/repo/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@


@locked
def update(self, target):
def update(self, target, rev=None):
from dvc.stage import Stage

stage = Stage.load(self, target)
stage.update()
stage.update(rev)

stage.dump()

return stage
4 changes: 2 additions & 2 deletions dvc/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,11 +405,11 @@ def reproduce(self, interactive=False, **kwargs):

return self

def update(self):
def update(self, rev=None):
if not self.is_repo_import and not self.is_import:
raise StageUpdateError(self.relpath)

self.deps[0].update()
self.deps[0].update(rev=rev)
locked = self.locked
self.locked = False
try:
Expand Down
2 changes: 1 addition & 1 deletion scripts/completion/dvc.bash
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ _dvc_run='--no-exec -f --file -c --cwd -d --deps -o --outs -O --outs-no-cache --
_dvc_status='-j --jobs -r --remote -a --all-branches -T --all-tags -d --with-deps -c --cloud $(compgen -G *.dvc)'
_dvc_unlock='$(compgen -G *.dvc)'
_dvc_unprotect='$(compgen -G *)'
_dvc_update='$(compgen -G *.dvc)'
_dvc_update='--rev $(compgen -G *.dvc)'
_dvc_version=''

# Params
Expand Down
1 change: 1 addition & 0 deletions scripts/completion/dvc.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ _dvc_unprotect=(
)

_dvc_update=(
"--rev[Git revision (e.g. SHA, branch, tag)]:Revision:"
"*:Stages:_files -g '(*.dvc|Dvcfile)'"
)

Expand Down
36 changes: 35 additions & 1 deletion tests/func/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os

from dvc.stage import Stage
from dvc.compat import fspath
from dvc.compat import fspath, fspath_py35


@pytest.mark.parametrize("cached", [True, False])
Expand Down Expand Up @@ -131,3 +131,37 @@ def test_update_import_url(tmp_dir, dvc, tmp_path_factory):

assert dst.is_file()
assert dst.read_text() == "updated file content"


def test_update_rev(tmp_dir, dvc, scm, git_dir):
with git_dir.chdir():
git_dir.scm_gen({"foo": "foo"}, commit="first")

dvc.imp(fspath(git_dir), "foo")
assert (tmp_dir / "foo.dvc").exists()

with git_dir.chdir(), git_dir.branch("branch1", new=True):
git_dir.scm_gen({"foo": "foobar"}, commit="branch1 commit")
branch1_head = git_dir.scm.get_rev()

with git_dir.chdir(), git_dir.branch("branch2", new=True):
git_dir.scm_gen({"foo": "foobar foo"}, commit="branch2 commit")
branch2_head = git_dir.scm.get_rev()

stage = dvc.update("foo.dvc", rev="branch1")
assert stage.deps[0].def_repo == {
"url": fspath(git_dir),
"rev": "branch1",
"rev_lock": branch1_head,
}
with open(fspath_py35(tmp_dir / "foo")) as f:
assert "foobar" == f.read()

stage = dvc.update("foo.dvc", rev="branch2")
assert stage.deps[0].def_repo == {
"url": fspath(git_dir),
"rev": "branch2",
"rev_lock": branch2_head,
}
with open(fspath_py35(tmp_dir / "foo")) as f:
assert "foobar foo" == f.read()
10 changes: 7 additions & 3 deletions tests/unit/command/test_update.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import pytest
from dvc.cli import parse_args
from dvc.command.update import CmdUpdate


def test_update(dvc, mocker):
@pytest.mark.parametrize(
"command,rev", [(["update"], None), (["update", "--rev", "REV"], "REV")]
)
def test_update(dvc, mocker, command, rev):
targets = ["target1", "target2", "target3"]
cli_args = parse_args(["update"] + targets)
cli_args = parse_args(command + targets)
assert cli_args.func == CmdUpdate
cmd = cli_args.func(cli_args)
m = mocker.patch("dvc.repo.Repo.update")

assert cmd.run() == 0

calls = [mocker.call(target) for target in targets]
calls = [mocker.call(target, rev) for target in targets]
m.assert_has_calls(calls)

0 comments on commit 46e5053

Please sign in to comment.