ci: drive releases with release-please and Communique notes#143
Merged
Conversation
Replace the Unreleased-changelog workflow, the release/* changelog
workflow, and the local release:prep/release:finalize scripts (release-it)
with a single release-please flow: a runner executes release-please as a
library with Communique registered as the changelog generator, maintaining
one release PR whose merge creates the tag + GitHub Release and dispatches
the existing tag-driven publish pipeline.
- src/tools/release-please-runner.ts: registerChangelogNotes('communique')
shells out to `communique generate HEAD <last-tag> --concise`; outputs
drive workflow dispatches (CI onto the release branch, release.yml by tag)
since workflow-token pushes/tags never trigger other workflows.
- Heading style for new CHANGELOG sections is `## [<version>] - <date>`
(no v: release-please's PR-body parser needs a digit after the bracket);
unit tests pin that contract and the insertion point against the
installed release-please internals.
- CHANGELOG.md drops the [Unreleased] section: the release PR is the
unreleased view now.
- pnpm-workspace.yaml: aube supportedArchitectures matrix (keeps the
lockfile host-independent) and a documented trustPolicyExclude for
@octokit/endpoint@9.0.6 (last-CJS octokit line ships no provenance).
- ADR 0009 records the decision; ADR 0002 (release-it) is superseded.
Change-Id: If33cccf3ae5d1054992a619d2dab4c1539a01fbc
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
The release branch carries a component suffix (release-please--branches--main--components--agent-tty) because getBranchComponent() ignores include-component-in-tag; resolve the branch from the open PR instead of hardcoding it. Change-Id: Ibf4b9480f96860317aa0bec4838f6d9d8715c4e0 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Communique hard-fails when CHANGELOG.md lacks an Unreleased heading, and it feeds that section's body to the LLM as draft material to reconcile into generated notes. Restore the section and replace release-please's stock Changelog updater (via a node-strategy subclass registered over the builtin type) with one that inserts release sections below the anchor — the stock insertion regex matches '## [Unreleased]' and would insert above it — and clears the reconciled draft body so it cannot leak into later releases. Also add a changelogPreview field to --dry-run output so the resulting CHANGELOG.md can be inspected without pushing. Change-Id: I634dd707083c5d53163e624760c9099b8dd1ff9d Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
A live run produced '## Changed' (H2) where the historical changelog nests '### Changed' (H3) under each version heading; demote stray H2s and drop a duplicate leading version heading if the LLM emits one. Change-Id: I3f8ff8223d8482bffac556d90b32fd348597fab6 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Under the release-please flow the GitHub Release already exists when release.yml runs, so the edit path is the normal route; without the flags a prerelease (e.g. an rc rehearsal) would take over the Latest badge. Change-Id: I82bf91dbb61c8751e8c13578f83ff8b95e8fc8a8 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
- Write release outputs before rebuilding the release PR and guard the workflow dispatch steps with !cancelled(): a notes failure (LLM outage) after createReleases() tagged a release previously meant release.yml was never dispatched, and a rerun could not recover it (the merged PR label has already flipped to autorelease: tagged). - Make the changelog section-boundary scan and the H2 demotion fence-aware so '#'-prefixed lines inside fenced code blocks in staged drafts or LLM output are never mistaken for headings. - Fail with an error naming communique when it exits 0 without writing the --output file, instead of a bare readFileSync ENOENT. - Move formatChangelogSection's heading-contract JSDoc back onto the function it documents. Change-Id: Ie5f78cb5e52338a1f9b55c4b5d7df0818c900fcc Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the changelog/release machinery (the
[Unreleased]bot-PR workflow, therelease/*changelog workflow, and the localrelease:prep/release:finalizescripts) with a single release-please-driven flow that keeps Communique as the changelog author:chore(release): <version>) maintained on every push tomain, carrying the version bump plus a Communique-writtenCHANGELOG.mdsection. Merging it is the release: the next workflow run creates thev<version>tag + GitHub Release and dispatches the existing tag-drivenrelease.ymlpublish pipeline (which is unchanged).src/tools/release-please-runner.tsregisters Communique viaregisterChangelogNotes('communique', ...)(communique generate HEAD <last-tag> --concise, previous tag passed explicitly so both tools agree on the range). Precedent: npm/template-oss runs release-please the same way.## [Unreleased]stays at the top of CHANGELOG.md — Communique hard-requires the heading and feeds its body to the LLM as draft material to reconcile into generated notes. Release-please's stock updater would insert new sections above it, so a custom updater (wired via anode-strategy subclass) inserts release sections below the anchor and clears any reconciled draft so it can't leak into later releases. Maintainers can stage draft wording under[Unreleased]in a small PR and Communique folds it into the next release's notes.bump-minor-pre-major+bump-patch-for-minor-pre-major, matching the project's pre-1.0 history (breaking → minor, feat/fix → patch).Release-As:footers override.v(## [0.4.2] - <date>): release-please recovers the version from the merged PR body with a parser that requires a digit right after the bracket — with avthere, merge would create no release. Unit tests pin this contract against the installed release-please internals. Generated bodies are also normalized against LLM drift (stray H2 section headings demoted to the house###style).gh workflow rundispatches (CI + validate-skills onto the release branch,release.ymlby tag input).release-pleaseis an exact-pinned devDependency. Its CJS-only octokit 9.x line ships no npm provenance, so@octokit/endpoint@9.0.6gets a documentedtrustPolicyExcludein the newpnpm-workspace.yaml(which also pins an explicitsupportedArchitecturesmatrix so lockfile regeneration stays host-independent —aube addon macOS had silently dropped the linux/win32 optional-dep entries).docs/RELEASE-PROCESS.mdrewritten for the new flow.What releasing looks like now
release.yml(quality gates → verified tarball → editorial Communique notes + assets → npm trusted publish), all as before.Verification
vheading constraint,chore(release): ${version}title parsing, and the Unreleased-aware updater (insert below the anchor, clear staged drafts, self-heal a missing heading).actionlint+zizmorclean; format/lint/typecheck/build green.--dry-runwith a real ANTHROPIC_API_KEY against this branch: Communique generated real curated notes for these changes, the candidate PR came out aschore(release): 0.4.2with a parseable body, and thechangelogPreviewshowed exactly the intended file shape — empty[Unreleased]on top, new## [0.4.2]section below it, historical## [v0.4.1]untouched.After merging (operational notes)
mainafter merge opens the first release PR — sanity-check its version + notes before merging it.automation/update-unreleased-changelogPR (if any) should be closed; its workflow no longer exists.ANTHROPIC_API_KEYsecret (orOPENAI_API_KEY+COMMUNIQUE_MODELvar) — same contract as the retired workflows.🤖 Generated with Claude Code