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.
Files changed (88) hide show
  1. copier_project-0.28.0/.gitignore +23 -0
  2. copier_project-0.28.0/AGENTS.md +30 -0
  3. copier_project-0.28.0/CONTRIBUTING.md +39 -0
  4. copier_project-0.28.0/LICENSE +21 -0
  5. copier_project-0.28.0/PKG-INFO +139 -0
  6. copier_project-0.28.0/README.md +109 -0
  7. copier_project-0.28.0/copier_project/__init__.py +9 -0
  8. copier_project-0.28.0/copier_project/__main__.py +145 -0
  9. copier_project-0.28.0/copier_project/py.typed +0 -0
  10. copier_project-0.28.0/copier_project/repo.py +176 -0
  11. copier_project-0.28.0/copier_project/update.py +88 -0
  12. copier_project-0.28.0/docs/contributing.md +6 -0
  13. copier_project-0.28.0/docs/development/requirements.md +24 -0
  14. copier_project-0.28.0/docs/development/updates.md +27 -0
  15. copier_project-0.28.0/docs/development/workflow.md +68 -0
  16. copier_project-0.28.0/docs/index.md +8 -0
  17. copier_project-0.28.0/docs/license.md +10 -0
  18. copier_project-0.28.0/docs/project-creation.md +85 -0
  19. copier_project-0.28.0/docs/project-development.md +45 -0
  20. copier_project-0.28.0/docs/project-release.md +34 -0
  21. copier_project-0.28.0/docs/project-setup.md +81 -0
  22. copier_project-0.28.0/docs/project-updates.md +33 -0
  23. copier_project-0.28.0/docs/project-variants.md +73 -0
  24. copier_project-0.28.0/docs/releasing.md +41 -0
  25. copier_project-0.28.0/docs/requirements.md +28 -0
  26. copier_project-0.28.0/docs/setup.md +63 -0
  27. copier_project-0.28.0/pyproject.toml +140 -0
  28. copier_project-0.28.0/tests/__init__.py +0 -0
  29. copier_project-0.28.0/tests/cli/__init__.py +0 -0
  30. copier_project-0.28.0/tests/cli/test_update.py +451 -0
  31. copier_project-0.28.0/tests/conftest.py +118 -0
  32. copier_project-0.28.0/tests/template/__init__.py +0 -0
  33. copier_project-0.28.0/tests/template/functional/__init__.py +0 -0
  34. copier_project-0.28.0/tests/template/functional/conftest.py +44 -0
  35. copier_project-0.28.0/tests/template/functional/test_pre_commit.py +142 -0
  36. copier_project-0.28.0/tests/template/functional/test_tasks.py +16 -0
  37. copier_project-0.28.0/tests/template/meta/__init__.py +0 -0
  38. copier_project-0.28.0/tests/template/meta/test_copier_config.py +24 -0
  39. copier_project-0.28.0/tests/template/render/common/__init__.py +0 -0
  40. copier_project-0.28.0/tests/template/render/common/__snapshots__/test_agents.ambr +129 -0
  41. copier_project-0.28.0/tests/template/render/common/__snapshots__/test_commit_check.ambr +109 -0
  42. copier_project-0.28.0/tests/template/render/common/__snapshots__/test_pre_commit.ambr +332 -0
  43. copier_project-0.28.0/tests/template/render/common/__snapshots__/test_renovate.ambr +41 -0
  44. copier_project-0.28.0/tests/template/render/common/conftest.py +10 -0
  45. copier_project-0.28.0/tests/template/render/common/test_agents.py +25 -0
  46. copier_project-0.28.0/tests/template/render/common/test_commit_check.py +35 -0
  47. copier_project-0.28.0/tests/template/render/common/test_pre_commit.py +25 -0
  48. copier_project-0.28.0/tests/template/render/common/test_renovate.py +17 -0
  49. copier_project-0.28.0/tests/template/render/generic/__init__.py +0 -0
  50. copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_contributing.ambr +1618 -0
  51. copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_mise_toml.ambr +269 -0
  52. copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_readme.ambr +508 -0
  53. copier_project-0.28.0/tests/template/render/generic/__snapshots__/test_workflows.ambr +212 -0
  54. copier_project-0.28.0/tests/template/render/generic/conftest.py +8 -0
  55. copier_project-0.28.0/tests/template/render/generic/test_contributing.py +37 -0
  56. copier_project-0.28.0/tests/template/render/generic/test_mise_toml.py +32 -0
  57. copier_project-0.28.0/tests/template/render/generic/test_readme.py +49 -0
  58. copier_project-0.28.0/tests/template/render/generic/test_structure.py +106 -0
  59. copier_project-0.28.0/tests/template/render/generic/test_workflows.py +30 -0
  60. copier_project-0.28.0/tests/template/render/python/__init__.py +0 -0
  61. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_compose.ambr +19 -0
  62. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_contributing.ambr +1062 -0
  63. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_dockerfile.ambr +175 -0
  64. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_docs.ambr +1570 -0
  65. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_license.ambr +5633 -0
  66. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_mise_toml.ambr +1873 -0
  67. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_pyproject.ambr +6585 -0
  68. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_readme.ambr +857 -0
  69. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_workflows.ambr +1728 -0
  70. copier_project-0.28.0/tests/template/render/python/__snapshots__/test_zensical.ambr +531 -0
  71. copier_project-0.28.0/tests/template/render/python/conftest.py +8 -0
  72. copier_project-0.28.0/tests/template/render/python/test_compose.py +29 -0
  73. copier_project-0.28.0/tests/template/render/python/test_contributing.py +46 -0
  74. copier_project-0.28.0/tests/template/render/python/test_dockerfile.py +35 -0
  75. copier_project-0.28.0/tests/template/render/python/test_docs.py +86 -0
  76. copier_project-0.28.0/tests/template/render/python/test_license.py +27 -0
  77. copier_project-0.28.0/tests/template/render/python/test_mise_toml.py +48 -0
  78. copier_project-0.28.0/tests/template/render/python/test_pyproject.py +86 -0
  79. copier_project-0.28.0/tests/template/render/python/test_readme.py +73 -0
  80. copier_project-0.28.0/tests/template/render/python/test_structure.py +154 -0
  81. copier_project-0.28.0/tests/template/render/python/test_workflows.py +115 -0
  82. copier_project-0.28.0/tests/template/render/python/test_zensical.py +53 -0
  83. copier_project-0.28.0/tests/template/render/questions/__init__.py +0 -0
  84. copier_project-0.28.0/tests/template/render/questions/test_copyright_license.py +67 -0
  85. copier_project-0.28.0/tests/template/render/questions/test_template_variant.py +52 -0
  86. copier_project-0.28.0/tests/template/utils.py +129 -0
  87. copier_project-0.28.0/tests/test_version.py +5 -0
  88. 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
+ [![License](https://img.shields.io/github/license/smkent/copier-project)](https://github.com/smkent/copier-project/blob/main/LICENSE)
37
+ [![PyPI](https://img.shields.io/pypi/v/copier-project)](https://pypi.org/project/copier-project/)
38
+ [![Python](https://img.shields.io/pypi/pyversions/copier-project)](https://pypi.org/project/copier-project/)
39
+ [![GitHub stars](https://img.shields.io/github/stars/smkent/copier-project?style=social)](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
+ [![License](https://img.shields.io/github/license/smkent/copier-project)](https://github.com/smkent/copier-project/blob/main/LICENSE)
7
+ [![PyPI](https://img.shields.io/pypi/v/copier-project)](https://pypi.org/project/copier-project/)
8
+ [![Python](https://img.shields.io/pypi/pyversions/copier-project)](https://pypi.org/project/copier-project/)
9
+ [![GitHub stars](https://img.shields.io/github/stars/smkent/copier-project?style=social)](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