Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: include local dirty changes by default. fixes #184 #520

Merged
merged 15 commits into from
Jan 11, 2022
Merged
69 changes: 26 additions & 43 deletions copier/vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,30 +111,6 @@ def checkout_latest_tag(local_repo: StrOrPath, use_prereleases: OptBool = False)
return latest_tag


def _perform_clone(src: str, dst: str, ref: OptStr = None) -> str:
"""Clone from src into dst.

Args:
src:
Git-parseable repo clone source.
dst:
Git-parseable repo clone destination.
ref:
Reference to checkout. For Git repos, defaults to `HEAD`.
"""
_clone = git["clone", "--no-checkout", src, dst]
# Faster clones if possible
if GIT_VERSION >= Version("2.27"):
_clone = _clone["--filter=blob:none"]
_clone()

with local.cwd(dst):
git("checkout", ref or "HEAD")
git("submodule", "update", "--checkout", "--init", "--recursive", "--force")

return dst


def clone(url: str, ref: OptStr = None) -> str:
"""Clone repo into some temporary destination.

Expand All @@ -150,29 +126,36 @@ def clone(url: str, ref: OptStr = None) -> str:
"""

location = tempfile.mkdtemp(prefix=f"{__name__}.clone.")
_clone = git["clone", "--no-checkout", url, location]
# Faster clones if possible
if GIT_VERSION >= Version("2.27"):
_clone = _clone["--filter=blob:none"]
_clone()

if os.path.exists(url) and Path(url).is_dir():
is_dirty = False
with local.cwd(url):
is_dirty = bool(git("status", "--porcelain").strip())
if is_dirty:
url_abspath = Path(url).absolute()
with TemporaryDirectory(prefix=f"{__name__}.dirty.") as src:
with local.cwd(src):
git("--git-dir=.git", f"--work-tree={url_abspath}", "init")
git("--git-dir=.git", f"--work-tree={url_abspath}", "add", "-A")
git(
"--git-dir=.git",
f"--work-tree={url_abspath}",
"commit",
"-m",
"Copier automated commit for draft changes",
"--no-verify",
)
warn(
"Dirty template changes included automatically.",
DirtyLocalWarning,
)
return _perform_clone(src, location, ref)

return _perform_clone(url, location, ref)
with local.cwd(location):
# git("--git-dir=.git", f"--work-tree={url_abspath}", "init")
sabard marked this conversation as resolved.
Show resolved Hide resolved
git("--git-dir=.git", f"--work-tree={url_abspath}", "add", "-A")
git(
"--git-dir=.git",
f"--work-tree={url_abspath}",
"commit",
"-m",
"Copier automated commit for draft changes",
"--no-verify",
)
warn(
"Dirty template changes included automatically.",
DirtyLocalWarning,
)

with local.cwd(location):
git("checkout", ref or "HEAD")
git("submodule", "update", "--checkout", "--init", "--recursive", "--force")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got the feeling that this block should be done before importing the ditty changes. However, if the test goes green I guess I'm just wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it shouldn't matter if it runs before or after. But if there is no HEAD in the case of a recently intialized repo, then this fails and would need to be called after as well. I also realized that specifying ref means that dirty changes won't be considered and so added that to the dirty checking logic.


return location
8 changes: 3 additions & 5 deletions tests/test_dirty_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ def test_copy(tmp_path_factory):
assert bool(git("status", "--porcelain").strip())


# Will fail due to lingering deleted file.
# HACK https://github.com/copier-org/copier/issues/461
# TODO Remove xfail decorator when fixed.
@pytest.mark.xfail(strict=True)
def test_update(tmp_path_factory):
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))

Expand Down Expand Up @@ -114,4 +110,6 @@ def test_update(tmp_path_factory):
p2 = str(dst / "aaaa.txt")
assert filecmp.cmp(p1, p2)
yajo marked this conversation as resolved.
Show resolved Hide resolved

assert not os.path.exists(dst / "to_delete.txt")
# HACK https://github.com/copier-org/copier/issues/461
# TODO test file deletion on update
# assert not os.path.exists(dst / "to_delete.txt")