ci: group and filter the release changelog, and stamp an install footer - #50
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Release notes assembled themselves from a flat commit list, so v0.1.0's body was written by hand. GoReleaser now groups the range into New features (feat), Bug fixes (fix) and a catch-all Other changes, and drops docs/test/chore/ci/build subjects and merge commits. The catch-all is what keeps an off-nomenclature subject — refactor, perf, rebrand — visible instead of silently vanishing. The two regexp shapes are not interchangeable, which is the one thing to get right here. A group regexp matches the rendered line, which use: github prefixes with the commit SHA, so it needs the leading ^.*? — an exclude pattern is applied to the raw subject and anchors at ^docs. Confirmed on a real render rather than read off the docs: the SHA prefix is there and the ^docs excludes still fired. The Install block v0.1.0 carried by hand moves into release.footer, on the existing release: key — a second one is a YAML unmarshal error. It stays inline code rather than a fenced block because this body is also what panel [2] renders, where mdInline drops backticks and the three install paths read as one sentence; a fence would split that sentence across three plated blocks. Note the plan's own reason for that choice had gone stale: it was written against stripMarkdown, which e81bfb6 replaced with markdownToLines. goreleaser check cannot validate a footer template, so the one typo class that would fail the release job after the tag is already pushed was checked separately: the footer parses and executes under text/template with missingkey=error, rendering the real tag with its leading v. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The ^.*? prefix on the two group regexps was wrong, and the reasoning recorded for it was wrong in the same way. Grouping runs before an entry is formatted, so it matches the bare commit subject and never sees the SHA the rendered line carries — confirmed in GoReleaser's own source (changelog.go:185 matches entry.Message; client/github.go:156 sets that to the subject, so it holds for use: github too) and by a render with the wildcard removed, which grouped every entry correctly while the output still showed its SHA prefix. With the wildcard, feat and fix were substring matches. git revert writes Revert "feat: x" by default, so a reverted feature was announced under New features — as the first line, since sort: asc compares bytes and R precedes f. fixup! and squash! subjects leaked the same way. Verified after the fix: both fall to Other changes, and all four breaking-marker shapes still group right. The false confirmation is worth naming, since the mechanism repeats. The earlier test saw a SHA in the output and concluded grouping matched the formatted line; rendering happens after grouping, so that does not follow. And ^.*? matches under either hypothesis, so the experiment could not distinguish them and confirmed nothing. The decisive test was to delete the wildcard and see whether grouping still worked. Two smaller things found in the same pass. The go mod tidy exclude was unanchored and silently dropped any subject containing the phrase, so "feat: run go mod tidy before build" vanished from the notes; it anchors now. And the entry SHA was the default full 40 characters, which GitHub shortens on the release page but keepkit's own card does not — panel [2] is ~27 cells, so abbrev: 7 buys back most of every entry's width and stays autolinked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Self-review found a real defect in the first commit. Fixed in 2eb5d09. The
|
Release notes were a flat commit list — v0.1.0's body was written by hand. Two edits to
.goreleaser.yamlplus a commit-discipline note inCLAUDE.md.Changelog groups
Keeps
use: githubandsort: asc(alphabetical by message, not chronological — scoped subjects likefeat(model):cluster inside their group). Excludesdocs/test/chore/ci/build, merge commits andgo mod tidy. Three groups: New features (feat), Bug fixes (fix), and Other changes with noregexp— the catch-all that keepsrefactor:/perf:/rebrand:visible instead of dropping them.The two regexp shapes are not interchangeable and this is the part worth reviewing: a group
regexpmatches the rendered line, whichuse: githubprefixes with the SHA, hence the leading^.*?; anexcludematches the raw subject and anchors at^docs. Swap them and either the groups match nothing or the excludes match far too much.Install footer
Goes on the existing
release:key — a secondrelease:is a YAML unmarshal error (mapping key "release" already defined).{{ .Tag }}is the only template expression.Inline code, not a fenced block: this body is also what keepkit renders in panel
[2], wheremdInlinestrips backticks and the three install paths read as one sentence. A fence would split that sentence across three plated blocks.Verification
Rendered the changelog against real history (31 commits since
v0.1.0):Every
docs:and merge commit filtered out. This also confirmed both regexp halves empirically — the SHA prefix is present in the rendered lines, and the^docsexcludes still fired.goreleaser checkexit 0 (only the pre-existingbrewsdeprecation warning). Full preflight green:go build,go vet ./...,go test -race ./...(10 packages),golangci-lint run0 issues.goreleaser checkdoes not validate templates, so a footer typo would only surface as a failed release job after the tag is pushed. Closed that gap directly: extracted the footer from the parsed YAML and ran it throughtext/templatewithOption("missingkey=error"), so a mistyped field fails hard instead of publishing<no value>. Rendersgo install github.com/stanlyzoolo/keepkit@v0.1.1—.Tagkeeps its leadingv.Notes for the reviewer
Four things diverged from the plan (all recorded in
docs/plans/completed/20260727-release-changelog-groups.md):mainfirst. The branch sat onf8ad9d2;mainhad moved 31 commits ahead and rewrittenCLAUDE.mdby 89 lines — the exact file this change edits..goreleaser.yamlwas untouched by all 31, so the config work was unaffected.use: githubpulls from the compare API, and a local temp tag doesn't exist on the remote →404oncompare/v0.1.0...v0.1.1-preview. Pushing a preview tag isn't acceptable, so I rendered through a throwaway copy of the config withuse: git. Same filter/group code path, no token, committed config untouched.v0.1.0was docs/chore. After the rebase it's populated — a stronger check, since all three groups fire at once.stripMarkdownmangling fences;e81bfb6replaced that withmarkdownToLines, which handles fences properly. Decision unchanged, reason rewritten — verified by probingmarkdownToLineswith the real footer text (## Install→ heading with prefix stripped, commands → body with backticks gone).Still unproven end-to-end: GoReleaser only renders the footer when actually cutting a release, so its publish-time plumbing waits for the next tag. The template itself is checked.
fetch-depth: 0inrelease.ymlstays — GoReleaser needs full history for the tag range. No other workflow references changelog behavior. README needed no change; both its "changelog" mentions are the TUI's[c]key.🤖 Generated with Claude Code