Repository navigation
ci: release from annotated tags; remove CHANGELOG-archive.md - #1588
dimitri-yatsenko wants to merge 4 commits into
Conversation
Release history now lives entirely in git tags and GitHub Releases. Every version the archive covered (0.3.2 through 0.14.3) has a tag and a release carrying its notes.
A release is now an annotated tag vX.Y.Z on master whose message is the release notes. Pushing the tag runs the new Release workflow: it checks the tag, runs the lint and test workflows as the gate, builds the package at the tag, publishes it to PyPI, creates the GitHub release with the tag's message as its notes and the wheel and sdist attached, and posts to Slack. The check (`.github/scripts/check_release_tag.sh`) fetches the tag object itself, since checkout can store an annotated tag as a lightweight ref. It fails on a lightweight tag, naming the `git tag -a` command, and on a tag whose commit is not on master. It stops without publishing on a tag whose message has a `Retroactive:` line, which marks a past release re-tagged with its notes. Running the workflow by hand from a tag publishes it to TestPyPI, or, with testpypi unchecked, repeats a failed release. This replaces release-drafter: the Manual Draft Release workflow, its configuration, and the workflow that published a release once its draft was published, including the archived upload-release-asset action. The lint and test workflows gain a workflow_call trigger so the release can run them. RELEASE_MEMO.md describes how a release is cut, and CONTRIBUTING.md points to it. Pull request titles still state the user-visible change, since the notes are written from them; labels no longer drive the notes.
86e3038 to
4d2b8fe
Compare
MilagrosMarin
left a comment
There was a problem hiding this comment.
Thanks @dimitri-yatsenko, this is a clean design: tags as the single record, a gate that refuses lightweight tags, and the retroactive history preserved. I checked that the past tags (e.g. v2.0.0, v0.14.3, v0.11.2) are already annotated on the remote, and CI is green.
Releasing from the GitHub UI
The web UI can't create an annotated tag. "Draft a new release → Create new tag on publish" makes a lightweight tag, so a release done the usual UI way would:
- create the GitHub release and the tag,
- fail
check_release_tag.sh(lightweight), so nothing reaches PyPI, - need the CLI to fix, and then
gh release createfails because the release already exists.
Could we support a UI path? One option:
- Maintainer writes the notes in a draft release (Save draft, which doesn't create the tag).
- A
workflow_dispatch"Tag release" workflow (input: version) reads the draft body and creates the annotated tag via the API. - Since a tag pushed with
GITHUB_TOKENwon't triggerrelease.yaml, either call it directly (workflow_call) or use an App token. release.yamlpublishes the existing draft (gh release edit --draft=false+ upload assets) instead ofgh release create.
If that's out of scope, a line in RELEASE_MEMO.md saying "don't create the tag from the Releases page; it makes a lightweight tag" would prevent a confusing first failure.
Minor
- Re-runs: if a step after
gh release createfails (e.g. Slack), re-running fails at create. Skipping when the release exists would keep re-runs idempotent. - Since pushing
v*now publishes to PyPI, a tag ruleset restricting who can createv*tags may be worth adding if one isn't in place. - RELEASE_MEMO.md says never delete a pushed tag, while the lightweight-tag error says to delete and force-push. Worth noting that a tag rejected by the check is the exception.
Let me know what you think!
|
One more small thing on the release flow: step 3 leaves a
The draft-release workflow suggested above would remove the local file entirely, since the notes would live in the draft. |
Write the release notes to git tag on standard input (-F -) so no notes file is left in the working tree. Note that tags created from the Releases page are lightweight and refused, and that a tag refused before publishing is the one tag that may be replaced. The release step updates an existing GitHub release instead of failing on re-run.
|
Fixed in 00bff96: step 3 now passes the notes to |
|
Thanks @MilagrosMarin. Fixed in 00bff96:
|
|
@MilagrosMarin the browser release path you proposed is now #1680, as a follow-up so this PR stays focused on tag-based releases. The tag ruleset is a repository setting and will be handled separately. |
Releases become annotated tags whose messages are the release notes, and the changelog file is removed. The history lives in the tags' messages; the GitHub releases mirror them.
Releases from annotated tags
A release is an annotated tag
vX.Y.Zonmaster, created withgit tag -a vX.Y.Z --cleanup=verbatim -F notes.md. Pushing it runs the new Release workflow (.github/workflows/release.yaml):.github/scripts/check_release_tag.sh). It fetches the tag object itself, because checkout can store an annotated tag as a lightweight ref.git tag -acommand.master.Retroactive:line. Such a tag records a past release.workflow_calltrigger for this.gh release create "$TAG" --verify-tag --notes-file <the tag's message> dist/*. This replaces the archivedupload-release-assetaction.Running the workflow by hand from a tag publishes it to TestPyPI. With testpypi unchecked, it repeats a release that failed partway.
This replaces release-drafter: the Manual Draft Release workflow,
release_drafter.yaml, and the workflow that published a release once its draft was published. Labels no longer produce the notes, but a pull request's title must still state its user-visible change, because the notes are written from the titles.RELEASE_MEMO.mddescribes how to cut a release, andCONTRIBUTING.mdpoints to it.The history in the tags
Every past release that has notes has been re-tagged as an annotated tag on the same commit, with those notes as its message:
CHANGELOG-archive.md(47 versions);A version with no notes anywhere keeps its tag as it is. That applies to v0.4.8, v0.6.1, v0.7.1, v0.8.1, v0.8.2 and v0.10.2.
A re-tagged message ends like this:
No tag moved to another commit, so
pip install git+...@vX.Y.Z, the versions hatch-vcs derives, and the GitHub releases are unaffected.If your clone already has these tags, a plain
git fetch --tagsreports "would clobber existing tag" for them. Rungit fetch --force --tagsonce.With the history in the tags,
CHANGELOG-archive.mdis removed. Nothing else refers to it or to release-drafter.Checks
actionlint, with shellcheck, passes on the new and changed workflows. shellcheck passes on the check script.The check script was run on a scratch repository against five tags:
mastergit tag -acommandmastervX.Y.ZA clone that stores the annotated tag as a lightweight ref is still read as annotated.
Supersedes #1609.