Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,31 @@ 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"; \
for hook in pre-commit commit-msg; do \
script="$$repo_root/scripts/$$hook.sh"; \
hook_path="$$hooks_dir/$$hook"; \
tmp_path="$$hook_path.tmp"; \
[ -f "$$script" ] || { echo "missing hook script: $$script" >&2; exit 1; }; \
{ \
printf '%s\n' '#!/usr/bin/env bash'; \
printf '%s\n' '# generated by make install-hooks'; \
printf '%s\n' 'set -euo pipefail'; \
printf '%s\n' 'repo_root=$$(git rev-parse --show-toplevel)'; \
printf 'exec "$$repo_root/scripts/%s.sh" "$$@"\n' "$$hook"; \
} > "$$tmp_path"; \
chmod +x "$$tmp_path"; \
mv "$$tmp_path" "$$hook_path"; \
done; \
echo "✓ hooks installed ($$hooks_dir/pre-commit, $$hooks_dir/commit-msg)"
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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(#19): tighten config validation`
- `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:
This installs `pre-commit` and `commit-msg` into Git's active hooks directory as small wrapper scripts. That works with the default `.git/hooks`, custom `core.hooksPath`, and linked worktrees because each hook resolves the current checkout at runtime.

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`

Expand Down
41 changes: 41 additions & 0 deletions scripts/commit-msg.sh
Original file line number Diff line number Diff line change
@@ -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-Za-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: <empty>" >&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 git hooks
build(release): bump version to v0.3.5
allowed: Merge..., Revert..., fixup! ..., squash! ...
EOF

exit 1
2 changes: 1 addition & 1 deletion scripts/pre-commit.sh
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading