build: add pre-commit hook gating lint + test + build

`.githooks/pre-commit` runs `make lint test build` on every commit,
catching unformatted Go (`gofmt -l`), `go vet` regressions, shellcheck
errors on scripts/, broken unit tests, and broken builds before they
reach the index. Activate per-clone with `make install-hooks`, which
points `core.hooksPath` at `.githooks/`. Bypass for in-flight WIP
commits with `git commit --no-verify`.

The hook directory is tracked in git (unlike .git/hooks/) so a clone
+ `make install-hooks` is enough to opt in; no per-machine
hand-installation. .PHONY and the help line both list the new
target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thales Maciel 2026-04-28 15:08:41 -03:00
parent 6b4e1922b0
commit 0c77b042ed
No known key found for this signature in database
GPG key ID: 33112E6833C34679
2 changed files with 33 additions and 2 deletions

23
.githooks/pre-commit Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# pre-commit gate. Runs lint (gofmt -l + go vet + shellcheck), unit
# tests, and a build before any commit lands. Activate once via
# `make install-hooks`, which points core.hooksPath at this directory.
#
# Bypass for in-flight WIP commits with `git commit --no-verify`.
set -euo pipefail
# Resolve repo root so the hook works from any subdirectory.
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
# `make lint` already wraps `gofmt -l`, `go vet`, and shellcheck.
echo '[pre-commit] lint'
make --no-print-directory lint
echo '[pre-commit] test'
make --no-print-directory test
echo '[pre-commit] build'
make --no-print-directory build
echo '[pre-commit] ok'

View file

@ -42,7 +42,7 @@ $(error smoke-one needs SCENARIO=name (see `make smoke-list` for names))
endif
endif
.PHONY: help build banger bangerd test fmt tidy clean install uninstall lint lint-go lint-shell coverage coverage-html coverage-total coverage-combined coverage-combined-html smoke smoke-build smoke-list smoke-one smoke-coverage-html smoke-clean smoke-fresh
.PHONY: help build banger bangerd test fmt tidy clean install uninstall lint lint-go lint-shell coverage coverage-html coverage-total coverage-combined coverage-combined-html smoke smoke-build smoke-list smoke-one smoke-coverage-html smoke-clean smoke-fresh install-hooks
help:
@printf '%s\n' \
@ -66,7 +66,8 @@ help:
' make smoke-one SCENARIO=NAME Run a single smoke scenario (still does the install preamble)' \
' make smoke-fresh smoke-clean + smoke — purges stale smoke-owned installs before a clean supported-path run' \
' make smoke-coverage-html HTML coverage report from the last smoke run' \
' make smoke-clean Remove the smoke build tree and purge any stale smoke-owned system install'
' make smoke-clean Remove the smoke build tree and purge any stale smoke-owned system install' \
' make install-hooks Point core.hooksPath at .githooks (lint + test + build run on every commit)'
build: $(BINARIES)
@ -151,6 +152,13 @@ fmt:
tidy:
$(GO) mod tidy
# Local-only: redirect git's hook lookup at .githooks/ so .githooks/pre-commit
# fires on every `git commit`. Idempotent. Bypass an individual commit with
# `git commit --no-verify`.
install-hooks:
git config core.hooksPath .githooks
@echo 'core.hooksPath -> .githooks (run `git config --unset core.hooksPath` to revert)'
clean:
rm -rf "$(BUILD_BIN_DIR)" coverage.out coverage.html