- parsers/ package: rust / python / go / typescript / generic
- parser registry with language+recipe -> fallback resolution
- fingerprint hash (kind+file+line+code) for cross-run dedup
- runner.py post-exec hook: parse log, persist findings, count on job row
(extraction runs before mark_job_finished so callers polling on terminal
status see findings_count populated atomically)
- db.insert_finding / list_findings / increment_findings_count DAOs already
shipped in wave 1; wired here
- GET /jobs/{id}/findings now returns real data (server route already
shipped; was returning empty list because nothing populated the table)
- tests/test_parsers/: 6 modules + 11 fixtures (rust/python/go/typescript)
- tests/test_runner_findings.py: 3 integration tests
- README: tick steps 2-6, add Findings section
Suite: 108 passing (62 wave-1 + 46 new).
Spec: memory/spec-crafting-table.md
34 lines
1.1 KiB
Python
34 lines
1.1 KiB
Python
"""Fallback parser — used when no language-specific parser claims the recipe.
|
|
|
|
Behavior is intentionally minimal. We don't try to extract anything from
|
|
arbitrary stdout for unknown (language, recipe) combos — that's a v0.2
|
|
problem. All we do is: if the recipe exited non-zero, emit a single
|
|
``recipe_fail`` finding so the digest can flag "something went wrong" without
|
|
hand-grepping the log. exit_code 0 = no findings.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from .base import Finding
|
|
|
|
|
|
class GenericParser:
|
|
@classmethod
|
|
def matches(cls, language: str, recipe: str) -> bool:
|
|
# Always true — the registry uses this as the last-resort fallback.
|
|
return True
|
|
|
|
@classmethod
|
|
def parse(cls, raw_log: str, exit_code: int, recipe: str) -> list[Finding]:
|
|
if exit_code == 0:
|
|
return []
|
|
return [
|
|
Finding(
|
|
kind="recipe_fail",
|
|
severity="warn",
|
|
code=f"exit_{exit_code}",
|
|
message=(
|
|
f"recipe '{recipe}' exited with status {exit_code}; "
|
|
f"see job log for details"
|
|
),
|
|
)
|
|
]
|