copier-project 0.28.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copier_project-0.28.0/.gitignore +23 -0
- copier_project-0.28.0/AGENTS.md +30 -0
- copier_project-0.28.0/CONTRIBUTING.md +39 -0
- copier_project-0.28.0/LICENSE +21 -0
- copier_project-0.28.0/PKG-INFO +139 -0
- copier_project-0.28.0/README.md +109 -0
- copier_project-0.28.0/copier_project/__init__.py +9 -0
- copier_project-0.28.0/copier_project/__main__.py +145 -0
- copier_project-0.28.0/copier_project/py.typed +0 -0
- copier_project-0.28.0/copier_project/repo.py +176 -0
- copier_project-0.28.0/copier_project/update.py +88 -0
- copier_project-0.28.0/docs/contributing.md +6 -0
- copier_project-0.28.0/docs/development/requirements.md +24 -0
- copier_project-0.28.0/docs/development/updates.md +27 -0
- copier_project-0.28.0/docs/development/workflow.md +68 -0
- copier_project-0.28.0/docs/index.md +8 -0
- copier_project-0.28.0/docs/license.md +10 -0
- copier_project-0.28.0/docs/project-creation.md +85 -0
- copier_project-0.28.0/docs/project-development.md +45 -0
- copier_project-0.28.0/docs/project-release.md +34 -0
- copier_project-0.28.0/docs/project-setup.md +81 -0
- copier_project-0.28.0/docs/project-updates.md +33 -0
- copier_project-0.28.0/docs/project-variants.md +73 -0
- copier_project-0.28.0/docs/releasing.md +41 -0
- copier_project-0.28.0/docs/requirements.md +28 -0
- copier_project-0.28.0/docs/setup.md +63 -0
- copier_project-0.28.0/pyproject.toml +140 -0
- copier_project-0.28.0/tests/__init__.py +0 -0
- copier_project-0.28.0/tests/cli/__init__.py +0 -0
- copier_project-0.28.0/tests/cli/test_update.py +451 -0
- copier_project-0.28.0/tests/conftest.py +118 -0
- copier_project-0.28.0/tests/template/__init__.py +0 -0
- copier_project-0.28.0/tests/template/functional/__init__.py +0 -0
- copier_project-0.28.0/tests/template/functional/conftest.py +44 -0
- copier_project-0.28.0/tests/template/functional/test_pre_commit.py +142 -0
- copier_project-0.28.0/tests/template/functional/test_tasks.py +16 -0
- copier_project-0.28.0/tests/template/meta/__init__.py +0 -0
- copier_project-0.28.0/tests/template/meta/test_copier_config.py +24 -0
- copier_project-0.28.0/tests/template/render/common/__init__.py +0 -0
- copier_project-0.28.0/tests/template/render/common/__snapshots__/test_agents.ambr +129 -0
- copier_project-0.28.0/tests/template/render/common/__snapshots__/test_commit_check.ambr +109 -0
- copier_project-0.28.0/tests/template/render/common/__snapshots__/test_pre_commit.ambr +332 -0
- copier_project-0.28.0/tests/template/render/common/__snapshots__/test_renovate.ambr +41 -0
- copier_project-0.28.0/tests/template/render/common/conftest.py +10 -0
- copier_project-0.28.0/tests/template/render/common/test_agents.py +25 -0
- copier_project-0.28.0/tests/template/render/common/test_commit_check.py +35 -0
- copier_project-0.28.0/tests/template/render/common/test_pre_commit.py +25 -0
- copier_project-0.28.0/tests/template/render/common/test_renovate.py +17 -0
- copier_project-0.28.0/tests/template/render/generic/__init__.py +0 -0
- copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_contributing.ambr +1618 -0
- copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_mise_toml.ambr +269 -0
- copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_readme.ambr +508 -0
- copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_workflows.ambr +212 -0
- copier_project-0.28.0/tests/template/render/generic/conftest.py +8 -0
- copier_project-0.28.0/tests/template/render/generic/test_contributing.py +37 -0
- copier_project-0.28.0/tests/template/render/generic/test_mise_toml.py +32 -0
- copier_project-0.28.0/tests/template/render/generic/test_readme.py +49 -0
- copier_project-0.28.0/tests/template/render/generic/test_structure.py +106 -0
- copier_project-0.28.0/tests/template/render/generic/test_workflows.py +30 -0
- copier_project-0.28.0/tests/template/render/python/__init__.py +0 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_compose.ambr +19 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_contributing.ambr +1062 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_dockerfile.ambr +175 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_docs.ambr +1570 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_license.ambr +5633 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_mise_toml.ambr +1873 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_pyproject.ambr +6585 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_readme.ambr +857 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_workflows.ambr +1728 -0
- copier_project-0.28.0/tests/template/render/python/__snapshots__/test_zensical.ambr +531 -0
- copier_project-0.28.0/tests/template/render/python/conftest.py +8 -0
- copier_project-0.28.0/tests/template/render/python/test_compose.py +29 -0
- copier_project-0.28.0/tests/template/render/python/test_contributing.py +46 -0
- copier_project-0.28.0/tests/template/render/python/test_dockerfile.py +35 -0
- copier_project-0.28.0/tests/template/render/python/test_docs.py +86 -0
- copier_project-0.28.0/tests/template/render/python/test_license.py +27 -0
- copier_project-0.28.0/tests/template/render/python/test_mise_toml.py +48 -0
- copier_project-0.28.0/tests/template/render/python/test_pyproject.py +86 -0
- copier_project-0.28.0/tests/template/render/python/test_readme.py +73 -0
- copier_project-0.28.0/tests/template/render/python/test_structure.py +154 -0
- copier_project-0.28.0/tests/template/render/python/test_workflows.py +115 -0
- copier_project-0.28.0/tests/template/render/python/test_zensical.py +53 -0
- copier_project-0.28.0/tests/template/render/questions/__init__.py +0 -0
- copier_project-0.28.0/tests/template/render/questions/test_copyright_license.py +67 -0
- copier_project-0.28.0/tests/template/render/questions/test_template_variant.py +52 -0
- copier_project-0.28.0/tests/template/utils.py +129 -0
- copier_project-0.28.0/tests/test_version.py +5 -0
- copier_project-0.28.0/tests/utils.py +57 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.egg-info/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
|
|
6
|
+
# uv and packaging
|
|
7
|
+
.venv*/
|
|
8
|
+
/build/
|
|
9
|
+
/dist/
|
|
10
|
+
uv.lock
|
|
11
|
+
|
|
12
|
+
# mise
|
|
13
|
+
mise.local.toml
|
|
14
|
+
.mise.local.toml
|
|
15
|
+
|
|
16
|
+
# Development tools
|
|
17
|
+
.cache/
|
|
18
|
+
.coverage*
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
/htmlcov/
|
|
22
|
+
/site/
|
|
23
|
+
coverage.xml
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Environment/Tools
|
|
2
|
+
|
|
3
|
+
* `mise` manages dev tools and tasks, including `uv` which manages Python and dependencies.
|
|
4
|
+
* Use `uv add`/`uv run python` instead of bare `pip`/`python`
|
|
5
|
+
* `mise install`: After-clone setup (install tools, dependencies, pre-commit hooks)
|
|
6
|
+
* `mise run lint`: Pre-commit hooks (via `pre-commit`-compatible `prek`) including lint, format, type check (ruff, ty)
|
|
7
|
+
* `mise run test`: Run tests (accepts pytest arguments)
|
|
8
|
+
* `mise run lt`: Lint+test (no arguments)
|
|
9
|
+
* `mise run snapup`: Update test snapshots (syrupy, accepts pytest arguments)
|
|
10
|
+
|
|
11
|
+
# Commit conventions
|
|
12
|
+
|
|
13
|
+
* Keep commit messages concise and in plain language, so a maintainer can
|
|
14
|
+
quickly understand the change. Use a short subject, and add a body only when
|
|
15
|
+
the change needs explaining, in a few lines about why. Don't list changed
|
|
16
|
+
files, restate the diff, or report test results.
|
|
17
|
+
* If a commit contains code or text largely generated by an LLM, add an
|
|
18
|
+
`Assisted-by: <tool>:<model>` trailer, for example with `git commit --trailer`.
|
|
19
|
+
* Don't add `Co-authored-by` or `Signed-off-by` lines for LLM tools, links to
|
|
20
|
+
LLM sessions, or promotional lines such as "Generated with [...]".
|
|
21
|
+
|
|
22
|
+
# Submitting contributions
|
|
23
|
+
|
|
24
|
+
* You may commit locally without asking. Before submitting anything, such as
|
|
25
|
+
pushing commits or creating or editing a pull request, issue, or comment,
|
|
26
|
+
show the user (who is the contributor) exactly what will be submitted, and
|
|
27
|
+
wait for their explicit approval. Submit it as approved. This includes but is
|
|
28
|
+
not limited to commit messages, titles, and bodies.
|
|
29
|
+
* Keep titles and descriptions short and specific. Don't restate what the diff
|
|
30
|
+
already shows.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Contributing to copier-project
|
|
2
|
+
|
|
3
|
+
**Contributions are welcome!**
|
|
4
|
+
|
|
5
|
+
Thank you for your time and interest in improving
|
|
6
|
+
**copier-project**!
|
|
7
|
+
|
|
8
|
+
## Contribution resources
|
|
9
|
+
|
|
10
|
+
* **Web site**: **<https://smkent.github.io/copier-project>**
|
|
11
|
+
for general project information, usage, and development documentation
|
|
12
|
+
* **Repository**: <https://github.com/smkent/copier-project>
|
|
13
|
+
for submitting pull requests
|
|
14
|
+
* **Issue tracker**: <https://github.com/smkent/copier-project/issues>
|
|
15
|
+
for questions or bug reports
|
|
16
|
+
|
|
17
|
+
## Contribution terms
|
|
18
|
+
|
|
19
|
+
By submitting a contribution to copier-project, you agree that it is
|
|
20
|
+
licensed under the project's license, the
|
|
21
|
+
[MIT License](https://github.com/smkent/copier-project/blob/main/LICENSE),
|
|
22
|
+
with no additional terms,
|
|
23
|
+
and that you have the right to submit it under that license.
|
|
24
|
+
|
|
25
|
+
## LLM use
|
|
26
|
+
|
|
27
|
+
A contributor is always the author of their contributions.
|
|
28
|
+
You must read, review, and understand everything you submit, including
|
|
29
|
+
LLM-generated code or text, and be able to explain it on request.
|
|
30
|
+
Contributions must be submitted by a person, not autonomously by a bot or
|
|
31
|
+
LLM agent.
|
|
32
|
+
|
|
33
|
+
If a commit contains code or text largely generated by an LLM, add an
|
|
34
|
+
`Assisted-by: <tool>:<model>` trailer to its message. This can be done
|
|
35
|
+
automatically with `git commit --trailer="Assisted-by: <tool>:<model>"`.
|
|
36
|
+
|
|
37
|
+
Do not use `Co-authored-by:` for LLM attribution. LLMs are tools, not authors.
|
|
38
|
+
Do not include LLM session URLs, or promotional lines such as
|
|
39
|
+
"Generated with [...]."
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stephen Kent and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: copier-project
|
|
3
|
+
Version: 0.28.0
|
|
4
|
+
Summary: Copier template for software projects with modern tooling
|
|
5
|
+
Project-URL: Homepage, https://smkent.github.io/copier-project
|
|
6
|
+
Project-URL: Repository, https://github.com/smkent/copier-project
|
|
7
|
+
Project-URL: Issues, https://github.com/smkent/copier-project/issues
|
|
8
|
+
Author-email: Stephen Kent <smkent@smkent.net>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
|
+
Classifier: Topic :: Documentation
|
|
21
|
+
Classifier: Topic :: Software Development
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: pyyaml>=6
|
|
26
|
+
Requires-Dist: rich>=15
|
|
27
|
+
Requires-Dist: typer>=0.9
|
|
28
|
+
Requires-Dist: typing-extensions>=4.1; python_version < '3.12'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# copier-project
|
|
32
|
+
|
|
33
|
+
[Copier][copier] template for software projects with modern tooling
|
|
34
|
+
|
|
35
|
+
[![Copier][copier-badge]][copier]
|
|
36
|
+
[](https://github.com/smkent/copier-project/blob/main/LICENSE)
|
|
37
|
+
[](https://pypi.org/project/copier-project/)
|
|
38
|
+
[](https://pypi.org/project/copier-project/)
|
|
39
|
+
[](https://github.com/smkent/copier-project)
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
Install required software:
|
|
44
|
+
|
|
45
|
+
- [**mise-en-place**][mise]: `curl https://mise.run | sh` or
|
|
46
|
+
[alternate installation method][mise-installation]
|
|
47
|
+
- [**Copier**][copier]: `mise use -g copier` or `uv tool install copier`
|
|
48
|
+
|
|
49
|
+
Create a new project from the template:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
copier copy "gh:smkent/copier-project" /new/project/path
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**[For more details, see the documentation!][docs-usage]**
|
|
56
|
+
|
|
57
|
+
## Variants and features
|
|
58
|
+
|
|
59
|
+
The **Generic** project variant is a language-agnostic project template with
|
|
60
|
+
features common to all project variants:
|
|
61
|
+
|
|
62
|
+
* [**mise-en-place**][mise] ("mise") for development toolchain management
|
|
63
|
+
|
|
64
|
+
[![mise][mise-badge]][mise]
|
|
65
|
+
|
|
66
|
+
* [**prek**][prek] for [pre-commit][pre-commit] compatible git hooks, with
|
|
67
|
+
[**GitHub Actions**][github-actions] CI workflow
|
|
68
|
+
|
|
69
|
+
[![prek][prek-badge]][prek]
|
|
70
|
+
|
|
71
|
+
* Contribution terms including selectable LLM use policy, with commit message
|
|
72
|
+
checks by [**commit-check**][commit-check]
|
|
73
|
+
|
|
74
|
+
[![commit-check][commit-check-badge]][commit-check]
|
|
75
|
+
|
|
76
|
+
* Update automation with [**Renovate**][renovate] and
|
|
77
|
+
[**`copier update`**][copier-update]
|
|
78
|
+
|
|
79
|
+
[![Copier][copier-badge]][copier-update]
|
|
80
|
+
[![renovate][renovate-badge]][renovate]
|
|
81
|
+
|
|
82
|
+
### Python
|
|
83
|
+
|
|
84
|
+
The **Python** project variant adds Python-specific features:
|
|
85
|
+
|
|
86
|
+
* [Astral][astral] toolset: [**uv**][uv], [**ruff**][ruff], and [**ty**][ty]
|
|
87
|
+
|
|
88
|
+
[![uv][uv-badge]][uv]
|
|
89
|
+
[![ruff][ruff-badge]][ruff]
|
|
90
|
+
[![ty][ty-badge]][ty]
|
|
91
|
+
|
|
92
|
+
* [**PyPI package**][pypi] and [**container image**][ghcr-docs] release
|
|
93
|
+
automation via [**GitHub Actions**][github-actions]
|
|
94
|
+
* [**pytest**][pytest] test framework with [**codecov.io**][codecovio] support
|
|
95
|
+
* [**Zensical**][zensical] project documentation with automatic deployment to
|
|
96
|
+
[**GitHub Pages**][github-pages]
|
|
97
|
+
|
|
98
|
+
## Credits
|
|
99
|
+
|
|
100
|
+
This template was inspired by [pawamoy/copier-uv][copier-uv] and
|
|
101
|
+
[ritwiktiwari/copier-astral][copier-astral] -- Thanks!
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
Copyright (C) 2026 Stephen Kent and contributors
|
|
106
|
+
|
|
107
|
+
Licensed under the MIT License
|
|
108
|
+
([`MIT`](https://github.com/smkent/copier-project/blob/main/LICENSE)).
|
|
109
|
+
|
|
110
|
+
[astral]: https://astral.sh
|
|
111
|
+
[codecovio]: https://codecov.io
|
|
112
|
+
[commit-check]: https://commit-check.com
|
|
113
|
+
[commit-check-badge]: https://commit-check.com/badge.svg
|
|
114
|
+
[copier-astral]: https://ritwiktiwari.github.io/copier-astral/
|
|
115
|
+
[copier-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-purple.json
|
|
116
|
+
[copier-update]: https://copier.readthedocs.io/en/stable/updating/
|
|
117
|
+
[copier-uv]: https://pawamoy.github.io/copier-uv/
|
|
118
|
+
[copier]: https://copier.readthedocs.io
|
|
119
|
+
[docs-usage]: https://smkent.github.io/copier-project/requirements/
|
|
120
|
+
[ghcr-docs]: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
|
|
121
|
+
[github-actions]: https://github.com/features/actions
|
|
122
|
+
[github-pages]: https://pages.github.com
|
|
123
|
+
[mise]: https://mise.jdx.dev
|
|
124
|
+
[mise-installation]: https://mise.jdx.dev/installing-mise.html
|
|
125
|
+
[mise-badge]: https://mise-versions.jdx.dev/badge.svg
|
|
126
|
+
[pre-commit]: https://pre-commit.com/
|
|
127
|
+
[prek-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json
|
|
128
|
+
[prek]: https://prek.j178.dev/
|
|
129
|
+
[pypi]: https://pypi.org
|
|
130
|
+
[pytest]: https://docs.pytest.org
|
|
131
|
+
[renovate-badge]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?logo=renovatebot
|
|
132
|
+
[renovate]: https://docs.renovatebot.com/
|
|
133
|
+
[ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
134
|
+
[ruff]: https://docs.astral.sh/ruff/
|
|
135
|
+
[ty-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json
|
|
136
|
+
[ty]: https://docs.astral.sh/ty/
|
|
137
|
+
[uv-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json
|
|
138
|
+
[uv]: https://docs.astral.sh/uv/
|
|
139
|
+
[zensical]: https://zensical.org/
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# copier-project
|
|
2
|
+
|
|
3
|
+
[Copier][copier] template for software projects with modern tooling
|
|
4
|
+
|
|
5
|
+
[![Copier][copier-badge]][copier]
|
|
6
|
+
[](https://github.com/smkent/copier-project/blob/main/LICENSE)
|
|
7
|
+
[](https://pypi.org/project/copier-project/)
|
|
8
|
+
[](https://pypi.org/project/copier-project/)
|
|
9
|
+
[](https://github.com/smkent/copier-project)
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
Install required software:
|
|
14
|
+
|
|
15
|
+
- [**mise-en-place**][mise]: `curl https://mise.run | sh` or
|
|
16
|
+
[alternate installation method][mise-installation]
|
|
17
|
+
- [**Copier**][copier]: `mise use -g copier` or `uv tool install copier`
|
|
18
|
+
|
|
19
|
+
Create a new project from the template:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
copier copy "gh:smkent/copier-project" /new/project/path
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**[For more details, see the documentation!][docs-usage]**
|
|
26
|
+
|
|
27
|
+
## Variants and features
|
|
28
|
+
|
|
29
|
+
The **Generic** project variant is a language-agnostic project template with
|
|
30
|
+
features common to all project variants:
|
|
31
|
+
|
|
32
|
+
* [**mise-en-place**][mise] ("mise") for development toolchain management
|
|
33
|
+
|
|
34
|
+
[![mise][mise-badge]][mise]
|
|
35
|
+
|
|
36
|
+
* [**prek**][prek] for [pre-commit][pre-commit] compatible git hooks, with
|
|
37
|
+
[**GitHub Actions**][github-actions] CI workflow
|
|
38
|
+
|
|
39
|
+
[![prek][prek-badge]][prek]
|
|
40
|
+
|
|
41
|
+
* Contribution terms including selectable LLM use policy, with commit message
|
|
42
|
+
checks by [**commit-check**][commit-check]
|
|
43
|
+
|
|
44
|
+
[![commit-check][commit-check-badge]][commit-check]
|
|
45
|
+
|
|
46
|
+
* Update automation with [**Renovate**][renovate] and
|
|
47
|
+
[**`copier update`**][copier-update]
|
|
48
|
+
|
|
49
|
+
[![Copier][copier-badge]][copier-update]
|
|
50
|
+
[![renovate][renovate-badge]][renovate]
|
|
51
|
+
|
|
52
|
+
### Python
|
|
53
|
+
|
|
54
|
+
The **Python** project variant adds Python-specific features:
|
|
55
|
+
|
|
56
|
+
* [Astral][astral] toolset: [**uv**][uv], [**ruff**][ruff], and [**ty**][ty]
|
|
57
|
+
|
|
58
|
+
[![uv][uv-badge]][uv]
|
|
59
|
+
[![ruff][ruff-badge]][ruff]
|
|
60
|
+
[![ty][ty-badge]][ty]
|
|
61
|
+
|
|
62
|
+
* [**PyPI package**][pypi] and [**container image**][ghcr-docs] release
|
|
63
|
+
automation via [**GitHub Actions**][github-actions]
|
|
64
|
+
* [**pytest**][pytest] test framework with [**codecov.io**][codecovio] support
|
|
65
|
+
* [**Zensical**][zensical] project documentation with automatic deployment to
|
|
66
|
+
[**GitHub Pages**][github-pages]
|
|
67
|
+
|
|
68
|
+
## Credits
|
|
69
|
+
|
|
70
|
+
This template was inspired by [pawamoy/copier-uv][copier-uv] and
|
|
71
|
+
[ritwiktiwari/copier-astral][copier-astral] -- Thanks!
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
Copyright (C) 2026 Stephen Kent and contributors
|
|
76
|
+
|
|
77
|
+
Licensed under the MIT License
|
|
78
|
+
([`MIT`](https://github.com/smkent/copier-project/blob/main/LICENSE)).
|
|
79
|
+
|
|
80
|
+
[astral]: https://astral.sh
|
|
81
|
+
[codecovio]: https://codecov.io
|
|
82
|
+
[commit-check]: https://commit-check.com
|
|
83
|
+
[commit-check-badge]: https://commit-check.com/badge.svg
|
|
84
|
+
[copier-astral]: https://ritwiktiwari.github.io/copier-astral/
|
|
85
|
+
[copier-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-purple.json
|
|
86
|
+
[copier-update]: https://copier.readthedocs.io/en/stable/updating/
|
|
87
|
+
[copier-uv]: https://pawamoy.github.io/copier-uv/
|
|
88
|
+
[copier]: https://copier.readthedocs.io
|
|
89
|
+
[docs-usage]: https://smkent.github.io/copier-project/requirements/
|
|
90
|
+
[ghcr-docs]: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
|
|
91
|
+
[github-actions]: https://github.com/features/actions
|
|
92
|
+
[github-pages]: https://pages.github.com
|
|
93
|
+
[mise]: https://mise.jdx.dev
|
|
94
|
+
[mise-installation]: https://mise.jdx.dev/installing-mise.html
|
|
95
|
+
[mise-badge]: https://mise-versions.jdx.dev/badge.svg
|
|
96
|
+
[pre-commit]: https://pre-commit.com/
|
|
97
|
+
[prek-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json
|
|
98
|
+
[prek]: https://prek.j178.dev/
|
|
99
|
+
[pypi]: https://pypi.org
|
|
100
|
+
[pytest]: https://docs.pytest.org
|
|
101
|
+
[renovate-badge]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?logo=renovatebot
|
|
102
|
+
[renovate]: https://docs.renovatebot.com/
|
|
103
|
+
[ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
104
|
+
[ruff]: https://docs.astral.sh/ruff/
|
|
105
|
+
[ty-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json
|
|
106
|
+
[ty]: https://docs.astral.sh/ty/
|
|
107
|
+
[uv-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json
|
|
108
|
+
[uv]: https://docs.astral.sh/uv/
|
|
109
|
+
[zensical]: https://zensical.org/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Copier template for software projects with modern tooling."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError
|
|
4
|
+
from importlib.metadata import version as import_version
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
version = import_version(__name__)
|
|
8
|
+
except PackageNotFoundError: # pragma: no cover
|
|
9
|
+
version = "0.0.0"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import TYPE_CHECKING, Annotated
|
|
8
|
+
|
|
9
|
+
from rich import print # noqa: A004
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
from rich.text import Text
|
|
14
|
+
from typer import Argument, Context, Exit, Option, Typer
|
|
15
|
+
|
|
16
|
+
from .repo import RepoTarget
|
|
17
|
+
from .update import UpdateAction
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
console = Console()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Args:
|
|
27
|
+
Repos = Annotated[
|
|
28
|
+
list[str],
|
|
29
|
+
Argument(
|
|
30
|
+
help=(
|
|
31
|
+
"Repositories to update. Accepts gh:user/repo"
|
|
32
|
+
" or github.com/user/repo."
|
|
33
|
+
)
|
|
34
|
+
),
|
|
35
|
+
]
|
|
36
|
+
DryRun = Annotated[
|
|
37
|
+
bool, Option("--dry-run", "-n", help="Skip push and PR creation.")
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
cli = Typer(
|
|
42
|
+
help="copier-project utilities",
|
|
43
|
+
add_completion=False,
|
|
44
|
+
no_args_is_help=True,
|
|
45
|
+
pretty_exceptions_enable=False,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@cli.callback()
|
|
50
|
+
def setup(ctx: Context) -> None:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class UpdateStatus(Enum):
|
|
55
|
+
UPDATED = "bold green"
|
|
56
|
+
CURRENT = "bold blue"
|
|
57
|
+
FAILED = "bold red"
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def formatted_name(self) -> Text:
|
|
61
|
+
return Text(f"{self.name:<7}", style=self.value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass
|
|
65
|
+
class UpdateResult:
|
|
66
|
+
repo: RepoTarget
|
|
67
|
+
status: UpdateStatus
|
|
68
|
+
exception: Exception | None = None
|
|
69
|
+
pr_url: str | None = None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@cli.command()
|
|
73
|
+
def update(
|
|
74
|
+
repos: Args.Repos,
|
|
75
|
+
*,
|
|
76
|
+
vcs_ref: Annotated[
|
|
77
|
+
str | None, Option("--vcs-ref", "-r", help="Template ref to update to")
|
|
78
|
+
] = None,
|
|
79
|
+
dry_run: Args.DryRun = False,
|
|
80
|
+
branch: Annotated[str, Option(help="Branch name to create.")] = "updates",
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Apply copier-project template updates to downstream repositories."""
|
|
83
|
+
results = []
|
|
84
|
+
|
|
85
|
+
repo_targets = {(target := RepoTarget(repo)).url: target for repo in repos}
|
|
86
|
+
for target in repo_targets.values():
|
|
87
|
+
try:
|
|
88
|
+
pr_url = UpdateAction(
|
|
89
|
+
target, branch=branch, vcs_ref=vcs_ref, dry_run=dry_run
|
|
90
|
+
)()
|
|
91
|
+
if pr_url:
|
|
92
|
+
results.append(
|
|
93
|
+
UpdateResult(target, UpdateStatus.UPDATED, pr_url=pr_url)
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
results.append(UpdateResult(target, UpdateStatus.CURRENT))
|
|
97
|
+
except Exception as exc: # noqa: BLE001
|
|
98
|
+
console.print_exception()
|
|
99
|
+
results.append(
|
|
100
|
+
UpdateResult(target, status=UpdateStatus.FAILED, exception=exc)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
_print_summary(results, dry_run=dry_run)
|
|
104
|
+
if any(r.status == UpdateStatus.FAILED for r in results):
|
|
105
|
+
raise Exit(1)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _print_summary(results: Sequence[UpdateResult], *, dry_run: bool) -> None:
|
|
109
|
+
if not results:
|
|
110
|
+
return
|
|
111
|
+
grid = Table.grid(padding=(0, 1), expand=True)
|
|
112
|
+
grid.add_column()
|
|
113
|
+
grid.add_column()
|
|
114
|
+
grid.add_column()
|
|
115
|
+
for result in sorted(results, key=lambda r: r.repo.github_repo):
|
|
116
|
+
grid.add_row(
|
|
117
|
+
result.status.formatted_name,
|
|
118
|
+
Text.from_markup(
|
|
119
|
+
f"[link={result.repo.url}]{result.repo.github_repo}[/link]",
|
|
120
|
+
style="bold",
|
|
121
|
+
),
|
|
122
|
+
Text(str(result.pr_url or result.exception)),
|
|
123
|
+
)
|
|
124
|
+
title = Text("Update Results", style="bold")
|
|
125
|
+
if dry_run:
|
|
126
|
+
title += Text(" (dry run)", style="green")
|
|
127
|
+
print(
|
|
128
|
+
Panel(grid, title=title, title_align="left", expand=False, padding=1)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def setup_env() -> None:
|
|
133
|
+
os.environ.pop("VIRTUAL_ENV", default=None)
|
|
134
|
+
os.environ["TERMINAL_WIDTH"] = str(
|
|
135
|
+
min(shutil.get_terminal_size().columns, 100)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main() -> None:
|
|
140
|
+
setup_env()
|
|
141
|
+
cli()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
main()
|
|
File without changes
|