"""Create a Gitea issue when CI fails. Called from CI workflows.""" import argparse import json import os import urllib.request import urllib.error def main(): parser = argparse.ArgumentParser() parser.add_argument("--sha", required=True) parser.add_argument("--branch", required=True) parser.add_argument("--run", required=True) parser.add_argument("--message", required=True) parser.add_argument("--gitea-url", default=os.environ.get("GITEA_URL", ""), help="Gitea instance URL (default: $GITEA_URL)") parser.add_argument("--repo", default=os.environ.get("GITEA_REPO", ""), help="Repo path e.g. org/repo (default: $GITEA_REPO)") parser.add_argument("--api-token", default=os.environ.get("GITEA_API_TOKEN", "")) parser.add_argument("--workflow", default="CI", help="Workflow name (default: CI)") parser.add_argument("--labels", default="ci-failure", help="Comma-separated labels (default: ci-failure)") args = parser.parse_args() if not args.gitea_url or not args.repo: parser.error("--gitea-url and --repo are required (or set GITEA_URL and GITEA_REPO)") sha_short = args.sha[:7] run_url = f"{args.gitea_url}/{args.repo}/actions/runs/{args.run}" labels = [l.strip() for l in args.labels.split(",") if l.strip()] title = f"[{args.workflow}] Failure: {args.message[:80]}" body = ( f"## {args.workflow} 测试失败\n\n" f"- **Commit:** {sha_short}\n" f"- **Branch:** {args.branch}\n" f"- **工作流运行:** {run_url}\n\n" f"请检查上述链接查看失败详情。\n\n" f"### 下一步\n" f"- [ ] 分析失败原因\n" f"- [ ] 修复代码\n" f"- [ ] 提交 PR 触发 CI 重测" ) payload = json.dumps({ "title": title, "body": body, "labels": labels, }).encode("utf-8") url = f"{args.gitea_url}/api/v1/repos/{args.repo}/issues" req = urllib.request.Request(url, data=payload, method="POST") req.add_header("Authorization", f"token {args.api_token}") req.add_header("Content-Type", "application/json") try: with urllib.request.urlopen(req) as resp: data = json.loads(resp.read()) print(f"Issue created: {data.get('html_url', data.get('url', 'unknown'))}") except urllib.error.HTTPError as e: print(f"Failed to create issue: {e.code} {e.reason}") print(e.read().decode()) raise if __name__ == "__main__": main()