67 lines
2.0 KiB
Python
67 lines
2.0 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Enforce Ariadne's per-file source coverage contract."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
def _source_files(root: Path) -> list[str]:
|
||
|
|
files: list[str] = []
|
||
|
|
for path in sorted(root.rglob("*.py")):
|
||
|
|
if "__pycache__" in path.parts:
|
||
|
|
continue
|
||
|
|
files.append(path.as_posix())
|
||
|
|
return files
|
||
|
|
|
||
|
|
|
||
|
|
def _coverage_percent(file_payload: object) -> float | None:
|
||
|
|
if not isinstance(file_payload, dict):
|
||
|
|
return None
|
||
|
|
summary = file_payload.get("summary")
|
||
|
|
if not isinstance(summary, dict):
|
||
|
|
return None
|
||
|
|
value = summary.get("percent_covered")
|
||
|
|
if isinstance(value, (int, float)):
|
||
|
|
return float(value)
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> int:
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
parser.add_argument("coverage_json")
|
||
|
|
parser.add_argument("--source-root", default="ariadne")
|
||
|
|
parser.add_argument("--threshold", type=float, default=95.0)
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
coverage_path = Path(args.coverage_json)
|
||
|
|
source_root = Path(args.source_root)
|
||
|
|
payload = json.loads(coverage_path.read_text(encoding="utf-8"))
|
||
|
|
files = payload.get("files") if isinstance(payload, dict) else None
|
||
|
|
if not isinstance(files, dict):
|
||
|
|
print(f"{coverage_path}: missing files coverage map")
|
||
|
|
return 1
|
||
|
|
|
||
|
|
failures: list[str] = []
|
||
|
|
for source_file in _source_files(source_root):
|
||
|
|
percent = _coverage_percent(files.get(source_file))
|
||
|
|
if percent is None:
|
||
|
|
failures.append(f"{source_file}: missing from coverage report")
|
||
|
|
elif percent < args.threshold:
|
||
|
|
failures.append(f"{source_file}: {percent:.2f}% below {args.threshold:.2f}%")
|
||
|
|
|
||
|
|
if failures:
|
||
|
|
print("coverage contract failed:")
|
||
|
|
for failure in failures:
|
||
|
|
print(f" - {failure}")
|
||
|
|
return 1
|
||
|
|
|
||
|
|
print(f"coverage contract passed: {len(_source_files(source_root))} files >= {args.threshold:.2f}%")
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
raise SystemExit(main())
|