Skip to content

ci: publish releases from the tag, and refuse a tag that skips the changelog - #90

Merged
iyashjayesh merged 1 commit into
mainfrom
ci/release-automation
Aug 29, 2026
Merged

iyashjayesh merged 1 commit into
mainfrom
ci/release-automation

Conversation

@iyashjayesh

Copy link
Copy Markdown
Owner

Answers "can this be controlled from CI/CD?" — mostly yes, and the part worth automating isn't the part you'd expect.

The trap it closes

Cutting a release was four manual steps, and the one that mattered was easiest to skip: stamping CHANGELOG.md. A tag pushed without it gives you:

  • a release page with no notes
  • a docs site that silently shows nothing new — the generator reads CHANGELOG.md, not tags
  • a tagged tree whose own changelog is missing its own entry

Nothing checked for any of it.

What the workflow does

On a v* tag:

  1. Verify the newest stamped section in CHANGELOG.md matches the tag. Fails with both versions named if not.
  2. Publish the GitHub release using that section as the notes — so the release page and the docs site are fed from one source instead of being retyped.
  3. Optionally dispatch a rebuild to the docs site. Skipped cleanly without SITE_REBUILD_TOKEN rather than failing the release; the site already rebuilds daily, so this only shortens the delay.

What stays manual, on purpose

Stamping remains a reviewed PR. I could have CI move [Unreleased] entries under a version heading and push to main — but deciding what shipped, and describing it well, is not a job for a script. It's also the step where today's changelog caught two real problems: a self-contradicting "Known gaps" entry, and eight ### Fixed headings that needed consolidating. A bot would have shipped both.

There's an ordering trap too: stamping after tagging means the tag points at a tree whose changelog lacks its own entry. Keeping the stamp in the commit that gets tagged avoids that entirely.

Verified before committing

Ran the guard's exact shell against the real CHANGELOG.md:

v1.7.0 → PASS: 104 lines of notes
v1.8.0 → FAIL: does not match newest stamped [1.7.0]
v9.9.9 → FAIL: does not match newest stamped [1.7.0]

Workflow YAML parses; steps resolve in order.

Your release flow after this

  1. Stamp CHANGELOG.md → PR → merge
  2. git tag v1.8.0 && git push origin v1.8.0

CI does the rest. And if you forget step 1, step 2 fails loudly instead of quietly publishing an empty release.

…angelog

Cutting a release was four manual steps, and the one that mattered was
the easiest to skip: stamping CHANGELOG.md. A tag pushed without it
produces a release with no notes, a docs site that silently shows
nothing new, and a tagged tree whose own changelog is missing its own
entry. Nothing checked for it.

Pushing a v* tag now verifies that the newest stamped section in
CHANGELOG.md matches the tag, and fails with an explicit message naming
both versions if it does not. It then publishes the GitHub release with
that section as the notes, so the release page and the docs site are
both fed from the same source rather than being retyped.

The stamping stays a reviewed pull request. Deciding what shipped, and
saying it clearly, is not a job for a script -- only the mechanical
steps after it are automated.

An optional final step dispatches a rebuild to the docs site. It is
skipped cleanly when SITE_REBUILD_TOKEN is absent rather than failing
the release, because the site already rebuilds daily on its own; the
dispatch only shortens the delay.

Guard logic verified against the real CHANGELOG before committing:
v1.7.0 passes and extracts 104 lines of notes, v1.8.0 and v9.9.9 both
fail by name.
@iyashjayesh
iyashjayesh merged commit 0ad1097 into main Aug 29, 2026
5 checks passed
@iyashjayesh
iyashjayesh deleted the ci/release-automation branch August 29, 2026 21:47
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.

1 participant