6eac0b2cf2
Worker Base Image Build / Build Worker Base Images (worker-base-builder-cache, infra/docker/worker-base-builder.Dockerfile, worker-base-builder, builder) (push) Failing after 1m54s
Worker Base Image Build / Build Worker Base Images (worker-base-runtime-cache, infra/docker/worker-base-runtime.Dockerfile, worker-base-runtime, runtime) (push) Failing after 1m36s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Failing after 1m29s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m4s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m2s
CI/CD Pipeline / Unit Tests (push) Successful in 3m38s
CI/CD Pipeline / Integration Tests (push) Successful in 2m0s
CI/CD Pipeline / Frontend Lint (push) Successful in 28s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 44s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Failing after 2m16s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m14s
CI/CD Pipeline / Build Staging Worker Image (push) Failing after 2m0s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
同步内容: 1. CI流水线配置(ci-pipeline.yml)与develop对齐 2. PR构建脚本docker_build_only.sh增加buildx→docker build回退 3. pre-build步骤worker基础镜像构建增加buildx回退 4. 单元测试脚本全量覆盖率改为仅报告不阻塞 5. diff-cover依赖加入requirements-dev.txt 6. worker base builder/runtime Dockerfile同步 7. test_config_oss.py clear=False→clear=True修复OSS污染 8. Frontend Lint增加prettier依赖
170 lines
5.1 KiB
Python
Executable File
170 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
CI 触发模块 - 重新运行失败 job、重跑整个 workflow、取消 run
|
|
|
|
支持操作:
|
|
- rerun_failed: 重跑失败的 jobs
|
|
- rerun_all: 重跑整个 workflow
|
|
- cancel: 取消运行中的 run
|
|
|
|
用法:
|
|
python3 scripts/ci/chatops/ci_trigger.py --run-id 456 --action rerun_failed
|
|
python3 scripts/ci/chatops/ci_trigger.py --run-id 456 --action rerun_all
|
|
python3 scripts/ci/chatops/ci_trigger.py --run-id 456 --action cancel
|
|
|
|
设计:
|
|
- 与飞书机器人 /ci rerun 命令对接
|
|
- 操作前自动校验 run 状态,避免无效操作
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
from . import config
|
|
from .gitea_client import GiteaClient
|
|
|
|
|
|
class CITrigger:
|
|
"""CI 操作触发器"""
|
|
|
|
def __init__(self, gitea_client=None):
|
|
self.gitea = gitea_client or GiteaClient()
|
|
|
|
# ── 触发操作 ─────────────────────────────────────
|
|
|
|
def rerun_failed(self, run_id):
|
|
"""重跑失败的 jobs
|
|
|
|
Returns:
|
|
dict: {success, message, new_run_id?}
|
|
"""
|
|
run = self.gitea.get_run(run_id)
|
|
if not run:
|
|
return {"success": False, "message": f"Run {run_id} 不存在"}
|
|
|
|
status = run.get("status", "")
|
|
if status != "completed":
|
|
return {
|
|
"success": False,
|
|
"message": f"Run {run_id} 当前状态为 {status},仅 completed 状态才能重跑",
|
|
}
|
|
|
|
result = self.gitea.rerun_failed_jobs(run_id)
|
|
if result is None:
|
|
return {"success": False, "message": "重跑请求失败"}
|
|
|
|
# Gitea rerun 后返回的 run id 通常不变(复用原 run)
|
|
return {
|
|
"success": True,
|
|
"message": f"已触发重跑失败 jobs: Run #{run_id}",
|
|
"run_id": run_id,
|
|
"run_url": f"{config.GITEA_URL}/{config.GITEA_REPO}/actions/runs/{run_id}",
|
|
}
|
|
|
|
def rerun_all(self, run_id):
|
|
"""重跑整个 workflow run
|
|
|
|
Returns:
|
|
dict: {success, message, run_id, run_url}
|
|
"""
|
|
run = self.gitea.get_run(run_id)
|
|
if not run:
|
|
return {"success": False, "message": f"Run {run_id} 不存在"}
|
|
|
|
status = run.get("status", "")
|
|
if status == "running" or status == "pending":
|
|
return {
|
|
"success": False,
|
|
"message": f"Run {run_id} 正在运行中,无需重跑",
|
|
}
|
|
|
|
result = self.gitea.rerun_run(run_id)
|
|
if result is None:
|
|
return {"success": False, "message": "重跑请求失败"}
|
|
|
|
return {
|
|
"success": True,
|
|
"message": f"已触发完整重跑: Run #{run_id}",
|
|
"run_id": run_id,
|
|
"run_url": f"{config.GITEA_URL}/{config.GITEA_REPO}/actions/runs/{run_id}",
|
|
}
|
|
|
|
def cancel_run(self, run_id):
|
|
"""取消运行中的 run
|
|
|
|
Returns:
|
|
dict: {success, message}
|
|
"""
|
|
run = self.gitea.get_run(run_id)
|
|
if not run:
|
|
return {"success": False, "message": f"Run {run_id} 不存在"}
|
|
|
|
status = run.get("status", "")
|
|
if status == "completed":
|
|
return {
|
|
"success": False,
|
|
"message": f"Run {run_id} 已完成,无需取消",
|
|
}
|
|
|
|
result = self.gitea.cancel_run(run_id)
|
|
if result is None:
|
|
return {"success": False, "message": "取消请求失败"}
|
|
|
|
return {
|
|
"success": True,
|
|
"message": f"已取消 Run #{run_id}",
|
|
"run_id": run_id,
|
|
}
|
|
|
|
def rerun_latest_failed(self, branch="develop", workflow_id=None):
|
|
"""重跑指定分支最近一次失败的 run
|
|
|
|
用于快速恢复场景,不需要先查 run_id
|
|
"""
|
|
runs, _ = self.gitea.list_runs(branch=branch, workflow_id=workflow_id, status="failure", limit=5)
|
|
if not runs:
|
|
return {"success": False, "message": f"{branch} 分支没有失败的 run"}
|
|
|
|
latest = runs[0]
|
|
run_id = latest.get("id")
|
|
return self.rerun_failed(run_id)
|
|
|
|
|
|
# ── CLI 入口 ──────────────────────────────────────────
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="CI 触发操作")
|
|
parser.add_argument("--run-id", required=True, help="Workflow Run ID")
|
|
parser.add_argument(
|
|
"--action",
|
|
required=True,
|
|
choices=["rerun_failed", "rerun_all", "cancel"],
|
|
help="操作类型",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
trigger = CITrigger()
|
|
|
|
if args.action == "rerun_failed":
|
|
result = trigger.rerun_failed(args.run_id)
|
|
elif args.action == "rerun_all":
|
|
result = trigger.rerun_all(args.run_id)
|
|
elif args.action == "cancel":
|
|
result = trigger.cancel_run(args.run_id)
|
|
else:
|
|
print(f"未知操作: {args.action}")
|
|
return 1
|
|
|
|
status = "✅" if result["success"] else "❌"
|
|
print(f"{status} {result['message']}")
|
|
if result.get("run_url"):
|
|
print(f" {result['run_url']}")
|
|
|
|
return 0 if result["success"] else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|