-
Release v0.28.0
StableSome checks failedchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 7schangelog-body-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (pull_request) Has been skippedfragment-check / changelog fragment-kind (pull_request) Successful in 6sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 8smanifest-check / check (pull_request) Successful in 0sregister-check / register-drift check (pull_request) Successful in 6sregister-check / check (pull_request) Successful in 0stests / bats (pull_request) Successful in 1m51stests / shellcheck (pull_request) Successful in 7scheck-self-bootstrap / check (push) Failing after 4srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0stests / bats (push) Successful in 1m51stests / shellcheck (push) Successful in 12smirror-on-cut / mirror-1 (release) Successful in 1smirror-on-cut / mirror (release) Successful in 0sreleased this
2026-07-06 21:12:56 +02:00 | 1086 commits to main since this releasev0.28.0 tightens release-note hygiene and release-cut reliability. Register-check now covers commit subjects and composed text. CHANGELOG output is normalized and readability-gated. Orphan-check handles breaking-change footers and legitimate prep-PR merges. Codeberg mirroring is decoupled from the cut workflow.
Added
Per-line exemption for
register-check. Files scanned byregister-checksometimes legitimately use pattern words in adopter-relevant contexts — a role title in a doc, a program name in a script. A trailing# register-check: allowmarker suppresses that one line's match (<!-- register-check: allow -->in Markdown and HTML). No action required. Scrubbing the pattern remains first-resort;.register-allowlistat file scope is second-resort; the line marker is the last resort. The--stdinscan called fromrelease-prep.shignores markers, so composed content stays gated. Closes #396.Register-check now scans commit subjects and composed CHANGELOG content. Chamber-name attributions in commit subjects used to ride into
CHANGELOG.mdpast the file-scan gate. The compose step read subjects the file scan never touched. Two new modes close the gap.--git-log RANGEscans commit subjects at PR review time.--stdinscans arbitrary text and runs fromrelease-prep.shon the composed section before it lands inCHANGELOG.md, catching drift from any source. Recommended for adopters using commit-subject → CHANGELOG composition (cc_list_commits_since/cc_categorize_commits_since): setcheck_commit_subjects: 'true'on thereusable-register-check.ymlinput. Fragments-only adopters can leave the default ('false'). Closes #403.Fragment authors can hard-wrap paragraphs without breaking the rendered CHANGELOG.
release-prep.shnow normalizes compiled sections before they transition intoCHANGELOG.md. Blank lines stay paragraph boundaries. Structural markdown — lists, headers, blockquotes, fenced code — passes through verbatim. Continuation lines within a paragraph join with a single space. A hyphen-word rejoin heuristic catches breaks inside hyphenated words. If a residual[a-z]- [a-z]pattern survives, the step fails loud on the offending source so the fragment can be fixed before release-prep ships. No action required. Hard-wrapping fragments at ~72 columns continues to work. Closes #420.CHANGELOG bodies get a readability check.
changelog-body-checknow flags long sentences, deep parenthetical nesting, and long paragraphs on newly-composed sections before the release-prep PR reaches operator eyes. Defaults: sentence fails at 30 words (warns at 25), paragraph fails at 100 words (warns at 75), parenthetical nesting fails above depth 2. Historical sections stay out of scope — the check targets the newest version block only. Recommended for adopters wanting different thresholds: override via new inputs onreusable-changelog-body-check.yml—sentence_max_words,sentence_warn_words,paren_depth_max,paragraph_max_words,paragraph_warn_words. Author-side guidance lives indocs/conventions.md"Writing adopter-facing prose". Closes #421.Changed
Orphan-check now catches
BREAKING CHANGE:body-footer commits. Arefactor:orchore:commit whose body carries aBREAKING CHANGE:footer is bump-worthy per conventional-commits. The pre-fix range-walk inrelease-decide.shkeyed only on the subject and false-skipped them.release-decide.shnow delegates release-relevance tocc_bump_level_from_subjectinscripts/lib/conventional-commits.sh. The helper handles subject-levelfeat!/fix!markers AND body-levelBREAKING CHANGE:footers, so orphan-check uses the same rules as the release-cut bump logic. Any future addition to the bump-worthy type set (for example,perf:) propagates automatically. No action required. Closes #424.check-self-bootstrapdocstrings clarify their scope. The script and workflow headers now open with "Pin-drift detection, NOT content validation." A red on a PR that touches a compose-script means the mechanism is firing correctly. The pinned ref needs to advance to catch main up at the next cut. It does not mean something is wrong with the code. Content-quality gates (shellcheck, bats, register-check) are named explicitly so a reader triaging a failure knows where content-questions live. No action required. Closes #432.Fixed
Orphan-check no longer false-fires on a legitimate cut — v1.0.0 must-fix follow-up to #417. Release-toolkit's own v0.27.0 cut on PR#406 tripped
release-decide.shwith the exact fail-loud the detector was designed to emit. The detector's signature —semver_compare(CHANGELOG_TOP, manifest.last_released) == 1— matches both an orphan-post-cancellation AND a legitimate cut-in-progress. Both have CHANGELOG advanced, manifest not yet updated, and no tag yet. The distinguisher is action-context, not signature.release-decide.shnow readsHEAD_SUBJECTearly and matches it againstPREP_SUBJECT_RE. When HEAD IS a prep-PR merge commit AND the version it cuts equalsCHANGELOG_TOP, the check skips — that is the legitimate cut-about-to-fire path. Any other HEAD shape (a bystander push after a cancelled cut) still fires the fail-loud. Both prep-merge subject styles are handled:chore(release): prepare vX.Y.Z(merge / rebase) andchore(release): vX.Y.Z(squash-merge using the PR title). Three new regression tests lock the behavior. No action required. Closes #417.Codeberg mirror no longer runs inside the cut workflow. A new
.forgejo/workflows/mirror-on-cut.ymltriggers on therelease: publishedevent. It fires either on immediate-mode publication, or when the operator clicks Publish on a draft.The in-graph
mirror:job is removed fromrelease.yml. It combinedcontinue-on-error: truewith auses:job, which Forgejo Actions correctly rejects per the GitHub Actions schema. Mirror-outages, PAT-rotations, and Codeberg-side timeouts no longer cascade into cut-failure. Mirror-failure never touches the cut workflow's job graph.Adopter action required only if you fork the toolkit's workflow files and mirror to Codeberg from your own copy. Move the mirror job into a separate
release: published-triggered workflow rather than amirror:job insiderelease.yml. Thereusable-mirror-to-codeberg.ymldocstring shows the new pattern. Closes #427.Removed
None.
Deprecated
None.
Upgrade
- Optional: set
check_commit_subjects: 'true'onreusable-register-check.ymlif you compose CHANGELOG entries from commit subjects. Default remains'false'for fragments-only adopters. See #403. - Optional: override readability thresholds via new inputs on
reusable-changelog-body-check.yml—sentence_max_words,sentence_warn_words,paren_depth_max,paragraph_max_words,paragraph_warn_words. Defaults follow the "Writing adopter-facing prose" convention. See #421. - Required if you fork the toolkit's workflow files and mirror releases to Codeberg from your own copy: move the mirror job into a separate
release: published-triggered workflow rather than an inlinemirror:job inrelease.yml. Toolkit-self's ownmirror-on-cut.ymlis a working example. See #427.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Optional: set