Skip to content

ci: fail the release run on a missing tag and reject markup in release notes - #164

Merged
MikeGrier merged 4 commits into
mainfrom
mikegrier/release-guard-unreleased-components
Oct 22, 2026
Merged

MikeGrier merged 4 commits into
mainfrom
mikegrier/release-guard-unreleased-components

Conversation

@MikeGrier

Copy link
Copy Markdown
Owner

Prevents a repeat of the #160 release, where release-please skipped three components and reported success.

Cause. release-please reads the merged release PR body as HTML. A BREAKING CHANGE: footer is copied into it unescaped, and a subject is escaped except inside backticks. A generic such as Key<A> opens an element that is never closed, and two of them swallow the sections after them. Those components got no tag or release, and their crates.io publishes never ran.

Changes

  • check-release-tags.cjs: after both phases, release.cjs fails if any package in the config has a manifest version with no tag. The run now fails when this happens, and lists the missing tags.
  • check-commit-text.cjs and a commit text CI job: reject angle-bracket markup in a BREAKING CHANGE: footer or inside backticks in a subject. Addresses such as Co-authored-by trailers are allowed.
  • DEVELOPMENT.md: documents both and the repair.

Verification. The lint is tested against release-please's own PullRequestBody.parse: flagged and backticked footers lose components, and Key[A] keeps all of them. Backticks do not protect. The tag check passes on the current tree, and removing the verify call fails two tests. The lint flags exactly the five commits in the last 40 on main that carried generics.

Commit scope is ci:, so it triggers no release.

…t markup in release notes

release-please reads the merged release pull request body as HTML. A generic in a BREAKING CHANGE footer (or backticked in a subject) opens an element that is never closed, two of them drop later components from the body, and those components get no release or tag while the run still succeeds. The manifest on main already names their new versions, and the dependent publish workflows then time out waiting for the crate.

The release run now fails after both phases when a package in the config has a manifest version with no tag. A commit-text job rejects the markup on the pull request. Both are checked against release-please's own body parser, which showed that backticks do not protect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 22, 2026 21:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The lint misses implicit breaking-change notes from ! subjects, and tag verification rejects legitimate unreleased bootstrap versions.

2 open issues
What changed in this PR

This PR hardens release automation against the skipped component releases seen in #160, adding commit-text validation and a post-run tag check.

Changes:

  • Reject markup in breaking-change footers and backticked commit subjects.
  • Fail release runs when configured manifest versions lack tags.
  • Add regression tests and document the failure mode and repair procedure.
File Description
DEVELOPMENT.md Documents markup restrictions, tag verification, and release repair.
.github/​workflows/​ci.yml Adds pull-request commit-text validation.
.github/​release/​release.test.cjs Tests verification ordering and failure propagation.
.github/​release/​release.cjs Runs tag verification after release and proposal creation.
.github/​release/​check-release.test.cjs Tests tag checks and release-body markup handling.
.github/​release/​check-release-tags.cjs Detects configured manifest versions without tags.
.github/​release/​check-commit-text.cjs Scans commit messages for unsafe release-note markup.

Review effort: Balanced

Comment thread .github/release/check-commit-text.cjs Outdated
Comment thread .github/release/check-release-tags.cjs
… version a changelog records

Review of the release guard found two gaps.

The commit-text lint re-read the BREAKING CHANGE footer syntax itself, so it missed that a ! subject is a breaking note and enters the release body unescaped, and that an explicit footer replaces that note. It now takes the notes from release-please's parseConventionalCommits, so the lint and the release agree by construction. The CI job installs the release tooling for that.

The tag check demanded a tag for every manifest version, so registering a crate at a bootstrap version in a chore commit would fail the next release run before its first release exists. A tag is now owed only to a version the package's CHANGELOG.md records, which the release pull request writes in the same commit that sets the version; the tree's two bootstrap crates are the regression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 22, 2026 21:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The tag-listing endpoint access fails at runtime, and a test incorrectly requires unreleased bootstrap packages to remain in the repository.

2 open issues
2 resolved since last review

Review effort: Balanced

Comment thread .github/release/check-release-tags.cjs Outdated
Comment thread .github/release/check-release.test.cjs Outdated
… depending on release state

Review of the release guard found that the tag lister was never exercised: every test injected a replacement. It read the legacy octokit.repos alias, which the locked @octokit/rest 20 still provides (checked against the real client and the live repository), but the rest namespace is the one the client documents. The lister now uses it, and a test exercises the real lister with a fake client, and asserts the locked client exposes the endpoint where the lister reads it.

The verification test required the tree to keep an unreleased bootstrap package, so it would have failed once every crate had released. It now loops over whatever is recorded or unrecorded, and the fixed bootstrap fixture carries the distinction.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 22, 2026 21:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Tag verification can check an older checkout than the release phase processes, allowing skipped newer releases to go undetected in that run.

1 open issue
2 resolved since last review

Review effort: Balanced

Comment thread .github/release/check-release-tags.cjs
Review of the release guard found that the check reads the push's checkout while the release phase loads the live default branch, so a release pull request merged while a run waits or starts could be released by this run and verified against older files.

The check now runs only when the branch tip was the checkout both before the release phase began and after it ended, and otherwise notes that it was skipped. The skipped case is not a gap: the workflow serializes runs, and the run for the newer push checks out the newer revision and makes the same check. Both the trailing-checkout and the moved-during-the-phase cases are regressions, and removing either half of the condition fails one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 22, 2026 21:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The safeguards depend on live GitHub state and workflow serialization, and dependency-backed tests were not executed during review.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@MikeGrier
MikeGrier merged commit a7a01e8 into main Oct 22, 2026
46 checks passed
@MikeGrier
MikeGrier deleted the mikegrier/release-guard-unreleased-components branch October 22, 2026 21:50
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