From 5cc83e85e42ab533b7819eda94b1a8ece0449d73 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 3 Oct 2026 13:26:23 +1000 Subject: [PATCH 1/2] Bring the release docs in line with the automated flow An audit of the release docs after v1.10.0 shipped: - RELEASING.md (generated for PyPI libraries) gains "If a step fails": re-running Prepare release, held CI, re-running Release on merge, and re-dispatching publish.yml (or bumping, since PyPI never takes a version twice). "Sanity checks before tagging" becomes "before releasing", since tagging is no longer a manual step. - The fragment template says Prepare release collects fragments. - The README's manual `copier update` gains `--trust`, lists the release workflows among those `v1` delivers, and says how to recover a template release, including a bump-v1 dispatch. - The CHANGELOG preamble and bump-v1.yml said copier reads the version with `git describe`; it uses dunamai, which takes the commit's newest tag by date. The advice (annotate release tags, keep v1 lightweight) stands; the reason is corrected. The preamble also describes releases going through Prepare template release. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/bump-v1.yml | 11 ++++++----- CHANGELOG.md | 4 ++-- README.md | 9 ++++++--- changelog.d/20261003_000000_release_docs.md | 4 ++++ template/changelog.d/TEMPLATE.md | 2 +- ...if publish_to_pypi %}RELEASING.md{% endif %}.jinja | 11 ++++++++++- 6 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 changelog.d/20261003_000000_release_docs.md diff --git a/.github/workflows/bump-v1.yml b/.github/workflows/bump-v1.yml index ebd018a..b5d6275 100644 --- a/.github/workflows/bump-v1.yml +++ b/.github/workflows/bump-v1.yml @@ -146,10 +146,11 @@ jobs: run: | set -euo pipefail # The Move step below puts v1 on this same commit, and copier reads a - # template's version with `git describe --tags`. That prefers an - # annotated tag over a lightweight one, and falls back to the newest - # when they tie -- so with both lightweight it answers "v1", copier - # parses that as version 1, and every consumer above 1.0.0 fails + # template's version through dunamai, which takes the commit's newest + # tag by date. An annotated tag's date is when it was tagged; a + # lightweight tag's is its commit's. With both lightweight they tie, + # dunamai can answer "v1", copier parses that as version 1, and every + # consumer above 1.0.0 fails # `copier update` with "Downgrades are not supported". Not merely the # scheduled runs: an explicit `--vcs-ref v1.8.0` reads the same commit # and fails identically, which strands the project entirely. @@ -157,7 +158,7 @@ jobs: # Publishing a release for a tag that does not exist yet -- the GitHub # UI's default, and `gh release create` without --verify-tag -- makes # that lightweight tag. Rather than refuse the release over it, give - # the tag an annotation here so it outranks v1 and describe answers + # the tag an annotation here so it outranks v1 and copier reads # "v1.8.0". Annotating v1 too would break it again: v1 is re-tagged on # every release, so it would always be the newer of the two. # diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d9dee..fc9c634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), Two things are worth knowing about how versions work here, because this repo ships CI rather than a package: -- **`v1` is a moving major tag.** Consumers pin `python-ci.yml@v1` and `node-ci.yml@v1`, so publishing a release is what actually delivers a change to them — `.github/workflows/bump-v1.yml` moves `v1` onto each published `v1.x` release. Changes to the reusable workflows reach every project the moment that happens, with no `copier update` needed. -- **Release tags are annotated; `v1` stays lightweight.** They end up on the same commit, and copier reads a template's version with `git describe --tags`, which prefers the annotated tag. Get this backwards and copier reads the version as `1` and refuses every consumer's update as a downgrade. `bump-v1.yml` maintains this on its own — it annotates the release tag if publishing left it lightweight, and creates `v1` lightweight — so releases can still be cut from the GitHub UI. +- **`v1` is a moving major tag.** Consumers pin `python-ci.yml@v1` and `node-ci.yml@v1`, so a release is what actually delivers a change to them. Releases go through the **Prepare template release** workflow (see the README); merging its pull request tags the release and starts `.github/workflows/bump-v1.yml`, which moves `v1` onto it. A release published by hand from the GitHub UI starts bump-v1 too. Changes to the reusable workflows reach every project the moment that happens, with no `copier update` needed. +- **Release tags are annotated; `v1` stays lightweight.** They end up on the same commit, and copier reads a template's version through dunamai, which takes the commit's newest tag by date: an annotated tag's date is when it was tagged, a lightweight tag's is its commit's. So the annotated release tag outranks `v1`. Get this backwards and copier reads the version as `1` and refuses every consumer's update as a downgrade. `bump-v1.yml` maintains this on its own — it annotates the release tag if publishing left it lightweight, and creates `v1` lightweight — so releases can still be cut from the GitHub UI. - **Changes to *scaffolded* files reach projects only through `copier update`.** `.pre-commit-config.yaml`, `biome.json`, `pyproject.toml` and friends are copied at scaffold time, so a project picks them up when it runs an update — automatically if it opted into `template-update.yml`. Entries for 1.0.0 through 1.5.2 were backfilled from git history after the fact, so they describe what each tag contained rather than having been written alongside it. diff --git a/README.md b/README.md index 0db05c1..b256dce 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ project's local edits, so customisations survive. Answering no leaves the workflow out. It does **not** cut the project off from template updates: `.copier-answers.yml` is written either way, so -`uvx copier update` still works by hand whenever you want it. Worth declining +`uvx copier update --trust` still works by hand whenever you want it. Worth declining for a repo that should pull template changes on its own schedule rather than weekly — one in a release freeze, or one whose local edits have diverged far enough that every update run conflicts and the PRs become noise. @@ -222,8 +222,9 @@ enough that every update run conflicts and the PRs become noise. Two things worth knowing about the scope: - **Reusable workflow changes need no update run.** Consumers pin - `python-ci.yml@v1` and `node-ci.yml@v1`, so moving the `v1` tag propagates - those immediately. The update workflow exists only for the copied files — + `python-ci.yml@v1`, `node-ci.yml@v1` and the release workflows + (`prepare-release.yml@v1`, `release-on-merge.yml@v1`), so moving the `v1` + tag propagates those immediately. The update workflow exists only for the copied files — `.pre-commit-config.yaml`, `biome.json`, `pyproject.toml` and friends. - **It requires `.copier-answers.yml`.** A project adapted by hand rather than scaffolded has no baseline for copier to merge from, and the workflow fails @@ -250,6 +251,8 @@ One-time setup: _Settings → Actions → General_ → **Allow GitHub Actions to 2. On the pull request's Checks tab, click **Approve workflows to run**, then review it. Add a summary paragraph under the new heading if the release needs one. 3. Merge it. **Template release on merge** tags the merge commit and creates the GitHub release, then starts `bump-v1.yml`, which checks the changelog, annotates the tag, and moves `v1`. +If a step fails, the generated projects' RELEASING.md notes apply here too. Re-running Prepare template release replaces its own branch, and re-running Template release on merge skips what already succeeded. If bump-v1 fails after the tag exists, re-run it, or start it with `gh workflow run bump-v1.yml --ref vX.Y.Z`. On a dispatch, it accepts only the newest final `v1.X.Y` tag. + Each pull request to this repo adds a fragment under `changelog.d/` (`uvx --from scriv scriv create`), configured by `changelog.d/scriv.ini`. Publishing a release by hand from the GitHub UI still works: `bump-v1.yml` runs on the release event as before. ## Versioning diff --git a/changelog.d/20261003_000000_release_docs.md b/changelog.d/20261003_000000_release_docs.md new file mode 100644 index 0000000..aeab9af --- /dev/null +++ b/changelog.d/20261003_000000_release_docs.md @@ -0,0 +1,4 @@ +### Fixed + +- The release docs match the automated flow. RELEASING.md gains an "If a step fails" section covering re-runs, held CI and a failed publish, and its pre-release checks no longer say "before tagging". The fragment template says Prepare release collects fragments. The README's manual update command has `--trust`, and it lists the release workflows among those that `v1` delivers. +- The CHANGELOG preamble and `bump-v1.yml` explain why release tags must be annotated correctly. Copier reads the version through dunamai, which takes the newest tag by date, not with `git describe`. diff --git a/template/changelog.d/TEMPLATE.md b/template/changelog.d/TEMPLATE.md index 64e9ea6..ac30106 100644 --- a/template/changelog.d/TEMPLATE.md +++ b/template/changelog.d/TEMPLATE.md @@ -1,6 +1,6 @@