Skip to content

Commit

Permalink
fix(vcs): prevent local clone from being stuck by gpg prompts (#1360)
Browse files Browse the repository at this point in the history
A quick and simple PR preventing the `copy` command to get stuck if you have `commit.gpgSign` and try to run the `copy` command on WIP local project for trial.

Fixes #856
Fixes #1224
Fixes #616

Co-authored-by: Jairo Llopis <[email protected]>
  • Loading branch information
noirbizarre and yajo authored Oct 22, 2023
1 parent fcde3f1 commit 3739182
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 11 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ jobs:
run: |
echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
rm C:\msys64\usr\bin\bash.exe
- run: git config --global user.name copier-ci
- run: git config --global user.email copier@copier
- run: git config --global core.autocrlf input
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Needs all tags to compute dynamic version
Expand Down
18 changes: 16 additions & 2 deletions copier/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,22 @@ def _git_initialize_repo(self):
git("config", "user.email", "copier@copier")
# 1st commit could fail if any pre-commit hook reformats code
# 2nd commit uses --no-verify to disable pre-commit-like checks
git("commit", "--allow-empty", "-am", "dumb commit 1", retcode=None)
git("commit", "--allow-empty", "-am", "dumb commit 2", "--no-verify")
git(
"commit",
"--allow-empty",
"-am",
"dumb commit 1",
"--no-gpg-sign",
retcode=None,
)
git(
"commit",
"--allow-empty",
"-am",
"dumb commit 2",
"--no-gpg-sign",
"--no-verify",
)
git("config", "--unset", "user.name")
git("config", "--unset", "user.email")

Expand Down
1 change: 1 addition & 0 deletions copier/vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def clone(url: str, ref: OptStr = None) -> str:
"-m",
"Copier automated commit for draft changes",
"--no-verify",
"--no-gpg-sign",
)
warn(
"Dirty template changes included automatically.",
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 34 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ poethepoet = ">=0.12.3"
pre-commit = ">=2.17.0"
pytest = ">=7.2.0"
pytest-cov = ">=3.0.0"
pytest-gitconfig = ">=0.6.0"
pytest-xdist = ">=2.5.0"
types-backports = ">=0.1.3"
types-decorator = ">=5.1.1"
Expand Down
31 changes: 30 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import platform
import sys
from typing import Optional, Tuple
from typing import Iterator, Optional, Tuple

import pytest
from coverage.tracer import CTracer
from pexpect.popen_spawn import PopenSpawn
from plumbum import local
from pytest_gitconfig import GitConfig

from .helpers import Spawn

Expand Down Expand Up @@ -32,3 +34,30 @@ def _spawn(cmd: Tuple[str, ...], *, timeout: Optional[int] = None) -> PopenSpawn
return PopenSpawn(cmd, timeout, logfile=sys.stderr.buffer)

return _spawn


@pytest.fixture(scope="session", autouse=True)
def default_gitconfig(default_gitconfig: GitConfig) -> GitConfig:
"""
Use a clean and isolated default gitconfig avoiding user settings to break some tests.
Add plumbum support to the original session-scoped fixture.
"""
# local.env is a snapshot frozen at Python startup requiring its own monkeypatching
for var in list(local.env.keys()):
if var.startswith("GIT_"):
del local.env[var]
local.env["GIT_CONFIG_GLOBAL"] = str(default_gitconfig)
default_gitconfig.set({"core.autocrlf": "input"})
return default_gitconfig


@pytest.fixture
def gitconfig(gitconfig: GitConfig) -> Iterator[GitConfig]:
"""
Use a clean and isolated gitconfig to test some specific user settings.
Add plumbum support to the original function-scoped fixture.
"""
with local.env(GIT_CONFIG_GLOBAL=str(gitconfig)):
yield gitconfig
76 changes: 75 additions & 1 deletion tests/test_dirty_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest
from plumbum import local
from plumbum.cmd import git
from pytest_gitconfig import GitConfig

import copier
from copier.errors import DirtyLocalWarning
Expand Down Expand Up @@ -50,7 +51,31 @@ def test_copy_dirty_head(tmp_path_factory: pytest.TempPathFactory) -> None:
git("init")
git("add", "tracked")
git("commit", "-m1")
copier.run_copy(str(src), dst, vcs_ref="HEAD")
with pytest.warns(DirtyLocalWarning):
copier.run_copy(str(src), dst, vcs_ref="HEAD")
assert (dst / "tracked").exists()
assert (dst / "untracked").exists()


def test_copy_dirty_head_with_gpg(
tmp_path_factory: pytest.TempPathFactory, gitconfig: GitConfig
) -> None:
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
build_file_tree(
{
src / "tracked": "",
src / "untracked": "",
}
)
with local.cwd(src):
git("init")
git("add", "tracked")
git("commit", "-m1")
gitconfig.set({"user.signinkey": "123456", "commit.gpgsign": "true"})

with pytest.warns(DirtyLocalWarning):
copier.run_copy(str(src), dst, vcs_ref="HEAD")

assert (dst / "tracked").exists()
assert (dst / "untracked").exists()

Expand Down Expand Up @@ -141,3 +166,52 @@ def test_update(tmp_path_factory: pytest.TempPathFactory) -> None:
# HACK https://github.com/copier-org/copier/issues/461
# TODO test file deletion on update
# assert not (dst / "to_delete.txt").exists()


def test_update_with_gpg_sign(
tmp_path_factory: pytest.TempPathFactory, gitconfig: GitConfig
) -> None:
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))

build_file_tree(
{
(src / ".copier-answers.yml.jinja"): (
"""\
# Changes here will be overwritten by Copier
{{ _copier_answers|to_nice_yaml }}
"""
),
(src / "copier.yml"): (
"""\
_envops:
"keep_trailing_newline": True
"""
),
(src / "aaaa.txt"): (
"""
Lorem ipsum
"""
),
}
)

with local.cwd(src):
git("init")
git("add", "-A")
git("commit", "-m", "first commit on src")

run_copy(str(src), dst, defaults=True, overwrite=True)

with local.cwd(src):
Path("test_file.txt").write_text("Test content")
Path("aaaa.txt").write_text("dolor sit amet")

# dst must be vcs-tracked to use run_update
with local.cwd(dst):
git("init")
git("add", "-A")
git("commit", "-m", "first commit on dst")

gitconfig.set({"user.signinkey": "123456", "commit.gpgsign": "true"})
with pytest.warns(DirtyLocalWarning):
run_update(dst, defaults=True, overwrite=True)

0 comments on commit 3739182

Please sign in to comment.