diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 1499c10..82ddcdf 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "github-release", - "version": "0.8.4", + "version": "0.8.5", "description": "Safe, automated GitHub releases with supply chain security. Prevents dangerous gh release commands, orchestrates version bumps, signed tags, and CI-driven releases across ecosystems (TYPO3, PHP, Node.js, Go, Python, Rust, skill repos).", "repository": "https://github.com/netresearch/github-release-skill", "license": "(MIT AND CC-BY-SA-4.0)", diff --git a/skills/github-release/SKILL.md b/skills/github-release/SKILL.md index 96c5346..6e1066a 100644 --- a/skills/github-release/SKILL.md +++ b/skills/github-release/SKILL.md @@ -5,7 +5,7 @@ license: "(MIT AND CC-BY-SA-4.0). See LICENSE-MIT and LICENSE-CC-BY-SA-4.0" compatibility: "Requires gh CLI, git with GPG/SSH signing configured." metadata: author: Netresearch DTT GmbH - version: "0.8.4" + version: "0.8.5" repository: https://github.com/netresearch/github-release-skill allowed-tools: Bash(gh:*) Bash(git:*) Read Write Edit Glob Grep --- diff --git a/skills/github-release/references/release-process.md b/skills/github-release/references/release-process.md index 96f827d..646c342 100644 --- a/skills/github-release/references/release-process.md +++ b/skills/github-release/references/release-process.md @@ -58,6 +58,20 @@ explicit go, or fix first. Shipping a release with a known open bug from the same stream, then being asked "why did you release with known bugs?", is the failure this gate prevents. +#### Release authorization is per-release — momentum is not a mandate + +A release is outward-facing and (once published) immutable, so **cutting or +even staging one requires an explicit, current instruction for *that* release** +— not inference from a finished feature cycle. Authorization does not carry +forward: "do the release" for version N does not authorize version N+1, and +"fix these issues / finish this PR" never authorizes a release at all. The +autonomous pipeline for feature work *ends* at merged PRs + green CI + closed +issues; then stop and report "release-ready — say the word to cut X.Y.Z". Do +not create `release/*` branches, bump versions, or arm a release PR to +auto-merge without a per-release go. (Staging counts: a bumped, auto-merged +release PR is a release the user did not ask for. "Did you release? I wasn't +asking for a release." is the failure this prevents.) + ### Phase 2: Review and Merge ``` @@ -87,6 +101,25 @@ On mismatch, abort: do not tag, do not push. Cross-check against the API when in doubt: `gh api repos/{owner}/{repo}/commits/main --jq .sha` must equal `git rev-parse HEAD`. +**Reconcile the CHANGELOG against the whole range before tagging — position +is not content.** Step 2 proves you are tagging main's tip; it does *not* +prove the CHANGELOG describes what that tip actually contains. Between the +moment the release PR was prepared and the moment you tag, *other* PRs can +merge onto main — features from a parallel work stream, dependency bumps, +another author's fix — none of them in the `[X.Y.Z]` section you wrote at +prep time. Tagging then ships them undocumented. Immediately before the tag: + +```bash +PREVIOUS_TAG=$(git describe --tags --abbrev=0) # the last release tag +git log --first-parent --pretty='%s' "$PREVIOUS_TAG"..HEAD # everything the tag will ship +``` + +Diff that list against the `[X.Y.Z]` CHANGELOG section and add every merged +feature/fix that is missing (read the PR/ADR to describe it accurately). Do +not trust a CHANGELOG written when the release PR opened — main drifts past a +staged release. If reconciling adds material, land it as a `docs(changelog)` +PR and re-verify step 2 before tagging. + The tag MUST be: - **Annotated** (`-a` or `-s`), never lightweight - **Signed** (`-s` for GPG/SSH signing) — required for SLSA L1+