From b7d46eb47246e012ace3c60fd5a30ac1316b5b52 Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Sun, 2 Aug 2026 13:54:30 -0600 Subject: [PATCH] Document immutable releases in the release process Release immutability is now enabled for this repository, so a published release permanently locks its Git tag to a commit, and deleting the release does not free the tag name for reuse. Reorder the steps so the signed tag is created and pushed before the release is drafted, and have the draft select that existing tag. Letting GitHub create the tag at publish time produces an unsigned, lightweight tag pointing at whatever main resolves to at that moment - both of which immutability then makes permanent. Also record that the v6 major tag must never have a release attached: immutability locks only tags that have a release of their own, which is what keeps the conventional major-tag force-push legal. Co-Authored-By: Claude Opus 5 (1M context) --- RELEASING.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 27c877a0..f90a3ac5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -9,20 +9,39 @@ - If new features have been added, bump the minor version (eg `4.1.1` → `4.2.0`) - If a new major release is required, bump the major version (eg `4.1.1` → `5.0.0`) - Note: The gradle actions follow the GitHub Actions convention of including a .0 patch number for the first release of a minor version, unlike the Gradle convention which omits the trailing .0. +- Release immutability is a one-time repository setting (Settings → General → Releases → "Enable release immutability"), and applies to every release published thereafter. ## Release gradle/actions -- Create a tag for the release. The tag should have the format `v6.2.0` + +> [!IMPORTANT] +> Releases in this repository are [immutable](https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases). +> Once a release is published, its Git tag is permanently locked to a commit and its assets can no +> longer be changed. Deleting the release does not release the tag name for reuse — a mistake in +> `v6.3.0` means the next release must be `v6.3.1`. Everything below is ordered so that the tag is +> correct *before* anything is published. +> +> Drafts are exempt: a draft release, and its tag, can still be edited or deleted freely. + +- Create and push the tag for the release **before** drafting it. The tag should have the format `v6.2.0` + - Your HEAD must point at the commit to be released. - From CLI: `git tag -s -m "v6.2.0" v6.2.0 && git push --tags` - Note that we sign the tag and set the commit message for the tag to the newly released version. + - Do **not** let GitHub create the tag when the release is published. It creates an unsigned, + lightweight tag pointing at whatever `main` resolves to at that moment — so anything merged + while the draft was open is silently included. Immutability makes both permanent. - Go to https://github.com/gradle/actions/releases and "Draft new release" - - Use the newly created tag and copy the tag name exactly as the release title. + - Select the existing tag — do not use "Create new tag on publish" — and copy the tag name exactly as the release title. - Craft release notes content based on issues closed, PRs merged and commits - Include a Full changelog link in the format https://github.com/gradle/actions/compare/v2.12.0...v3.0.0 + - Finalize the notes now, while the release is still a draft. - Publish the release. + - Confirm immutability took effect: `gh api repos/gradle/actions/releases/tags/v6.2.0 --jq .immutable` should print `true`. - Force push the `v6` tag (or current major version) to point to the new release. It is conventional for users to bind to a major release version using this tag. - From CLI: `git tag -f -s -a -m "v6.2.0" v6 && git push -f --tags` - Note that we sign the tag and set the commit message for the tag to the newly released version. - Your HEAD must point at the commit to be tagged. + - Never attach a GitHub release to the `v6` tag. Immutability locks only those tags that have a + release of their own, so the major tag remains movable precisely as long as it has none. ## Post release steps