Repository: copier-org/copier
Pull request #1832 (2024-10-23 13:38:50)

build(renovate): configure semantic commit type `build`
I've re-configured Renovate to use the semantic commit type `build` for all commits. The previous setting was behaving differently than I thought. I thought `fix` would only be used when also the manifest was updated, but it turns out that any runtime dependency updates would use `fix`. This is not desirable when maintaining a _library_ because lock file updates shouldn't be communicated to the users in the changelog. Thus, I've removed the previous configuration and added an override preset to use `build` for all updates.


Patch:
diff --git a/copier/main.py b/copier/main.py
index b616bb0..bb514fb 100644
--- a/copier/main.py
+++ b/copier/main.py
@@ -520,7 +520,7 @@ class Worker:
 
         self.answers = result
 
-    @cached_property
+    @property
     def answers_relpath(self) -> Path:
         """Obtain the proper relative path for the answers file.
 
diff --git a/copier/tools.py b/copier/tools.py
index 983e712..d2f5f06 100644
--- a/copier/tools.py
+++ b/copier/tools.py
@@ -230,16 +230,15 @@ def get_git_objects_dir(path: Path) -> Path:
     from .vcs import get_git
 
     git = get_git()
-    return Path(
+    return path.joinpath(
         git(
             "-C",
             path,
             "rev-parse",
-            "--path-format=absolute",
             "--git-path",
             "objects",
         ).strip()
-    )
+    ).absolute()
 
 
 def set_git_alternates(*repos: Path, path: Path = Path(".")) -> None:
diff --git a/poetry.lock b/poetry.lock
index 5d3e70b..27faad0 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -667,13 +667,13 @@ pyyaml = ">=5.1"
 
 [[package]]
 name = "mkdocs-material"
-version = "9.5.42"
+version = "9.5.43"
 description = "Documentation that simply works"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316"},
-    {file = "mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2"},
+    {file = "mkdocs_material-9.5.43-py3-none-any.whl", hash = "sha256:4aae0664c456fd12837a3192e0225c17960ba8bf55d7f0a7daef7e4b0b914a34"},
+    {file = "mkdocs_material-9.5.43.tar.gz", hash = "sha256:83be7ff30b65a1e4930dfa4ab911e75780a3afc9583d162692e434581cb46979"},
 ]
 
 [package.dependencies]
@@ -1199,17 +1199,17 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
 
 [[package]]
 name = "pytest-cov"
-version = "5.0.0"
+version = "6.0.0"
 description = "Pytest plugin for measuring coverage."
 optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
 files = [
-    {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
-    {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
+    {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
+    {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
 ]
 
 [package.dependencies]
-coverage = {version = ">=5.2.1", extras = ["toml"]}
+coverage = {version = ">=7.5", extras = ["toml"]}
 pytest = ">=4.6"
 
 [package.extras]
@@ -1572,13 +1572,13 @@ files = [
 
 [[package]]
 name = "types-psutil"
-version = "6.1.0.20241022"
+version = "6.1.0.20241102"
 description = "Typing stubs for psutil"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "types-psutil-6.1.0.20241022.tar.gz", hash = "sha256:aa2a6d4accea4b2ef1feee82959d9d9e99568fefa3c872bbc38c21c39dacaf1c"},
-    {file = "types_psutil-6.1.0.20241022-py3-none-any.whl", hash = "sha256:df526391733c5ad8bfe1fe98b43e5ac2a1e0ce5d398574575dabcc7fabc9ea54"},
+    {file = "types-psutil-6.1.0.20241102.tar.gz", hash = "sha256:8cbe086b9c29f5c0aa55c4422498c07a8e506f096205761dba088905198551dc"},
+    {file = "types_psutil-6.1.0.20241102-py3-none-any.whl", hash = "sha256:61f836f8ba48f28f0d290d3bcd902f9130ce5057a1676e6ecbefb6141e2743f4"},
 ]
 
 [[package]]
@@ -1741,4 +1741,4 @@ type = ["pytest-mypy"]
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.9"
-content-hash = "2faadc22481219780bbf25b968d5391829a1e2833281e7b0f6947e97d7697008"
+content-hash = "ff0c17bbced2ef047a991d8a2905dcbba444ddae6b0a245be25e1b7d05db52d3"
diff --git a/pyproject.toml b/pyproject.toml
index 601fcec..904b7bb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -56,7 +56,7 @@ pytest-gitconfig = ">=0.6.0"
 pytest-xdist = ">=2.5.0"
 types-backports = ">=0.1.3"
 types-colorama = ">=0.4"
-types-psutil = "*"
+types-psutil = ">=0"
 types-pygments = ">=2.17"
 types-pyyaml = ">=6.0.4"
 typing-extensions = { version = ">=3.10.0.0,<5.0.0", python = "<3.10" }
diff --git a/renovate.json b/renovate.json
index 9bb857f..2245d7f 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,6 +1,6 @@
 {
   "$schema": "https://docs.renovatebot.com/renovate-schema.json",
-  "extends": ["config:recommended"],
+  "extends": ["config:recommended", ":semanticCommitType(build)"],
   "nix": {
     "enabled": true
   },
@@ -17,14 +17,6 @@
     {
       "matchManagers": ["github-actions"],
       "addLabels": ["github_actions"]
-    },
-    {
-      "matchPackageNames": ["*"],
-      "semanticCommitType": "build"
-    },
-    {
-      "matchDepTypes": ["dependencies"],
-      "semanticCommitType": "fix"
     }
   ]
 }


Test patch:
diff --git a/tests/test_answersfile_templating.py b/tests/test_answersfile_templating.py
index dbf68bd..6a951b8 100644
--- a/tests/test_answersfile_templating.py
+++ b/tests/test_answersfile_templating.py
@@ -78,3 +78,43 @@ def test_answersfile_templating(
     assert (tmp_path / first_answers_file).exists()
     answers = load_answersfile_data(tmp_path, first_answers_file)
     assert answers["module_name"] == "mymodule"
+
+
+def test_answersfile_templating_with_message_before_copy(
+    tmp_path_factory: pytest.TempPathFactory,
+) -> None:
+    """Test templated `_answers_file` setting with `_message_before_copy`.
+
+    Checks that the tempated answers file name is rendered correctly while
+    having printing a message before the "copy" operation, which uses the render
+    context before including any answers from the questionnaire.
+    """
+    src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
+    build_file_tree(
+        {
+            (src / "copier.yml"): (
+                """\
+                _answers_file: ".copier-answers-{{ module_name }}.yml"
+                _message_before_copy: "Hello world"
+
+                module_name:
+                    type: str
+                """
+            ),
+            (src / "{{ _copier_conf.answers_file }}.jinja"): (
+                """\
+                # Changes here will be overwritten by Copier
+                {{ _copier_answers|to_nice_yaml }}
+                """
+            ),
+            (src / "result.txt.jinja"): "{{ module_name }}",
+        }
+    )
+    copier.run_copy(
+        str(src), dst, data={"module_name": "mymodule"}, overwrite=True, unsafe=True
+    )
+    assert (dst / ".copier-answers-mymodule.yml").exists()
+    answers = load_answersfile_data(dst, ".copier-answers-mymodule.yml")
+    assert answers["module_name"] == "mymodule"
+    assert (dst / "result.txt").exists()
+    assert (dst / "result.txt").read_text() == "mymodule"
diff --git a/tests/test_updatediff.py b/tests/test_updatediff.py
index 0aca3f4..4105318 100644
--- a/tests/test_updatediff.py
+++ b/tests/test_updatediff.py
@@ -1652,3 +1652,55 @@ def test_update_dont_validate_computed_value(
     run_update(dst, overwrite=True)
     answers = yaml.safe_load(answers_file.read_text())
     assert "computed" not in answers
+
+
+def test_update_git_submodule(tmp_path_factory: pytest.TempPathFactory) -> None:
+    src, dst, submodule = map(tmp_path_factory.mktemp, ("src", "dst", "submodule"))
+
+    with local.cwd(src):
+        build_file_tree(
+            {
+                "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}",
+                "version.txt": "v1",
+            }
+        )
+        git("init")
+        git("add", ".")
+        git("commit", "-m1")
+        git("tag", "v1")
+
+    run_copy(str(src), submodule)
+
+    with local.cwd(submodule):
+        git("init")
+        git("add", ".")
+        git("commit", "-m1")
+
+    assert (submodule / ".copier-answers.yml").is_file()
+    assert (submodule / "version.txt").is_file()
+    assert (submodule / "version.txt").read_text() == "v1"
+
+    with local.cwd(dst):
+        git("init")
+        # See https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85
+        # for more details on why we need to set `protocol.file.allow=always` to
+        # be able to clone a local submodule.
+        git("-c", "protocol.file.allow=always", "submodule", "add", submodule, "sub")
+        git("add", ".")
+        git("commit", "-m", "add submodule")
+
+    assert (dst / "sub" / ".copier-answers.yml").is_file()
+    assert (dst / "sub" / "version.txt").is_file()
+    assert (dst / "sub" / "version.txt").read_text() == "v1"
+
+    with local.cwd(src):
+        build_file_tree({"version.txt": "v2"})
+        git("add", ".")
+        git("commit", "-m2")
+        git("tag", "v2")
+
+    run_update(dst / "sub", overwrite=True)
+
+    assert (dst / "sub" / ".copier-answers.yml").is_file()
+    assert (dst / "sub" / "version.txt").is_file()
+    assert (dst / "sub" / "version.txt").read_text() == "v2"