#!/usr/bin/env python3 """Append structured tester issue evidence to an existing run snapshot.""" from __future__ import annotations import argparse from pathlib import Path from typing import Any import yaml from failure_feedback import attach_feedback def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="将 tester 失败结构化回流到 run YAML/CSV") parser.add_argument("--run", required=True, type=Path) parser.add_argument("--trigger", choices=("pr", "requirement", "bug")) parser.add_argument("--target", default="") parser.add_argument("--related-issue", default="") parser.add_argument("--dispatcher", default="dispatcher") parser.add_argument("--testcase", default="", help="为一条失败结果补充 testcase issue 字段") parser.add_argument("--issue-type", choices=("product", "test")) parser.add_argument("--expected", default="") parser.add_argument("--observed", default="") parser.add_argument("--artifact-hash", default="") parser.add_argument("--environment", default="") parser.add_argument("--evidence-path", default="") parser.add_argument("--reproduction", default="") parser.add_argument("--next-step", default="") args = parser.parse_args(argv) data: dict[str, Any] = yaml.safe_load(args.run.read_text(encoding="utf-8")) or {} if args.testcase: rows = data.get("results") if not isinstance(rows, list): raise SystemExit("run 缺少 results 列表") row = next((item for item in rows if isinstance(item, dict) and str(item.get("id")) == args.testcase), None) if row is None: raise SystemExit(f"找不到 testcase: {args.testcase}") row["issue"] = { key: value for key, value in { "issue_type": args.issue_type, "expected": args.expected, "observed": args.observed, "artifact_hash": args.artifact_hash, "environment": args.environment, "evidence_path": args.evidence_path, "reproduction": args.reproduction, "next_step": args.next_step, }.items() if value } output = attach_feedback( data, trigger=args.trigger, target=args.target, related_issue=args.related_issue, dispatcher=args.dispatcher, ) args.run.write_text(yaml.safe_dump(output, allow_unicode=True, sort_keys=False), encoding="utf-8") csv_path = "" try: from generate_run_csv import export_run_csv csv_path = str(export_run_csv(args.run.parents[3], run_path=args.run)) except (ImportError, OSError, SystemExit, ValueError): pass print(f"updated {args.run} defects={len(output.get('defects') or [])} csv={csv_path}") return 0 if __name__ == "__main__": raise SystemExit(main())