feat(repair-agent): scan all bug sources and improve CI/CD triage
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 2m56s

- task_manager: scan runtime + cicd + deployment sources (not just runtime)
- claude_service: add CI/CD-specific triage rules for build/deploy failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
zyc 2026-02-24 13:33:08 +08:00
parent aa3a5b8c5d
commit 75fe8dfc0c
2 changed files with 71 additions and 49 deletions

View File

@ -197,6 +197,8 @@ class ClaudeService:
## 判断规则
### 运行时错误runtime
属于 **无法复现 / 不需要修复** 的情况CANNOT_REPRODUCE
1. JWT Token 过期认证失败 正常认证流程不是代码 Bug
2. HTTP 405 Method Not Allowed 客户端请求了错误的方法
@ -210,6 +212,19 @@ class ClaudeService:
2. 数据库约束错误IntegrityError由项目代码逻辑引起
3. TypeError / AttributeError 出现在项目视图或模型中
### CI/CD 构建错误CICDFailure
属于 **需要修复** 的情况FIX
1. Docker build 失败且日志中包含代码编译/语法错误SyntaxErrorImportErrorModuleNotFoundError
2. npm/pip install 成功但 build 阶段因代码问题失败
3. Dockerfile RUN 命令因项目代码问题报错
属于 **无法复现 / 不需要修复** 的情况CANNOT_REPRODUCE
1. Docker 镜像仓库认证失败推送失败 基础设施问题
2. kubectl 部署失败K8s 资源不足 运维问题
3. 网络超时镜像拉取失败 瞬态错误
4. 日志中没有具体代码错误只有通用构建/部署失败信息
请先用 Grep/Read 查看相关源文件确认当前代码状态然后给出判断
**最后一行必须输出以下格式之一只输出一个**

View File

@ -28,9 +28,60 @@ class TaskManager:
"""
all_bugs: dict[int, Bug] = {}
for status in ("NEW", "PENDING_FIX"):
for source in ("runtime", "cicd", "deployment"):
for status in ("NEW", "PENDING_FIX"):
try:
params: dict[str, str] = {"status": status, "source": source}
if project_id:
params["project_id"] = project_id
response = self.client.get(
f"{self.base_url}/api/v1/bugs",
params=params,
)
response.raise_for_status()
data = response.json()
for item in data.get("items", []):
bug_id = item["id"]
if bug_id in all_bugs:
continue
stack_trace = item.get("stack_trace")
if isinstance(stack_trace, str):
stack_trace = stack_trace.split("\n")
all_bugs[bug_id] = Bug(
id=bug_id,
project_id=item["project_id"],
environment=item.get("environment", "production"),
level=item.get("level", "ERROR"),
error={
"type": item.get("error_type", "Unknown"),
"message": item.get("error_message", ""),
"file_path": item.get("file_path"),
"line_number": item.get("line_number"),
"stack_trace": stack_trace,
},
context=item.get("context"),
status=BugStatus(item.get("status", "NEW")),
retry_count=item.get("retry_count", 0),
)
except httpx.HTTPError as e:
logger.error(f"获取 {source}/{status} 状态 Bug 列表失败: {e}")
bugs = list(all_bugs.values())
logger.info(f"获取到 {len(bugs)} 个待修复 Bugruntime + cicd + deployment")
return bugs
def fetch_failed_bugs(self, project_id: Optional[str] = None) -> list[Bug]:
"""
获取修复失败的 Bug 列表FIX_FAILED 状态所有来源
"""
all_bugs: dict[int, Bug] = {}
for source in ("runtime", "cicd", "deployment"):
try:
params: dict[str, str] = {"status": status, "source": "runtime"}
params: dict[str, str] = {"status": "FIX_FAILED", "source": source}
if project_id:
params["project_id"] = project_id
@ -51,7 +102,7 @@ class TaskManager:
stack_trace = stack_trace.split("\n")
all_bugs[bug_id] = Bug(
id=bug_id,
id=item["id"],
project_id=item["project_id"],
environment=item.get("environment", "production"),
level=item.get("level", "ERROR"),
@ -63,57 +114,13 @@ class TaskManager:
"stack_trace": stack_trace,
},
context=item.get("context"),
status=BugStatus(item.get("status", "NEW")),
status=BugStatus.FIX_FAILED,
retry_count=item.get("retry_count", 0),
)
except httpx.HTTPError as e:
logger.error(f"获取 {status} 状态 Bug 列表失败: {e}")
logger.error(f"获取 {source}/FIX_FAILED Bug 列表失败: {e}")
bugs = list(all_bugs.values())
logger.info(f"获取到 {len(bugs)} 个待修复 BugNEW + PENDING_FIX")
return bugs
def fetch_failed_bugs(self, project_id: Optional[str] = None) -> list[Bug]:
"""
获取修复失败的 Bug 列表FIX_FAILED 状态
"""
bugs: list[Bug] = []
try:
params: dict[str, str] = {"status": "FIX_FAILED", "source": "runtime"}
if project_id:
params["project_id"] = project_id
response = self.client.get(
f"{self.base_url}/api/v1/bugs",
params=params,
)
response.raise_for_status()
data = response.json()
for item in data.get("items", []):
stack_trace = item.get("stack_trace")
if isinstance(stack_trace, str):
stack_trace = stack_trace.split("\n")
bugs.append(Bug(
id=item["id"],
project_id=item["project_id"],
environment=item.get("environment", "production"),
level=item.get("level", "ERROR"),
error={
"type": item.get("error_type", "Unknown"),
"message": item.get("error_message", ""),
"file_path": item.get("file_path"),
"line_number": item.get("line_number"),
"stack_trace": stack_trace,
},
context=item.get("context"),
status=BugStatus.FIX_FAILED,
retry_count=item.get("retry_count", 0),
))
except httpx.HTTPError as e:
logger.error(f"获取 FIX_FAILED Bug 列表失败: {e}")
logger.info(f"获取到 {len(bugs)} 个 FIX_FAILED Bug")
return bugs