Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion copier_update/tests/test_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,19 @@ def update_repository(self, repository: Repository, answers_file: str, token: st


class CommandRecordingUpdater(Updater):
def __init__(self, client: FakeClient, *, status: str) -> None:
def __init__(self, client: FakeClient, *, status: str, invalid_diff: str = "") -> None:
super().__init__(client, now=lambda: datetime(2026, 8, 1, 12, 34, 56, tzinfo=UTC))
self.commands: list[tuple[list[str], str | None]] = []
self.status = status
self.invalid_diff = invalid_diff

def _run(self, command, *, cwd=None, token=None, capture_output=False):
command = list(command)
self.commands.append((command, token))
if command[:2] == ["git", "clone"]:
Path(command[-1]).mkdir()
if command == ["git", "diff", "--check"] and self.invalid_diff:
raise subprocess.CalledProcessError(2, command, output=self.invalid_diff)
stdout = self.status if command[:3] == ["git", "status", "--porcelain"] else ""
return subprocess.CompletedProcess(command, 0, stdout=stdout, stderr="")

Expand Down Expand Up @@ -195,3 +198,19 @@ def test_repository_update_stops_when_copier_changes_only_ignored_files():
assert not updater.update_repository(repository, ".copier-answers.yaml", "repository-token")
assert not any(command[:2] == ["git", "commit"] for command, _ in updater.commands)
assert client.pull_requests == []


def test_repository_update_stops_when_copier_leaves_conflicts():
repository = Repository(id=20, full_name="owner/repository", default_branch="main")
client = FakeClient([repository])
updater = CommandRecordingUpdater(
client,
status=" M README.md\n",
invalid_diff="README.md:1: leftover conflict marker\n",
)

with pytest.raises(RuntimeError, match="Copier produced invalid changes"):
updater.update_repository(repository, ".copier-answers.yaml", "repository-token")

assert not any(command[:2] == ["git", "push"] for command, _ in updater.commands)
assert client.pull_requests == []
5 changes: 5 additions & 0 deletions copier_update/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ def update_repository(self, repository: Repository, answers_file: str, token: st
token=token,
)
self._run(["copier", "update", "-A", "-f", "-a", answers_file], cwd=repository_path, token=token)
try:
self._run(["git", "diff", "--check"], cwd=repository_path, capture_output=True)
except subprocess.CalledProcessError as error:
details = (error.stdout or error.stderr or "").strip()
raise RuntimeError(f"Copier produced invalid changes for {repository.full_name}:\n{details}") from error

if not self._has_meaningful_changes(repository_path):
LOGGER.info("No update available for %s", repository.full_name)
Expand Down