From 442413581d731675f7fa03895879e33412417f27 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Sun, 19 Jul 2026 18:09:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(ci):=20=E6=8E=A5=E5=85=A5=20AgentLoop=20Tr?= =?UTF-8?q?ace=20=E4=B8=8A=E6=8A=A5=20(rebase=20onto=20develop)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为所有 CI workflow 的所有 job 添加 Trace 上报步骤, 包含从 develop 合入的 ACR 镜像清理策略等最新改动。 --- .gitea/scripts/ci_trace_report.py | 336 ++++++++++++++++++++++++ .gitea/workflows/auto-approve.yml | 17 ++ .gitea/workflows/auto-merge.yml | 17 ++ .gitea/workflows/ci-build.yml | 136 ++++++++++ .gitea/workflows/ci-cd.yml | 103 +++++++- .gitea/workflows/ci-trigger-monitor.yml | 17 ++ .gitea/workflows/code-review.yml | 17 ++ .gitea/workflows/daily-check.yml | 85 ++++++ .gitea/workflows/preview-cleanup.yml | 17 ++ .gitea/workflows/preview-deploy.yml | 17 ++ 10 files changed, 761 insertions(+), 1 deletion(-) create mode 100755 .gitea/scripts/ci_trace_report.py diff --git a/.gitea/scripts/ci_trace_report.py b/.gitea/scripts/ci_trace_report.py new file mode 100755 index 000000000..394ee1b9d --- /dev/null +++ b/.gitea/scripts/ci_trace_report.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python3 +""" +CI Trace 上报脚本 - 用于 Gitea Actions workflow 中上报 Trace 数据到 AgentLoop + +在 CI workflow 的每个 job 中调用: + - 开始时:python3 .gitea/scripts/ci_trace_report.py --status running + - 结束时:python3 .gitea/scripts/ci_trace_report.py --status ok --start-time $CI_TRACE_START_TIME + +环境变量(Gitea Actions 内置): + GITEA_REPOSITORY / GITHUB_REPOSITORY - 仓库名 (owner/repo) + GITEA_WORKFLOW / GITHUB_WORKFLOW - workflow 名称 + GITEA_JOB / GITHUB_JOB - job ID + GITEA_SHA / GITHUB_SHA - commit SHA + GITEA_REF_NAME / GITHUB_REF_NAME - 分支名 + GITEA_RUN_ID / GITHUB_RUN_ID - run ID + GITEA_ACTOR / GITHUB_ACTOR - 触发者 + GITEA_EVENT_NAME / GITHUB_EVENT_NAME - 事件类型 + PR_NUMBER / GITEA_PR_NUMBER - PR 号(如果是 PR 触发) + +AgentLoop 配置(通过 Secrets 注入): + AGENTLOOP_LICENSE_KEY - LicenseKey(必填) + AGENTLOOP_ENDPOINT - Trace 上报地址(可选,有默认值) + AGENTLOOP_PROJECT - SLS Project 名(可选) + AGENTLOOP_WORKSPACE - CMS Workspace 名(可选) +""" + +import os +import sys +import json +import time +import uuid +import argparse +import urllib.request +import urllib.error + + +# ========== 默认配置 ========== +DEFAULT_ENDPOINT = "https://proj-xtrace-495e81719a1fd9a2c5fd671eefafbe-cn-hangzhou.cn-hangzhou.log.aliyuncs.com/apm/trace/opentelemetry/v1/traces" +DEFAULT_PROJECT = "proj-xtrace-495e81719a1fd9a2c5fd671eefafbe-cn-hangzhou" +DEFAULT_WORKSPACE = "agentloop-13b8d6efb7fde6e9b193eb982ade68e2" + + +# ========== OTLP Protobuf 手动编码 ========== + +def _encode_varint(value): + result = bytearray() + while value > 0x7F: + result.append((value & 0x7F) | 0x80) + value >>= 7 + result.append(value & 0x7F) + return bytes(result) + +def _encode_tag(field_number, wire_type): + return _encode_varint((field_number << 3) | wire_type) + +def _encode_string_field(field_number, value): + value_bytes = value.encode('utf-8') + return _encode_tag(field_number, 2) + _encode_varint(len(value_bytes)) + value_bytes + +def _encode_bytes_field(field_number, value_bytes): + return _encode_tag(field_number, 2) + _encode_varint(len(value_bytes)) + value_bytes + +def _encode_int_field(field_number, value): + return _encode_tag(field_number, 0) + _encode_varint(value & 0xFFFFFFFFFFFFFFFF) + +def _encode_message_field(field_number, message_bytes): + return _encode_tag(field_number, 2) + _encode_varint(len(message_bytes)) + message_bytes + +def _encode_key_value(key, value_str): + any_value = _encode_string_field(1, value_str) + return _encode_string_field(1, key) + _encode_message_field(2, any_value) + +def _encode_status(status_code, status_msg=""): + data = _encode_int_field(1, status_code) + if status_msg: + data += _encode_string_field(2, status_msg) + return data + +def _encode_span(trace_id_bytes, span_id_bytes, parent_span_id_bytes, + name, start_time_unix_nano, end_time_unix_nano, + span_kind, attributes, status_code, status_msg=""): + data = b"" + data += _encode_bytes_field(1, trace_id_bytes) + data += _encode_bytes_field(2, span_id_bytes) + if parent_span_id_bytes: + data += _encode_bytes_field(3, parent_span_id_bytes) + data += _encode_string_field(4, name) + data += _encode_int_field(5, span_kind) + data += _encode_int_field(6, start_time_unix_nano) + data += _encode_int_field(7, end_time_unix_nano) + for key, value in attributes.items(): + kv = _encode_key_value(key, str(value)) + data += _encode_message_field(9, kv) + status = _encode_status(status_code, status_msg) + data += _encode_message_field(12, status) + return data + +def _encode_resource_spans(service_name, scope_spans_bytes): + svc_kv = _encode_key_value("service.name", service_name) + resource = _encode_message_field(1, svc_kv) + data = _encode_message_field(1, resource) + data += _encode_message_field(2, scope_spans_bytes) + return data + +def _encode_scope_spans(scope_name, spans_bytes_list): + scope = _encode_string_field(1, scope_name) + data = _encode_message_field(1, scope) + for span_bytes in spans_bytes_list: + data += _encode_message_field(2, span_bytes) + return data + +def _encode_traces_data(resource_spans_bytes_list): + data = b"" + for rs_bytes in resource_spans_bytes_list: + data += _encode_message_field(1, rs_bytes) + return data + + +# ========== 辅助函数 ========== + +def _gen_trace_id(): + return uuid.uuid4().bytes + +def _gen_span_id(): + return uuid.uuid4().bytes[:8] + +def _env(name, default=""): + """获取环境变量,支持 GITEA_ 和 GITHUB_ 前缀""" + val = os.getenv(name, "") + if val: + return val + # 尝试另一种前缀 + if name.startswith("GITEA_"): + alt = "GITHUB_" + name[6:] + return os.getenv(alt, default) + if name.startswith("GITHUB_"): + alt = "GITEA_" + name[7:] + return os.getenv(alt, default) + return default + + +def _get_pr_number(): + """从环境变量或事件文件中获取 PR 号""" + # 直接从环境变量 + pr = os.getenv("PR_NUMBER", "") or os.getenv("GITEA_PR_NUMBER", "") + if pr: + return pr + + # 从 GITHUB_EVENT_PATH 读取 + event_path = os.getenv("GITHUB_EVENT_PATH", "") or os.getenv("GITEA_EVENT_PATH", "") + if event_path and os.path.isfile(event_path): + try: + with open(event_path, "r") as f: + event = json.load(f) + if "pull_request" in event and "number" in event["pull_request"]: + return str(event["pull_request"]["number"]) + except Exception: + pass + + return "" + + +def _get_ci_attributes(): + """从 CI 环境变量中收集属性""" + attrs = { + "ci.repo": _env("GITEA_REPOSITORY") or _env("GITHUB_REPOSITORY") or "unknown", + "ci.workflow": _env("GITEA_WORKFLOW") or _env("GITHUB_WORKFLOW") or "unknown", + "ci.job": _env("GITEA_JOB") or _env("GITHUB_JOB") or "unknown", + "ci.commit_sha": _env("GITEA_SHA") or _env("GITHUB_SHA") or "unknown", + "ci.branch": _env("GITEA_REF_NAME") or _env("GITHUB_REF_NAME") or "unknown", + "ci.run_id": _env("GITEA_RUN_ID") or _env("GITHUB_RUN_ID") or "unknown", + "ci.actor": _env("GITEA_ACTOR") or _env("GITHUB_ACTOR") or "unknown", + "ci.event": _env("GITEA_EVENT_NAME") or _env("GITHUB_EVENT_NAME") or "unknown", + } + pr = _get_pr_number() + if pr: + attrs["ci.pr_number"] = pr + return attrs + + +# ========== 核心上报逻辑 ========== + +def build_trace(service_name, trace_name, status, duration_ms, attributes=None): + """构建一条完整的 Trace 数据,返回 protobuf bytes。""" + trace_id = _gen_trace_id() + end_time = int(time.time() * 1e9) + start_time = end_time - int(duration_ms * 1e6) + status_code = 1 if status in ("ok", "running") else 2 + status_msg = "" if status in ("ok", "running") else "Job failed" + + main_attrs = { + "agent.trace_name": trace_name, + "agent.service": service_name, + "ci.trace_status": status, + } + if attributes: + main_attrs.update(attributes) + + main_span = _encode_span( + trace_id_bytes=trace_id, + span_id_bytes=_gen_span_id(), + parent_span_id_bytes=b"", + name=trace_name, + start_time_unix_nano=start_time, + end_time_unix_nano=end_time, + span_kind=1, + attributes=main_attrs, + status_code=status_code, + status_msg=status_msg, + ) + + scope_spans = _encode_scope_spans("ci-trace", [main_span]) + resource_spans = _encode_resource_spans(service_name, scope_spans) + return _encode_traces_data([resource_spans]) + + +def report_ci_trace(service_name, trace_name, status="ok", duration_ms=1000, + endpoint=None, license_key=None, project=None, workspace=None, + extra_attributes=None): + """ + 上报 CI Trace 数据。返回 (success: bool, message: str) + 永远不会抛出异常,失败也返回 False。 + """ + try: + endpoint = endpoint or os.getenv("AGENTLOOP_ENDPOINT", DEFAULT_ENDPOINT) + license_key = license_key or os.getenv("AGENTLOOP_LICENSE_KEY", "") + project = project or os.getenv("AGENTLOOP_PROJECT", DEFAULT_PROJECT) + workspace = workspace or os.getenv("AGENTLOOP_WORKSPACE", DEFAULT_WORKSPACE) + + if not license_key: + return False, "[Trace] 跳过上报:未配置 AGENTLOOP_LICENSE_KEY" + + # 收集 CI 属性 + attrs = _get_ci_attributes() + if extra_attributes: + attrs.update(extra_attributes) + + payload = build_trace( + service_name=service_name, + trace_name=trace_name, + status=status, + duration_ms=duration_ms, + attributes=attrs, + ) + + headers = { + "Content-Type": "application/x-protobuf", + "x-arms-license-key": license_key, + "x-arms-project": project, + "x-cms-workspace": workspace, + } + + req = urllib.request.Request(endpoint, data=payload, headers=headers, method="POST") + try: + with urllib.request.urlopen(req, timeout=10) as resp: + status_code = resp.status + resp_body = resp.read().decode("utf-8", errors="replace") + except urllib.error.HTTPError as e: + status_code = e.code + resp_body = e.read().decode("utf-8", errors="replace") + + if status_code in (200, 202): + return True, f"[Trace] ✓ 上报成功: {service_name} / {trace_name} ({status}, {duration_ms}ms)" + else: + return False, f"[Trace] ⚠ 上报失败: HTTP {status_code} - {resp_body[:200]}" + except Exception as e: + return False, f"[Trace] ⚠ 上报异常: {type(e).__name__}: {str(e)}" + + +def main(): + parser = argparse.ArgumentParser(description="CI AgentLoop Trace 上报") + parser.add_argument("--service", dest="service_name", + default=os.getenv("TRACE_SERVICE", ""), + help="服务名称(也可通过 TRACE_SERVICE 环境变量设置)") + parser.add_argument("--name", dest="trace_name", + default=os.getenv("TRACE_NAME", ""), + help="Trace 名称(也可通过 TRACE_NAME 环境变量设置)") + parser.add_argument("--status", default=os.getenv("TRACE_STATUS", "ok"), + choices=["ok", "error", "running"], + help="状态: ok / error / running(默认 ok)") + parser.add_argument("--start-time", dest="start_time", + default=os.getenv("TRACE_START_TIME", ""), + help="开始时间戳(秒),用于计算 duration;不填则用默认 1s") + parser.add_argument("--duration-ms", dest="duration_ms", type=int, default=0, + help="直接指定耗时(毫秒),优先级高于 --start-time") + parser.add_argument("--attrs", default="", + help="附加属性(JSON 字符串)") + + args = parser.parse_args() + + # 必须参数检查 + if not args.service_name: + print("[Trace] ⚠ 跳过上报:未指定 service(--service 或 TRACE_SERVICE)") + sys.exit(0) + + # 计算耗时 + duration_ms = args.duration_ms + if duration_ms <= 0 and args.start_time: + try: + start_ts = float(args.start_time) + duration_ms = int((time.time() - start_ts) * 1000) + except (ValueError, TypeError): + duration_ms = 1000 + if duration_ms <= 0: + duration_ms = 1000 # 默认 1 秒 + + # 解析附加属性 + extra_attrs = {} + if args.attrs: + try: + extra_attrs = json.loads(args.attrs) + except json.JSONDecodeError: + pass + + # 生成 trace_name:如果没指定,用 workflow+job + trace_name = args.trace_name + if not trace_name: + wf = _env("GITEA_WORKFLOW") or _env("GITHUB_WORKFLOW") or "CI" + job = _env("GITEA_JOB") or _env("GITHUB_JOB") or "job" + trace_name = f"{wf} / {job}" + + success, msg = report_ci_trace( + service_name=args.service_name, + trace_name=trace_name, + status=args.status, + duration_ms=duration_ms, + extra_attributes=extra_attrs, + ) + + print(msg) + # 永远 exit 0,不影响 CI + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/.gitea/workflows/auto-approve.yml b/.gitea/workflows/auto-approve.yml index bd6916f0b..a12cd4b57 100755 --- a/.gitea/workflows/auto-approve.yml +++ b/.gitea/workflows/auto-approve.yml @@ -17,6 +17,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="auto-approve" TRACE_NAME="自动批准 / Auto Approve on CI Green" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Auto approve when CI passes shell: bash env: @@ -172,3 +180,12 @@ jobs: echo echo "⏰ 等待超时(20分钟),CI尚未全部完成" exit 0 + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="auto-approve" TRACE_NAME="自动批准 / Auto Approve on CI Green" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/auto-merge.yml b/.gitea/workflows/auto-merge.yml index ac1b75ee3..6a6a6890c 100755 --- a/.gitea/workflows/auto-merge.yml +++ b/.gitea/workflows/auto-merge.yml @@ -17,6 +17,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="auto-merge" TRACE_NAME="自动合并 / Auto Merge on CI Green + Approved" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Auto merge when CI passes and approved shell: bash env: @@ -172,3 +180,12 @@ jobs: echo echo "等待超时(30分钟)" exit 0 + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="auto-merge" TRACE_NAME="自动合并 / Auto Merge on CI Green + Approved" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/ci-build.yml b/.gitea/workflows/ci-build.yml index 3a12d9226..acaefb031 100644 --- a/.gitea/workflows/ci-build.yml +++ b/.gitea/workflows/ci-build.yml @@ -95,6 +95,14 @@ jobs: tar.extract(member, '.') INNERPY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -144,6 +152,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Build Staging ${{ matrix.service_display }} Image" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" deploy-staging: name: Deploy Staging (Watchtower auto-deploy) runs-on: runtime-builder @@ -200,6 +217,14 @@ jobs: tar.extract(member, '.') INNERPY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -302,6 +327,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Deploy Staging" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" staging-e2e: name: Staging E2E Tests runs-on: runtime-builder @@ -355,6 +389,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -382,6 +424,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Staging E2E Tests" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" staging-api-tests: name: Staging API Integration Tests runs-on: runtime-builder @@ -435,6 +486,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -462,6 +521,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Staging API Integration Tests" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" build-production: name: Build Production ${{ matrix.service_display }} Image runs-on: runtime-builder @@ -536,6 +604,14 @@ jobs: tar.extract(member, '.') INNERPY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -586,6 +662,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Build Production ${{ matrix.service_display }} Image" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" deploy-production: name: Deploy Production runs-on: runtime-builder @@ -642,6 +727,14 @@ jobs: tar.extract(member, '.') INNERPY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -732,6 +825,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Deploy Production" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" production-e2e: name: Production Browser E2E runs-on: runtime-builder @@ -745,6 +847,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\n# Retry up to 5 times with backoff for transient 5xx errors\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"' Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -773,6 +883,15 @@ jobs: ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" acr-cleanup: name: ACR Image Cleanup runs-on: runtime-builder @@ -827,6 +946,14 @@ with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar: tar.extract(member, '.') INNERPY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="ci-build" TRACE_NAME="CI构建 / ACR Image Cleanup" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Clean up old ACR images shell: sh env: @@ -845,3 +972,12 @@ INNERPY run: | set +e NOTIFY_MODE=failure JOB_NAME="ACR Image Cleanup" python3 scripts/ci_notify.py + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="ci-build" TRACE_NAME="CI构建 / ACR Image Cleanup" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index fc2c19270..5edecc6a6 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -35,6 +35,14 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Check changed files id: check shell: bash @@ -63,6 +71,15 @@ jobs: echo "🔧 包含全栈变更,运行完整CI" fi + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" validate: needs: check-frontend-only if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' @@ -81,6 +98,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\"\ )\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -233,6 +258,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Validate Code Quality And Tests" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" unit-tests: needs: check-frontend-only if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' @@ -252,6 +286,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\"\ )\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -425,6 +467,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Unit Tests" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" integration-tests: name: Integration Tests runs-on: ci-l2 @@ -447,6 +498,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\"\ )\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -544,6 +603,15 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Integration Tests" python3 scripts/ci_notify.py ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" frontend-lint: name: Frontend Lint runs-on: ci-check @@ -555,6 +623,14 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\"\ )\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -596,6 +672,15 @@ jobs: ' + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" frontend-unit-test: name: Frontend Unit Tests runs-on: ci-check @@ -608,6 +693,14 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: 'set -eu @@ -637,4 +730,12 @@ jobs: NOTIFY_MODE=failure JOB_NAME="Frontend Unit Tests" python3 scripts/ci_notify.py - ' \ No newline at end of file + ' - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/ci-trigger-monitor.yml b/.gitea/workflows/ci-trigger-monitor.yml index 69234b47a..eb58af3fd 100644 --- a/.gitea/workflows/ci-trigger-monitor.yml +++ b/.gitea/workflows/ci-trigger-monitor.yml @@ -22,6 +22,14 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="ci-trigger-monitor" TRACE_NAME="CI触发监控 / Monitor CI Trigger Reliability" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Check CI trigger status for all open PRs env: GITEA_API_TOKEN: ${{ secrets.REVIEW_GITEA_TOKEN }} @@ -34,3 +42,12 @@ jobs: python3 scripts/ci_trigger_monitor.py # 监控脚本永远不fail,避免告警风暴 exit 0 + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="ci-trigger-monitor" TRACE_NAME="CI触发监控 / Monitor CI Trigger Reliability" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/code-review.yml b/.gitea/workflows/code-review.yml index 23f3c1eb0..837032300 100644 --- a/.gitea/workflows/code-review.yml +++ b/.gitea/workflows/code-review.yml @@ -25,6 +25,14 @@ jobs: with: fetch-depth: 0 + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="code-review" TRACE_NAME="AI代码审查 / AI Code Review" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Install dependencies run: | python3 -m pip install --upgrade pip @@ -51,3 +59,12 @@ jobs: python3 scripts/ci_code_review.py # 审查脚本异常不影响 CI 通过 continue-on-error: true + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="code-review" TRACE_NAME="AI代码审查 / AI Code Review" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/daily-check.yml b/.gitea/workflows/daily-check.yml index 209ae1283..dc6e9c419 100644 --- a/.gitea/workflows/daily-check.yml +++ b/.gitea/workflows/daily-check.yml @@ -64,6 +64,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Production Smoke Test" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Production health check & smoke test id: smoke shell: sh @@ -107,6 +115,15 @@ jobs: exit $SMOKE_EXIT # ── 2. Staging API 集成测试 ───────────────────────────────────────── + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Production Smoke Test" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" staging-api-tests: name: Staging API Integration Tests runs-on: saas @@ -161,6 +178,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Staging API Integration Tests" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Run API smoke test on staging id: smoke shell: sh @@ -244,6 +269,15 @@ jobs: fi # ── 3. Staging 浏览器 E2E ────────────────────────────────────────── + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Staging API Integration Tests" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" staging-e2e: name: Staging Browser E2E runs-on: saas @@ -298,6 +332,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Staging Browser E2E" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Run Playwright E2E on staging id: e2e shell: sh @@ -333,6 +375,15 @@ jobs: exit $EXIT_CODE # ── 4. 性能基线巡检 ──────────────────────────────────────────────── + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Staging Browser E2E" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" performance-check: name: Performance Baseline Check runs-on: saas @@ -456,6 +507,14 @@ jobs: echo "耗时: ${ELAPSED}s" echo "======================================" + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Performance Baseline Check" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Generate performance report id: report shell: sh @@ -581,6 +640,15 @@ jobs: fi # ── 5. 每日巡检汇总报告 ──────────────────────────────────────────── + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Performance Baseline Check" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" daily-report: name: Daily Check Report runs-on: saas @@ -656,3 +724,20 @@ jobs: # 不 exit 1,因为我们用了 always(),保持 report job 成功, # 但其他失败的 job 已经让整体流水线标记为失败 fi + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Daily Check Report" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="daily-check" TRACE_NAME="每日健康检查 / Daily Check Report" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/preview-cleanup.yml b/.gitea/workflows/preview-cleanup.yml index c40c1df15..fddf261a4 100755 --- a/.gitea/workflows/preview-cleanup.yml +++ b/.gitea/workflows/preview-cleanup.yml @@ -61,6 +61,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Extract PR number shell: sh run: | @@ -193,3 +201,12 @@ jobs: > /dev/null echo "Cleanup comment posted" + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" diff --git a/.gitea/workflows/preview-deploy.yml b/.gitea/workflows/preview-deploy.yml index f9c0cef7b..0b922f283 100755 --- a/.gitea/workflows/preview-deploy.yml +++ b/.gitea/workflows/preview-deploy.yml @@ -72,6 +72,14 @@ jobs: tar.extract(member, '.') PY + - name: Record start time & report trace start + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\necho "CI_TRACE_START_TIME=$(date +%s)" >> $GITHUB_ENV\nTRACE_SERVICE="" TRACE_NAME="" python3 .gitea/scripts/ci_trace_report.py --status running\n\nexit 0\n" - name: Record job start time shell: sh run: | @@ -272,3 +280,12 @@ jobs: run: | set +e NOTIFY_MODE=failure JOB_NAME="Deploy Preview Environment" python3 scripts/ci_notify.py + - name: Report trace end (always) + if: always() + shell: sh + env: + AGENTLOOP_ENDPOINT: ${ secrets.AGENTLOOP_ENDPOINT } + AGENTLOOP_LICENSE_KEY: ${ secrets.AGENTLOOP_LICENSE_KEY } + AGENTLOOP_PROJECT: ${ secrets.AGENTLOOP_PROJECT } + AGENTLOOP_WORKSPACE: ${ secrets.AGENTLOOP_WORKSPACE } + run: "set +e\n\nif [ "${{ job.status }}" = "success" ]; then\n TRACE_STATUS="ok"\nelse\n TRACE_STATUS="error"\nfi\n\nTRACE_SERVICE="" TRACE_NAME="" TRACE_STATUS="$TRACE_STATUS" python3 .gitea/scripts/ci_trace_report.py --start-time "$CI_TRACE_START_TIME"\n\nexit 0\n" -- 2.54.0