Skip to content

Commit eb7a9e2

Browse files
committed
fix(updating): run tasks in Git repository with subproject's Git config
1 parent 99dc1a0 commit eb7a9e2

3 files changed

Lines changed: 66 additions & 10 deletions

File tree

copier/_main.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,15 @@ def _apply_update(self) -> None: # noqa: C901
11881188
).strip()
11891189
)
11901190
subproject_subdir = self.subproject.local_abspath.relative_to(subproject_top)
1191+
subproject_git_config_path = Path(
1192+
git(
1193+
"-C",
1194+
self.subproject.local_abspath,
1195+
"rev-parse",
1196+
"--absolute-git-dir",
1197+
).strip(),
1198+
"config",
1199+
)
11911200

11921201
with (
11931202
TemporaryDirectory(
@@ -1211,6 +1220,13 @@ def _apply_update(self) -> None: # noqa: C901
12111220
# https://github.com/orgs/copier-org/discussions/2345
12121221
exclude=[*self.template.exclude, *self.exclude],
12131222
) as old_worker:
1223+
# Initialize a Git repository in the temporary destination and configure
1224+
# it to include the Git configuration of the real destination, so
1225+
# tasks/migrations that rely on Git configuration (e.g., GitHub CLI) can
1226+
# work properly when running in the temporary destination.
1227+
with local.cwd(old_copy):
1228+
git("init")
1229+
git("config", "include.path", subproject_git_config_path)
12141230
old_worker.run_copy()
12151231
# Run pre-migration tasks
12161232
with Phase.use(Phase.MIGRATE):
@@ -1222,7 +1238,8 @@ def _apply_update(self) -> None: # noqa: C901
12221238
with local.cwd(subproject_top):
12231239
subproject_head = git("write-tree").strip()
12241240
with local.cwd(old_copy):
1225-
self._git_initialize_repo()
1241+
git("add", ".")
1242+
self._git_commit()
12261243
# Configure borrowing Git objects from the real destination.
12271244
set_git_alternates(subproject_top)
12281245
# Save a list of files that were intentionally removed in the generated
@@ -1282,9 +1299,17 @@ def _apply_update(self) -> None: # noqa: C901
12821299
exclude=exclude_plus_removed,
12831300
vcs_ref=self.resolved_vcs_ref,
12841301
) as new_worker:
1302+
# Initialize a Git repository in the temporary destination and configure
1303+
# it to include the Git configuration of the real destination, so
1304+
# tasks/migrations that rely on Git configuration (e.g., GitHub CLI) can
1305+
# work properly when running in the temporary destination.
1306+
with local.cwd(new_copy):
1307+
git("init")
1308+
git("config", "include.path", subproject_git_config_path)
12851309
new_worker.run_copy()
12861310
with local.cwd(new_copy):
1287-
self._git_initialize_repo()
1311+
git("add", ".")
1312+
self._git_commit()
12881313
new_copy_head = git("rev-parse", "HEAD").strip()
12891314
# Extract diff between temporary destination and real destination
12901315
# with some special handling of newly added files in both the project
@@ -1474,13 +1499,6 @@ def _apply_update(self) -> None: # noqa: C901
14741499
self.template.migration_tasks("after", self.subproject.template) # type: ignore[arg-type]
14751500
)
14761501

1477-
def _git_initialize_repo(self) -> None:
1478-
"""Initialize a git repository in the current directory."""
1479-
git = get_git()
1480-
git("init", retcode=None)
1481-
git("add", ".")
1482-
self._git_commit()
1483-
14841502
def _git_commit(self, message: str = "dumb commit") -> None:
14851503
git = get_git()
14861504
# 1st commit could fail if any pre-commit hook reformats code

tests/test_updatediff.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,3 +2225,36 @@ def test_render_copier_conf_as_json_without_circular_reference(
22252225

22262226
run_update(str(dst), overwrite=True, unsafe=True)
22272227
assert (dst / "copier_conf.json").exists()
2228+
2229+
2230+
def test_tasks_run_in_git_repo_with_subproject_config(
2231+
tmp_path_factory: pytest.TempPathFactory,
2232+
) -> None:
2233+
"""Test that tasks run in a Git repo with the subproject's Git config."""
2234+
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
2235+
2236+
build_file_tree(
2237+
{
2238+
(src / "{{ _copier_conf.answers_file }}.jinja"): (
2239+
"{{ _copier_answers|to_yaml }}"
2240+
),
2241+
(src / "copier.yml"): (
2242+
f"""\
2243+
_tasks:
2244+
- command: git remote get-url origin >> {dst / "git-origin-task.txt"}
2245+
when: "{{{{ _copier_operation == 'update' }}}}"
2246+
"""
2247+
),
2248+
}
2249+
)
2250+
git_save(src)
2251+
2252+
run_copy(str(src), dst, unsafe=True)
2253+
2254+
with local.cwd(dst):
2255+
git_save()
2256+
git("remote", "add", "origin", remote := "http://example.com/repo.git")
2257+
2258+
run_update(dst, unsafe=True, overwrite=True)
2259+
2260+
assert (dst / "git-origin-task.txt").read_text() == f"{remote}\n" * 3

tests/test_vcs.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,11 @@ def test_update_using_local_source_path_with_tilde(tmp_path: Path) -> None:
177177

178178
# generate project and assert correct path in answers
179179
worker = run_copy(
180-
src_path=user_src_path, dst_path=tmp_path, defaults=True, unsafe=True
180+
src_path=user_src_path,
181+
dst_path=tmp_path,
182+
defaults=True,
183+
unsafe=True,
184+
skip_tasks=True,
181185
)
182186
assert worker.answers.combined["_src_path"] == user_src_path
183187

@@ -192,6 +196,7 @@ def test_update_using_local_source_path_with_tilde(tmp_path: Path) -> None:
192196
overwrite=True,
193197
answers_file=".copier-answers.autopretty.yml",
194198
unsafe=True,
199+
skip_tasks=True,
195200
)
196201
assert worker.answers.combined["_src_path"] == user_src_path
197202

0 commit comments

Comments
 (0)