forked from prebid/salesagent
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.pre-commit-config.yaml
More file actions
309 lines (270 loc) · 12.4 KB
/
.pre-commit-config.yaml
File metadata and controls
309 lines (270 loc) · 12.4 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
repos:
- repo: local
hooks:
# Check for tenant.config references
- id: no-tenant-config
name: No tenant.config references
entry: sh -c 'if grep -r "tenant\.config\|tenant\[.config.\]" --include="*.py" . | grep -v "test_migration\|postmortem\|pre-commit"; then echo "Found tenant.config references!"; exit 1; fi'
language: system
pass_filenames: false
# Enforce JSONType usage for all JSON columns
- id: enforce-jsontype
name: Enforce JSONType usage (not plain JSON)
entry: sh -c 'if grep -rE "Column\(JSON[,)]" --include="*.py" src/core/database/models.py; then echo "❌ Found Column(JSON) usage! Use Column(JSONType) instead. See CLAUDE.md for pattern."; exit 1; fi'
language: system
pass_filenames: false
always_run: true
# Enforce SQLAlchemy 2.0 patterns (no legacy session.query)
- id: enforce-sqlalchemy-2-0
name: Enforce SQLAlchemy 2.0 patterns (no session.query)
entry: uv run python .pre-commit-hooks/check_sqlalchemy_2_0.py
language: system
files: '^(src/|product_catalog_providers/).*\.py$'
pass_filenames: true
# Prevent skipping tests (but allow skip_ci for CI-specific issues)
- id: no-skip-tests
name: No @pytest.mark.skip decorators allowed
entry: sh -c 'if grep -r "@pytest\.mark\.skip[^_]" --include="test_*.py" tests/ | grep -v skip_ci; then echo "❌ Found @pytest.mark.skip decorators! Tests must not be skipped."; exit 1; fi'
language: system
pass_filenames: false
always_run: true
# integration_v2 tests cannot be skipped at all (no skip, no skip_ci)
- id: no-skip-integration-v2
name: integration_v2 tests cannot be skipped (no skip or skip_ci)
entry: sh -c 'if grep -r "@pytest\.mark\.skip" --include="test_*.py" tests/integration_v2/; then echo "❌ integration_v2 tests cannot use @pytest.mark.skip or @pytest.mark.skip_ci! All v2 tests must run in CI."; exit 1; fi'
language: system
pass_filenames: false
always_run: true
# Prevent over-mocking (mocking internal implementation instead of external I/O)
- id: no-excessive-mocking
name: Prevent excessive mocking in tests
entry: uv run python scripts/check_test_mocking.py
language: system
pass_filenames: false
always_run: true
# Check for missing imports (prevent NameError bugs)
- id: check-import-usage
name: Check for classes/functions used without imports
entry: uv run python .pre-commit-hooks/check_import_usage.py
language: system
files: '^src/.*\.py$'
pass_filenames: true
# Check for unsafe response attribute access (prevent AttributeError bugs)
- id: check-response-attribute-access
name: Detect unsafe response attribute access patterns
entry: uv run python scripts/hooks/check_response_attribute_access.py
language: system
files: '^src/.*\.py$'
pass_filenames: true
# Check A2A skill test coverage
- id: a2a-skill-coverage
name: Verify 100% A2A skill coverage
entry: uv run python scripts/check_a2a_skill_coverage.py
language: system
pass_filenames: false
always_run: true
# Check Admin UI route test coverage
- id: admin-route-coverage
name: Verify 100% Admin UI GET route test coverage
entry: uv run python scripts/check_admin_route_coverage.py
language: system
pass_filenames: false
always_run: true
# Detect testing anti-patterns (over-mocking, missing coverage)
- id: detect-test-antipatterns
name: Detect testing anti-patterns
entry: uv run python scripts/detect_test_antipatterns.py
language: system
files: '^(tests/.*\.py|src/a2a_server/adcp_a2a_server\.py)$'
pass_filenames: true
# Check roundtrip tests exist for all apply_testing_hooks calls
- id: check-roundtrip-tests
name: Verify roundtrip tests exist for apply_testing_hooks operations
entry: uv run python .pre-commit-hooks/check_roundtrip_tests.py
language: system
pass_filenames: false
always_run: true
# Check MCP/A2A parameter alignment
- id: check-parameter-alignment
name: Check MCP/A2A parameter alignment with _impl functions
entry: sh -c 'uv run python .pre-commit-hooks/check_parameter_alignment.py || echo "⚠️ Parameter mismatches found (non-blocking for now)" >&2'
language: system
pass_filenames: false
always_run: true
# Ensure smoke tests pass
- id: smoke-tests
name: Run smoke tests (critical paths)
entry: uv run pytest tests/smoke/ -v --tb=short -m smoke
language: system
pass_filenames: false
stages: [manual] # Run with: pre-commit run smoke-tests
# Check for multiple Alembic migration heads
- id: check-migration-heads
name: Check for multiple Alembic migration heads
entry: uv run python scripts/ops/check_migration_heads.py --quiet
language: system
pass_filenames: false
always_run: true
# Validate migrations can run
- id: test-migrations
name: Test database migrations
entry: sh -c 'cp adcp_local.db .test.db && DATABASE_URL=sqlite:///.test.db python migrate.py && rm .test.db'
language: system
pass_filenames: false
stages: [manual] # Changed from commit to manual - run with: pre-commit run test-migrations
# Run quick unit tests before commit (optional - can be skipped with --no-verify)
- id: pytest-unit
name: Run unit tests (optional)
entry: sh -c 'uv run pytest tests/unit/ -x --tb=short -q || echo "⚠️ Tests failed but continuing (use --no-verify to skip)"'
language: system
pass_filenames: false
stages: [manual] # Changed to manual - run with: pre-commit run pytest-unit
verbose: true
# Test AdCP contract compliance
- id: adcp-contract-tests
name: Verify AdCP protocol compliance
entry: uv run pytest tests/unit/test_adcp_contract.py -v --tb=short
language: system
pass_filenames: false
always_run: true
# Test MCP contract validation (prevent validation errors like 'brief' is required)
- id: mcp-contract-validation
name: MCP contract validation tests
entry: uv run pytest tests/integration/test_mcp_contract_validation.py -v --tb=short
language: system
files: '^(src/core/schemas\.py|src/core/main\.py)$'
pass_filenames: false
# Audit required fields to catch over-validation
- id: audit-required-fields
name: Audit required fields for over-validation
entry: uv run python scripts/audit_required_fields.py
language: system
files: '^src/core/schemas\.py$'
pass_filenames: false
verbose: true
# Check AdCP schema sync (critical for buyer compatibility)
- id: adcp-schema-sync
name: Verify AdCP schema sync
entry: uv run python scripts/check_schema_sync.py --ci
language: system
pass_filenames: false
always_run: true
# Validate adapter usage (prevents field name mismatches like deliveries → media_buy_deliveries)
- id: validate-adapter-usage
name: Validate adapter schema field names
entry: uv run python scripts/validate_adapter_usage.py
language: system
files: '^(src/core/main\.py|src/core/schema_adapters\.py)$'
pass_filenames: false
# Validate adapter schemas match official AdCP JSON schemas
- id: adapter-schema-compliance
name: Validate adapter schemas match AdCP spec
entry: uv run pytest tests/unit/test_adapter_schema_compliance.py -v --tb=short
language: system
files: '^(src/core/schema_adapters\.py|schemas/v1/.*\.json)$'
pass_filenames: false
always_run: true
# Check Pydantic-AdCP schema alignment (prevents client validation errors like missing promoted_offering)
- id: pydantic-adcp-alignment
name: Pydantic model alignment with AdCP schemas (REGRESSION PREVENTION)
entry: uv run pytest tests/unit/test_pydantic_schema_alignment.py::TestSpecificFieldValidation -v --tb=short
language: system
files: '^(src/core/schemas\.py|schemas/v1/.*\.json)$'
pass_filenames: false
always_run: true
# Prevent A2A regression issues (URL format, function calls)
- id: a2a-regression-check
name: A2A regression prevention
entry: python3 scripts/validate_a2a_fixes.py
language: system
files: ^src/a2a_server/
pass_filenames: false
# Audit E2E tests for non-existent tool calls
- id: e2e-test-audit
name: E2E test contract validation (prevents calling non-existent tools)
entry: uv run python scripts/audit_e2e_tests.py
language: system
pass_filenames: false
always_run: true
# Validate A2A AdCP spec compliance (prevents legacy format acceptance)
- id: a2a-adcp-compliance
name: A2A AdCP spec compliance validation
entry: uv run python scripts/validate_a2a_adcp_compliance.py
language: system
files: ^src/a2a_server/
pass_filenames: false
# Prevent problematic function call patterns
- id: no-fn-calls
name: No .fn() call patterns
entry: sh -c 'if grep -r "\.fn(" src/ --include="*.py" | grep -v test; then echo "❌ Found .fn() calls - use direct function calls"; exit 1; fi'
language: system
files: ^src/
pass_filenames: false
# Validate schema-database field alignment (prevents AttributeError bugs)
- id: schema-database-alignment
name: Schema-database field alignment validation
entry: uv run python scripts/validate_schema_database_alignment.py --quiet
language: system
files: '^(src/core/schemas\.py|src/core/database/models\.py)$'
pass_filenames: false
# Validate MCP tool-schema parameter alignment (prevents datetime.combine bugs)
- id: mcp-schema-alignment
name: MCP tool-schema parameter alignment
entry: uv run python tools/validate_mcp_schemas.py
language: system
files: '^(src/core/schemas\.py|src/core/main\.py)$'
pass_filenames: false
# Check generated schemas are in sync with JSON schemas
# NOTE: Removed this hook - script doesn't exist and check_schema_sync.py
# already validates schema alignment (runs on every commit via adcp-schema-sync)
# Test MCP endpoints (requires server running)
- id: mcp-endpoint-tests
name: Test MCP endpoints
entry: echo Run MCP tests with uv run pytest tests/integration/test_mcp_endpoints_comprehensive.py
language: system
pass_filenames: false
stages: [manual] # Manual because it needs server running
# Check mypy error count doesn't increase (no regression)
# Much faster than per-file checks: 3s vs 2+ minutes
- id: mypy-no-regression
name: Check mypy error count (no regression)
entry: uv run python scripts/check_mypy_no_regression.py
language: system
files: '\.py$'
pass_filenames: false
always_run: false # Only run when Python files changed
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=1000']
- id: check-json
- id: check-merge-conflict
- id: check-ast
- id: debug-statements
- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.11
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
# Type checking with mypy (manual for now - too many errors)
# Run manually with: uv run mypy src/ --config-file=mypy.ini
# - repo: https://github.com/pre-commit/mirrors-mypy
# rev: v1.18.2
# hooks:
# - id: mypy
# args: [--config-file=mypy.ini]
# additional_dependencies:
# - sqlalchemy[mypy]==2.0.36
# - types-requests
# - types-python-dateutil
# files: '^src/'
# exclude: '^src/adapters/google_ad_manager_original\.py$'