diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 0000000..4bf8b55 --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# commit-msg: enforce the project's commit subject style. +# +# The subject (first line) MUST be: VERB - Short description +# - VERB : an ALL-CAPS verb, >= 3 letters +# (e.g. ADDED, FIXED, STYLED, DOCUMENTED, CLEANED, REVERTED, +# CONFIGURED, IMPROVED, POLISHED, REMOVED, RENAMED, REFACTORED) +# - then " - " (space hyphen space) +# - then a description (capitalized, imperative, no trailing period). +# +# Good: +# FIXED - Load .env in drizzle.config so drizzle-kit targets the right DB +# STYLED - Turn the admin portfolio overview into a professional table +# +# Bad (rejected): +# Flatten portfolio category routes to /portfolio/[slug] (no VERB prefix) +# feat(hero): add ambient backdrop (wrong style) +# +# Install once: git config core.hooksPath .githooks +# Emergency skip: git commit --no-verify +# +set -euo pipefail + +msg_file="$1" + +# First non-empty, non-comment line = the subject. +subject="$(grep -vE '^[[:space:]]*#' "$msg_file" | grep -vE '^[[:space:]]*$' | head -n1 || true)" + +# Let git's own housekeeping commits through untouched. +case "$subject" in + Merge\ * | Revert\ * | fixup!\ * | squash!\ *) exit 0 ;; +esac + +pattern='^[A-Z]{3,} - .+' +if [[ ! "$subject" =~ $pattern ]]; then + cat >&2 <= 3 letters), then " - ", then the description. + (Emergency skip: git commit --no-verify) + +EOF + exit 1 +fi diff --git a/CLAUDE.md b/CLAUDE.md index 19b8e97..167d351 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -125,4 +125,30 @@ SITE_RUNTIME_ORIGIN Internal origin for middleware to fetch runtime state - If a task may affect routing, auth, i18n, or runtime config, inspect `proxy.ts`, `lib/admin-routing.ts`, `i18n/routing.ts`, and the relevant `lib/app-config.ts` modules first. - For schema or database changes, inspect the Drizzle schema (`lib/db/schema.ts`), the drizzle-kit migration flow, and migration impact before editing. - Ask before performing large refactors, file moves, destructive changes, or broad formatting changes. -- When updating behavior, also update docs/specs if the change affects public behavior, business rules, or architecture. \ No newline at end of file +- When updating behavior, also update docs/specs if the change affects public behavior, business rules, or architecture. + +## Git commit messages (MANDATORY) + +Every commit subject **must** follow this exact style, or the `commit-msg` hook +(`.githooks/commit-msg`) will reject the commit: + +``` +VERB - Short description +``` + +- `VERB` is an ALL-CAPS verb, at least 3 letters — e.g. `ADDED`, `FIXED`, + `STYLED`, `REMOVED`, `RENAMED`, `REFACTORED`, `IMPROVED`, `DOCUMENTED`, + `CLEANED`, `REVERTED`, `CONFIGURED`, `POLISHED`. +- Then exactly `" - "` (space, hyphen, space). +- Then a capitalized, imperative description with no trailing period. + +Good: `FIXED - Load .env in drizzle.config so drizzle-kit targets the right DB` +Bad (rejected): `Flatten portfolio category routes` — no `VERB` prefix. +Bad (rejected): `feat(hero): add backdrop` — Conventional Commits is NOT used here. + +Do **not** add any `Co-Authored-By` / "Generated with Claude Code" attribution +lines to commits in this repo. Write the body (when useful) as wrapped prose or +bullet points explaining the *why*, matching the existing history. + +The hook and the test gate are activated per clone with: +`git config core.hooksPath .githooks` (emergency skip: `git commit --no-verify`). \ No newline at end of file