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