-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlefthook.yml
More file actions
136 lines (115 loc) · 5.73 KB
/
Copy pathlefthook.yml
File metadata and controls
136 lines (115 loc) · 5.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# ── ToopSet — Lefthook Hooks ──────────────────────────────────────────────────
# Pre-commit: fast, staged-only checks (formatting, security, quick lint).
# Pre-push: heavier validation (typecheck, full lint, build, backend checks).
# Tests are excluded from both — they require a running PostgreSQL database.
# CI is the final safety layer.
# ──────────────────────────────────────────────────────────────────────────────
# Docs: https://github.com/evilmartians/lefthook
# Hide meta (hook header) and execution (command itself) from per-command output.
# Success/failure/summary still shown.
output:
- meta
- execution
pre-commit:
parallel: true
commands:
# ── General hygiene ────────────────────────────────────────────────────────
trailing-whitespace:
glob: "*.{py,ts,tsx,js,jsx,css,md,yml,yaml,json,mjs,mts,html,toml,cfg,ini,txt,sh,bat}"
run: for f in {staged_files}; do sed -i '' 's/[[:space:]]*$//' "$f"; done
stage_fixed: true
eof-newline:
glob: "*"
run: |
for f in {staged_files}; do
[ -s "$f" ] && tail -c1 "$f" | read -r _ || printf '\n' >> "$f"
done
stage_fixed: true
merge-conflict:
glob: "*"
run: |
conflicts=$(grep -lP '^<<<<<<< |^=======$|^>>>>>>> ' {staged_files} 2>/dev/null || true)
if [ -n "$conflicts" ]; then
echo "✗ Merge conflict markers in: $conflicts"
exit 1
fi
detect-private-key:
glob: "*"
run: |
keys=$(grep -lP 'BEGIN\s+(RSA|DSA|EC|OPENSSH)\s+PRIVATE\s+KEY' {staged_files} 2>/dev/null || true)
if [ -n "$keys" ]; then
echo "✗ Private key detected in: $keys"
exit 1
fi
lf-line-endings:
glob: "*"
run: |
for f in {staged_files}; do
grep -lP '\r\n' "$f" 2>/dev/null && sed -i '' 's/\r$//' "$f" || true
done
stage_fixed: true
# ── Backend: Ruff format + lint (staged only) ─────────────────────────────
ruff-format:
glob: "backend/**/*.py"
run: ruff format {staged_files}
stage_fixed: true
ruff-check:
glob: "backend/**/*.py"
run: ruff check --fix {staged_files}
stage_fixed: true
# ── Frontend: Prettier + ESLint (staged only) ─────────────────────────────
prettier:
glob: "frontend/**/*.{js,ts,jsx,tsx,css,json,md,mjs,mts}"
run: cd frontend && npx prettier --write --ignore-unknown $(printf '%s\n' {staged_files} | sed 's|^frontend/||')
stage_fixed: true
eslint:
glob: "frontend/**/*.{ts,tsx,js,jsx}"
run: cd frontend && npx eslint --fix $(printf '%s\n' {staged_files} | sed 's|^frontend/||')
stage_fixed: true
# ── Pre-push (heavier — run before pushing) ──────────────────────────────────
# These catch issues that wouldn't be spotted by staged-only checks.
# If any fails, fix it locally before pushing.
pre-push:
parallel: false
commands:
# ── Frontend ────────────────────────────────────────────────────────────────
typecheck:
run: cd frontend && npx tsc --noEmit
eslint-full:
run: cd frontend && npx eslint .
build:
run: cd frontend && npx next build
# ── Backend ─────────────────────────────────────────────────────────────────
ruff-check-full:
glob: "backend/**/*.py"
run: cd backend && ruff check .
ruff-format-check:
glob: "backend/**/*.py"
run: cd backend && ruff format --check .
mypy:
glob: "backend/**/*.py"
run: cd backend && mypy app
# ── CI config validation ───────────────────────────────────────────────────
yaml-validate:
glob: ".github/**/*.yml"
run: python3 -c "import yaml; yaml.safe_load(open('{staged_files}')); print(' ✓ YAML valid')"
# ── Migration revision check (static, no DB) ───────────────────────────────────────────────────
migration-check:
glob: "backend/migrations/versions/*.py"
run: cd backend && python3 -m scripts.check_revisions --strict
# ── Main-branch-only checks ─────────────────────────────────────────────────
dep-audit:
run: |
if [ "$(git rev-parse --abbrev-ref HEAD)" = "main" ]; then
npx --prefix frontend pnpm audit --audit-level=high || true
else
echo " ─ Skipping dep audit on feature branch"
fi
env-validate:
run: |
if [ "$(git rev-parse --abbrev-ref HEAD)" = "main" ]; then
[ -f .env ] && echo " ✓ .env found" || echo " ⚠ .env missing"
[ -f backend/.env ] && echo " ✓ backend/.env found" || echo " ⚠ backend/.env missing"
else
echo " ─ Skipping env check on feature branch"
fi