Add ci_report_hook/src/ci_report_hook/core.py
This commit is contained in:
parent
176a79fac7
commit
a1eecfea11
1 changed files with 92 additions and 0 deletions
92
ci_report_hook/src/ci_report_hook/core.py
Normal file
92
ci_report_hook/src/ci_report_hook/core.py
Normal file
|
|
@ -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."
|
||||||
Loading…
Reference in a new issue