fix(release): correct the changelog baseline and stop minting dev tags per merge (PRINFRA-507) - #287
Conversation
…s per merge (PRINFRA-507) v0.7.0 published notes covering one commit instead of five. The cause was not GoReleaser: .goreleaser.yaml has no changelog block, so the baseline defaults to the previous tag of any kind, and dev-release.yml minted a prerelease on every push to main. The tag immediately before v0.7.0 was a dev build cut minutes earlier, so the range was that one merge. Three changes, smallest first: Dev releases become on-demand. The push trigger produced 78 prereleases against 22 stable, nearly all with zero downloads, and RELEASE.md has always documented dev builds as manually dispatched — the workflow simply did more than the doc claimed. Dropping it removes the tag spam and the thing that corrupted the baseline. Dev builds are still one `gh workflow run` away, so the occasional real use and the `heygen update` dev channel both survive. GORELEASER_PREVIOUS_TAG pins the baseline to the previous *stable* tag, using the same filter the pre-release checklist already uses. Belt and braces: it keeps the range correct even if a dev tag lands in between again, and it is the safety net for a release cut without an agent driving the checklist. Verified against the real tags: cutting v0.7.0 resolves to v0.6.0 and yields the five commits that actually shipped. Post-release gains the step that was missing entirely: publishing the changelog generated in step 7. Nothing does it automatically and nothing fails if it is skipped, so the doc now says so plainly rather than leaving the notes to be written and discarded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both review findings fixed:
Unreachable in this repo (22 stable tags), but it's the kind of thing that only ever fires on a fresh fork, where nobody is watching for it. |
3a27ece to
12559ab
Compare
somanshreddy
left a comment
There was a problem hiding this comment.
Endorse (COMMENTED — my own account; GH-APPROVE to @rames Jusso). Root cause + fix are correct. Dev-per-merge tags shadowed GoReleaser's changelog baseline (it baselines on the previous tag of any kind → a dev tag cut minutes before the stable release → notes cover one commit). The fix:
- dev builds on-demand — dropped the
push: [main]trigger; on-demand dispatch only. - baseline pinned to the previous stable tag — the new step resolves
GORELEASER_PREVIOUS_TAGviagit tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -vFx "$version" | head -n1. The regex correctly excludes-dev./prerelease tags, and-vFx "$version"excludes the current release, so the changelog range is the full release whoever cuts it. First-stable edge handled (leave the override unset, not empty — right call, since GoReleaser doesn't document empty-value semantics). - curated-notes post-release step now documented.
Hardest look: dropping per-merge dev prereleases is low-risk — 78 dev tags / ~zero downloads, and RELEASE.md already described dev as manually-dispatched (so the doc is genuinely unchanged on that point). "Inference from zeros, not proof" is a fair caveat; if you want proof the per-asset download counts are queryable via gh api repos/.../releases, but the zeros + the changelog-corruption cost make the tradeoff clearly right. Clean fix — and it closes the loop on the #284/#286 release-gate line (the surface diff catches what shipped; this makes the changelog say it).
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Layering on Somansh's self-endorsement (COMMENTED — leaving the stamp for OG). Diagnosis + fix land cleanly; three observations for later and one call-out that isn't in the diff.
What I verified
-
Author + CI.
somanshreddy(human, co-authoredclaude). All required checks green. -
Zero-download claim (empirical, not repeated). Enumerated the 4 most recent dev prereleases via
gh api /repos/heygen-com/heygen-cli/releases --paginate:tag published asset downloads v0.6.1-dev.2026081206282026-08-12 06:30Z 0 v0.6.1-dev.2026081205532026-08-12 05:55Z 0 v0.6.1-dev.2026081205502026-08-12 05:52Z 0 v0.6.1-dev.2026081120032026-08-11 20:05Z 0 Total across the last four: 0. Claim verified. Worth naming that #5 back (
v0.6.1-dev.202608050333) is 22 downloads and there are ~5–6 older dev tags in the 15–22 range — so "occasional real use" (your PR-body phrasing) is the accurate reading. The framing in the description already handles this honestly; no ask. -
Baseline selector correctness.
^v[0-9]+\.[0-9]+\.[0-9]+$correctly excludes every-dev./-rc/-beta/-alphaprerelease — not just dev tags. Good.--sort=-v:refnamegives semver-aware ordering (v1.10.0 > v1.2.0).grep -vFx "$version"fully-anchored + fixed-string: safe becauseValidate versionalready pins$versionto^v[0-9]+\.[0-9]+\.[0-9]+$before this step runs, so no metacharacters can leak.- The "Create git tag" step pushes the new tag before Resolve runs, so the newly-created tag is in the local tag DB — self-exclusion via
-vFxis what makes this work. Correct sequencing. - First-stable edge: leave
GORELEASER_PREVIOUS_TAGunset (not empty) — right call given GoReleaser doesn't document empty-value semantics.
-
Sibling consistency. The exact same regex
^v[0-9]+\.[0-9]+\.[0-9]+$is now used in three places:dev-release.ymlcompute step,release-stable.ymlresolve step, and RELEASE.md'sLAST_STABLEpre-release checklist. Consistent — this fix reuses the filter that was already there, not inventing a new pattern. Positive.
Observations (not blockers)
-
v0.7.0 itself is not backfilled by this PR. The mechanism fix is forward-only:
RELEASE.mdgains a step to publish curated notes for future releases, but the publicv0.7.0release page still shows notes covering the one commit. If v0.7.0 matters as a discoverable release page (users landing on it from GitHub orheygen update --versiondocs), a one-shotgh release edit v0.7.0 --notes-file <curated>after this PR merges closes the loop. Otherwise the visible page stays misleading. -
No dry-run for baseline selection. The only way to test the resolve step today is to cut a real release. If a nightly-build workflow ever gets added that reintroduces per-push dev tags — or if the regex silently drifts — the same class of bug re-emerges silently. A
workflow_dispatchinput likedry_run: truethat runs Resolve and echoes the chosen baseline (without invoking GoReleaser) would give this fix a keeper. Not this PR; noting for the punch list. -
-rc/-betatreatment is by design but worth naming. The regex excludes all prereleases. If the team ever adopts RC cuts (v0.8.0-rc.1→v0.8.0),v0.8.0's baseline resolves tov0.7.0, notv0.8.0-rc.1— the changelog will span the RC's contents plus anything added between RC and final. That's arguably the right default for "what shipped in this release," but it's a semantic choice that would surprise anyone who assumed RC-to-final diffing. Worth a comment on the resolve step if RC cuts are ever on the roadmap.
Nits
RELEASE.mdtag-format update ({YYYYMMDD}.{shorthash}→{YYYYMMDDHHmm}) is a straight correction — the compute step indev-release.ymlproducesdate -u +%Y%m%d%H%Mwith no shorthash, so the prior doc had drifted silently. The "doc always documented X" framing in the PR body is a bit generous on this specific line; the doc has been correct on the trigger semantics (manually dispatched) but stale on the format. Minor.
What I didn't verify
- I didn't actually run the new resolve step against a real tag list in a dry-run harness — verified by reading the regex and cross-checking against the tag list from
gh api /releases. If concerns above (2) is picked up as a follow-up, the same script becomes the verification.
— Review by Rames D Jusso
|
Thanks — three of four land, one is already done. Obs 1 (v0.7.0 not backfilled) — already closed, before this PR. The curated notes went onto v0.7.0 with Obs 2 (no dry-run for baseline selection) — agreed, and the sharpest of the three. Cutting a real release is currently the only way to exercise the resolve step, which is a bad property for the one piece of logic whose failure mode is silent. A Obs 3 ( Nit — fair, and my PR body was loose. "The doc always documented this" is true of the trigger (manually dispatched, never mentioned the push trigger) and not of the format, which had drifted to No code changes from this round. |
jrusso1020
left a comment
There was a problem hiding this comment.
Approving. Verified at 12559ab9: all six required contexts green (test on ubuntu / macos / windows, lint, secrets, goreleaser-check). No CODEOWNERS in this repo, so REVIEW_REQUIRED here was the missing approval rather than a missing owner.
The baseline resolver is correct where it counts. I ran its pipeline against a synthetic tag list and it picks v0.7.0 out of v0.8.0 / v0.7.0 / v0.7.0-dev.202608120628 / v0.6.1. Two things are quietly load-bearing and both hold: grep -vFx "$version" matters because Create git tag pushes the current tag two steps earlier, so it is already in git tag --list by the time this runs; and fetch-depth: 0 on the checkout is what makes that list complete, since a default shallow fetch would leave only the tag just created.
One nit, not a blocker: the first-stable branch cannot execute. Under set -euo pipefail, a failing grep inside a command-substitution assignment aborts the step, so when nothing matches, the step dies at the assignment and never reaches if [ -z "$prev" ]. Confirmed in all three shapes:
- no stable tags at all: exit 1, branch never reached
- only stable tag is the current version: exit 1, branch never reached
- normal case:
prev=v0.7.0, exit 0
Unreachable in this repo (26 stable releases exist), and the failure mode would be a loud step failure at release time rather than a silently wrong changelog, so it does not change the verdict. It matters if these workflows get copied to a new repo, which is the usual fate of release workflows: the first release there would die on a bare grep exit instead of printing the message the comment promises. One-line fix if you want the branch to do what it says: ... | head -n 1 || true)".
Smaller: the dev-release.yml comment's counts read 78 ... against 22 stable releases, and today the repo has 109 prereleases against 26 stable releases. Same direction, and the argument is stronger with the real numbers, but it is a permanent comment so worth correcting while it is cheap.
Doc change is accurate: the dev tags actually minted are YYYYMMDDHHmm (e.g. v0.6.1-dev.202608120628), so RELEASE.md had been documenting a {YYYYMMDD}.{shorthash} format that is not what ships. Publishing the curated notes as an explicit post-release step is the right call given nothing fails when it is skipped.
— Rames Jusso
Scope
Surfaces: CLI | Module: Release process
Summary
v0.7.0 published release notes covering one commit instead of five. Device auth login, brand glossaries and the deprecation feature all shipped invisible to anyone reading the release page.
Root cause
Not GoReleaser being unhelpful.
.goreleaser.yamlhas nochangelog:block, so the baseline defaults to the previous tag of any kind — anddev-release.ymlminted a prerelease on every push tomain:Five dev tags sat between the two stable releases. The changelog was correct for the range it was given; the range was wrong.
Fix
Dev releases become on-demand. The push trigger produced 78 prereleases against 22 stable, nearly all with zero downloads — the last four have zero between them. RELEASE.md has always documented dev builds as manually dispatched (
gh workflow run dev-release.yml) and never mentioned the push trigger, so this makes the workflow match the doc rather than changing the contract. Dev builds stay one dispatch away, preserving the occasional real use and theheygen updatedev channel.GORELEASER_PREVIOUS_TAGpins the baseline to the previous stable tag, reusing the filter the pre-release checklist already relies on. This is belt and braces: it keeps the range right if a dev tag ever lands in between again, and it is the safety net for a release cut without an agent driving the checklist.Post-release gains the missing step — publishing the changelog from step 7. Nothing does it automatically and nothing fails if it is skipped, so the doc now says that plainly instead of leaving notes to be written and thrown away.
Testing
Workflow changes, so verified by exercising the logic rather than by unit tests.
v0.7.0resolves tov0.6.0and yields the 5 commits that actually shipped, versus the 1 that was published. Cuttingv0.8.0resolves tov0.7.0.release-stable.ymlwould not surface until the next release attempt).make lintand the full suite green.Deliberately not included
GoReleaser
changelog:grouping. With the baseline fixed the fallback is already a correct commit list for the release, and the curated notes replace it anyway — grouping would only ever polish a path that gets overwritten.Note for reviewers
One behavior change worth a conscious nod: anyone habitually pulling "the newest dev build" now has to ask for one. Download counts say nobody is, but that is inference from zeros, not proof.