lefthook.yml
Rama main · réplica de lectura del repositorio original.
# Lefthook git hooks configuration
# Install: lefthook install (or make install-hooks)
# Docs: https://github.com/evilmartians/lefthook
pre-commit:
parallel: true
commands:
# Este repo es PUBLICO. docs/ son notas y planes internos (infra, nombres de
# secretos, decisiones sin publicar) y esta en .gitignore — pero .gitignore no
# frena un `git add -f`, que es exactamente como se colaron la primera vez.
no-internal-docs:
run: |
staged=$(git diff --cached --name-only --diff-filter=ACMR | grep -iE '^docs/' || true)
if [ -n "$staged" ]; then
echo "Rutas de docs/ internas en el commit (repo publico):"
echo "$staged"
echo "Sacalas con: git restore --staged <ruta>"
exit 1
fi
# Windows PowerShell 5.1 reads a script through the ANSI code page unless it
# has a BOM, and the harness deploys them with one — but a curly quote or a
# mojibake example in a COMMENT is still enough to break a string literal
# on a machine whose code page differs (test/windows/README.md). ASCII only;
# a leading UTF-8 BOM is allowed, it is what the README asks for. Python, not
# grep -P: whether PCRE flags the BOM's bytes depends on the grep build.
ps1-ascii:
glob: "test/windows/*.ps1"
run: |
python3 -c "import sys; bad=[f for f in sys.argv[1:] if not open(f,'rb').read().removeprefix(b'\xef\xbb\xbf').isascii()]; bad and print('Non-ASCII bytes in harness scripts (keep test/windows/*.ps1 ASCII):', *bad, sep='\n'); sys.exit(1 if bad else 0)" {staged_files}
gofmt-check:
glob: "*.go"
run: test -z "$(gofmt -l .)" || { echo "Files not formatted:"; gofmt -l .; exit 1; }
go-vet:
glob: "*.go"
run: go vet ./...
go-build:
glob: "*.go"
run: go build ./...
# --allow-parallel-runners on EVERY golangci invocation in this hook:
# `parallel: true` starts this command and arch-gate at the same moment, and
# without the flag the second one to start dies on golangci's global flock
# ("parallel golangci-lint is running", exit 3) and fails the commit. It
# reproduced 3/3 with cold caches; warm caches only hid it by finishing first.
golangci-lint:
glob: "*.go"
run: |
if command -v golangci-lint &> /dev/null; then
golangci-lint run --allow-parallel-runners ./...
else
echo "golangci-lint not installed, skipping (install: https://golangci-lint.run/welcome/install/)"
fi
# docker-entrypoint.sh is PID 1 of the published image (privilege drop,
# mount ownership) and no Go test executes it — shellcheck is the only gate
# it has. Mirrors the "shell" job in .github/workflows/ci.yml.
shellcheck:
glob: "*.sh"
run: |
if command -v shellcheck &> /dev/null; then
shellcheck docker-entrypoint.sh scripts/check-arch.sh scripts/download-ffmpeg-static.sh scripts/release.sh
else
echo "shellcheck not installed, skipping (install: https://www.shellcheck.net/)"
fi
# Architectural / SOLID gate — blocks spaghetti & god-files in NEW/CHANGED code only
# (legacy grandfathered vs origin/main). File size <500, func length, cyclo + cognitive
# complexity 15, nesting, dup, max-params 5. See .golangci.arch.yml + scripts/check-arch.sh.
arch-gate:
glob: "*.go"
run: |
bash scripts/check-arch.sh || exit 1
if command -v golangci-lint &> /dev/null; then
# Once per GOOS, exactly like `make arch`: a single pass never loads
# //go:build windows|darwin files, so the ~35 platform-constrained
# non-test files would commit unanalysed while golangci prints
# "0 issues". Skipping the loop here is the half-fix that lets a
# commit through and fails `make arch` afterwards.
for goos in linux windows darwin; do
GOOS=$goos golangci-lint run --allow-parallel-runners -c .golangci.arch.yml ./... || exit 1
done
else
echo "golangci-lint not installed, skipping arch lint (file-length gate still ran)"
fi
pre-push:
commands:
go-test:
glob: "*.go"
run: go test -race -count=1 -timeout=120s ./...
commit-msg:
scripts:
validate.sh:
runner: bash