feat: add commit message normalizer and validator - #224
Conversation
494a8f8 to
6d341f3
Compare
|
Addressed the blocking review finding. Defect: the normalizer deleted every body line starting with Fix: the hook no longer deletes comment lines at all. I verified empirically that git runs its own cleanup after the commit-msg hook, and only strips comments when it should — an editor-authored message loses its template, while Verified against a no-hook baseline in a scratch repo: The body now survives exactly as it would without the hook, while the subject is still normalized. With Tests: wrote the cases red first, including two end-to-end tests that install the hook into a scratch repo and drive real One documented tradeoff: a trailing |
Standardize commit messages on Conventional Commits with a dependency-free normalizer, a validator, an opt-in commit-msg hook, and a CI job that lints every commit in the PR range. No history is rewritten. Nightshift-Task: commit-normalize Nightshift-Ref: https://github.com/marcus/nightshift
6d341f3 to
6f52f4b
Compare
What
Standardizes commit messages with a dependency-free normalizer + validator, an opt-in local
commit-msghook, and a PR-range CI lint job.The standard
Derived from this repo's own history, not imposed: of the last 300 subjects, ~132 are already Conventional Commits (
feat75,fix29,docs20,chore4,test3). So:Types:
feat fix docs style refactor perf test build ci chore revert. Subject ≤ 72 chars, no trailing period, blank line before body, trailers last.What it does
scripts/normalize-commit-msg.shauto-fixes only what is mechanically unambiguous:Fix: Thing.fix: thingFeat(api)!: Drop v1 endpoints.feat(api)!: drop v1 endpointsfeat(api) - add thingfeat(api): add thing[feat] add thingfeat: add thingfix:tighten timeoutfix: tighten timeoutPlus structure: strips git comment lines, rstrips, collapses blank runs, inserts the blank line after the subject, and inserts the blank line git needs before a trailer block (otherwise
Co-Authored-By:/Nightshift-Task:are silently swallowed into the body).It deliberately does not guess:
Update readmehas no known type, so it is left alone andscripts/validate-commit-msg.shrejects it with an explanation and a suggested fix. Same for empty and over-length subjects.Merge, revert,
fixup!,squash!andamend!messages pass through untouched. Normalization is idempotent (covered by tests).Opt-in, and non-invasive
make install-hooks. Nothing changes your git config as a side effect..git/hookssymlink convention rather thancore.hooksPath. Deliberate: settingcore.hooksPathwould have silently disabled the existingpre-commithook.NORMALIZE_COMMIT_MSG=0 git commit ...or--no-verify.CI
.github/workflows/commit-lint.ymlvalidates every commit in the PR range only and reports all failures at once. No existing history is rewritten and no already-merged commit is retroactively judged.Tests
tests/run-commit-msg-tests.sh— 32 assertions covering every transformation, both skip paths, each rejection reason, trailer preservation, and idempotence. Written before the implementation and run to red first. Wired intomake checkand CI. Verified underdashas well asbash.The commit on this branch was itself created by typing a deliberately malformed message (
Feat: Add commit message normalizer and validator.) and letting the installed hook fix it.🤖 Generated with Claude Code