ci: enforce Conventional Commits with a commitlint gate#660
Open
EivMeyer wants to merge 1 commit into
Open
Conversation
semantic-release derives the release version from commit-message types, but nothing validated those messages, so a non-conventional subject (missing, unknown, or wrong-case type) can silently break version bumps. - add .commitlintrc.json (extends config-conventional; long body/footer lines allowed for squash-merge bodies) - add a Husky commit-msg hook for local validation - add a fast, dependency-light commitlint CI job that validates PR commit messages via npx, failing before the expensive check job Part of #640. The trunk cutover items (removing enforce-main-pr-source, the GitHub App release token) ride with the dev/main reconciliation, not this PR.
This was referenced Jul 15, 2026
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.
What
Adds a commitlint gate so the Conventional Commit messages that
semantic-releaserelies on are actually enforced..commitlintrc.json— extends@commitlint/config-conventional; long body/footer lines allowed (squash-merge bodies have Markdown tables and links). Mirrors the config inthe-open-engine/agents, per "same approach everywhere.".husky/commit-msg— local validation hook (none existed; onlypre-commit/pre-pushwere present).commitlintjob — validates every PR commit's message vianpx, running before the expensivecheckjob so bad messages fail fast. Dependency-light (nonpm cineeded for the gate).Why
semantic-releasederives the version bump from commit-message type (fix:→ patch,feat:→ minor, etc.). Nothing validated those messages, so a non-conventional subject silently produces no bump or the wrong one — a contributor to the version drift tracked in #640.Validation
Ran the exact CI config against real messages:
(Note: a doubled prefix like
feat: feat(x): ...passes — commitlint readsfeatas the type and the rest as the subject. This gate targets missing/unknown/wrong-case types, which is what breaks version computation.)Scope boundary
This PR is deliberately just the gate. The trunk cutover items from #640 ride with the
dev/mainreconciliation, not here:enforce-main-pr-sourceCI job (which currently mandates thedev → mainpromotion that causes the divergence)GITHUB_TOKENfor a repo-scoped release GitHub Appmain-didn't-move guard onrelease.ymlFollow-ups surfaced while implementing (for the reconciliation, not this PR)
mainhas.releaserc.json(with@semantic-release/git+changelog, which commit the version back), butdev'spackage.jsonhas an inlinereleaseblock without thegitplugin — so under dev's config no version-bump commit is written. Likely a direct contributor to branch ≠ npm drift. Consolidate to one config.Base is
devper the repo's currentenforce-main-pr-sourcepolicy.