diff --git a/ci_report_hook/src/ci_report_hook/core.py b/ci_report_hook/src/ci_report_hook/core.py new file mode 100644 index 0000000..3505dd2 --- /dev/null +++ b/ci_report_hook/src/ci_report_hook/core.py @@ -0,0 +1,92 @@ +import json +import os +from pathlib import Path +from datetime import datetime +from typing import Any, Dict + + +class CIReport: + """Datenmodell für einen CI-Run-Report.""" + + def __init__( + self, + timestamp: str, + run_id: str, + decision: str, + margin: float, + flaky_flag: bool, + subset_flip_count: int, + mischfenster_p95: float, + ) -> None: + self.timestamp = timestamp + self.run_id = run_id + self.decision = decision + self.margin = margin + self.flaky_flag = flaky_flag + self.subset_flip_count = subset_flip_count + self.mischfenster_p95 = mischfenster_p95 + + def to_json(self) -> Dict[str, Any]: + """Serialisiert den Bericht in ein JSON-kompatibles Dictionary.""" + return { + "timestamp": self.timestamp, + "run_id": self.run_id, + "decision": self.decision, + "margin": self.margin, + "flaky_flag": self.flaky_flag, + "subset_flip_count": self.subset_flip_count, + "mischfenster_p95": self.mischfenster_p95, + } + + +def record_ci_run( + run_id: str, + decision: str, + margin: float, + flaky_flag: bool, + subset_flip_count: int, + mischfenster_p95: float, +) -> None: + """Speichert die Daten eines CI-Runs als JSON-Datei im Reports-Ordner.""" + + # Input-Validation + if not isinstance(run_id, str) or not run_id: + raise ValueError("run_id muss ein nicht-leerer String sein.") + if decision not in {"PASS", "WARN", "FAIL"}: + raise ValueError("decision muss PASS, WARN oder FAIL sein.") + if not isinstance(margin, (float, int)): + raise TypeError("margin muss eine float-Zahl sein.") + if not isinstance(flaky_flag, bool): + raise TypeError("flaky_flag muss vom Typ bool sein.") + if not isinstance(subset_flip_count, int) or subset_flip_count < 0: + raise ValueError("subset_flip_count muss eine nicht-negative ganze Zahl sein.") + if not isinstance(mischfenster_p95, (float, int)): + raise TypeError("mischfenster_p95 muss eine float-Zahl sein.") + + # Zeitstempel erzeugen + timestamp = datetime.now().isoformat(timespec='seconds') + + # CIReport-Objekt erstellen + report = CIReport( + timestamp=timestamp, + run_id=run_id, + decision=decision, + margin=float(margin), + flaky_flag=flaky_flag, + subset_flip_count=subset_flip_count, + mischfenster_p95=float(mischfenster_p95), + ) + + # Reports-Ordner sicherstellen + reports_dir = Path("reports") + reports_dir.mkdir(parents=True, exist_ok=True) + + # Dateiname ableiten + report_path = reports_dir / f"{run_id}.json" + + # JSON-Datei schreiben + with report_path.open("w", encoding="utf-8") as f: + json.dump(report.to_json(), f, ensure_ascii=False, indent=2) + + # Sanity-Check für CI (ci_ready) + assert report_path.exists(), f"Report-Datei {report_path} wurde nicht erstellt." \ No newline at end of file