Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 1m55s
36 KiB
36 KiB
Bug 自动修复工作流优化方案
文档版本: v1.0 创建日期: 2026-02-25 状态: 待实施
📋 目录
背景
现状
当前 Repair Agent 实现了 Bug 的自动修复功能,但存在以下问题:
- Git 工作流不规范:修复后直接在本地合并到 main 分支,无法在 Gitea 追溯
- 缺少人工审核:AI 修复的代码直接进入主分支,存在风险
- 状态过于复杂:9 个状态流转复杂,难以维护
- Web 界面功能缺失:无法在日志中台操作 PR 合并
目标
- ✅ 规范 Git 工作流,通过 PR 合并代码
- ✅ 增加人工审核环节,保障代码质量
- ✅ 简化 Bug 状态,优化状态流转
- ✅ 完善 Web 界面,提供便捷的操作入口
当前问题
问题 1:本地合并无法追溯
当前流程:
git checkout main
git merge fix/auto-xxx # ← 本地合并
git push origin main
git branch -d fix/auto-xxx
问题:
- ❌ Gitea 仓库里没有 PR 记录
- ❌ 无法在 Gitea UI 追溯这个修复来自哪个分支
- ❌ 团队成员不知道这个变更是怎么来的
- ❌ 无法进行代码审核和讨论
问题 2:状态过多且流转复杂
当前状态(9 个):
NEW → VERIFYING → CANNOT_REPRODUCE
↓
PENDING_FIX → FIXING → FIXED → VERIFIED → DEPLOYED
↓
FIX_FAILED
问题:
- ❌
VERIFYING和PENDING_FIX功能重叠 - ❌
FIXED和VERIFIED区分不明确 - ❌
CANNOT_REPRODUCE和FIX_FAILED都表示失败
问题 3:缺少人工审核环节
当前流程:
AI 修复 → commit → push → 本地 merge → push main
- ❌ 没有审核环节
- ❌ AI 改错了直接污染主分支
- ❌ 无法事前检查代码质量
优化方案
核心改进
- 通过 PR 合并代码:AI 修复后自动创建 PR,保留审核环节
- 简化 Bug 状态:从 9 个减少到 6 个,流转更清晰
- 完善 Web 界面:提供 PR 审核入口
关键对比
| 维度 | 当前方式(本地合并) | 优化方式(PR 合并) |
|---|---|---|
| 追溯性 | ❌ 无 PR 记录 | ✅ Gitea 有完整记录 |
| 审核 | ❌ 无审核环节 | ✅ 人工审核 |
| 安全性 | ⚠️ 直接影响 main | ✅ 合并前可检查 |
| 协作 | ❌ 团队不可见 | ✅ Gitea UI 可见 |
| 回滚 | 需要 revert | 关闭 PR 即可 |
状态设计
优化后的状态(6 个)
class BugStatus(str, Enum):
"""优化后的 Bug 状态"""
NEW = "NEW" # 新发现的 Bug
FIXING = "FIXING" # AI 正在修复
PENDING_REVIEW = "PENDING_REVIEW" # 已修复,等待人工审核(有 PR)
MERGED = "MERGED" # PR 已合并到 main 分支
DEPLOYED = "DEPLOYED" # 已部署到生产环境
FAILED = "FAILED" # 修复失败或无法修复
状态流转图
┌─────┐ Agent扫描 ┌────────┐ AI修复成功 ┌──────────────┐
│ NEW │ ───────────▶ │ FIXING │ ────────────▶ │PENDING_REVIEW│
└─────┘ └────────┘ └──────────────┘
│ │
AI修复失败 人工审核合并
↓ ↓
┌────────┐ ┌────────┐
│ FAILED │ │ MERGED │
└────────┘ └────────┘
│
CI/CD部署
↓
┌──────────┐
│ DEPLOYED │
└──────────┘
状态说明
| 状态 | 说明 | 触发条件 | 后续操作 |
|---|---|---|---|
| NEW | 新发现的 Bug | Log Center 接收到错误日志 | Agent 定时扫描并修复 |
| FIXING | AI 正在修复 | Agent 开始执行修复任务 | AI 修复完成或失败 |
| PENDING_REVIEW | 等待审核 | AI 修复成功,PR 已创建 | 人工在 Gitea 审核 |
| MERGED | 已合并 | PR 在 Gitea 被合并 | CI/CD 自动部署 |
| DEPLOYED | 已部署 | 部署到生产环境成功 | 结束 |
| FAILED | 修复失败 | AI 无法修复或测试失败 | 人工介入 |
完整工作流程
阶段 1:自动修复(Repair Agent)
1. 扫描 NEW 状态的 Bug
2. 更新状态: NEW → FIXING
3. 调用 Claude Code CLI 修复代码
4. 运行测试验证修复
5. commit + push fix 分支到远程
6. 调用 Gitea API 创建 PR
7. 更新状态: FIXING → PENDING_REVIEW
8. 上传修复报告(包含 PR 链接)
关键数据结构:
{
"bug_id": 123,
"status": "PENDING_REVIEW",
"repair_report": {
"pr_number": 45,
"pr_url": "https://gitea.xxx/owner/repo/pulls/45",
"branch_name": "fix/auto-20260225-1430",
"modified_files": ["app/views.py", "app/models.py"],
"diff": "...",
"test_passed": true,
"test_output": "..."
}
}
阶段 2:人工审核(Web 界面)
方案 A:跳转到 Gitea 审核(推荐)
优势:
- ✅ 实现简单,只需提供跳转链接
- ✅ 利用 Gitea 原生 PR 功能
- ✅ 支持完整的代码审核流程
用户操作流程:
1. 打开日志中台 Bug 列表
2. 筛选 "PENDING_REVIEW" 状态
3. 点击 Bug 查看详情
4. 查看修复报告(AI 分析、修改文件、测试结果)
5. 点击 "前往 Gitea 审核 PR" 按钮 → 新标签页打开
6. 在 Gitea 查看完整 diff
7. 确认无误 → 点击 "Merge" 按钮
或发现问题 → 点击 "Close" 并标记为 FAILED
方案 B:在日志中台内审核(高级)
优势:
- ✅ 无需跳转,统一操作界面
- ✅ 可定制审核流程
劣势:
- ⚠️ 需要开发 diff viewer
- ⚠️ 需要对接 Gitea API
用户操作流程:
1. 在日志中台 Bug 详情页
2. 查看嵌入的代码 diff
3. 点击 "批准并合并" 按钮
4. 后端调用 Gitea API 合并 PR
阶段 3:自动部署(CI/CD + Webhook)
3.1 Gitea Webhook 通知
Gitea 配置:
Settings → Webhooks → Add Webhook
- URL: https://your-log-center.com/api/webhooks/gitea
- Events: Pull Requests (merged)
- Secret: <配置密钥>
日志中台接收:
@router.post("/webhooks/gitea")
async def gitea_webhook(payload: dict):
"""接收 Gitea PR 合并事件"""
if payload["action"] == "merged":
pr_number = payload["pull_request"]["number"]
# 通过 PR 号找到对应的 Bug
bug = await find_bug_by_pr_number(pr_number)
if bug and bug.status == BugStatus.PENDING_REVIEW:
# 更新状态: PENDING_REVIEW → MERGED
await update_bug_status(bug.id, BugStatus.MERGED)
logger.info(f"Bug #{bug.id} PR 已合并,等待部署")
3.2 部署成功通知
CI/CD Pipeline 配置:
# .gitlab-ci.yml 或 Jenkinsfile
deploy:
stage: deploy
script:
- deploy_to_production.sh
- |
# 部署成功后通知日志中台
curl -X POST https://your-log-center.com/api/webhooks/deployment \
-H "Content-Type: application/json" \
-H "X-Secret: ${WEBHOOK_SECRET}" \
-d '{
"project_id": "rtc_backend",
"status": "success",
"commit": "'$CI_COMMIT_SHA'"
}'
日志中台更新状态:
@router.post("/webhooks/deployment")
async def deployment_webhook(payload: dict):
"""接收部署成功通知"""
if payload["status"] == "success":
commit = payload["commit"]
# 找到该 commit 关联的 Bug(MERGED 状态)
bugs = await find_bugs_by_commit(commit, status=BugStatus.MERGED)
for bug in bugs:
# 更新状态: MERGED → DEPLOYED
await update_bug_status(bug.id, BugStatus.DEPLOYED)
logger.info(f"Bug #{bug.id} 已部署到生产环境")
Web 界面设计
1. Bug 列表页
┌────────────────────────────────────────────────────────────┐
│ Bug 自动修复看板 🔍 [搜索框] [筛选▼] │
├────────────────────────────────────────────────────────────┤
│ │
│ 📊 今日统计 │
│ ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │
│ │ 🆕 新发现 │ 🔧 修复中 │ 🟡 待审核 │ ✅ 已合并 │ 🚀 已部署 │ │
│ │ 12 │ 3 │ 5 │ 8 │ 15 │ │
│ └──────────┴──────────┴──────────┴──────────┴──────────┘ │
│ │
│ 状态筛选: [ 全部 ] [ 🟡 待审核 ] [ 🔧 修复中 ] [ ❌ 失败 ] │
│ │
│ 🟡 待审核 (需要你的操作) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ #123 │ TypeError in user_login │ 🟡 待审核 │ 详情 │ │
│ │ │ rtc_backend | 2h ago │ │ → │ │
│ ├──────┼──────────────────────────────┼──────────┼─────┤ │
│ │ #124 │ NullPointerException │ 🟡 待审核 │ 详情 │ │
│ │ │ rtc_backend | 1h ago │ │ → │ │
│ ├──────┼──────────────────────────────┼──────────┼─────┤ │
│ │ #125 │ DB connection timeout │ 🟡 待审核 │ 详情 │ │
│ │ │ rtc_web | 30m ago │ │ → │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 🔧 修复中 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ #126 │ API endpoint error │ 🔧 修复中 │ ... │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
2. Bug 详情页(方案 A:跳转到 Gitea)
┌─────────────────────────────────────────────────────────────┐
│ ← 返回列表 Bug #123 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📌 基本信息 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 标题: TypeError: 'NoneType' object is not iterable │ │
│ │ 项目: rtc_backend │ │
│ │ 状态: 🟡 PENDING_REVIEW (待审核) │ │
│ │ 环境: production │ │
│ │ 发现时间: 2026-02-25 12:30:15 │ │
│ │ 修复时间: 2026-02-25 14:30:45 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 🐛 错误详情 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 文件: app/views.py │ │
│ │ 行号: 24 │ │
│ │ 错误: TypeError: 'NoneType' object is not iterable │ │
│ │ │ │
│ │ 堆栈: │ │
│ │ File "app/views.py", line 24, in user_login │ │
│ │ for item in request.user: │ │
│ │ TypeError: 'NoneType' object is not iterable │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 📋 修复报告 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ AI 分析: │ │
│ │ request.user 可能为 None,需要添加 null 检查 │ │
│ │ │ │
│ │ 修改文件: 2 个 │ │
│ │ - app/views.py (+3, -1) │ │
│ │ - tests/test_views.py (+12, -0) │ │
│ │ │ │
│ │ 测试结果: ✅ 通过 (2 tests passed) │ │
│ │ │ │
│ │ 修复分支: fix/auto-20260225-1430 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 🔗 Pull Request │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ PR #45: fix: auto repair bug #123 │ │
│ │ fix/auto-20260225-1430 → main │ │
│ │ │ │
│ │ 修改: 2 files changed (+15, -1) │ │
│ │ 状态: 🟡 Open (等待审核) │ │
│ │ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ 🔍 前往 Gitea 审核 PR → │ ← 主要操作 │ │
│ │ └──────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 📄 代码变更预览 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ app/views.py │ │
│ │ ───────────────────────────────────── │ │
│ │ 23 │ def user_login(request): │ │
│ │ -24 │ for item in request.user: │ │ ← 删除
│ │ +24 │ if request.user is not None: │ │ ← 新增
│ │ +25 │ for item in request.user: │ │ ← 新增
│ │ 26 │ # ... rest of code │ │
│ │ │ │
│ │ [查看完整 diff →] │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 📝 操作日志 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 2026-02-25 14:30 状态更新: FIXING → PENDING_REVIEW │ │
│ │ 2026-02-25 14:28 AI 修复完成,PR 已创建 │ │
│ │ 2026-02-25 14:25 开始自动修复 │ │
│ │ 2026-02-25 12:30 Bug 已记录 │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
3. 统计看板
┌────────────────────────────────────────────────────────────┐
│ 📊 Bug 修复统计 时间范围: [最近 7 天 ▼]│
├────────────────────────────────────────────────────────────┤
│ │
│ 整体指标 │
│ ┌──────────┬──────────┬──────────┬──────────┐ │
│ │ 总计发现 │ 自动修复 │ 修复成功率│ 平均耗时 │ │
│ │ 156 │ 142 │ 91.0% │ 12 min │ │
│ └──────────┴──────────┴──────────┴──────────┘ │
│ │
│ 每日趋势 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 40 ┤ │ │
│ │ 30 ┤ ● ● │ │
│ │ 20 ┤ ● ● ● ● │ │
│ │ 10 ┤ ● ● ● ● ● ● │ │
│ │ 0 └────────────────────────────────────── │ │
│ │ Mon Tue Wed Thu Fri Sat Sun │ │
│ │ │ │
│ │ ■ 新发现 ■ 自动修复 ■ 修复失败 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 项目分布 │
│ ┌──────────────┬───────────┬───────────┬─────────┐ │
│ │ 项目 │ 待审核 │ 已合并 │ 失败 │ │
│ ├──────────────┼───────────┼───────────┼─────────┤ │
│ │ rtc_backend │ 3 │ 12 │ 1 │ │
│ │ rtc_web │ 2 │ 8 │ 0 │ │
│ │ airhub_app │ 0 │ 5 │ 2 │ │
│ └──────────────┴───────────┴───────────┴─────────┘ │
└────────────────────────────────────────────────────────────┘
技术实施
修改清单
1. Repair Agent 端
文件:log_center/repair_agent/agent/git_manager.py
def create_pull_request(
self,
title: str,
description: str,
gitea_url: str,
gitea_token: str,
) -> tuple[bool, str]:
"""
调用 Gitea API 创建 Pull Request
Args:
title: PR 标题
description: PR 描述
gitea_url: Gitea 服务器地址
gitea_token: Gitea API Token
Returns:
(是否成功, PR URL 或错误信息)
"""
if not self.repo or not self.github_repo:
return False, "未配置 Git 仓库"
try:
# 解析仓库信息
# github_repo 格式: https://gitea.xxx/owner/repo.git
import re
match = re.search(r'([^/]+)/([^/]+?)(?:\.git)?$', self.github_repo)
if not match:
return False, "无法解析仓库信息"
owner, repo = match.groups()
current_branch = self.repo.active_branch.name
base_branch = "main" if "main" in self.repo.heads else "master"
# 调用 Gitea API
import httpx
api_url = f"{gitea_url}/api/v1/repos/{owner}/{repo}/pulls"
headers = {
"Authorization": f"token {gitea_token}",
"Content-Type": "application/json",
}
payload = {
"title": title,
"head": current_branch,
"base": base_branch,
"body": description,
}
response = httpx.post(api_url, json=payload, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
pr_url = data.get("html_url", "")
pr_number = data.get("number", 0)
logger.info(f"PR 创建成功: #{pr_number} - {pr_url}")
return True, pr_url
except Exception as e:
logger.error(f"创建 PR 失败: {e}")
return False, str(e)
文件:log_center/repair_agent/agent/core.py
修改自动提交部分(Line 256-267):
# 自动提交并创建 PR(仅在 Git 启用时)
if git_enabled and auto_commit and modified_files and git_manager:
bug_ids = ", ".join([f"#{b.id}" for b in bugs])
commit_msg = f"fix: auto repair bugs {bug_ids}"
# Step 1: commit 代码
git_manager.commit(commit_msg)
logger.info("代码已提交")
# Step 2: push fix 分支
git_manager.push()
logger.info("fix 分支已推送")
# Step 3: 创建 PR(替代原来的 merge_to_main_and_push)
success, pr_url = git_manager.create_pull_request(
title=commit_msg,
description=self._generate_pr_description(bugs, output, modified_files),
gitea_url=settings.gitea_url,
gitea_token=settings.gitea_token,
)
if success:
logger.info(f"PR 已创建: {pr_url}")
# 更新修复报告,添加 PR 信息
for bug in bugs:
self._update_pr_info(bug.id, pr_url)
else:
logger.warning(f"PR 创建失败: {pr_url},请手动创建")
elif not git_enabled and auto_commit:
logger.info("未配置 GitHub 仓库,跳过自动提交")
新增辅助方法:
def _generate_pr_description(
self,
bugs: list[Bug],
ai_output: str,
modified_files: list[str],
) -> str:
"""生成 PR 描述"""
lines = [
f"## 🤖 AI 自动修复",
"",
f"本 PR 修复了 {len(bugs)} 个 Bug:",
"",
]
for bug in bugs:
lines.append(f"- Bug #{bug.id}: {bug.error.type} - {bug.error.message[:50]}")
lines.extend([
"",
"## 📝 修复说明",
"",
ai_output[:500], # 截取前 500 字符
"",
"## 📄 修改文件",
"",
])
for file in modified_files[:10]: # 最多显示 10 个文件
lines.append(f"- `{file}`")
lines.extend([
"",
"---",
"",
"⚠️ **请仔细审核代码变更后再合并**",
])
return "\n".join(lines)
def _update_pr_info(self, bug_id: int, pr_url: str):
"""更新 Bug 的 PR 信息"""
try:
# 从 PR URL 提取 PR 号
import re
match = re.search(r'/pulls/(\d+)', pr_url)
pr_number = int(match.group(1)) if match else 0
# 调用 TaskManager 更新
self.task_manager.update_pr_info(bug_id, pr_number, pr_url)
except Exception as e:
logger.error(f"更新 PR 信息失败: {e}")
文件:log_center/repair_agent/models/bug.py
简化状态枚举:
class BugStatus(str, Enum):
"""Bug 状态"""
NEW = "NEW" # 新发现
FIXING = "FIXING" # 修复中
PENDING_REVIEW = "PENDING_REVIEW" # 待审核(有 PR)
MERGED = "MERGED" # 已合并
DEPLOYED = "DEPLOYED" # 已部署
FAILED = "FAILED" # 失败
文件:log_center/repair_agent/config/settings.py
新增配置项:
class Settings(BaseSettings):
# ... 现有配置 ...
# Gitea 配置
gitea_url: str = Field(
default="https://gitea.airlabs.art",
description="Gitea 服务器地址"
)
gitea_token: str = Field(
default="",
description="Gitea API Token"
)
# PR 配置
auto_create_pr: bool = Field(
default=True,
description="是否自动创建 PR"
)
2. Log Center 端
文件:log_center/app/models.py
更新 Bug 模型:
class ErrorLog(Base):
# ... 现有字段 ...
# 新增字段
pr_number = Column(Integer, nullable=True, comment="PR 编号")
pr_url = Column(String(500), nullable=True, comment="PR 链接")
branch_name = Column(String(200), nullable=True, comment="修复分支名")
文件:log_center/app/api/webhooks.py
新增 Gitea Webhook 接收端点:
@router.post("/webhooks/gitea")
async def gitea_webhook(
request: Request,
db: Session = Depends(get_db),
):
"""接收 Gitea PR 合并事件"""
try:
payload = await request.json()
# 验证签名(可选)
# verify_gitea_signature(request.headers, payload)
action = payload.get("action")
if action == "merged":
# PR 已合并
pr_number = payload["pull_request"]["number"]
repo_name = payload["repository"]["name"]
# 通过 PR 号和项目名找到对应的 Bug
bug = db.query(ErrorLog).filter(
ErrorLog.pr_number == pr_number,
ErrorLog.project_id.like(f"%{repo_name}%"),
ErrorLog.status == BugStatus.PENDING_REVIEW.value,
).first()
if bug:
# 更新状态
bug.status = BugStatus.MERGED.value
bug.updated_at = datetime.now()
db.commit()
logger.info(f"Bug #{bug.id} PR #{pr_number} 已合并")
return {"message": "Status updated"}
return {"message": "Event ignored"}
except Exception as e:
logger.error(f"处理 Gitea Webhook 失败: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/webhooks/deployment")
async def deployment_webhook(
payload: dict,
db: Session = Depends(get_db),
):
"""接收部署成功通知"""
try:
if payload.get("status") == "success":
commit_sha = payload["commit"]
project_id = payload["project_id"]
# 找到该 commit 关联的 Bug(MERGED 状态)
bugs = db.query(ErrorLog).filter(
ErrorLog.project_id == project_id,
ErrorLog.status == BugStatus.MERGED.value,
).all()
# TODO: 通过 commit SHA 精确匹配(需要记录 commit)
for bug in bugs:
bug.status = BugStatus.DEPLOYED.value
bug.deployed_at = datetime.now()
db.commit()
logger.info(f"已更新 {len(bugs)} 个 Bug 状态为 DEPLOYED")
return {"message": f"Updated {len(bugs)} bugs"}
return {"message": "Not a success deployment"}
except Exception as e:
logger.error(f"处理部署 Webhook 失败: {e}")
raise HTTPException(status_code=500, detail=str(e))
文件:log_center/app/api/tasks.py
新增接口:
@router.put("/bugs/{bug_id}/pr-info")
async def update_pr_info(
bug_id: int,
pr_number: int,
pr_url: str,
db: Session = Depends(get_db),
):
"""更新 Bug 的 PR 信息"""
bug = db.query(ErrorLog).filter(ErrorLog.id == bug_id).first()
if not bug:
raise HTTPException(status_code=404, detail="Bug not found")
bug.pr_number = pr_number
bug.pr_url = pr_url
db.commit()
return {"message": "PR info updated"}
文件:log_center/web/src/pages/BugDetail.tsx
添加 PR 信息展示:
{bug.status === 'PENDING_REVIEW' && bug.pr_url && (
<Card title="Pull Request" style={{ marginTop: 16 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<div>
<Tag color="orange">待审核</Tag>
<Text strong>PR #{bug.pr_number}</Text>: {bug.branch_name} → main
</div>
<Statistic
title="修改文件"
value={bug.repair_report?.modified_files?.length || 0}
suffix="个"
/>
<Button
type="primary"
icon={<LinkOutlined />}
href={bug.pr_url}
target="_blank"
>
前往 Gitea 审核 PR
</Button>
</Space>
</Card>
)}
实施计划
Phase 1:核心功能(必须实施)
时间:2-3 天
任务清单
-
Repair Agent 端
- 新增
create_pull_request()方法 - 修改
fix_project()逻辑,移除merge_to_main_and_push() - 状态更新为
PENDING_REVIEW - 修复报告包含 PR 信息
- 配置文件添加 Gitea 相关参数
- 新增
-
Log Center 端
- 数据库添加
pr_number,pr_url,branch_name字段 - 简化 Bug 状态枚举(6 个)
- 新增 Gitea Webhook 接收端点
- Bug 详情页显示 PR 信息
- "前往 Gitea 审核" 按钮
- 数据库添加
-
Gitea 配置
- 创建 API Token
- 配置 Webhook(PR 合并事件)
-
测试验证
- 端到端测试完整流程
- 验证 PR 创建成功
- 验证状态自动更新
预期效果
NEW → FIXING → PENDING_REVIEW (有 PR) → [人工审核] → MERGED
Phase 2:优化体验(可选,后续迭代)
时间:1 周
任务清单
-
Web 界面优化
- 嵌入 diff viewer 组件
- 在日志中台直接批准/拒绝 PR
- 批量审核功能
- 统计看板优化
-
通知系统
- 邮件通知(PR 创建、合并)
- 钉钉/企业微信通知
- 消息中心
-
高级功能
- PR 自动审批(测试通过 + 低风险)
- 审批流程配置(指定审批人)
- PR 评论同步到日志中台
决策清单
需要确认的事项
-
1. 状态简化方案
- ✅ 采用 6 个状态(NEW, FIXING, PENDING_REVIEW, MERGED, DEPLOYED, FAILED)
- ❌ 保留现有 9 个状态
-
2. 审核方式
- ✅ 方案 A:跳转到 Gitea 审核(推荐,简单快速)
- ❌ 方案 B:在日志中台内审核(高级,需要更多开发)
-
3. 实施阶段
- ✅ Phase 1:核心功能(必须,2-3 天)
- ⚠️ Phase 2:优化体验(可选,1 周)
-
4. Gitea 配置信息
- Gitea 服务器地址:
https://gitea.xxx.com - Gitea Token:已生成并配置
- Webhook Secret:已配置
- Gitea 服务器地址:
附录
A. 数据库迁移脚本
# alembic/versions/xxx_add_pr_info.py
def upgrade():
op.add_column('error_logs', sa.Column('pr_number', sa.Integer(), nullable=True))
op.add_column('error_logs', sa.Column('pr_url', sa.String(500), nullable=True))
op.add_column('error_logs', sa.Column('branch_name', sa.String(200), nullable=True))
# 迁移旧状态到新状态
op.execute("""
UPDATE error_logs
SET status = 'FAILED'
WHERE status IN ('FIX_FAILED', 'CANNOT_REPRODUCE')
""")
op.execute("""
UPDATE error_logs
SET status = 'NEW'
WHERE status IN ('VERIFYING', 'PENDING_FIX')
""")
def downgrade():
op.drop_column('error_logs', 'branch_name')
op.drop_column('error_logs', 'pr_url')
op.drop_column('error_logs', 'pr_number')
B. Gitea Webhook 配置示例
Webhook URL:
https://your-log-center.com/api/webhooks/gitea
Webhook Events:
- ✅ Pull Requests (merged)
Payload 示例:
{
"action": "merged",
"number": 45,
"pull_request": {
"id": 45,
"number": 45,
"title": "fix: auto repair bugs #123",
"head": {
"ref": "fix/auto-20260225-1430"
},
"base": {
"ref": "main"
},
"merged": true,
"merged_at": "2026-02-25T15:30:00Z"
},
"repository": {
"name": "rtc_backend",
"full_name": "airlabs/rtc_backend"
}
}
C. CI/CD 部署通知配置
.gitlab-ci.yml 示例:
stages:
- test
- build
- deploy
deploy:production:
stage: deploy
only:
- main
script:
- echo "Deploying to production..."
- ./deploy.sh
- |
# 通知日志中台部署成功
curl -X POST https://your-log-center.com/api/webhooks/deployment \
-H "Content-Type: application/json" \
-H "X-Secret: ${WEBHOOK_SECRET}" \
-d '{
"project_id": "rtc_backend",
"status": "success",
"commit": "'${CI_COMMIT_SHA}'",
"deployed_at": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
}'
参考资料
文档维护:
- 创建:2026-02-25
- 更新:待更新
- 负责人:待指定