Skip to content

fix(release): stop dropping release-notes headings and first bullet - #1046

Merged
ToreMerkely merged 1 commit into
mainfrom
fix-release-notes-tag-body
Jul 28, 2026
Merged

fix(release): stop dropping release-notes headings and first bullet#1046
ToreMerkely merged 1 commit into
mainfrom
fix-release-notes-tag-body

Conversation

@ToreMerkely

Copy link
Copy Markdown
Contributor

Release notes are carried in the annotated tag message. Two defects combined to truncate them — v2.35.0 published with only its last bullet, losing the # Breaking changes heading, the breaking-change bullet, and the # Improvements heading.

Root cause

  1. git tag -a -F stripped the headings. Both tag-creation paths (bin/release-interactive.sh, Makefile release target) omitted --cleanup, so git's default cleanup removed every line starting with # as commentary.
  2. %(contents:body) then ate the first bullet. The workflow read the tag body with %(contents:body), which omits the message's first paragraph as a "subject". With the headings already gone, that paragraph was the first bullet.

Defect 2 was latent on its own: had the headings survived, %(contents:body) would have swallowed # Breaking changes instead.

Changes

  • bin/release-interactive.sh and Makefile — pass --cleanup=verbatim to git tag -a.
  • .github/workflows/release.yml — read %(contents) instead of %(contents:body).
  • Added a guard for the make release tag=vX.Y.Z fallback path, which tags with the version as the entire message. %(contents) is non-empty there, so without the guard GoReleaser would receive vX.Y.Z as the whole release body instead of falling back to its default changelog.

Verification

Defect 2 is confirmed against the real v2.35.0 tag: %(contents) returns both bullets where %(contents:body) returns only the second.

The --cleanup=verbatim behaviour is not empirically verified here — it rests on git's documented default (--cleanup=strip removes commentary) plus the observed symptom (headings present in dist/release_notes.md, absent from the pushed tag). The next release exercises it for real; worth a look at the tag message before the workflow runs.

The already-published v2.35.0 release body has been corrected by hand. Its annotated tag still carries the stripped message.

🤖 Generated with Claude Code

Release notes are carried in the annotated tag message, but two defects
combined to truncate them. v2.35.0 shipped with only its last bullet.

- `git tag -a -F` used git's default cleanup, which strips lines starting
  with '#' as commentary, deleting the markdown headings. Pass
  --cleanup=verbatim in both tag-creation paths.
- The workflow read the tag with %(contents:body), which omits the first
  paragraph as a "subject". Once the headings were gone that paragraph
  was the first bullet, so it was discarded too. Use %(contents).

%(contents) is non-empty for tags made by the `make release tag=vX.Y.Z`
fallback, whose whole message is just the version, so guard against
passing that to GoReleaser as release notes and keep its default
changelog for that path.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Claude finished @ToreMerkely's task in 2m 1s —— View job


Code Review — release notes fix

  • Read PR diff and surrounding release infra (release.yml, Makefile, bin/release-interactive.sh, bin/suggest-version-ai.sh)
  • Verify both defects and their fixes
  • Check for other tag-body readers that need the same change
  • Edge-case / correctness pass
  • Post review

This is a clean, well-diagnosed fix. The root-cause writeup matches the code: git's default --cleanup=strip eats # heading lines, and %(contents:body) drops the first paragraph as a "subject". Both fixes are correct and minimal.

Correctness ✅

  • --cleanup=verbatim on git tag -a -F (both Makefile:221 and release-interactive.sh:57) is the right fix — strip is git-tag's documented default and is exactly what removes # lines. Verbatim preserves the markdown headings intact.
  • %(contents) vs %(contents:body) — correct. %(contents) returns subject+body, so the first bullet/heading is no longer swallowed. $(...) strips the trailing newline and printf '%s' adds none, which is fine for GoReleaser.
  • The fallback guard (release.yml:177-181) is a necessary companion change: %(contents) is non-empty for the -m"$(tag)" path, so without the guard the bare version string would be passed as the whole release body instead of falling back to GoReleaser's changelog. Good catch — this would have been a latent regression introduced by the %(contents) switch itself.

Consistency ✅

  • Grepped the tree — release.yml:176 is the only reader of the tag body, so no other call sites need updating.
  • The -m"$(tag)" branch in Makefile:221 correctly does not get --cleanup=verbatim (a plain version string needs no protection), and the workflow guard handles that path. The two changes are consistent with each other.

Minor notes (non-blocking)

  • The fallback guard rests on a string match (see inline comment) — fine in practice, just an assumption worth knowing about. A structurally cleaner alternative would be to have the tag= path signal "no notes" out of band (e.g. an empty/sentinel body) rather than string-matching the version, but that's more invasive than this fix warrants.
  • No automated coverage here (release infra), so the --cleanup=verbatim behaviour is only exercised by the next real release — as the PR body honestly flags. Eyeballing the pushed tag message (git tag -l --format='%(contents)' vX.Y.Z) before the workflow runs is a good idea, as suggested.

Static checks

Only shell/YAML/Makefile changed — no Go sources touched — so go build / go vet / go mod tidy are N/A for this diff.

Nice work 👍

Thorough root-cause analysis with the two defects cleanly separated (including the observation that defect 2 was latent behind defect 1), honest verification notes about what was and wasn't empirically confirmed, and explanatory comments left inline in both scripts so the next person doesn't re-introduce the bug. The guard addition shows the interaction between the two fixes was thought through rather than each fixed in isolation.
· branch fix-release-notes-tag-body

@ToreMerkely
ToreMerkely enabled auto-merge (squash) July 28, 2026 12:12
Comment thread .github/workflows/release.yml
@ToreMerkely
ToreMerkely merged commit 462dea9 into main Jul 28, 2026
16 checks passed
@ToreMerkely
ToreMerkely deleted the fix-release-notes-tag-body branch July 28, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants