From 23bafa62d4c943e8e8825f98fa21b9034ba971d4 Mon Sep 17 00:00:00 2001 From: Marcus Vorwaller Date: Sun, 12 Apr 2026 03:19:32 -0700 Subject: [PATCH] chore(hooks): normalize commit subjects Nightshift-Task: commit-normalize Nightshift-Ref: https://github.com/marcus/nightshift --- Makefile | 16 ++++++++++++---- README.md | 34 ++++++++++++++++++++++++++++------ scripts/commit-msg.sh | 41 +++++++++++++++++++++++++++++++++++++++++ scripts/pre-commit.sh | 2 +- 4 files changed, 82 insertions(+), 11 deletions(-) create mode 100755 scripts/commit-msg.sh diff --git a/Makefile b/Makefile index 088be01..17e33bd 100644 --- a/Makefile +++ b/Makefile @@ -75,10 +75,18 @@ help: @echo " check - Run tests and lint" @echo " install - Build and install to Go bin directory" @echo " calibrate-providers - Compare local Claude/Codex session usage for calibration" - @echo " install-hooks - Install git pre-commit hook" + @echo " install-hooks - Install git hooks (pre-commit + commit-msg)" @echo " help - Show this help" -# Install git pre-commit hook +# Install git hooks install-hooks: - @ln -sf ../../scripts/pre-commit.sh .git/hooks/pre-commit - @echo "✓ pre-commit hook installed (.git/hooks/pre-commit → scripts/pre-commit.sh)" + @repo_root="$$(git rev-parse --show-toplevel)"; \ + hooks_dir="$$(git rev-parse --git-path hooks)"; \ + case "$$hooks_dir" in \ + /*) ;; \ + *) hooks_dir="$$repo_root/$$hooks_dir" ;; \ + esac; \ + mkdir -p "$$hooks_dir"; \ + ln -sf "$$repo_root/scripts/pre-commit.sh" "$$hooks_dir/pre-commit"; \ + ln -sf "$$repo_root/scripts/commit-msg.sh" "$$hooks_dir/commit-msg"; \ + echo "✓ hooks installed ($$hooks_dir/pre-commit -> $$repo_root/scripts/pre-commit.sh, $$hooks_dir/commit-msg -> $$repo_root/scripts/commit-msg.sh)" diff --git a/README.md b/README.md index 84f92cd..8351be3 100644 --- a/README.md +++ b/README.md @@ -258,18 +258,40 @@ Each task has a default cooldown interval to prevent the same task from running ## Development -### Pre-commit hooks +### Commit messages -Install the git pre-commit hook to catch formatting and vet issues before pushing: +Use this format for new local commits: + +```text +type(scope): summary +``` + +If a scope does not add clarity, `type: summary` is also valid. Allowed types: `feat`, `fix`, `docs`, `refactor`, `test`, `build`, `chore`, `ci`, `perf`. + +Examples: +- `feat(tasks): add commit message validator` +- `fix(config): preserve provider YAML keys` +- `docs: document git hooks` +- `build(release): bump version to v0.3.5` +- `chore(release): prepare v0.3.5` + +Merge, revert, `fixup!`, and `squash!` commits are exempt. This standard applies to future commits only; existing history stays as-is. + +### Git hooks + +Install the git hooks to catch formatting, vet, build, and commit-message issues before pushing: ```bash make install-hooks ``` -This symlinks `scripts/pre-commit.sh` into `.git/hooks/pre-commit`. The hook runs: -- **gofmt** — flags any staged `.go` files that need formatting -- **go vet** — catches common correctness issues -- **go build** — ensures the project compiles +This installs symlinks into Git's active hooks directory, so it works with the default `.git/hooks`, `core.hooksPath`, and linked worktrees. `make install-hooks` installs both `pre-commit` and `commit-msg`. + +The hooks run: +- **gofmt** - flags any staged `.go` files that need formatting +- **go vet** - catches common correctness issues +- **go build** - ensures the project compiles +- **commit-msg** - validates the first line of the commit message To bypass in a pinch: `git commit --no-verify` diff --git a/scripts/commit-msg.sh b/scripts/commit-msg.sh new file mode 100755 index 0000000..5e99ed0 --- /dev/null +++ b/scripts/commit-msg.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# commit-msg hook for nightshift +# Install: make install-hooks +set -euo pipefail + +msg_file=${1:?commit message file required} +subject="" + +IFS= read -r subject < "$msg_file" || true +subject=${subject%$'\r'} + +case "$subject" in + Merge\ *|Revert\ *|fixup!\ *|squash!\ *) + exit 0 + ;; +esac + +pattern='^(feat|fix|docs|refactor|test|build|chore|ci|perf)(\([a-z0-9._/-]+\))?(!)?: [^[:space:]].*$' + +if [[ "$subject" =~ $pattern ]]; then + exit 0 +fi + +if [[ -n "$subject" ]]; then + echo "invalid commit subject: $subject" >&2 +else + echo "invalid commit subject: " >&2 +fi + +cat >&2 <<'EOF' +use: type(scope): summary +or: type: summary +types: feat fix docs refactor test build chore ci perf +examples: + feat(tasks): add commit message validator + docs: document commit hooks + build(release): bump version to v0.3.5 +allowed: Merge..., Revert..., fixup! ..., squash! ... +EOF + +exit 1 diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh index c597d65..975f717 100755 --- a/scripts/pre-commit.sh +++ b/scripts/pre-commit.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # pre-commit hook for nightshift -# Install: make install-hooks (or: ln -sf ../../scripts/pre-commit.sh .git/hooks/pre-commit) +# Install: make install-hooks set -euo pipefail PASS=0