#!/bin/sh # Pre-commit hook: run CI-equivalent checks on staged files. # Fails the commit if any check fails — matches CI pipeline in .gitea/workflows/ci.yaml. # # To skip: git commit --no-verify set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Colour FAILED=0 # ---------- Frontend (prettier --write, then eslint) ---------- FRONTEND_STAGED=$(git diff --cached --name-only -- 'frontend/' | head -1) if [ -n "$FRONTEND_STAGED" ]; then printf "${YELLOW}Auto-formatting staged frontend files with prettier...${NC}\n" cd frontend && npx prettier --write . 2>&1 # Re-stage any files prettier modified so formatting is included in the commit cd .. git diff --name-only -- 'frontend/' | xargs -r git add fi # Always run eslint — catches pre-existing issues that would fail the pipeline printf "${YELLOW}Checking eslint (all files)...${NC}\n" if ! cd frontend && npx eslint . 2>&1; then printf "${RED}✖ eslint failed${NC}\n" FAILED=1 fi cd .. # ---------- Backend checks (only if backend/ files changed) ---------- BACKEND_FILES=$(git diff --cached --name-only -- 'backend/' | head -1) if [ -n "$BACKEND_FILES" ]; then printf "${YELLOW}Checking go vet...${NC}\n" if ! cd backend && go vet -tags "test,dev" ./... 2>&1; then printf "${RED}✖ go vet failed${NC}\n" FAILED=1 fi cd .. printf "${YELLOW}Checking golangci-lint...${NC}\n" if ! cd backend && golangci-lint run ./... --timeout 3m 2>&1; then printf "${RED}✖ golangci-lint failed${NC}\n" FAILED=1 fi cd .. printf "${YELLOW}Checking staticcheck...${NC}\n" if ! cd backend && staticcheck -tags "test,dev" ./... 2>&1; then printf "${RED}✖ staticcheck failed${NC}\n" FAILED=1 fi cd .. printf "${YELLOW}Checking gosec...${NC}\n" if ! cd backend && gosec -severity medium -tags "test,dev" ./... 2>&1; then printf "${RED}✖ gosec failed${NC}\n" FAILED=1 fi cd .. printf "${YELLOW}Checking go mod tidy...${NC}\n" cp backend/go.sum backend/go.sum.bak cp backend/go.mod backend/go.mod.bak cd backend && go mod tidy && cd .. if ! diff -q backend/go.sum backend/go.sum.bak >/dev/null 2>&1 || ! diff -q backend/go.mod backend/go.mod.bak >/dev/null 2>&1; then printf "${RED}✖ go.mod or go.sum out of date — run 'go mod tidy' and stage the changes${NC}\n" FAILED=1 fi rm -f backend/go.sum.bak backend/go.mod.bak fi # ---------- Global checks ---------- printf "${YELLOW}Checking secrets...${NC}\n" if command -v gitleaks >/dev/null 2>&1; then if ! gitleaks detect --source . --no-banner 2>&1; then printf "${RED}✖ gitleaks detected secrets${NC}\n" FAILED=1 fi else printf " (gitleaks not installed — skipping; CI will catch secrets)\n" fi # ---------- Result ---------- if [ "$FAILED" -ne 0 ]; then printf "\n${RED}Commit blocked — fix the issues above, then commit again.${NC}\n" printf "${YELLOW}To skip checks: git commit --no-verify${NC}\n" exit 1 fi printf "${GREEN}✓ All pre-commit checks passed${NC}\n" exit 0