mirror of
https://github.com/copier-org/copier.git
synced 2025-05-05 15:32:54 +00:00
336 lines
11 KiB
Python
336 lines
11 KiB
Python
from pathlib import Path
|
|
from textwrap import dedent
|
|
from typing import Literal
|
|
|
|
import pytest
|
|
from plumbum import local
|
|
|
|
import copier
|
|
from copier._user_data import load_answersfile_data
|
|
|
|
from .helpers import BRACKET_ENVOPS_JSON, SUFFIX_TMPL, build_file_tree, git, git_init
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def template_path(tmp_path_factory: pytest.TempPathFactory) -> str:
|
|
root = tmp_path_factory.mktemp("template")
|
|
build_file_tree(
|
|
{
|
|
(root / "api_project" / "api_readme.md"): "",
|
|
(root / "api_project" / "[[ _copier_conf.answers_file ]].tmpl"): (
|
|
"[[ _copier_answers|to_nice_yaml ]]"
|
|
),
|
|
(root / "conf_project" / "conf_readme.md"): (
|
|
"""\
|
|
# Template subdirectory
|
|
|
|
This is the template README.
|
|
"""
|
|
),
|
|
(root / "conf_project" / "conf_readme.md.tmpl"): (
|
|
"""\
|
|
# Demo subdirectory
|
|
|
|
Generated using previous answers `_subdirectory` value.
|
|
"""
|
|
),
|
|
(root / "conf_project" / "[[ _copier_conf.answers_file ]].tmpl"): (
|
|
"[[ _copier_answers|to_nice_yaml ]]"
|
|
),
|
|
(root / "conf_project" / "[[ filename ]].tmpl"): (
|
|
"[[ filename ]] contents"
|
|
),
|
|
(root / "copier.yml"): (
|
|
f"""\
|
|
_templates_suffix: {SUFFIX_TMPL}
|
|
_envops: {BRACKET_ENVOPS_JSON}
|
|
choose_subdir:
|
|
type: str
|
|
default: conf_project
|
|
choices:
|
|
- api_project
|
|
- conf_project
|
|
_subdirectory: "[[ choose_subdir ]]"
|
|
filename:
|
|
type: str
|
|
default: mock_filename
|
|
"""
|
|
),
|
|
}
|
|
)
|
|
with local.cwd(root):
|
|
git_init()
|
|
return str(root)
|
|
|
|
|
|
def test_copy_subdirectory_api_option(template_path: str, tmp_path: Path) -> None:
|
|
copier.run_copy(
|
|
template_path,
|
|
tmp_path,
|
|
defaults=True,
|
|
overwrite=True,
|
|
data={"choose_subdir": "api_project"},
|
|
)
|
|
assert (tmp_path / "api_readme.md").exists()
|
|
assert not (tmp_path / "conf_readme.md").exists()
|
|
|
|
|
|
def test_copy_subdirectory_config(template_path: str, tmp_path: Path) -> None:
|
|
copier.run_copy(template_path, tmp_path, defaults=True, overwrite=True)
|
|
assert (tmp_path / "conf_readme.md").exists()
|
|
assert not (tmp_path / "api_readme.md").exists()
|
|
|
|
|
|
def test_copy_subdirectory_config_no_overwrite(
|
|
template_path: str, tmp_path: Path
|
|
) -> None:
|
|
copier.run_copy(template_path, tmp_path, defaults=True, overwrite=False)
|
|
assert (tmp_path / "conf_readme.md").exists()
|
|
assert (tmp_path / "mock_filename").exists()
|
|
assert "mock_filename contents" in (tmp_path / "mock_filename").read_text()
|
|
assert "# Demo subdirectory" in (tmp_path / "conf_readme.md").read_text()
|
|
assert "# Template subdirectory" not in (tmp_path / "conf_readme.md").read_text()
|
|
assert not (tmp_path / "api_readme.md").exists()
|
|
|
|
|
|
def test_update_subdirectory(template_path: str, tmp_path: Path) -> None:
|
|
copier.run_copy(template_path, tmp_path, defaults=True, overwrite=True)
|
|
|
|
with local.cwd(tmp_path):
|
|
git_init()
|
|
|
|
copier.run_update(dst_path=tmp_path, defaults=True, overwrite=True)
|
|
assert not (tmp_path / "conf_project").exists()
|
|
assert not (tmp_path / "api_project").exists()
|
|
assert not (tmp_path / "api_readme.md").exists()
|
|
assert (tmp_path / "conf_readme.md").exists()
|
|
|
|
|
|
def test_update_subdirectory_from_root_path(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
with local.cwd(src):
|
|
build_file_tree(
|
|
{
|
|
"copier.yaml": (
|
|
"""\
|
|
q1:
|
|
type: str
|
|
default: a1
|
|
"""
|
|
),
|
|
"file1.jinja": (
|
|
"""\
|
|
version 1
|
|
hello
|
|
{{ q1 }}
|
|
bye
|
|
"""
|
|
),
|
|
"{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}",
|
|
}
|
|
)
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m1")
|
|
git("tag", "1")
|
|
build_file_tree(
|
|
{
|
|
"file1.jinja": (
|
|
"""\
|
|
version 2
|
|
hello
|
|
{{ q1 }}
|
|
bye
|
|
"""
|
|
),
|
|
}
|
|
)
|
|
git("commit", "-am2")
|
|
git("tag", "2")
|
|
with local.cwd(dst):
|
|
build_file_tree({"dst_top_file": "one"})
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m0")
|
|
copier.run_copy(
|
|
str(src),
|
|
dst / "subfolder",
|
|
vcs_ref="1",
|
|
defaults=True,
|
|
overwrite=True,
|
|
answers_file=".custom.copier-answers.yaml",
|
|
)
|
|
assert (dst / "subfolder" / "file1").read_text() == "version 1\nhello\na1\nbye\n"
|
|
with local.cwd(dst):
|
|
git("add", ".")
|
|
git("commit", "-m1")
|
|
copier.run_update(
|
|
"subfolder",
|
|
defaults=True,
|
|
overwrite=True,
|
|
answers_file=".custom.copier-answers.yaml",
|
|
)
|
|
answers = load_answersfile_data(dst / "subfolder", ".custom.copier-answers.yaml")
|
|
assert answers["_commit"] == "2"
|
|
assert (dst / "subfolder" / "file1").read_text() == "version 2\nhello\na1\nbye\n"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"conflict, readme, expect_reject",
|
|
[
|
|
(
|
|
"rej",
|
|
"upstream version 2\n",
|
|
True,
|
|
),
|
|
(
|
|
"inline",
|
|
dedent(
|
|
"""\
|
|
<<<<<<< before updating
|
|
downstream version 1
|
|
=======
|
|
upstream version 2
|
|
>>>>>>> after updating
|
|
"""
|
|
),
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_new_version_uses_subdirectory(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
conflict: Literal["rej", "inline"],
|
|
readme: str,
|
|
expect_reject: bool,
|
|
) -> None:
|
|
# Template in v1 doesn't have a _subdirectory;
|
|
# in v2 it moves all things into a subdir and adds that key to copier.yml.
|
|
# Some files change. Downstream project has evolved too. Does that work as expected?
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
|
|
# First, create the template with an initial README
|
|
build_file_tree(
|
|
{
|
|
(src / "README.md"): "upstream version 1",
|
|
(src / "{{_copier_conf.answers_file}}.jinja"): (
|
|
"{{_copier_answers|to_nice_yaml}}"
|
|
),
|
|
}
|
|
)
|
|
with local.cwd(src):
|
|
git_init("hello template")
|
|
git("tag", "v1")
|
|
|
|
# Generate the project a first time, assert the README exists
|
|
copier.run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
assert (dst / "README.md").exists()
|
|
assert load_answersfile_data(dst).get("_commit") == "v1"
|
|
|
|
# Start versioning the generated project
|
|
with local.cwd(dst):
|
|
git_init("hello project")
|
|
|
|
# After first commit, change the README, commit again
|
|
Path("README.md").write_text("downstream version 1")
|
|
git("commit", "-am", "updated readme")
|
|
|
|
# Now change the template
|
|
with local.cwd(src):
|
|
# Update the README
|
|
Path("README.md").write_text("upstream version 2")
|
|
|
|
# Create a subdirectory, move files into it
|
|
subdir = Path("subdir")
|
|
subdir.mkdir()
|
|
Path("README.md").rename(subdir / "README.md")
|
|
Path("{{_copier_conf.answers_file}}.jinja").rename(
|
|
subdir / "{{_copier_conf.answers_file}}.jinja"
|
|
)
|
|
|
|
# Add the subdirectory option to copier.yml
|
|
Path("copier.yml").write_text(f"_subdirectory: {subdir}")
|
|
|
|
# Commit the changes
|
|
git("add", ".", "-A")
|
|
git("commit", "-m", "use a subdirectory now")
|
|
git("tag", "v2")
|
|
|
|
# Finally, update the generated project
|
|
copier.run_update(dst_path=dst, defaults=True, overwrite=True, conflict=conflict)
|
|
assert load_answersfile_data(dst).get("_commit") == "v2"
|
|
|
|
# Assert that the README still exists, and the conflicts were handled
|
|
# correctly.
|
|
assert (dst / "README.md").exists()
|
|
|
|
assert (dst / "README.md").read_text().splitlines() == readme.splitlines()
|
|
assert (dst / "README.md.rej").exists() == expect_reject
|
|
|
|
# Also assert the subdirectory itself was not rendered
|
|
assert not (dst / subdir).exists()
|
|
|
|
|
|
def test_new_version_changes_subdirectory(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
) -> None:
|
|
# Template in v3 changes from one subdirectory to another.
|
|
# Some file evolves also. Sub-project evolves separately.
|
|
# Sub-project is updated. Does that work as expected?
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
|
|
# First, create the template with an initial subdirectory and README inside it
|
|
build_file_tree(
|
|
{
|
|
(src / "copier.yml"): "_subdirectory: subdir1\n",
|
|
(src / "subdir1" / "[[_copier_conf.answers_file]].tmpl"): (
|
|
"[[_copier_answers|to_nice_yaml]]\n"
|
|
),
|
|
(src / "subdir1" / "README.md"): "upstream version 1\n",
|
|
}
|
|
)
|
|
with local.cwd(src):
|
|
git_init("hello template")
|
|
|
|
# Generate the project a first time, assert the README exists
|
|
copier.run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
assert (dst / "README.md").exists()
|
|
|
|
# Start versioning the generated project
|
|
with local.cwd(dst):
|
|
git_init("hello project")
|
|
|
|
# After first commit, change the README, commit again
|
|
Path("README.md").write_text("downstream version 1\n")
|
|
git("commit", "-am", "updated readme")
|
|
|
|
# Now change the template
|
|
with local.cwd(src):
|
|
# Update the README
|
|
Path("subdir1", "README.md").write_text("upstream version 2\n")
|
|
|
|
# Rename the subdirectory
|
|
Path("subdir1").rename("subdir2")
|
|
|
|
# Update copier.yml to reflect this change
|
|
Path("copier.yml").write_text("_subdirectory: subdir2\n")
|
|
|
|
# Commit the changes
|
|
git("add", ".", "-A")
|
|
git("commit", "-m", "changed from subdir1 to subdir2")
|
|
|
|
# Finally, update the generated project
|
|
copier.run_copy(
|
|
str(src), dst, defaults=True, overwrite=True, skip_if_exists=["README.md"]
|
|
)
|
|
|
|
# Assert that the README still exists, and was NOT force updated
|
|
assert (dst / "README.md").exists()
|
|
assert (dst / "README.md").read_text() == "downstream version 1\n"
|
|
|
|
# Also assert the subdirectories themselves were not rendered
|
|
assert not (dst / "subdir1").exists()
|
|
assert not (dst / "subdir2").exists()
|