forge-template 0.3.1__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 (240) hide show
  1. forge_template-0.3.1/.gitattributes +12 -0
  2. forge_template-0.3.1/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
  3. forge_template-0.3.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. forge_template-0.3.1/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
  5. forge_template-0.3.1/.github/dependabot.yml +12 -0
  6. forge_template-0.3.1/.github/labels.toml +100 -0
  7. forge_template-0.3.1/.github/pull_request_template.md +16 -0
  8. forge_template-0.3.1/.github/workflows/release.yml +137 -0
  9. forge_template-0.3.1/.github/workflows/test-template.yml +211 -0
  10. forge_template-0.3.1/.gitignore +220 -0
  11. forge_template-0.3.1/.pre-commit-config.yaml +46 -0
  12. forge_template-0.3.1/AGENTS.md +1 -0
  13. forge_template-0.3.1/CLAUDE.md +374 -0
  14. forge_template-0.3.1/CONTRIBUTING.md +275 -0
  15. forge_template-0.3.1/LICENSE +21 -0
  16. forge_template-0.3.1/PKG-INFO +148 -0
  17. forge_template-0.3.1/README.md +124 -0
  18. forge_template-0.3.1/SECURITY.md +24 -0
  19. forge_template-0.3.1/copier.yml +256 -0
  20. forge_template-0.3.1/docs/README.md +69 -0
  21. forge_template-0.3.1/docs/adr/0001-record-architecture-decisions.md +37 -0
  22. forge_template-0.3.1/docs/adr/0002-copier-over-cookiecutter.md +47 -0
  23. forge_template-0.3.1/docs/adr/0003-two-repo-split.md +40 -0
  24. forge_template-0.3.1/docs/adr/0004-build-backend-and-versioning.md +57 -0
  25. forge_template-0.3.1/docs/adr/0005-git-cliff-for-changelogs.md +43 -0
  26. forge_template-0.3.1/docs/adr/0006-mypy-default-pyright-optional.md +44 -0
  27. forge_template-0.3.1/docs/adr/0007-mkdocs-pinned-below-2.md +43 -0
  28. forge_template-0.3.1/docs/adr/0008-remove-make-task-runner.md +48 -0
  29. forge_template-0.3.1/docs/adr/0009-branch-and-pr-workflow.md +56 -0
  30. forge_template-0.3.1/docs/adr/0010-forge-architectural-terminology.md +61 -0
  31. forge_template-0.3.1/docs/adr/0011-forge-foundation-guarantees.md +72 -0
  32. forge_template-0.3.1/docs/adr/0012-conservative-foundation-scope.md +78 -0
  33. forge_template-0.3.1/docs/adr/0013-python-support-policy.md +70 -0
  34. forge_template-0.3.1/docs/adr/0014-editor-neutral-foundation.md +60 -0
  35. forge_template-0.3.1/docs/adr/0015-owner-local-runtime-configuration.md +78 -0
  36. forge_template-0.3.1/docs/adr/0016-owner-local-environment-inputs.md +78 -0
  37. forge_template-0.3.1/docs/adr/0017-owner-local-structured-logging.md +79 -0
  38. forge_template-0.3.1/docs/adr/0018-owner-local-paths-and-resources.md +87 -0
  39. forge_template-0.3.1/docs/adr/0019-owner-local-exceptions.md +96 -0
  40. forge_template-0.3.1/docs/adr/0020-generated-project-secret-safeguards.md +78 -0
  41. forge_template-0.3.1/docs/adr/0021-defer-sbom-and-release-provenance.md +86 -0
  42. forge_template-0.3.1/docs/adr/0022-pin-github-actions-by-full-commit-sha.md +69 -0
  43. forge_template-0.3.1/docs/adr/0023-projectspec-protocol-v1.md +64 -0
  44. forge_template-0.3.1/docs/adr/0024-component-manifest-protocol-v1.md +73 -0
  45. forge_template-0.3.1/docs/adr/0025-deterministic-composition-order.md +93 -0
  46. forge_template-0.3.1/docs/adr/0026-file-conflict-and-override-rules.md +105 -0
  47. forge_template-0.3.1/docs/adr/0027-template-variable-contract.md +99 -0
  48. forge_template-0.3.1/docs/adr/0028-composition-contract-fixtures.md +99 -0
  49. forge_template-0.3.1/docs/adr/0029-stable-template-engine-api.md +90 -0
  50. forge_template-0.3.1/docs/adr/0030-generated-project-validation.md +66 -0
  51. forge_template-0.3.1/docs/adr/0031-library-archetype-contract.md +67 -0
  52. forge_template-0.3.1/docs/adr/0032-render-component-content-paths.md +68 -0
  53. forge_template-0.3.1/docs/adr/0033-migrate-library-production-catalogue.md +89 -0
  54. forge_template-0.3.1/docs/adr/0034-select-cli-application-reference-archetype.md +77 -0
  55. forge_template-0.3.1/docs/adr/0035-implement-cli-application-archetype.md +91 -0
  56. forge_template-0.3.1/docs/adr/0036-publish-the-engine-to-pypi.md +104 -0
  57. forge_template-0.3.1/docs/adr/README.md +49 -0
  58. forge_template-0.3.1/docs/cli-application-archetype.md +241 -0
  59. forge_template-0.3.1/docs/component-manifests.md +322 -0
  60. forge_template-0.3.1/docs/composition-fixtures.md +108 -0
  61. forge_template-0.3.1/docs/composition-order.md +159 -0
  62. forge_template-0.3.1/docs/configuration-ownership.md +139 -0
  63. forge_template-0.3.1/docs/editor-integration.md +128 -0
  64. forge_template-0.3.1/docs/environment-variables.md +183 -0
  65. forge_template-0.3.1/docs/exception-ownership.md +181 -0
  66. forge_template-0.3.1/docs/file-conflicts.md +223 -0
  67. forge_template-0.3.1/docs/foundation-guarantees.md +189 -0
  68. forge_template-0.3.1/docs/foundation-scope.md +244 -0
  69. forge_template-0.3.1/docs/generated-project-validation.md +119 -0
  70. forge_template-0.3.1/docs/github-action-pinning.md +128 -0
  71. forge_template-0.3.1/docs/library-archetype.md +275 -0
  72. forge_template-0.3.1/docs/paths-and-resources.md +143 -0
  73. forge_template-0.3.1/docs/project-spec.md +227 -0
  74. forge_template-0.3.1/docs/python-support.md +146 -0
  75. forge_template-0.3.1/docs/roadmap-v1/ARCHITECTURE.md +108 -0
  76. forge_template-0.3.1/docs/roadmap-v1/README.md +144 -0
  77. forge_template-0.3.1/docs/roadmap-v1/REPOSITORY-OWNERSHIP.md +133 -0
  78. forge_template-0.3.1/docs/roadmap-v1/ROADMAP.md +39 -0
  79. forge_template-0.3.1/docs/roadmap-v1/github-issues/CROSS-REPO-DEPENDENCIES.md +37 -0
  80. forge_template-0.3.1/docs/roadmap-v1/github-issues/GITHUB-SETUP.md +51 -0
  81. forge_template-0.3.1/docs/roadmap-v1/github-issues/forge-template/ISSUE-INDEX.md +74 -0
  82. forge_template-0.3.1/docs/roadmap-v1/roadmap/00-governance-and-principles/README.md +32 -0
  83. forge_template-0.3.1/docs/roadmap-v1/roadmap/01-python-core/README.md +23 -0
  84. forge_template-0.3.1/docs/roadmap-v1/roadmap/02-developer-experience/README.md +28 -0
  85. forge_template-0.3.1/docs/roadmap-v1/roadmap/03-quality-and-ci/README.md +25 -0
  86. forge_template-0.3.1/docs/roadmap-v1/roadmap/04-runtime-and-configuration/README.md +52 -0
  87. forge_template-0.3.1/docs/roadmap-v1/roadmap/05-security-and-supply-chain/README.md +60 -0
  88. forge_template-0.3.1/docs/roadmap-v1/roadmap/06-extension-and-composition-contract/README.md +47 -0
  89. forge_template-0.3.1/docs/roadmap-v1/roadmap/07-forge-cli-integration/README.md +29 -0
  90. forge_template-0.3.1/docs/roadmap-v1/roadmap/08-reference-archetype-validation/README.md +51 -0
  91. forge_template-0.3.1/docs/roadmap-v1/roadmap/09-blueprint-compatibility/README.md +24 -0
  92. forge_template-0.3.1/docs/secret-handling.md +133 -0
  93. forge_template-0.3.1/docs/structured-logging.md +179 -0
  94. forge_template-0.3.1/docs/supply-chain-provenance.md +156 -0
  95. forge_template-0.3.1/docs/template-engine-api.md +260 -0
  96. forge_template-0.3.1/docs/template-variables.md +212 -0
  97. forge_template-0.3.1/docs/terminology.md +286 -0
  98. forge_template-0.3.1/pyproject.toml +225 -0
  99. forge_template-0.3.1/scripts/check_wheel.py +135 -0
  100. forge_template-0.3.1/scripts/labels.py +188 -0
  101. forge_template-0.3.1/scripts/verify-ci.sh +89 -0
  102. forge_template-0.3.1/src/forge_template/__init__.py +75 -0
  103. forge_template-0.3.1/src/forge_template/adr.py +145 -0
  104. forge_template-0.3.1/src/forge_template/component_manifest.py +691 -0
  105. forge_template-0.3.1/src/forge_template/components/__init__.py +5 -0
  106. forge_template-0.3.1/src/forge_template/components/cli/component.toml +48 -0
  107. forge_template-0.3.1/src/forge_template/components/cli/content/src/{{project.package_name}}/__init__.py.jinja +10 -0
  108. forge_template-0.3.1/src/forge_template/components/cli/content/src/{{project.package_name}}/__main__.py.jinja +6 -0
  109. forge_template-0.3.1/src/forge_template/components/cli/content/src/{{project.package_name}}/cli.py.jinja +57 -0
  110. forge_template-0.3.1/src/forge_template/components/cli/content/src/{{project.package_name}}/py.typed +0 -0
  111. forge_template-0.3.1/src/forge_template/components/cli/content/tests/__init__.py +0 -0
  112. forge_template-0.3.1/src/forge_template/components/cli/content/tests/test_cli.py.jinja +48 -0
  113. forge_template-0.3.1/src/forge_template/components/cli/extensions/archetype-metadata.toml.jinja +1 -0
  114. forge_template-0.3.1/src/forge_template/components/cli/extensions/build-configuration.toml.jinja +3 -0
  115. forge_template-0.3.1/src/forge_template/components/cli/extensions/build-system.toml.jinja +2 -0
  116. forge_template-0.3.1/src/forge_template/components/cli/extensions/classifiers.toml.jinja +1 -0
  117. forge_template-0.3.1/src/forge_template/components/cli/extensions/entry-points.toml.jinja +2 -0
  118. forge_template-0.3.1/src/forge_template/components/cli/extensions/readme-project-shape.md.jinja +20 -0
  119. forge_template-0.3.1/src/forge_template/components/cli/extensions/runtime-dependencies.toml.jinja +1 -0
  120. forge_template-0.3.1/src/forge_template/components/library/component.toml +39 -0
  121. forge_template-0.3.1/src/forge_template/components/library/content/src/{{project.package_name}}/__init__.py.jinja +10 -0
  122. forge_template-0.3.1/src/forge_template/components/library/content/src/{{project.package_name}}/py.typed +0 -0
  123. forge_template-0.3.1/src/forge_template/components/library/content/tests/__init__.py +0 -0
  124. forge_template-0.3.1/src/forge_template/components/library/content/tests/test_smoke.py.jinja +7 -0
  125. forge_template-0.3.1/src/forge_template/components/library/extensions/archetype-metadata.toml.jinja +5 -0
  126. forge_template-0.3.1/src/forge_template/components/library/extensions/build-configuration.toml.jinja +18 -0
  127. forge_template-0.3.1/src/forge_template/components/library/extensions/build-system.toml.jinja +10 -0
  128. forge_template-0.3.1/src/forge_template/components/library/extensions/gitignore-project-shape.jinja +3 -0
  129. forge_template-0.3.1/src/forge_template/components/library/extensions/readme-project-shape.md.jinja +6 -0
  130. forge_template-0.3.1/src/forge_template/components/library/options.schema.json +19 -0
  131. forge_template-0.3.1/src/forge_template/composition.py +172 -0
  132. forge_template-0.3.1/src/forge_template/engine.py +1173 -0
  133. forge_template-0.3.1/src/forge_template/file_conflicts.py +331 -0
  134. forge_template-0.3.1/src/forge_template/foundation/__init__.py +6 -0
  135. forge_template-0.3.1/src/forge_template/foundation/content/.editorconfig +15 -0
  136. forge_template-0.3.1/src/forge_template/foundation/content/.gitattributes +10 -0
  137. forge_template-0.3.1/src/forge_template/foundation/content/.gitignore.jinja +31 -0
  138. forge_template-0.3.1/src/forge_template/foundation/content/.python-version.jinja +1 -0
  139. forge_template-0.3.1/src/forge_template/foundation/content/CONTRIBUTING.md.jinja +42 -0
  140. forge_template-0.3.1/src/forge_template/foundation/content/LICENSE.jinja +40 -0
  141. forge_template-0.3.1/src/forge_template/foundation/content/README.md.jinja +40 -0
  142. forge_template-0.3.1/src/forge_template/foundation/content/SECURITY.md.jinja +33 -0
  143. forge_template-0.3.1/src/forge_template/foundation/content/pyproject.toml.jinja +159 -0
  144. forge_template-0.3.1/src/forge_template/foundation/foundation.toml +37 -0
  145. forge_template-0.3.1/src/forge_template/foundation_source.py +187 -0
  146. forge_template-0.3.1/src/forge_template/github_actions.py +81 -0
  147. forge_template-0.3.1/src/forge_template/project_spec.py +178 -0
  148. forge_template-0.3.1/src/forge_template/py.typed +0 -0
  149. forge_template-0.3.1/src/forge_template/render.py +285 -0
  150. forge_template-0.3.1/src/forge_template/schema.py +291 -0
  151. forge_template-0.3.1/src/forge_template/template_variables.py +441 -0
  152. forge_template-0.3.1/template/.copier-answers.yml.jinja +3 -0
  153. forge_template-0.3.1/template/.editorconfig +15 -0
  154. forge_template-0.3.1/template/.env.example.jinja +7 -0
  155. forge_template-0.3.1/template/.gitattributes +11 -0
  156. forge_template-0.3.1/template/.github/CODEOWNERS.jinja +7 -0
  157. forge_template-0.3.1/template/.github/ISSUE_TEMPLATE/bug_report.yml.jinja +38 -0
  158. forge_template-0.3.1/template/.github/ISSUE_TEMPLATE/config.yml +1 -0
  159. forge_template-0.3.1/template/.github/ISSUE_TEMPLATE/feature_request.yml.jinja +26 -0
  160. forge_template-0.3.1/template/.github/pull_request_template.md.jinja +12 -0
  161. forge_template-0.3.1/template/.github/workflows/ci.yml.jinja +172 -0
  162. forge_template-0.3.1/template/.github/{% if dependency_updates == 'dependabot' %}dependabot.yml{% endif %}.jinja +39 -0
  163. forge_template-0.3.1/template/.gitignore.jinja +40 -0
  164. forge_template-0.3.1/template/.pre-commit-config.yaml.jinja +35 -0
  165. forge_template-0.3.1/template/.python-version.jinja +1 -0
  166. forge_template-0.3.1/template/CHANGELOG.md.jinja +16 -0
  167. forge_template-0.3.1/template/CONTRIBUTING.md.jinja +97 -0
  168. forge_template-0.3.1/template/LICENSE.jinja +35 -0
  169. forge_template-0.3.1/template/README.md.jinja +142 -0
  170. forge_template-0.3.1/template/SECURITY.md.jinja +36 -0
  171. forge_template-0.3.1/template/pyproject.toml.jinja +293 -0
  172. forge_template-0.3.1/template/src/{{package_name}}/__init__.py.jinja +10 -0
  173. forge_template-0.3.1/template/src/{{package_name}}/py.typed +0 -0
  174. forge_template-0.3.1/template/tests/__init__.py +0 -0
  175. forge_template-0.3.1/template/tests/test_smoke.py.jinja +7 -0
  176. forge_template-0.3.1/template/{% if dependency_updates == 'renovate' %}renovate.json{% endif %}.jinja +52 -0
  177. forge_template-0.3.1/template/{% if use_docs %}docs{% endif %}/adr/0001-record-architecture-decisions.md.jinja +26 -0
  178. forge_template-0.3.1/template/{% if use_docs %}docs{% endif %}/adr/README.md.jinja +8 -0
  179. forge_template-0.3.1/template/{% if use_docs %}docs{% endif %}/index.md.jinja +11 -0
  180. forge_template-0.3.1/template/{% if use_docs %}docs{% endif %}/reference.md.jinja +3 -0
  181. forge_template-0.3.1/template/{% if use_docs %}mkdocs.yml{% endif %}.jinja +49 -0
  182. forge_template-0.3.1/tests/__init__.py +0 -0
  183. forge_template-0.3.1/tests/composition_contract.py +153 -0
  184. forge_template-0.3.1/tests/conftest.py +164 -0
  185. forge_template-0.3.1/tests/fixtures/component_manifests/changelog/component.toml +13 -0
  186. forge_template-0.3.1/tests/fixtures/component_manifests/changelog/content/a-top.txt +1 -0
  187. forge_template-0.3.1/tests/fixtures/component_manifests/changelog/content/nested/a-deep.txt +1 -0
  188. forge_template-0.3.1/tests/fixtures/component_manifests/changelog/content/z-top.txt +1 -0
  189. forge_template-0.3.1/tests/fixtures/component_manifests/coverage/component.toml +18 -0
  190. forge_template-0.3.1/tests/fixtures/component_manifests/coverage/content/.coveragerc +2 -0
  191. forge_template-0.3.1/tests/fixtures/component_manifests/coverage/extensions/ci-step.yml.jinja +2 -0
  192. forge_template-0.3.1/tests/fixtures/component_manifests/documentation/component.toml +13 -0
  193. forge_template-0.3.1/tests/fixtures/component_manifests/documentation/content/mkdocs.yml.jinja +1 -0
  194. forge_template-0.3.1/tests/fixtures/component_manifests/github/component.toml +18 -0
  195. forge_template-0.3.1/tests/fixtures/component_manifests/github/content/ci.yml.jinja +5 -0
  196. forge_template-0.3.1/tests/fixtures/component_manifests/github/options.schema.json +10 -0
  197. forge_template-0.3.1/tests/fixtures/component_manifests/library/component.toml +14 -0
  198. forge_template-0.3.1/tests/fixtures/component_manifests/library/content/pyproject.toml.jinja +7 -0
  199. forge_template-0.3.1/tests/fixtures/component_manifests/library/options.schema.json +16 -0
  200. forge_template-0.3.1/tests/fixtures/component_manifests/library-v2/component.toml +21 -0
  201. forge_template-0.3.1/tests/fixtures/component_manifests/library-v2/content/src/{{project.package_name}}/py.typed +0 -0
  202. forge_template-0.3.1/tests/fixtures/component_manifests/library-v2/extensions/pyproject-build-system.toml.jinja +2 -0
  203. forge_template-0.3.1/tests/fixtures/component_manifests/library-v2/options.schema.json +11 -0
  204. forge_template-0.3.1/tests/fixtures/foundation/content/pyproject.toml.jinja +6 -0
  205. forge_template-0.3.1/tests/fixtures/foundation/foundation.toml +6 -0
  206. forge_template-0.3.1/tests/fixtures/golden/extension.json +43 -0
  207. forge_template-0.3.1/tests/fixtures/golden/full.json +81 -0
  208. forge_template-0.3.1/tests/fixtures/golden/minimal.json +18 -0
  209. forge_template-0.3.1/tests/fixtures/invalid_components/colliding-first/component.toml +13 -0
  210. forge_template-0.3.1/tests/fixtures/invalid_components/colliding-first/content/shared.txt +1 -0
  211. forge_template-0.3.1/tests/fixtures/invalid_components/colliding-second/component.toml +13 -0
  212. forge_template-0.3.1/tests/fixtures/invalid_components/colliding-second/content/shared.txt +1 -0
  213. forge_template-0.3.1/tests/fixtures/invalid_components/conflicting-first/component.toml +13 -0
  214. forge_template-0.3.1/tests/fixtures/invalid_components/conflicting-first/content/placeholder.txt +1 -0
  215. forge_template-0.3.1/tests/fixtures/invalid_components/conflicting-second/component.toml +13 -0
  216. forge_template-0.3.1/tests/fixtures/invalid_components/conflicting-second/content/placeholder.txt +1 -0
  217. forge_template-0.3.1/tests/fixtures/invalid_components/cycle-a/component.toml +13 -0
  218. forge_template-0.3.1/tests/fixtures/invalid_components/cycle-a/content/placeholder.txt +1 -0
  219. forge_template-0.3.1/tests/fixtures/invalid_components/cycle-b/component.toml +13 -0
  220. forge_template-0.3.1/tests/fixtures/invalid_components/cycle-b/content/placeholder.txt +1 -0
  221. forge_template-0.3.1/tests/test_adr.py +121 -0
  222. forge_template-0.3.1/tests/test_cli_archetype.py +166 -0
  223. forge_template-0.3.1/tests/test_cli_build.py +209 -0
  224. forge_template-0.3.1/tests/test_combos.py +113 -0
  225. forge_template-0.3.1/tests/test_component_manifest.py +733 -0
  226. forge_template-0.3.1/tests/test_composition.py +223 -0
  227. forge_template-0.3.1/tests/test_composition_contract.py +159 -0
  228. forge_template-0.3.1/tests/test_engine.py +695 -0
  229. forge_template-0.3.1/tests/test_file_conflicts.py +428 -0
  230. forge_template-0.3.1/tests/test_foundation_source.py +159 -0
  231. forge_template-0.3.1/tests/test_generated_project_validation.py +304 -0
  232. forge_template-0.3.1/tests/test_github_actions.py +69 -0
  233. forge_template-0.3.1/tests/test_library_archetype.py +247 -0
  234. forge_template-0.3.1/tests/test_library_build.py +172 -0
  235. forge_template-0.3.1/tests/test_project_spec.py +244 -0
  236. forge_template-0.3.1/tests/test_render.py +364 -0
  237. forge_template-0.3.1/tests/test_schema.py +206 -0
  238. forge_template-0.3.1/tests/test_template_variables.py +494 -0
  239. forge_template-0.3.1/tests/test_update.py +279 -0
  240. forge_template-0.3.1/uv.lock +1152 -0
@@ -0,0 +1,12 @@
1
+ # Normalise to LF in the repository. Without this, Windows checkouts get CRLF
2
+ # and a fresh clone's checked-out template/*.jinja files would render CRLF
3
+ # into every scaffolded project.
4
+ * text=auto eol=lf
5
+
6
+ *.png binary
7
+ *.jpg binary
8
+ *.gif binary
9
+ *.ico binary
10
+ *.pdf binary
11
+ *.zip binary
12
+ *.whl binary
@@ -0,0 +1,42 @@
1
+ name: Bug report
2
+ description: Report something that isn't working as expected
3
+ labels: ["type:bug"]
4
+ body:
5
+ - type: textarea
6
+ id: what-happened
7
+ attributes:
8
+ label: What happened?
9
+ description: What did you expect instead?
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: reproduce
15
+ attributes:
16
+ label: Steps to reproduce
17
+ description: >
18
+ Include the answers (or which combo, if this is about
19
+ `tests/test_combos.py`) that reproduce it.
20
+ placeholder: |
21
+ 1.
22
+ 2.
23
+ 3.
24
+ validations:
25
+ required: true
26
+
27
+ - type: input
28
+ id: template-version
29
+ attributes:
30
+ label: Template version
31
+ description: The tag `copier` scaffolded from, or `main` at a commit SHA
32
+ placeholder: "e.g. v0.1.1"
33
+ validations:
34
+ required: true
35
+
36
+ - type: input
37
+ id: copier-version
38
+ attributes:
39
+ label: Copier version
40
+ placeholder: "e.g. 9.4.1 (uv run copier --version)"
41
+ validations:
42
+ required: false
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: create-forge CLI issue
4
+ url: https://github.com/Sandsy09/create-forge/issues/new/choose
5
+ about: Report a problem with the `create-forge` CLI itself, not this template.
@@ -0,0 +1,26 @@
1
+ name: Feature request
2
+ description: Suggest an idea or enhancement
3
+ labels: ["type:feature"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What problem does this solve?
9
+ description: What are you trying to do that isn't possible or easy today?
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: solution
15
+ attributes:
16
+ label: Proposed solution
17
+ description: What would you like to happen?
18
+ validations:
19
+ required: false
20
+
21
+ - type: textarea
22
+ id: alternatives
23
+ attributes:
24
+ label: Alternatives considered
25
+ validations:
26
+ required: false
@@ -0,0 +1,12 @@
1
+ version: 2
2
+
3
+ updates:
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
8
+ day: monday
9
+ open-pull-requests-limit: 5
10
+ labels: ["type:chore", "area:ci"]
11
+ commit-message:
12
+ prefix: ci
@@ -0,0 +1,100 @@
1
+ # Shared GitHub label taxonomy for create-forge and forge-template.
2
+ #
3
+ # This is the source of truth -- applied with `uv run poe labels:sync`
4
+ # (scripts/labels.py), which also accepts `--repo OWNER/NAME` so the same
5
+ # manifest drives forge-template. See CONTRIBUTING.md's Labels section.
6
+ #
7
+ # Group labels are namespaced "<group>:<label>" (e.g. "area:cli"). Entries
8
+ # under [unprefixed] keep GitHub's stock names -- "good first issue" and
9
+ # "help wanted" are special-cased by GitHub's own issue-discovery UI, so
10
+ # renaming them would cost real functionality for no benefit.
11
+ #
12
+ # Most `type:` values mirror the Conventional Commits prefixes both repos
13
+ # already enforce via their commit-msg hook. `type:epic` and `type:decision`
14
+ # classify roadmap planning work that does not map to a single commit.
15
+
16
+ [groups.area]
17
+ description = "Which part of the system an issue touches."
18
+ family = "blue"
19
+
20
+ [groups.area.labels]
21
+ cli = { color = "0a3069", description = "The Typer commands and their prompts" }
22
+ registry = { color = "0550ae", description = "templates.toml and the models that validate it" }
23
+ copier = { color = "0969da", description = "The Copier integration and copier.yml surface" }
24
+ template = { color = "218bff", description = "forge-template's scaffolded files and tasks" }
25
+ ci = { color = "54aeff", description = "GitHub Actions workflows and the checks they run" }
26
+ tests = { color = "80ccff", description = "The test suites and fixtures themselves" }
27
+ docs = { color = "b6e3ff", description = "README, CONTRIBUTING, ADRs, and other documentation" }
28
+ packaging = { color = "cae8ff", description = "pyproject.toml, dependencies, and the built wheel" }
29
+ release = { color = "ddf4ff", description = "Tagging, changelog generation, and the release workflow" }
30
+
31
+ [groups.type]
32
+ description = "What kind of work an issue or PR represents."
33
+ family = "purple"
34
+
35
+ [groups.type.labels]
36
+ epic = { color = "2f0f5f", description = "A roadmap stage grouping related child issues" }
37
+ decision = { color = "5526a5", description = "An architectural or product decision is required" }
38
+ bug = { color = "3e1f79", description = "Something isn't working" }
39
+ feature = { color = "6639ba", description = "New capability or request" }
40
+ refactor = { color = "8250df", description = "Structural change with no behaviour change" }
41
+ perf = { color = "a475f9", description = "Performance improvement" }
42
+ docs = { color = "c297ff", description = "Documentation-only change" }
43
+ test = { color = "d8b9ff", description = "Test-only change" }
44
+ chore = { color = "ecd8ff", description = "Maintenance with no user-facing effect" }
45
+
46
+ [groups.priority]
47
+ description = "How urgently an issue should be picked up."
48
+ family = "red"
49
+
50
+ [groups.priority.labels]
51
+ critical = { color = "82071e", description = "Drop everything" }
52
+ high = { color = "cf222e", description = "Should be next" }
53
+ medium = { color = "ff8182", description = "Normal priority" }
54
+ low = { color = "ffcecb", description = "Nice to have" }
55
+
56
+ [groups.size]
57
+ description = "Rough estimate of how much work an issue is."
58
+ family = "green"
59
+
60
+ [groups.size.labels]
61
+ xs = { color = "dafbe1", description = "Trivial -- minutes" }
62
+ s = { color = "aceebb", description = "Small -- a sitting" }
63
+ m = { color = "6fdd8b", description = "Medium -- a day or two" }
64
+ l = { color = "2da44e", description = "Large -- the better part of a week" }
65
+ xl = { color = "116329", description = "Extra large -- consider breaking it up" }
66
+
67
+ [groups.status]
68
+ description = "Where an issue stands, independent of priority or size."
69
+ family = "slate"
70
+
71
+ [groups.status.labels]
72
+ blocked = { color = "24292f", description = "Waiting on something outside this issue" }
73
+ needs-decision = { color = "57606a", description = "Blocked on a choice only a maintainer can make" }
74
+ needs-info = { color = "6e7781", description = "Waiting on more information before work can start" }
75
+ in-progress = { color = "8c959f", description = "Actively being worked on" }
76
+ deferred = { color = "afb8c1", description = "Confirmed out of scope for now, not forgotten" }
77
+
78
+ [groups.roadmap]
79
+ description = "Which Forge Foundation roadmap stage owns the work."
80
+ family = "orange"
81
+
82
+ [groups.roadmap.labels]
83
+ "00" = { color = "fff8c5", description = "Forge roadmap Stage 00 — Governance and Principles" }
84
+ "01" = { color = "fae17d", description = "Forge roadmap Stage 01 — Python Core" }
85
+ "02" = { color = "f7c843", description = "Forge roadmap Stage 02 — Developer Experience" }
86
+ "03" = { color = "f2b134", description = "Forge roadmap Stage 03 — Quality and CI" }
87
+ "04" = { color = "ed9b2d", description = "Forge roadmap Stage 04 — Runtime and Configuration" }
88
+ "05" = { color = "e78626", description = "Forge roadmap Stage 05 — Security and Supply Chain" }
89
+ "06" = { color = "df7020", description = "Forge roadmap Stage 06 — Extension and Composition" }
90
+ "07" = { color = "d45d1a", description = "Forge roadmap Stage 07 — Forge CLI Integration" }
91
+ "08" = { color = "bd4914", description = "Forge roadmap Stage 08 — Reference Archetype Validation" }
92
+ "09" = { color = "9f3610", description = "Forge roadmap Stage 09 — Blueprint Compatibility" }
93
+
94
+ # Repository-wide metadata that is clearer without a namespace. GitHub
95
+ # special-cases `good first issue` and `help wanted` in its discovery UI.
96
+ [unprefixed]
97
+ "good first issue" = { color = "7057ff", description = "Good for newcomers" }
98
+ "help wanted" = { color = "008672", description = "Extra attention is needed" }
99
+ "cross-repo" = { color = "1f6feb", description = "Coordinates work across create-forge and forge-template" }
100
+ "breaking-change" = { color = "b60205", description = "May require an incompatible migration or coordinated release" }
@@ -0,0 +1,16 @@
1
+ ## Summary
2
+
3
+ <!-- What does this change do, and why? -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `uv run poe check` passes locally
8
+ - [ ] `uv run poe combos` passes, if this touches `template/` or `copier.yml`
9
+ - [ ] `uv run poe update` passes, if this edits a file that already exists in
10
+ released projects
11
+ - [ ] An ADR is added under `docs/adr/`, if this makes a real architectural call
12
+ - [ ] A `_migrations` block is added, if any `template/` path was renamed or
13
+ deleted (see CLAUDE.md's invariant 3)
14
+ - [ ] Any conditional file I touched still ends in a real trailing newline
15
+ (invariant 1)
16
+ - [ ] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/)
@@ -0,0 +1,137 @@
1
+ name: Release template
2
+
3
+ # Tags are how Copier resolves "latest version" and how engine clients resolve
4
+ # package compatibility. pyproject.toml is the one version source: bump it in
5
+ # a reviewed PR, then run this workflow to create the matching tag and release.
6
+
7
+ on:
8
+ workflow_dispatch:
9
+ inputs:
10
+ dry_run:
11
+ description: Print the tag without creating it
12
+ type: boolean
13
+ default: false
14
+
15
+ permissions:
16
+ contents: write
17
+
18
+ env:
19
+ UV_VERSION: "0.12.0"
20
+
21
+ jobs:
22
+ release:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Read and validate version
30
+ id: version
31
+ shell: bash
32
+ run: |
33
+ version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
34
+ if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
35
+ echo "::error::project.version must be a final SemVer release, found: $version"
36
+ exit 1
37
+ fi
38
+
39
+ next="v$version"
40
+ latest=$(git tag -l 'v*' --sort=-v:refname | head -1)
41
+ if git rev-parse --verify --quiet "refs/tags/$next" >/dev/null; then
42
+ echo "::error::tag already exists: $next"
43
+ exit 1
44
+ fi
45
+ if [ -n "$latest" ] && [ "$(printf '%s\n%s\n' "$latest" "$next" | sort -V | tail -1)" != "$next" ]; then
46
+ echo "::error::project version $next is not newer than $latest"
47
+ exit 1
48
+ fi
49
+
50
+ echo "latest=${latest:-none}" >> "$GITHUB_OUTPUT"
51
+ echo "next=$next" >> "$GITHUB_OUTPUT"
52
+ echo "### ${latest:-none} → $next" >> "$GITHUB_STEP_SUMMARY"
53
+
54
+ - name: Changes since last release
55
+ id: notes
56
+ run: |
57
+ latest="${{ steps.version.outputs.latest }}"
58
+ {
59
+ echo "notes<<EOF"
60
+ if [ "$latest" = "none" ]; then
61
+ echo "Initial release."
62
+ else
63
+ git log "${latest}..HEAD" --pretty='- %s' --no-merges
64
+ fi
65
+ echo "EOF"
66
+ } >> "$GITHUB_OUTPUT"
67
+
68
+ - name: Warn on breaking template changes
69
+ run: |
70
+ latest="${{ steps.version.outputs.latest }}"
71
+ [ "$latest" = "none" ] && exit 0
72
+ moved=$(git diff --name-status "$latest..HEAD" -- template/ \
73
+ | grep -E '^(R|D)' || true)
74
+ if [ -n "$moved" ] && ! grep -q '_migrations' copier.yml; then
75
+ echo "::warning::Template files moved or deleted with no _migrations block:"
76
+ echo "$moved"
77
+ fi
78
+
79
+ - name: Create tag
80
+ if: ${{ !inputs.dry_run }}
81
+ run: |
82
+ git config user.name "github-actions[bot]"
83
+ git config user.email "github-actions[bot]@users.noreply.github.com"
84
+ git tag -a "${{ steps.version.outputs.next }}" \
85
+ -m "Release ${{ steps.version.outputs.next }}"
86
+ git push origin "${{ steps.version.outputs.next }}"
87
+
88
+ - name: GitHub release
89
+ if: ${{ !inputs.dry_run }}
90
+ env:
91
+ GH_TOKEN: ${{ github.token }}
92
+ run: |
93
+ gh release create "${{ steps.version.outputs.next }}" \
94
+ --title "${{ steps.version.outputs.next }}" \
95
+ --notes "${{ steps.notes.outputs.notes }}
96
+
97
+ ---
98
+ Existing projects can pull this in with \`uvx copier update --trust\`."
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # Publishes the public engine package built from the same commit the tag
102
+ # above points to. Uses PyPI Trusted Publishing (OIDC) -- no stored token.
103
+ # ADR 0036: only the public engine facade and content trees ship in this
104
+ # wheel; scripts/check_wheel.py (already required by CI's `wheel` job)
105
+ # re-verifies that here as a release-time safety net.
106
+ # ---------------------------------------------------------------------------
107
+ publish:
108
+ name: Publish to PyPI
109
+ runs-on: ubuntu-latest
110
+ needs: release
111
+ if: ${{ !inputs.dry_run }}
112
+ permissions:
113
+ id-token: write
114
+ environment:
115
+ name: pypi
116
+ url: https://pypi.org/p/forge-template
117
+ steps:
118
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
119
+
120
+ - name: Install uv
121
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
122
+ with:
123
+ version: ${{ env.UV_VERSION }}
124
+ enable-cache: true
125
+ python-version: "3.13"
126
+
127
+ - name: Install dependencies
128
+ run: uv sync --all-groups
129
+
130
+ - name: Check wheel contents
131
+ run: uv run poe check:wheel
132
+
133
+ - name: Build
134
+ run: uv build
135
+
136
+ - name: Publish
137
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,211 @@
1
+ name: Test template
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ # Catches upstream breakage (new ruff rules, uv releases) before users do.
9
+ schedule:
10
+ - cron: "0 6 * * 1"
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ env:
20
+ UV_VERSION: "0.12.0"
21
+
22
+ jobs:
23
+ # ---------------------------------------------------------------------------
24
+ # Cheap checks on the template repo itself.
25
+ # ---------------------------------------------------------------------------
26
+ lint:
27
+ name: Lint template
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
31
+
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
34
+ with:
35
+ version: ${{ env.UV_VERSION }}
36
+ enable-cache: true
37
+ python-version: "3.13"
38
+
39
+ - name: Install dependencies
40
+ run: uv sync --all-groups
41
+
42
+ # Same gate as `uv run pre-commit run --all-files` locally: ruff,
43
+ # shellcheck, and the whitespace/EOF hooks that guard invariant 1.
44
+ - name: Pre-commit
45
+ run: uv run pre-commit run --all-files --show-diff-on-failure
46
+
47
+ # copier.yml layout, computed-value defaults, the versioning /
48
+ # versioning_resolved indirection, question <-> template/** usage, and
49
+ # the docs/adr/ set -- see src/forge_template/{schema,adr}.py.
50
+ - name: Schema and unit tests
51
+ run: uv run poe check
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Scaffold every combination, then run the checks the generated CI runs.
55
+ # tests/test_combos.py is the single definition of every assertion here --
56
+ # see tests/conftest.py's --from-git option and _git_identity fixture (no
57
+ # manual `git config` step needed; the fixture supplies one when the runner
58
+ # has none, closing the bug class documented in CLAUDE.md's "Validation").
59
+ # ---------------------------------------------------------------------------
60
+ scaffold:
61
+ name: ${{ matrix.name }}
62
+ runs-on: ubuntu-latest
63
+ needs: lint
64
+ strategy:
65
+ fail-fast: false
66
+ matrix:
67
+ include:
68
+ - name: uv_build + static
69
+ combo: c1-uvbuild-static
70
+ - name: hatchling + static
71
+ combo: c2-hatch-static
72
+ - name: hatchling + vcs
73
+ combo: c3-hatch-vcs
74
+ - name: kitchen sink (all conditionals on)
75
+ combo: c4-kitchen-sink
76
+
77
+ steps:
78
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
+ with:
80
+ # Copier needs tag history to record _commit in the answers file.
81
+ fetch-depth: 0
82
+
83
+ - name: Install uv
84
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
85
+ with:
86
+ version: ${{ env.UV_VERSION }}
87
+ enable-cache: true
88
+ python-version: "3.13"
89
+
90
+ - name: Install dependencies
91
+ run: uv sync --all-groups
92
+
93
+ - name: Scaffold and verify -- ${{ matrix.combo }}
94
+ run: uv run pytest -m combos -k ${{ matrix.combo }} --from-git -v
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # Windows smoke test — path separators, line endings, missing Unix tools.
98
+ # ---------------------------------------------------------------------------
99
+ windows:
100
+ name: Windows smoke
101
+ runs-on: windows-latest
102
+ needs: lint
103
+ steps:
104
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
105
+ with:
106
+ fetch-depth: 0
107
+
108
+ - name: Install uv
109
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
110
+ with:
111
+ version: ${{ env.UV_VERSION }}
112
+ enable-cache: true
113
+ python-version: "3.13"
114
+
115
+ - name: Install dependencies
116
+ run: uv sync --all-groups
117
+
118
+ - name: Scaffold and verify -- c1-uvbuild-static
119
+ run: uv run pytest -m combos -k c1-uvbuild-static --from-git -v
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # Real uv build/install/import proof for the production Library and CLI
123
+ # archetypes -- tests/test_library_build.py, tests/test_cli_build.py.
124
+ # ---------------------------------------------------------------------------
125
+ archetype:
126
+ name: Archetype builds
127
+ runs-on: ubuntu-latest
128
+ needs: lint
129
+ steps:
130
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
131
+
132
+ - name: Install uv
133
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
134
+ with:
135
+ version: ${{ env.UV_VERSION }}
136
+ enable-cache: true
137
+ python-version: "3.13"
138
+
139
+ - name: Install dependencies
140
+ run: uv sync --all-groups
141
+
142
+ - name: Build every production archetype
143
+ run: uv run poe archetype
144
+
145
+ # ---------------------------------------------------------------------------
146
+ # copier update from the last release to HEAD must not explode, and local
147
+ # edits survive a merge. tests/test_update.py's two scenarios each skip
148
+ # themselves (not fail) when no tag exists yet -- the very first run.
149
+ # ---------------------------------------------------------------------------
150
+ update-compat:
151
+ name: copier update compatibility
152
+ runs-on: ubuntu-latest
153
+ needs: lint
154
+ steps:
155
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
156
+ with:
157
+ fetch-depth: 0
158
+
159
+ - name: Install uv
160
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
161
+ with:
162
+ version: ${{ env.UV_VERSION }}
163
+ enable-cache: true
164
+ python-version: "3.13"
165
+
166
+ - name: Install dependencies
167
+ run: uv sync --all-groups
168
+
169
+ - name: copier update scenarios
170
+ run: uv run pytest -m update -v
171
+
172
+ # ---------------------------------------------------------------------------
173
+ # Verifies the built wheel ships the public engine facade and content
174
+ # trees but excludes this repo's own CI tooling (adr.py, render.py,
175
+ # schema.py, github_actions.py) -- see ADR 0036 and scripts/check_wheel.py.
176
+ # ---------------------------------------------------------------------------
177
+ wheel:
178
+ name: Wheel contents
179
+ runs-on: ubuntu-latest
180
+ needs: lint
181
+ steps:
182
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
183
+
184
+ - name: Install uv
185
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
186
+ with:
187
+ version: ${{ env.UV_VERSION }}
188
+ enable-cache: true
189
+ python-version: "3.13"
190
+
191
+ - name: Install dependencies
192
+ run: uv sync --all-groups
193
+
194
+ - name: Check wheel
195
+ run: uv run poe check:wheel
196
+
197
+ # ---------------------------------------------------------------------------
198
+ # Single required status check for branch protection.
199
+ # ---------------------------------------------------------------------------
200
+ all-green:
201
+ name: All checks passed
202
+ runs-on: ubuntu-latest
203
+ needs: [lint, scaffold, windows, archetype, update-compat, wheel]
204
+ if: always()
205
+ steps:
206
+ - name: Verify
207
+ run: |
208
+ if echo "${{ join(needs.*.result, ',') }}" | grep -qE 'failure|cancelled'; then
209
+ echo "::error::One or more jobs failed"; exit 1
210
+ fi
211
+ echo "All jobs passed."