Skip to content

Commit 6104b0f

Browse files
committed
Add generation tests for private repos
Golden tests are done for all repo types setting them as private repos, and a full generation integration smoke test is done for an API private repo. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
1 parent 81d0538 commit 6104b0f

202 files changed

Lines changed: 9591 additions & 18 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

tests/integration/test_cookiecutter_generation.py

Lines changed: 113 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,25 @@
2626
"""
2727

2828

29-
@pytest.mark.integration
30-
@pytest.mark.cookiecutter
31-
@pytest.mark.parametrize("repo_type", [*config.RepositoryType])
32-
def test_golden(
33-
tmp_path: pathlib.Path,
34-
repo_type: config.RepositoryType,
35-
request: pytest.FixtureRequest,
36-
) -> None:
37-
"""Test generation of a new repo comparing it to a golden tree."""
29+
PROPRIETARY_TEST_REPO_TYPE = config.RepositoryType.API
30+
31+
32+
def _license_context(license_name: str) -> dict[str, str] | None:
33+
"""Get extra cookiecutter context for a license override."""
34+
if license_name == "MIT":
35+
return None
36+
return {"license": license_name}
37+
38+
39+
def _golden_case_name(repo_type: config.RepositoryType, *, license_name: str) -> str:
40+
"""Get the golden test case name for a repository type and license."""
41+
if license_name == "MIT":
42+
return repo_type.value
43+
return f"{repo_type.value}-{license_name.lower()}"
44+
45+
46+
def _golden_test_env() -> dict[str, str]:
47+
"""Get a deterministic environment for golden cookiecutter tests."""
3848
env = os.environ.copy()
3949
env.update(
4050
# Make sure file sorting, dates, etc. are deterministic.
@@ -45,17 +55,31 @@ def test_golden(
4555
# some flaky outputs can be disabled.
4656
GOLDEN_TEST="1",
4757
)
58+
return env
4859

60+
61+
def _assert_golden_generation(
62+
tmp_path: pathlib.Path,
63+
repo_type: config.RepositoryType,
64+
request: pytest.FixtureRequest,
65+
*,
66+
license_name: str = "MIT",
67+
) -> None:
68+
"""Assert a generated repository matches its golden files."""
4969
cwd = pathlib.Path().cwd()
5070
golden_path = (
5171
cwd
5272
/ "tests_golden"
5373
/ request.path.relative_to(cwd / "tests").with_suffix("")
54-
/ repo_type.value
74+
/ _golden_case_name(repo_type, license_name=license_name)
5575
)
5676

5777
generated_repo_path, run_result = _generate_repo(
58-
repo_type, tmp_path, capture_output=True, env=env
78+
repo_type,
79+
tmp_path,
80+
capture_output=True,
81+
extra_context=_license_context(license_name),
82+
env=_golden_test_env(),
5983
)
6084
stdout, stderr = _filter_generation_output(run_result)
6185
_assert_golden_file(golden_path, "cookiecutter-stdout", stdout)
@@ -66,23 +90,88 @@ def test_golden(
6690
)
6791

6892

69-
@pytest.mark.integration
70-
@pytest.mark.cookiecutter
71-
@pytest.mark.parametrize("repo_type", [*config.RepositoryType])
72-
def test_generation(tmp_path: pathlib.Path, repo_type: config.RepositoryType) -> None:
73-
"""Test generation of a new repo."""
93+
def _assert_generated_repo_checks(
94+
tmp_path: pathlib.Path,
95+
repo_type: config.RepositoryType,
96+
*,
97+
license_name: str = "MIT",
98+
) -> None:
99+
"""Assert a generated repository passes the basic nox checks."""
74100
cwd = pathlib.Path().cwd()
75-
repo_path, _ = _generate_repo(repo_type, tmp_path)
101+
repo_path, _ = _generate_repo(
102+
repo_type, tmp_path, extra_context=_license_context(license_name)
103+
)
76104
_run(repo_path, "python3", "-m", "venv", ".venv")
77105

78106
_update_pyproject_repo_config_dep(
79107
repo_config_path=cwd, repo_type=repo_type, repo_path=repo_path
80108
)
81109

110+
env = os.environ.copy()
111+
env["SETUPTOOLS_SCM_PRETEND_VERSION_FOR_FREQUENZ_REPO_CONFIG"] = "0.0.0"
82112
cmd = ". .venv/bin/activate; pip install .[dev-noxfile]; nox -e ci_checks_max pytest_min"
83113
print()
84114
print(f"Running in shell [{repo_path}]: {cmd}")
85-
subprocess.run(cmd, shell=True, cwd=repo_path, check=True)
115+
subprocess.run(cmd, shell=True, cwd=repo_path, check=True, env=env)
116+
117+
118+
@pytest.mark.integration
119+
@pytest.mark.cookiecutter
120+
@pytest.mark.parametrize(
121+
("repo_type", "license_name"),
122+
[
123+
*(
124+
pytest.param(repo_type, "MIT", id=repo_type.value)
125+
for repo_type in config.RepositoryType
126+
),
127+
*(
128+
pytest.param(
129+
repo_type,
130+
"Proprietary",
131+
id=f"{repo_type.value}-proprietary",
132+
)
133+
for repo_type in config.RepositoryType
134+
),
135+
],
136+
)
137+
def test_golden(
138+
tmp_path: pathlib.Path,
139+
repo_type: config.RepositoryType,
140+
license_name: str,
141+
request: pytest.FixtureRequest,
142+
) -> None:
143+
"""Test generation of a new repo comparing it to a golden tree."""
144+
_assert_golden_generation(
145+
tmp_path,
146+
repo_type,
147+
request,
148+
license_name=license_name,
149+
)
150+
151+
152+
@pytest.mark.integration
153+
@pytest.mark.cookiecutter
154+
@pytest.mark.parametrize(
155+
("repo_type", "license_name"),
156+
[
157+
*(
158+
pytest.param(repo_type, "MIT", id=repo_type.value)
159+
for repo_type in config.RepositoryType
160+
),
161+
pytest.param(
162+
PROPRIETARY_TEST_REPO_TYPE,
163+
"Proprietary",
164+
id=f"{PROPRIETARY_TEST_REPO_TYPE.value}-proprietary",
165+
),
166+
],
167+
)
168+
def test_generation(
169+
tmp_path: pathlib.Path,
170+
repo_type: config.RepositoryType,
171+
license_name: str,
172+
) -> None:
173+
"""Test generation of a new repo."""
174+
_assert_generated_repo_checks(tmp_path, repo_type, license_name=license_name)
86175

87176

88177
def _generate_repo(
@@ -91,9 +180,14 @@ def _generate_repo(
91180
/,
92181
*,
93182
capture_output: bool = False,
183+
extra_context: dict[str, str] | None = None,
94184
env: dict[str, str] | None = None,
95185
) -> tuple[pathlib.Path, subprocess.CompletedProcess[bytes]]:
96186
cwd = pathlib.Path().cwd()
187+
extra_args: list[str] = []
188+
if extra_context:
189+
extra_args.extend(f"{key}={value}" for key, value in extra_context.items())
190+
97191
run_result = _run(
98192
tmp_path,
99193
"cookiecutter",
@@ -102,6 +196,7 @@ def _generate_repo(
102196
f"type={repo_type.value}",
103197
"name=test",
104198
"description=Test description",
199+
*extra_args,
105200
capture_output=capture_output,
106201
env=env,
107202
)

tests_golden/integration/test_cookiecutter_generation/actor-proprietary/cookiecutter-stderr.txt

Whitespace-only changes.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
./.github/ISSUE_TEMPLATE/bug.yml: # TODO(cookiecutter): Add other parts
2+
./.github/ISSUE_TEMPLATE/config.yml: # TODO(cookiecutter): Make sure the GitHub repository has a discussion category "Support"
3+
./.github/keylabeler.yml: # TODO(cookiecutter): Add other parts
4+
./.github/labeler.yml:# TODO(cookiecutter): Add different parts of the source
5+
./CODEOWNERS:# TODO(cookiecutter): Add more specific code-owners, check if the default is correct
6+
./CODEOWNERS:* TODO(cookiecutter): Add codeowners (like @{github_org}/some-team)# Temporary, should probably change
7+
./README.md:TODO(cookiecutter): Improve the README file
8+
./mkdocs.yml: # TODO(cookiecutter): You might want to add other external references here
9+
./mkdocs.yml: # TODO(cookiecutter): You might want to change the logo, the file is located in "docs/"
10+
./mkdocs.yml: # TODO(cookiecutter): You probably want to update the social links
11+
./mkdocs.yml:# TODO(cookiecutter): "v0.x.x" is the GitHub repo default branch, you might want to update it
12+
./pyproject.toml:# TODO(cookiecutter): Remove and add more classifiers if appropriate
13+
./pyproject.toml:# TODO(cookiecutter): Remove and add more dependencies if appropriate
14+
./pyproject.toml:# TODO(cookiecutter): Remove and add more optional dependencies if appropriate
15+
./src/frequenz/actor/test/__init__.py:# TODO(cookiecutter): Remove this function
16+
./src/frequenz/actor/test/__init__.py:TODO(cookiecutter): Add a more descriptive module description.
17+
./tests/test_test.py:def test_test_fails() -> None: # TODO(cookiecutter): Remove
18+
./tests/test_test.py:def test_test_succeeds() -> None: # TODO(cookiecutter): Remove
19+
20+
--------------------------------------------------------------------------------
21+
22+
Your 🍪 frequenz-actor-test has been cut!
23+
24+
Here is a list of things that should be reviewed and FIXED:
25+
26+
Make sure to (create and) configure your GitHub repository too: https://frequenz-floss.github.io/frequenz-repo-config-python/latest/user-guide/start-a-new-project/configure-github/
27+
28+
After completing it you can amend the previous commit using `git commit --amend` or create a new commit for the changes using `git commit`.
29+
30+
You can make sure linting and tests pass by creating a virtual environment, installing the development dependencies and running `nox`:
31+
32+
cd frequenz-actor-test
33+
# Requires at least python version 3.11
34+
python3 -m venv .venv
35+
. .venv/bin/activate
36+
pip install .[dev-noxfile]
37+
nox
38+
39+
To generate and serve the documentation:
40+
pip install .[dev-mkdocs]
41+
mkdocs serve
42+
43+
To initialize the GitHub pages website:
44+
mike deploy --update-aliases v0.1-dev latest-dev latest
45+
mike set-default latest
46+
git push upstream gh-pages # or origin if you haven't forked the repo
47+
48+
Make sure that GitHub pages is enabled in your repository settings:
49+
https://github.com/frequenz-floss/frequenz-actor-test/settings/pages
50+
If all went well, your new website should be available soon at:
51+
https://frequenz-floss.github.io/frequenz-actor-test/
52+
53+
WARNING: Using a non-MIT license with a frequenz-floss project is not recommended.
54+
55+
If you had any issues or find any errors in the generated files, please report them!
56+
https://github.com/frequenz-floss/frequenz-repo-config-python/issues/new/choose
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"cookiecutter": {
3+
"Introduction": "",
4+
"type": "actor",
5+
"name": "test",
6+
"description": "Test description",
7+
"title": "Frequenz Test Actor",
8+
"keywords": "(comma separated: 'frequenz', <type> and <name> are included automatically)",
9+
"github_org": "frequenz-floss",
10+
"license": "Proprietary",
11+
"private_repo": "yes",
12+
"author_name": "Frequenz Energy-as-a-Service GmbH",
13+
"author_email": "floss@frequenz.com",
14+
"python_package": "frequenz.actor.test",
15+
"pypi_package_name": "frequenz-actor-test",
16+
"github_repo_name": "frequenz-actor-test",
17+
"default_codeowners": "(like @some-org/some-team; defaults to a team based on the repo type)"
18+
},
19+
"_cookiecutter": {
20+
"Introduction": "{{cookiecutter | introduction}}",
21+
"type": [
22+
"actor",
23+
"api",
24+
"app",
25+
"lib",
26+
"model"
27+
],
28+
"name": "test",
29+
"description": "Test description",
30+
"title": "{{cookiecutter | proj_title}}",
31+
"keywords": "(comma separated: 'frequenz', <type> and <name> are included automatically)",
32+
"github_org": "frequenz-floss",
33+
"license": [
34+
"Proprietary",
35+
"MIT"
36+
],
37+
"private_repo": [
38+
"{{ 'no' if cookiecutter.license == 'MIT' else 'yes' }}",
39+
"{{ 'yes' if cookiecutter.license == 'MIT' else 'no' }}"
40+
],
41+
"author_name": "Frequenz Energy-as-a-Service GmbH",
42+
"author_email": "floss@frequenz.com",
43+
"python_package": "{{cookiecutter | python_package}}",
44+
"pypi_package_name": "{{cookiecutter | pypi_package_name}}",
45+
"github_repo_name": "{{cookiecutter | github_repo_name}}",
46+
"default_codeowners": "(like @some-org/some-team; defaults to a team based on the repo type)"
47+
}
48+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
end_of_line = lf
9+
insert_final_newline = true
10+
11+
# Set default charset, indent style and trimming of whitespace
12+
[{.editorconfig,CODEOWNERS,LICENSE,*.{in,json,md,proto,py,pyi,toml,yaml,yml}}]
13+
charset = utf-8
14+
indent_style = space
15+
trim_trailing_whitespace = true
16+
17+
# 4 space indentation
18+
[*.{py,pyi}]
19+
indent_size = 4
20+
21+
# 2 space indentation
22+
[{.editorconfig,CODEOWNERS,LICENSE,*.{in,json,proto,toml,yaml,yml}}]
23+
indent_size = 2
24+
25+
# No indentation size specified for *.md because different blocks have
26+
# different indentation rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# GitHub issue form. For more information see:
2+
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms
3+
4+
name: Report something is not working properly 🐛
5+
description:
6+
Use this if there is something that is not working properly. If you are not
7+
sure or you need help making something work, please ask a question instead.
8+
labels:
9+
- "priority:❓"
10+
- "type:bug"
11+
body:
12+
- type: markdown
13+
attributes:
14+
value:
15+
Thanks for taking the time to fill out this bug report!
16+
- type: textarea
17+
id: what-happened
18+
attributes:
19+
label: What happened?
20+
description: Please tell us what happened that shouldn't have.
21+
placeholder: What happened that shouldn't have.
22+
validations:
23+
required: true
24+
- type: textarea
25+
id: what-expected
26+
attributes:
27+
label: What did you expect instead?
28+
description: Please tell us what did you expect to happen.
29+
placeholder: What did you expect to happen.
30+
validations:
31+
required: true
32+
- type: input
33+
id: version
34+
attributes:
35+
label: Affected version(s)
36+
description:
37+
Please add a comma-separated list of the versions affected by this
38+
issue.
39+
placeholder: 'Example: v0.11.0, v0.12.0'
40+
- type: dropdown
41+
id: part
42+
attributes:
43+
label: Affected part(s)
44+
description:
45+
Which parts of the repo are affected by this issue? Select all that
46+
apply.
47+
multiple: true
48+
options:
49+
- I don't know (part:❓)
50+
- Documentation (part:docs)
51+
- Unit, integration and performance tests (part:tests)
52+
- Build script, CI, dependencies, etc. (part:tooling)
53+
# TODO(cookiecutter): Add other parts
54+
# Please have in mind that that the part:xxx labels need to
55+
# be created in the GitHub repository.
56+
validations:
57+
required: true
58+
- type: textarea
59+
id: extra
60+
attributes:
61+
label: Extra information
62+
description:
63+
Please write here any extra information you think it might be relevant,
64+
e.g., if this didn't happen before, or if you suspect where the problem
65+
might be.
66+
placeholder: Any extra information you think it might be relevant.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# GitHub issue template chooser. For more information see:
2+
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
3+
4+
blank_issues_enabled: true
5+
contact_links:
6+
- name: Ask a question ❓
7+
url: https://github.com/frequenz-floss/frequenz-actor-test/discussions/new?category=support
8+
# TODO(cookiecutter): Make sure the GitHub repository has a discussion category "Support"
9+
# Rename the "Q&A" category to "Support" and change the emoji to 🆘 (SOS)
10+
about: Use this if you are not sure how to do something, have installation problems, etc.

0 commit comments

Comments
 (0)