soteria/scripts/loc_hygiene_check.py

98 lines
2.7 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""Enforce source-file LOC budgets with explicit per-file waivers."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--root", default=".")
parser.add_argument("--max-lines", type=int, default=500)
parser.add_argument("--waivers", required=True)
parser.add_argument("--summary-json", default="")
return parser.parse_args()
def iter_source_files(root: Path) -> list[Path]:
files: list[Path] = []
for rel_root, suffixes in (
("cmd", {".go"}),
("internal", {".go"}),
("web/src", {".ts", ".tsx", ".css"}),
):
base = root / rel_root
if not base.exists():
continue
for path in sorted(base.rglob("*")):
if not path.is_file():
continue
if path.suffix not in suffixes:
continue
rel = path.relative_to(root).as_posix()
if rel.endswith("_test.go"):
continue
if rel.startswith("internal/server/ui-dist/"):
continue
files.append(path)
return files
def load_waivers(path: Path) -> dict[str, int]:
waivers: dict[str, int] = {}
if not path.exists():
return waivers
for raw in path.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
parts = line.split("\t")
if len(parts) < 2:
continue
rel = parts[0]
try:
max_lines = int(parts[1])
except ValueError:
continue
waivers[rel] = max_lines
return waivers
def main() -> int:
args = parse_args()
root = Path(args.root).resolve()
waivers = load_waivers(Path(args.waivers).resolve())
violations: list[str] = []
over_500 = 0
for path in iter_source_files(root):
rel = path.relative_to(root).as_posix()
line_count = len(path.read_text(encoding="utf-8", errors="ignore").splitlines())
if line_count > 500:
over_500 += 1
limit = waivers.get(rel, args.max_lines)
if line_count > limit:
violations.append(f"{rel}: {line_count} lines (limit {limit})")
summary = {"over_500": over_500, "violations": len(violations)}
if args.summary_json:
Path(args.summary_json).write_text(json.dumps(summary, indent=2), encoding="utf-8")
if violations:
print("LOC hygiene check failed:")
for item in violations:
print(item)
return 1
print("LOC hygiene checks: ok")
return 0
if __name__ == "__main__":
sys.exit(main())