feat(ci): scope release version bumps to the deployable payload - #132
Conversation
The automatic push-triggered release path only gated whether to run semantic-release at all on logging.sh/workbench.yml having changed since the last tag; the actual version bump was still decided by scanning every commit since that tag regardless of what it touched. Merging PR #130 (a feat(ci): commit that changed only .github/workflows/release.yml, docs, and a skill file) demonstrated the problem directly: it cut v2.6.0 as a minor release even though nothing in the deployable payload changed, because workbench.yml had separately sat unreleased since 2.5.6. Add scripts/analyze-release-commits.sh and wire it in as .releaserc.json's analyzeCommitsCmd (replacing @semantic-release/commit- analyzer), so a commit's type only counts toward the release if that same commit's own diff touches logging.sh or workbench.yml. The manual workflow_dispatch pending-bump check in release.yml now calls the same script, so what it warns about always matches what the real release run will decide. workflow_dispatch's own synthetic --allow-empty commit is deliberately exempt from this path restriction (detected via GITHUB_EVENT_NAME) since its whole purpose is to force a chosen bump level regardless of what changed — path-filtering it would make manual dispatch unable to ever trigger a release. v2.6.0 itself is not reverted (immutable releases; the maintainer decided to leave it as-is) — this only changes behaviour going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KFf4oXoAAheW8AdAQ2q7G
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It rewires the release/versioning mechanism (removing commit-analyzer for a custom analyzeCommitsCmd) that could not be end-to-end verified in this environment, so it warrants human sign-off.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
This PR refines the release automation so that a version bump only happens when a commit's own diff touches the deployable payload (logging.sh or workbench.yml). It fixes the root cause behind the unwanted v2.6.0 minor bump (a feat(ci): commit that touched no payload file), replacing @semantic-release/commit-analyzer's releaseRules with a custom analyzeCommitsCmd script that both the workflow gate and semantic-release itself now share, keeping the auto-push and manual paths consistent. workflow_dispatch is intentionally exempted (via GITHUB_EVENT_NAME) so synthetic empty commits still force a bump.
Changes:
- Adds
scripts/analyze-release-commits.shthat path-filtersgit log(except forworkflow_dispatch) and prints the highest release type among in-scope commits. - Wires the script into
.releaserc.json(analyzeCommitsCmd) and bothrelease.ymldecision points, removing the duplicated inline regex logic. - Documents the new payload-scoping behavior and the manual-dispatch exception in
docs/releases.md.
| File | Description |
|---|---|
scripts/analyze-release-commits.sh |
New shared analyzer: filters commits by payload path and reports major/minor/patch (or nothing); exempts workflow_dispatch. |
.releaserc.json |
Removes commit-analyzer/releaseRules; adds analyzeCommitsCmd pointing at the new script on the existing @semantic-release/exec plugin. |
.github/workflows/release.yml |
Auto-push gate and manual pending-bump check now both call the shared script instead of inline regex. |
docs/releases.md |
Documents the analyzeCommitsCmd wiring and payload-scoping rationale, including the workflow_dispatch exception. |
The logic is coherent: the grep-based bump mapping matches the removed releaseRules (including #131's anchored BREAKING CHANGE fix), the script is executable (mode 100755), always exits 0 (the terminating if/elif/fi with no match yields status 0, so it won't spuriously fail set -e), and the workflow_dispatch exemption correctly preserves manual empty-commit releases. The only in-diff finding is a minor Bash-convention nit ([ ] vs [[ ]]).
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This script is Bash-targeted (it uses a Bash array), so per CLAUDE.md's shell compatibility guidelines it should use [[ ]] rather than the POSIX-portable [ ], matching the convention already used elsewhere in scripts/ (e.g. validate-commit-msg.sh, package-release.sh). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KFf4oXoAAheW8AdAQ2q7G
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It alters the release-versioning pipeline, whose end-to-end behavior (semantic-release + analyzeCommitsCmd integration) cannot be verified in this sandbox and carries operational risk if wrong.
Review effort: Balanced
Findings: None

Summary
Follow-up to #130/#131.
v2.6.0was cut as a minor release when #130 merged, even thoughthat PR only touched
.github/workflows/release.yml,docs/releases.md,CONTRIBUTING.md, anda skill file — nothing in the deployable payload. This happens because
semantic-release'sdefault commit analysis considers the type of every commit since the last tag regardless of what
it touched, and #130's path filter only gated whether to run
semantic-releaseat all(
workbench.ymlhad sat unreleased as achore:commit since 2.5.6, which was enough to satisfythat gate) — not which commits' types count toward the version.
Per the maintainer's decision,
v2.6.0itself is left as-is (immutable releases are enabled).This PR only changes behaviour going forward: a commit's type now only counts toward the version
if that same commit's own diff touches
logging.shorworkbench.yml.Change
scripts/analyze-release-commits.sh: given a last-release tag, filtersgit logbypathspec (
logging.sh,workbench.yml) and reports the highest bump type(major/minor/patch) among only the commits that touched one of those paths.
.releaserc.json: replaces@semantic-release/commit-analyzerwithanalyzeCommitsCmdon the existing@semantic-release/execplugin, pointing at the newscript — this is the officially supported way to fully customize
semantic-release's versiondecision (
analyzeCommitsCmddocs: stdout is the release type only, or nothing for no release)..github/workflows/release.yml: both the auto-push "should we even run semantic-release" gateand the manual
workflow_dispatchpending-bump safety check now call the same script, insteadof each having their own (previously slightly different, now identical) inline regex logic.
docs/releases.md: documents the newanalyzeCommitsCmdwiring and the payload-scopingrationale.
The workflow_dispatch exception
Manual dispatch creates a synthetic
--allow-emptycommit specifically to force a chosen bumplevel regardless of what changed — that's the entire point of #130's
bumpinput. Path-filteringthat commit would make it invisible to the analyzer (an empty commit touches no files), silently
breaking manual releases entirely. The script detects this via
GITHUB_EVENT_NAME(setautomatically by GitHub Actions) and skips path-filtering only for
workflow_dispatch— it fallsback to the previous unfiltered behaviour there, preserving #130's "Day-1 workbench.yml release"
scenario.
Testing
Verified against real repository history using
git worktree(this sandbox has noPAT_TOKEN,so a true end-to-end
semantic-releasedry run against GitHub wasn't possible — the script andthe workflow's bash wiring were tested directly instead):
975307e,feat(ci):, touches nopayload file): now correctly produces no release (was: minor → v2.6.0)
logging.shfix (19ba794,fix(#120): ...): correctly produces patchworkflow_dispatchevent, same feat(ci): add manual bump control and workbench.yml release detection #130 range: correctly still produces minor (unfiltered, sothe pending-bump warning still fires exactly as before)
workflow_dispatchevent with a synthetic emptyfix: ...commit appended: correctly stillproduces patch — manual dispatch is unaffected
.releaserc.jsonandrelease.ymlboth parse (json.load/yaml.safe_load)pre-commit run shellcheckon the new script and the workflow file — passedpre-commit run markdownlintondocs/releases.md— passedRelated issues
Follow-up to #130 (build spec) and #131 (bug fix) — addresses the maintainer's follow-up request
after observing the unwanted v2.6.0 minor bump.
🤖 Generated with Claude Code
https://claude.ai/code/session_017KFf4oXoAAheW8AdAQ2q7G
Generated by Claude Code