feat: commit-msg hook enforces conventional commit format

This commit is contained in:
pyr0ball 2026-03-02 19:14:31 -08:00
parent a7fbc42c11
commit d329d3c7ab
2 changed files with 59 additions and 0 deletions

32
.githooks/commit-msg Executable file
View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
# .githooks/commit-msg — enforces conventional commit format
# Format: type: description OR type(scope): description
set -euo pipefail
RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
VALID_TYPES="feat|fix|docs|chore|test|refactor|perf|ci|build"
MSG_FILE="$1"
MSG=$(head -1 "$MSG_FILE")
if [[ -z "${MSG// }" ]]; then
echo -e "${RED}Commit rejected:${NC} Commit message is empty."
exit 1
fi
if ! echo "$MSG" | grep -qE "^($VALID_TYPES)(\(.+\))?: .+"; then
echo -e "${RED}Commit rejected:${NC} Message does not follow conventional commit format."
echo ""
echo -e " Required: ${YELLOW}type: description${NC} or ${YELLOW}type(scope): description${NC}"
echo -e " Valid types: ${YELLOW}$VALID_TYPES${NC}"
echo ""
echo -e " Your message: ${YELLOW}$MSG${NC}"
echo ""
echo -e " Examples:"
echo -e " ${YELLOW}feat: add cover letter refinement${NC}"
echo -e " ${YELLOW}fix(wizard): handle missing user.yaml gracefully${NC}"
echo -e " ${YELLOW}docs: update tier system reference${NC}"
exit 1
fi
exit 0

View file

@ -48,3 +48,30 @@ run_hook_with "app/app.py" "import streamlit" && pass "allowed safe file" || \
fail "should have allowed safe file"
echo "All pre-commit hook tests passed."
# ── commit-msg hook tests ────────────────────────────────────────────────────
COMMIT_HOOK=".githooks/commit-msg"
tmpfile=$(mktemp)
echo "Test 5: accepts valid feat message"
echo "feat: add thing" > "$tmpfile"
bash "$COMMIT_HOOK" "$tmpfile" && pass "accepted feat" || fail "rejected valid feat"
echo "Test 6: accepts valid fix with scope"
echo "fix(auth): handle token expiry" > "$tmpfile"
bash "$COMMIT_HOOK" "$tmpfile" && pass "accepted fix(scope)" || fail "rejected valid fix(scope)"
echo "Test 7: rejects empty message"
echo "" > "$tmpfile"
bash "$COMMIT_HOOK" "$tmpfile" && fail "should reject empty" || pass "rejected empty"
echo "Test 8: rejects non-conventional message"
echo "updated the thing" > "$tmpfile"
bash "$COMMIT_HOOK" "$tmpfile" && fail "should reject non-conventional" || pass "rejected non-conventional"
echo "Test 9: rejects invalid type"
echo "yolo: ship it" > "$tmpfile"
bash "$COMMIT_HOOK" "$tmpfile" && fail "should reject invalid type" || pass "rejected invalid type"
rm -f "$tmpfile"
echo "All commit-msg hook tests passed."