log-center/docs/bug-repair-workflow-optimization.md
zyc 5611839fd8
Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 1m55s
fix git pr
2026-02-25 10:55:26 +08:00

36 KiB
Raw Permalink Blame History

Bug 自动修复工作流优化方案

文档版本: v1.0 创建日期: 2026-02-25 状态: 待实施


📋 目录


背景

现状

当前 Repair Agent 实现了 Bug 的自动修复功能,但存在以下问题:

  1. Git 工作流不规范:修复后直接在本地合并到 main 分支,无法在 Gitea 追溯
  2. 缺少人工审核AI 修复的代码直接进入主分支,存在风险
  3. 状态过于复杂9 个状态流转复杂,难以维护
  4. 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

问题:

  • VERIFYINGPENDING_FIX 功能重叠
  • FIXEDVERIFIED 区分不明确
  • CANNOT_REPRODUCEFIX_FAILED 都表示失败

问题 3缺少人工审核环节

当前流程:

AI 修复 → commit → push → 本地 merge → push main
  • 没有审核环节
  • AI 改错了直接污染主分支
  • 无法事前检查代码质量

优化方案

核心改进

  1. 通过 PR 合并代码AI 修复后自动创建 PR保留审核环节
  2. 简化 Bug 状态:从 9 个减少到 6 个,流转更清晰
  3. 完善 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 关联的 BugMERGED 状态)
        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 关联的 BugMERGED 状态)
            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
    • 配置 WebhookPR 合并事件)
  • 测试验证

    • 端到端测试完整流程
    • 验证 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已配置

附录

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
  • 更新:待更新
  • 负责人:待指定