feat: add commit-msg hook enforcing conventional commits#2
feat: add commit-msg hook enforcing conventional commits#2
Conversation
📝 WalkthroughWalkthroughAdds Conventional Commits enforcement: a commit-msg hook validating commit messages, a .gitmessage template, git config pointing to the template, and setup script changes to install and enable the hook and template. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Developer as Developer
participant Git as Git Client
participant Hook as ".githooks/commit-msg"
Developer->>Git: git commit (with message)
Git->>Hook: run commit-msg with message file
Hook->>Hook: check for merge commit or aliases (WIP/SAVEPOINT)
alt allowed
Hook-->>Git: exit 0 (allow commit)
Git-->>Developer: commit succeeds
else invalid format
Hook-->>Git: print usage, exit 1 (reject)
Git-->>Developer: commit aborted, show hook output
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
.githooks/commit-msg validates format, allows WIP/SAVEPOINT exceptions. hooksPath set locally (not globally) to avoid breaking other repos. Nightshift-Task: commit-normalize Nightshift-Ref: https://github.com/marcus/nightshift Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.githooks/commit-msg:
- Around line 16-27: Update the commit-msg validation to enforce the allowed
Conventional Commit types and support the breaking-change "!" indicator: replace
the loose pattern /^[a-z]+(\([a-z0-9_-]+\))?: .+/ with a pattern that enumerates
types and makes the scope and trailing "!" optional, e.g.
/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_-]+\))?(!)?:
.+/ applied to the same $msg variable, and keep the special-case acceptance for
exact messages like WIP, SAVEPOINT, and "WIPE SAVEPOINT" (either via a separate
equality check before the regex or by expanding the regex with alternation) so
those exceptions still pass.
- Around line 11-13: The commit-msg hook currently allows WIP/SAVEPOINT messages
but blocks auto-generated git revert messages; update the guard so revert
subjects like Revert "..." are accepted—either add "Revert" to the existing grep
pattern (e.g. grep -qE '^(WIP|SAVEPOINT|WIPE SAVEPOINT|Revert)') or add a
separate conditional that checks if the commit subject starts with "Revert" and
exits 0; modify the if that uses echo "$msg" | grep -qE ... to include this new
case so git revert messages are not rejected.
.githooks/commit-msg
Outdated
| if ! echo "$msg" | grep -qE '^[a-z]+(\([a-z0-9_-]+\))?: .+'; then | ||
| echo "ERROR: commit message must follow Conventional Commits format" | ||
| echo "" | ||
| echo " type: description" | ||
| echo " type(scope): description" | ||
| echo "" | ||
| echo " Allowed types: feat fix docs style refactor perf test build ci chore revert" | ||
| echo " Example: feat(auth): add login endpoint" | ||
| echo "" | ||
| echo " Exceptions: WIP, SAVEPOINT, WIPE SAVEPOINT" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
Regex misses the breaking-change ! indicator and is more permissive than documented
Two related gaps in the validation regex ^[a-z]+(\([a-z0-9_-]+\))?: .+:
- Breaking change
!not handled —feat!: descriptionandfeat(scope)!: descriptionare valid Conventional Commits syntax, but would be rejected because!is not represented in the pattern. - Type allow-list not enforced — the regex accepts any
[a-z]+string (e.g.,banana: fix), yet the error message advertises a specific list of allowed types. A user following the error message exactly is fine, but typos likefetaure: …silently pass.
🐛 Proposed fix — enumerate allowed types and support breaking-change `!`
-if ! echo "$msg" | grep -qE '^[a-z]+(\([a-z0-9_-]+\))?: .+'; then
+if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_-]+\))?!?: .+'; then🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.githooks/commit-msg around lines 16 - 27, Update the commit-msg validation
to enforce the allowed Conventional Commit types and support the breaking-change
"!" indicator: replace the loose pattern /^[a-z]+(\([a-z0-9_-]+\))?: .+/ with a
pattern that enumerates types and makes the scope and trailing "!" optional,
e.g.
/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_-]+\))?(!)?:
.+/ applied to the same $msg variable, and keep the special-case acceptance for
exact messages like WIP, SAVEPOINT, and "WIPE SAVEPOINT" (either via a separate
equality check before the regex or by expanding the regex with alternation) so
those exceptions still pass.
48fe0dd to
17ab5b4
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
git/config (1)
7-7: Heads-up: template path depends onsetup.shrunning successfully, and its scope is intentionally broader than the hook's.Two things worth being aware of:
~/.gitmessagemust exist before this setting takes effect. If the dotfiles are bootstrapped (e.g.,git/configis linked first) butsetup.shhasn't been run yet to create the symlink, everygit committhat opens an editor across all repos will emit a warning about the missing template file. Consider documenting the required bootstrap order, or guard the template setting insetup.shthe same waycore.hooksPathis set there.Template is global; hook enforcement is repo-scoped. The
[commit] templatehere propagates to every git repo on the machine, so contributors will see the Conventional Commits hint everywhere. Thecore.hooksPath(and thus the validation) is intentionally limited to the dotfiles repo (persetup.sh). This is a deliberate design choice that the PR description calls out explicitly — just worth confirming that's the intended UX, since users in other repos will see the prompt but experience no enforcement.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git/config` at line 7, The global commit template setting "template = ~/.gitmessage" can warn across all repos if the file doesn't exist and exposes the hint without enforcement; update setup.sh to only set the commit.template when the file exists (same guard used for setting core.hooksPath) or document the required bootstrap order in the repo README; specifically, in setup.sh check for the presence of ~/.gitmessage (or create the symlink) before running git config --global commit.template, and ensure core.hooksPath handling remains repo-scoped as intended.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@git/config`:
- Line 7: The global commit template setting "template = ~/.gitmessage" can warn
across all repos if the file doesn't exist and exposes the hint without
enforcement; update setup.sh to only set the commit.template when the file
exists (same guard used for setting core.hooksPath) or document the required
bootstrap order in the repo README; specifically, in setup.sh check for the
presence of ~/.gitmessage (or create the symlink) before running git config
--global commit.template, and ensure core.hooksPath handling remains repo-scoped
as intended.
Summary
.githooks/commit-msghook validating Conventional Commits format.gitmessagecommit template with format hintgit/configcore.hooksPathscoped to dotfiles repo only insetup.sh(not global — avoids breaking hooks in other repos)Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift
Summary by CodeRabbit