61 lines
1.7 KiB
Bash
Executable File
61 lines
1.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
source "$ROOT_DIR/scripts/harness/lib.sh"
|
|
|
|
main() {
|
|
cd "$ROOT_DIR"
|
|
local uv_bin
|
|
uv_bin="$(harness_require_tool uv)"
|
|
|
|
harness_run "$uv_bin" run --frozen --project "$ROOT_DIR" python - <<'PY'
|
|
import ast
|
|
from pathlib import Path
|
|
|
|
root = Path.cwd()
|
|
failures: list[str] = []
|
|
|
|
|
|
def fail(message: str) -> None:
|
|
failures.append(message)
|
|
|
|
|
|
class BackendDebugCallVisitor(ast.NodeVisitor):
|
|
def __init__(self, path: Path) -> None:
|
|
self.path = path
|
|
|
|
def visit_Call(self, node: ast.Call) -> None:
|
|
if isinstance(node.func, ast.Name) and node.func.id in {"print", "breakpoint"}:
|
|
fail(f"{self.path}:{node.lineno}: backend app code must use structured logging, not {node.func.id}()")
|
|
if (
|
|
isinstance(node.func, ast.Attribute)
|
|
and node.func.attr == "set_trace"
|
|
and isinstance(node.func.value, ast.Name)
|
|
and node.func.value.id == "pdb"
|
|
):
|
|
fail(f"{self.path}:{node.lineno}: remove pdb.set_trace() from backend app code")
|
|
self.generic_visit(node)
|
|
|
|
|
|
for path in sorted((root / "backend/app").rglob("*.py")):
|
|
rel = path.relative_to(root)
|
|
try:
|
|
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(rel))
|
|
except SyntaxError as exc:
|
|
fail(f"{rel}:{exc.lineno}: Python syntax error: {exc.msg}")
|
|
continue
|
|
BackendDebugCallVisitor(rel).visit(tree)
|
|
|
|
if failures:
|
|
for message in failures:
|
|
print(f"fail: {message}")
|
|
raise SystemExit(f"backend rules check failed: {len(failures)} failure(s)")
|
|
|
|
print("backend rules check passed")
|
|
PY
|
|
}
|
|
|
|
main "$@"
|