chore(P14-8): 完成运营化与验收收口
这个提交包含在:
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
||||
|
||||
def validate_step(step, idx):
|
||||
required_keys = {
|
||||
"id": str,
|
||||
"name": str,
|
||||
"enabled": bool,
|
||||
"status": str,
|
||||
"exit_code": int,
|
||||
"duration_ms": int,
|
||||
"started_at": str,
|
||||
"ended_at": str,
|
||||
"command": str
|
||||
}
|
||||
|
||||
for key, expected_type in required_keys.items():
|
||||
if key not in step:
|
||||
raise ValueError(f"Step[{idx}] missing required key: '{key}'")
|
||||
if not isinstance(step[key], expected_type):
|
||||
raise ValueError(f"Step[{idx}] '{key}' must be {expected_type.__name__}, got {type(step[key]).__name__}")
|
||||
|
||||
def validate_report(report_path: Path):
|
||||
if not report_path.exists():
|
||||
raise FileNotFoundError(f"Report file not found: {report_path}")
|
||||
|
||||
try:
|
||||
report = json.loads(report_path.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON format: {e}")
|
||||
|
||||
# Root Level
|
||||
if "schema_version" not in report or report["schema_version"] != "1.0":
|
||||
raise ValueError("Invalid or missing schema_version. Expected '1.0'")
|
||||
|
||||
if "generated_at" not in report or not isinstance(report["generated_at"], str):
|
||||
raise ValueError("Missing or invalid 'generated_at' string")
|
||||
|
||||
# Git
|
||||
if "git" not in report or not isinstance(report["git"], dict):
|
||||
raise ValueError("Missing or invalid 'git' object")
|
||||
if "sha" not in report["git"] or not isinstance(report["git"]["sha"], str):
|
||||
raise ValueError("Missing or invalid 'git.sha'")
|
||||
if "branch" not in report["git"] or not isinstance(report["git"]["branch"], str):
|
||||
raise ValueError("Missing or invalid 'git.branch'")
|
||||
|
||||
# Overall
|
||||
if "overall" not in report or not isinstance(report["overall"], dict):
|
||||
raise ValueError("Missing or invalid 'overall' object")
|
||||
|
||||
for key in ["duration_ms", "passed", "failed", "skipped", "total"]:
|
||||
if key not in report["overall"] or not isinstance(report["overall"][key], int):
|
||||
raise ValueError(f"Missing or invalid integer 'overall.{key}'")
|
||||
if "status" not in report["overall"] or not isinstance(report["overall"]["status"], str):
|
||||
raise ValueError("Missing or invalid string 'overall.status'")
|
||||
|
||||
# Steps
|
||||
if "steps" not in report or not isinstance(report["steps"], list):
|
||||
raise ValueError("Missing or invalid 'steps' array")
|
||||
|
||||
for idx, step in enumerate(report["steps"]):
|
||||
validate_step(step, idx)
|
||||
|
||||
logging.info(f"Report {report_path} passed schema validation (v1.0).")
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
logging.error("Usage: validate_regression_report.py <path/to/report.json>")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
validate_report(Path(sys.argv[1]))
|
||||
except Exception as e:
|
||||
logging.error(f"Validation failed: {e}")
|
||||
sys.exit(1)
|
||||
在新工单中引用
屏蔽一个用户