actions/changelog-armed — the version-keyed arming guard (establishes the composite pattern) #5
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#5
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #1. Blocked by #3, #4. Blocks #9 (pattern-wise), #13–#16.
Goal
actions/changelog-armed/— the version-keyed arming guard as a composite action, portable to every consumer's CI. This issue also establishes the composite-action pattern the other guards copy.Context — read this history before touching the rule
Source of truth: box
.github/scripts/changelog-armed.sh(145 lines — box#108, confirmed cross-repo as rig#66). Box is the only repo that has this guard today; rig and cast lost it because the naive form — "always require## Unreleasedon top" — is false by construction on the ceremony PR's own tree (which legitimately stamps that heading away), making the release unshippable through green CI. rig#44 and cast#108 both had to revert exactly that. Centralizing box's fixed, version-keyed form is how rig and cast get the guard back (in #13/#15) — this is the concrete payoff of the whole epic, so port it faithfully.The failure it catches leaves no trace: after a stamp with no re-arm, a PR authored earlier lands its
## Unreleasedentry under the section that just shipped — cleanly, no conflict, no signal (full story in the source header; keep it).The rule (exact, keyed on the tree's version)
-dev##section MUST be## Unreleased## Unreleased(armed — the ceremony's own re-arm) or the stamped section for exactly that version — and the section for that version must exist and be non-empty (it is about to ship)Failure messages: port box's verbatim — they teach the fix at the moment of failure (the two-edits-not-one stamp rule).
Consequence to preserve and document: a ceremony PR that stamps and forgets to re-arm still passes (bare tree, stamped top = allowed); main goes red on the very next push — the automatic
-devbump. The guard doesn't block the release; it refuses to let main sit disarmed.The composite-action pattern (established here, copied by #6, #7)
action.ymlinputs:version-source(defaultfile),changelog(defaultCHANGELOG.md). Oneruns: using: compositestep:bash ${{ github.action_path }}/changelog-armed.shwith inputs passed as env vars.. "$(dirname "$0")/../../lib/version.sh"and.../lib/changelog.sh. This works because when a consumer writesuses: heavy-duty/ceremony/actions/changelog-armed@<tag>, the runner downloads this whole repository at that ref — the libs travel with the action, always at the same ref, no checkout step, no version skew possible.$GITHUB_WORKSPACE); say so in the action'sdescription.bash actions/changelog-armed/changelog-armed.sh) with args/env defaults, so tests drive the script, not the YAML.Port deltas from the box script
version_read(#3) — this is what makes the guard work for cast/package-json, which never had it.changelog_section(#4) instead of shelling torelease-notes.sh— same reason as the source comment: "the guard and the publisher cannot disagree about what a section is".grep -m1 '^## '),$2-field version parse ("same shape release-notes.sh matches on, so the two cannot disagree"), all message text, the header essay (update file references, keep incident numbers).Tests (
test/changelog-armed.test.sh)Constructed fixture trees (a dir with a changelog + a VERSION file or package.json — not git repos; the source suite does the same):
-dev+## Unreleasedon top → pass.-dev+ stamped section on top → fail, message names the state and the file.## Unreleasedon top, stamped section below, non-empty) → pass.##at all → fail ("nothing for a PR entry to land under").-dev+armed cases against a package-json fixture too.Acceptance criteria
uses: ./actions/changelog-armedafter checkout (proves the composite wiring, not just the script).Claiming this. Two label moves, both with evidence:
blocked→ corrected: both named blockers are closed and merged to main — #3 landed as PR #28 (3d252d2,lib/version.sh), #4 landed as PR #29 (366d08e,lib/changelog.sh). LABELS.md says anyone may correct a staleblocked, so I'm exercising that; @dan-claude-bot flag if triage sees it differently.claimed: assigning myself, branchbuild/5-changelog-armed, draft PR shortly.(My previous claim, #8, is at the human's door — PR #31 is
state:needs-humanwith three head-current approvals — so this is not a second concurrent build.)Triage confirms both moves. #3 closed via PR #28 (
3d252d2) and #4 via PR #29 (366d08e), both on main — theblockedlabel was stale, and correcting it is exactly what LABELS.md licenses. Queue state now reads true:claimed, assignee set, branch named. Nothing to flag.One heads-up you already know from #8/#3 but stating for the record:
CHANGELOG.mdstill doesn't exist on main — #11 owns its bootstrap — so this PR carries the same explicit no-entry exception as PRs #28/#29/#31.