#!/usr/bin/env python3 """Append one evidence pointer to current.yaml and re-validate.""" from __future__ import annotations import argparse import sys from pathlib import Path from typing import Any from ship_lib import dump_yaml, load_yaml from validate_ship import validate_ship_dir KINDS = ("testRun", "artifact", "deploy", "pr", "commit") KEY = { "testRun": "testRuns", "artifact": "artifacts", "deploy": "deploys", "pr": "prs", "commit": "commits", } def _entry(kind: str, args: argparse.Namespace) -> dict[str, Any]: if kind == "testRun": if not args.path or not args.result: raise SystemExit("testRun 需要 --path 和 --result") row: dict[str, Any] = {"path": args.path, "result": args.result} if args.suite: row["suite"] = args.suite return row if kind == "artifact": if not args.sha: raise SystemExit("artifact 需要 --sha") row = {"sha": args.sha} if args.digest: row["digest"] = args.digest if args.ref: row["ref"] = args.ref if args.venue: row["venue"] = args.venue return row if kind == "deploy": if not args.env: raise SystemExit("deploy 需要 --env") row = {"env": args.env} if args.sha: row["revision"] = args.sha if args.health: row["health"] = args.health return row if kind == "pr": if not args.url: raise SystemExit("pr 需要 --url") row = {"url": args.url, "status": args.pr_status or "opened"} return row if kind == "commit": if not args.sha or not args.role: raise SystemExit("commit 需要 --sha 和 --role") return {"sha": args.sha, "role": args.role} raise SystemExit(f"未知 kind: {kind}") def main() -> int: parser = argparse.ArgumentParser(description="向 ship current.yaml 追加证据指针") parser.add_argument("ship_dir") parser.add_argument("--kind", required=True, choices=KINDS) parser.add_argument("--path") parser.add_argument("--result") parser.add_argument("--suite") parser.add_argument("--sha") parser.add_argument("--digest") parser.add_argument("--ref") parser.add_argument("--venue") parser.add_argument("--env") parser.add_argument("--health") parser.add_argument("--url") parser.add_argument("--pr-status") parser.add_argument("--role") args = parser.parse_args() ship_dir = Path(args.ship_dir).resolve() current_path = ship_dir / "current.yaml" data = load_yaml(current_path) if not isinstance(data, dict): raise SystemExit("current.yaml 不是 mapping") evidence = data.setdefault("evidence", {}) if not isinstance(evidence, dict): raise SystemExit("evidence 不是 mapping") key = KEY[args.kind] bucket = evidence.setdefault(key, []) if not isinstance(bucket, list): raise SystemExit(f"evidence.{key} 不是列表") bucket.append(_entry(args.kind, args)) dump_yaml(current_path, data) issues = validate_ship_dir(ship_dir) if issues: for item in issues: print(f"✗ {item}", file=sys.stderr) return 1 print(f"✓ 已追加 evidence.{key}") return 0 if __name__ == "__main__": raise SystemExit(main())