Files
BlueRoseNote/07-Other/AI/AI Agent/ClaudeCode/在 GitLab CICD 中部署 Claude Code 自动修复 Issue Bug.md

25 KiB
Raw Blame History

本文记录了在 GitLab 项目中集成 Claude Code CLI实现"给 Issue 打标签即可自动修复 Bug"的完整方案与实践过程。


目录


方案概述

核心思路:利用 GitLab CI/CD 的 Schedule定时调度 + Trigger触发器 机制,定时扫描带有 auto-fix 标签的 Issue自动启动 Claude Code CLI 分析代码、修复 Bug、提交代码并在 Issue 上回复修复摘要。

一句话流程:开发者给 Issue 打上 auto-fix 标签 → 定时任务自动触发 → Claude Code 读取 Issue、分析代码、实施修复 → 自动 commit & push → 在 Issue 评论中报告结果。


整体架构

┌─────────────────────────────────────────────────────────────────┐
│                        GitLab 项目                               │
│                                                                   │
│  ┌──────────┐    ┌──────────────────┐    ┌───────────────────┐  │
│  │  Issue    │    │  Schedule (定时)   │    │  Trigger Pipeline │  │
│  │ auto-fix  │───▶│ claude:scan-issues│───▶│ claude:fix-issue  │  │
│  │  标签     │    │  (alpine:3.19)   │    │   (node:20)       │  │
│  └──────────┘    └──────────────────┘    └─────────┬─────────┘  │
│                                                      │            │
│                                          ┌───────────▼─────────┐ │
│                                          │   Claude Code CLI   │ │
│                                          │ (npm i -g 安装)      │ │
│                                          │                     │ │
│                                          │ 1. 读取 Issue 详情   │ │
│                                          │ 2. 分析项目代码      │ │
│                                          │ 3. 实施修复          │ │
│                                          │ 4. 验证类型检查      │ │
│                                          │ 5. 提交 & 推送       │ │
│                                          │ 6. 评论 Issue        │ │
│                                          └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

标签状态机

Issue 通过标签流转追踪处理状态,确保不会被重复处理:

auto-fix  ──▶  claude-processing  ──▶  claude-done
(用户添加)      (扫描时切换)            (修复完成后设置)

前置条件

条件 说明
GitLab 实例 需要支持 CI/CD Schedules 和 Pipeline Triggers
Runner 可执行 Docker 镜像的 GitLab Runner
Anthropic API 访问 直接使用 Anthropic API 或通过内部代理
GitLab Personal Access Token 需要 api scope用于操作 Issue 和推送代码

第一步:配置 CI/CD Variables

进入 GitLab 项目 → Settings → CI/CD → Variables,添加以下变量:

变量名 类型 说明
GITLAB_ACCESS_TOKEN Masked Personal Access Tokenapi scope扫描 Job 使用
ANTHROPIC_AUTH_TOKEN Masked Anthropic API Key或内部代理的 auth token
TRIGGER_TOKEN 见下一步 Pipeline 触发器 Token

安全提示GITLAB_ACCESS_TOKENANTHROPIC_AUTH_TOKEN 务必勾选 Masked,防止在日志中泄露。

关于 Anthropic API 访问

如果你直接使用 Anthropic 官方 API需要设置

  • ANTHROPIC_AUTH_TOKEN = 你的 Anthropic API Key

如果使用内部代理(如本项目使用 openai.nie.netease.com),则在 CI Job 中通过环境变量指定:

variables:
  ANTHROPIC_BASE_URL: "https://openai.nie.netease.com"  # 内部代理地址

第二步:创建 Pipeline Trigger Token

进入 Settings → CI/CD → Pipeline trigger tokens,点击 Add trigger 创建一个触发器。

创建后会得到一个 Token将其记录下来。扫描 Job 将用此 Token 触发修复 Pipeline。

将该 Token 设置为 CI/CD Variable TRIGGER_TOKEN


第三步:编写 .gitlab-ci.yml

.gitlab-ci.yml 中添加 ai_fix Stage 和两个 Job。

Job 1: claude:scan-issues — 扫描 Issue

这是一个轻量级 Job使用 alpine:3.19 镜像,只做 API 调用:

stages:
  - ai_fix

claude:scan-issues:
  stage: ai_fix
  image: alpine:3.19
  before_script:
    - apk add --no-cache curl jq
  script:
    - |
      echo "Scanning for Issues with label 'auto-fix'..."

      # 校验必要变量
      for var in GITLAB_ACCESS_TOKEN TRIGGER_TOKEN ANTHROPIC_AUTH_TOKEN; do
        eval "val=\$$var"
        if [ -z "$val" ]; then
          echo "ERROR: $var is not set."
          exit 1
        fi
      done

      # 查询带 auto-fix 标签的 Issue排除已处理的
      ISSUES=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_ACCESS_TOKEN" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues?labels=auto-fix&not%5Blabels%5D=claude-processing,claude-done&state=opened&per_page=10")

      COUNT=$(echo "$ISSUES" | jq 'length')
      echo "Found $COUNT issue(s) with 'auto-fix' label."

      if [ "$COUNT" -eq 0 ] || [ "$COUNT" = "null" ]; then
        echo "Nothing to do."
        exit 0
      fi

      # 逐个处理
      echo "$ISSUES" | jq -r '.[].iid' | while read -r IID; do
        TITLE=$(echo "$ISSUES" | jq -r ".[] | select(.iid == $IID) | .title")
        echo ">>> Triggering fix for Issue #${IID}: ${TITLE}"

        # 1) 切换标签: auto-fix → claude-processing
        curl -s --request PUT \
          --header "PRIVATE-TOKEN: $GITLAB_ACCESS_TOKEN" \
          --header "Content-Type: application/json" \
          --data "{\"remove_labels\": \"auto-fix\", \"add_labels\": \"claude-processing\"}" \
          "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$IID" > /dev/null

        # 2) 通过 Trigger API 触发修复 Pipeline
        curl -s -X POST \
          --form "token=${TRIGGER_TOKEN}" \
          --form "ref=${CI_DEFAULT_BRANCH}" \
          --form "variables[ISSUE_IID]=${IID}" \
          --form "variables[GITLAB_TOKEN]=${GITLAB_ACCESS_TOKEN}" \
          --form "variables[ANTHROPIC_AUTH_TOKEN]=${ANTHROPIC_AUTH_TOKEN}" \
          "https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/trigger/pipeline"
      done
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'       # 定时触发
    - if: '$CI_PIPELINE_SOURCE == "web"'             # 手动触发
      when: manual
  allow_failure: true
  timeout: 5m

核心逻辑

  1. 通过 GitLab Issues API 查询 labels=auto-fix 且排除 claude-processingclaude-done 的 Issue
  2. 对每个 Issue 切换标签(防止重复处理)
  3. 通过 Pipeline Trigger API 启动独立的修复 Pipeline传入 ISSUE_IIDGITLAB_TOKENANTHROPIC_AUTH_TOKEN

Job 2: claude:fix-issue — 执行修复

这是核心修复 Job使用 node:20 镜像,安装并运行 Claude Code

claude:fix-issue:
  stage: ai_fix
  image: node:20
  variables:
    GIT_STRATEGY: clone
    GIT_DEPTH: 0                   # 完整克隆Claude 需要完整历史
    ANTHROPIC_BASE_URL: "https://api.anthropic.com"  # 或内部代理地址
    ANTHROPIC_MODEL: "claude-sonnet-4-6"
    DISABLE_AUTOUPDATER: "1"       # 禁止 Claude Code 自动更新
    DISABLE_PROMPT_CACHING: "1"
  before_script:
    - apt-get update && apt-get install -y git curl jq
    - npm install -g @anthropic-ai/claude-code
    - git config --global user.email "claude-bot@example.com"
    - git config --global user.name "Claude AI Bot"
  script:
    - |
      # Step 1: 获取 Issue 详情
      if [ -z "$ISSUE_IID" ]; then
        echo "ERROR: ISSUE_IID variable is required."
        exit 1
      fi

      ISSUE_JSON=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID")

      ISSUE_TITLE=$(echo "$ISSUE_JSON" | jq -r '.title // empty')
      ISSUE_DESCRIPTION=$(echo "$ISSUE_JSON" | jq -r '.description // empty')

      if [ -z "$ISSUE_TITLE" ]; then
        echo "ERROR: Could not fetch Issue #$ISSUE_IID"
        exit 1
      fi
      echo "Processing Issue #${ISSUE_IID}: ${ISSUE_TITLE}"
    - |
      # Step 2: 切换到主分支
      git checkout "$CI_DEFAULT_BRANCH"
      git pull origin "$CI_DEFAULT_BRANCH"
    - |
      # Step 3: 运行 Claude Code
      export ANTHROPIC_API_KEY="${ANTHROPIC_AUTH_TOKEN}"

      PROMPT="你是一个代码修复助手。请分析并修复以下 GitLab Issue

      ## Issue #${ISSUE_IID}: ${ISSUE_TITLE}

      ${ISSUE_DESCRIPTION}

      请:
      1. 分析项目代码,定位问题根因
      2. 实施修复
      3. 确保代码能通过类型检查TypeScript 项目运行 npx tsc --noEmit
      4. 用中文输出修复摘要(包括修改了哪些文件、改了什么、为什么这样改)

      项目根目录已准备就绪。"

      RESULT=$(claude -p "$PROMPT" \
        --bare \
        --permission-mode acceptEdits \
        --allowedTools "Bash,Read,Edit,Write,Glob,Grep" \
        --max-turns 30 \
        --output-format text \
        2>&1) || true

      echo "$RESULT" > repair_summary.txt
    - |
      # Step 4: 提交并推送
      git add -A
      git reset -- repair_summary.txt claude_stderr.txt 2>/dev/null || true

      if git diff --cached --quiet; then
        echo "No file changes detected."
        COMMIT_STATUS="no_changes"
      else
        git commit -m "fix(auto): resolve Issue #${ISSUE_IID} - ${ISSUE_TITLE} [skip ci]"
        git push "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" \
          HEAD:"$CI_DEFAULT_BRANCH"
        COMMIT_STATUS="pushed"
      fi
    - |
      # Step 5: 在 Issue 上发表评论
      SUMMARY=$(cat repair_summary.txt | head -200 | \
        sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')

      if [ "$COMMIT_STATUS" = "pushed" ]; then
        BODY="## ✅ Claude Code 自动修复完成\n\n修复已推送到 \`${CI_DEFAULT_BRANCH}\`。\n\nPipeline: ${CI_PIPELINE_URL}\n\n<details><summary>修复详情</summary>\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n</details>"
      else
        BODY="## ⚠️ Claude Code 分析完成\n\n未检测到需要变更的文件。\n\nPipeline: ${CI_PIPELINE_URL}\n\n<details><summary>分析详情</summary>\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n</details>"
      fi

      curl -s --request POST \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"body\": \"${BODY}\"}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID/notes"
    - |
      # Step 6: 更新标签为 claude-done
      curl -s --request PUT \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"remove_labels\": \"claude-processing\", \"add_labels\": \"claude-done\"}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID" > /dev/null
  rules:
    - if: '$CI_PIPELINE_SOURCE == "trigger" && $ISSUE_IID'   # 被 scan-issues 触发
    - if: '$CI_PIPELINE_SOURCE == "web" && $ISSUE_IID'       # 手动触发(需提供 ISSUE_IID
      when: manual
  allow_failure: true
  timeout: 30m

Claude Code CLI 关键参数说明

参数 说明
-p "$PROMPT" 非交互模式,直接传入提示词
--bare 精简输出,去掉装饰性格式
--permission-mode acceptEdits 自动接受文件编辑CI 环境必需)
--allowedTools "Bash,Read,Edit,Write,Glob,Grep" 限制可用工具,仅保留文件系统操作
--max-turns 30 最大对话轮次,防止无限循环
--output-format text 纯文本输出

第四步:创建定时调度

进入 CI/CD → Schedules,创建定时任务:

配置项 建议值 说明
Description Auto-fix Issue Scanner 任务描述
Interval Pattern */5 * * * * 每 5 分钟扫描一次
Cron Timezone 你的时区 例如 Asia/Shanghai
Target branch main 主分支

保存后Schedule 会按设定频率运行 claude:scan-issues Job。


第五步:编写 CLAUDE.md 项目指南

在项目根目录创建 CLAUDE.mdClaude Code 在 CI 中运行时会自动读取此文件作为上下文指导:

# Project Guidelines

## 项目结构
- `src/` — 主要源码
- `tests/` — 测试文件

## 开发规范
- 修改 TypeScript 代码后运行 `npx tsc --noEmit` 验证类型
- 不要修改 `.gitlab-ci.yml`(除非 Issue 明确要求)

## 关键技术
- 描述项目使用的框架、库、协议等

这个文件非常重要,它相当于给 Claude Code 提供了"项目知识",让 AI 了解项目结构和约束,从而做出更合理的修复。


使用流程

自动模式

  1. 在 GitLab 上创建一个 Issue描述清楚 Bug 的现象、复现步骤、期望行为
  2. 给该 Issue 添加标签 auto-fix
  3. 等待定时调度运行(默认每 5 分钟扫描一次)
  4. 标签自动变为 claude-processing(正在处理)
  5. 修复完成后标签变为 claude-doneIssue 评论中会出现修复摘要
  6. 如果有代码变更commit 会自动推送到 main 分支

手动模式(命令行触发)

项目提供了便捷脚本 scripts/trigger-fix.sh

# 设置环境变量
export TRIGGER_TOKEN="你的 Trigger Token"
export PROJECT_ID="项目 ID"          # Settings → General 可查看
export GITLAB_TOKEN="你的 PAT"
export ANTHROPIC_AUTH_TOKEN="你的 API Key"

# 触发修复
./scripts/trigger-fix.sh 42          # 42 是 Issue 的 IID

脚本内容很简洁,直接调用 GitLab Pipeline Trigger API

curl -X POST \
  --form "token=${TRIGGER_TOKEN}" \
  --form "ref=main" \
  --form "variables[ISSUE_IID]=${ISSUE_IID}" \
  --form "variables[GITLAB_TOKEN]=${GITLAB_TOKEN}" \
  --form "variables[ANTHROPIC_AUTH_TOKEN]=${ANTHROPIC_AUTH_TOKEN}" \
  "https://${GITLAB_HOST}/api/v4/projects/${PROJECT_ID}/trigger/pipeline"

关键设计细节

1. 为什么用两个 Job + Trigger 而非一个 Job

  • 隔离性:扫描和修复在不同 Pipeline 中运行,一个 Issue 修复失败不影响其他 Issue
  • 并行:多个 Issue 可以同时被触发修复(各自独立的 Pipeline
  • 可追溯:每个修复有独立的 Pipeline 记录

2. 标签状态机防重复

auto-fix → claude-processing → claude-done
  • 扫描 Query 排除 claude-processingclaude-done
  • 保证每个 Issue 只被处理一次

3. [skip ci] 避免递归触发

commit message 中包含 [skip ci],防止修复 commit 触发新的 Pipeline形成无限循环。

4. 临时文件排除

repair_summary.txtclaude_stderr.txt 通过 git reset 排除暂存区,通过 .gitignore 排除版本控制:

repair_summary.txt
claude_stderr.txt

5. Upload Job 与 Fix Job 互不干扰

Upload Job 的 rules 中明确排除 scheduletrigger 来源:

rules:
  - if: '$CI_PIPELINE_SOURCE == "schedule"'
    when: never
  - if: '$CI_PIPELINE_SOURCE == "trigger"'
    when: never

6. 完整克隆

variables:
  GIT_STRATEGY: clone
  GIT_DEPTH: 0

Claude Code 需要完整的仓库来分析代码,不能使用浅克隆。


踩坑记录与调试经验

1. Anthropic API 配置

问题Claude Code CLI 的环境变量名是 ANTHROPIC_API_KEY,但 CI 变量传递时用了别的名字。

解决:在 script 中显式映射:

export ANTHROPIC_API_KEY="${ANTHROPIC_AUTH_TOKEN}"

如果使用内部代理,还需设置 ANTHROPIC_BASE_URL。额外的 ANTHROPIC_MODELANTHROPIC_CUSTOM_MODEL_OPTION 变量用于指定模型。

2. Claude Code 自动更新

问题CI 环境中 Claude Code 尝试自动更新,导致超时或失败。

解决:设置环境变量禁用:

DISABLE_AUTOUPDATER: "1"

3. Issue 查询排除已处理的 Issue

问题:早期版本未排除 claude-processing/claude-done,导致同一 Issue 被反复触发。

解决:使用 GitLab API 的 not[labels] 参数:

?labels=auto-fix&not%5Blabels%5D=claude-processing,claude-done&state=opened

4. Git Push 认证

问题CI 环境默认的 git remote 可能不支持 push。

解决:使用 OAuth2 Token 方式构建 push URL

git push "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:main

5. 中文输出

问题Claude Code 默认可能以英文回复。

解决:在 Prompt 中明确要求 "请使用中文回复",确保修复摘要和 Issue 评论为中文。

6. 评论中的特殊字符转义

问题Claude 的输出可能包含 "\、换行等字符,直接放入 JSON 会破坏格式。

解决:通过 sed 链式转义:

SUMMARY=$(cat repair_summary.txt | head -200 | \
  sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')

完整 .gitlab-ci.yml 参考

以下是 ai_fix Stage 的完整配置,可直接复制到你的 .gitlab-ci.yml 中:

stages:
  # ... 你的其他 stages
  - ai_fix

# ============================================================
# AI Fix Stage - Auto-fix GitLab Issues with Claude Code
# ============================================================
# Required CI/CD Variables:
#   - GITLAB_ACCESS_TOKEN: Personal Access Token (api scope)
#   - ANTHROPIC_AUTH_TOKEN: Anthropic API Key
#   - TRIGGER_TOKEN: Pipeline trigger token
#
# Setup:
#   1. Create a Schedule (CI/CD → Schedules), e.g. every 5 min
#   2. Add label "auto-fix" to an Issue → auto triggers fix

claude:scan-issues:
  stage: ai_fix
  image: alpine:3.19
  before_script:
    - apk add --no-cache curl jq
  script:
    - |
      for var in GITLAB_ACCESS_TOKEN TRIGGER_TOKEN ANTHROPIC_AUTH_TOKEN; do
        eval "val=\$$var"
        if [ -z "$val" ]; then echo "ERROR: $var not set."; exit 1; fi
      done

      ISSUES=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_ACCESS_TOKEN" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues?labels=auto-fix&not%5Blabels%5D=claude-processing,claude-done&state=opened&per_page=10")

      COUNT=$(echo "$ISSUES" | jq 'length')
      echo "Found $COUNT issue(s)."
      [ "$COUNT" -eq 0 ] || [ "$COUNT" = "null" ] && exit 0

      echo "$ISSUES" | jq -r '.[].iid' | while read -r IID; do
        TITLE=$(echo "$ISSUES" | jq -r ".[] | select(.iid == $IID) | .title")
        echo ">>> Issue #${IID}: ${TITLE}"

        curl -s --request PUT \
          --header "PRIVATE-TOKEN: $GITLAB_ACCESS_TOKEN" \
          --header "Content-Type: application/json" \
          --data "{\"remove_labels\": \"auto-fix\", \"add_labels\": \"claude-processing\"}" \
          "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$IID" > /dev/null

        curl -s -X POST \
          --form "token=${TRIGGER_TOKEN}" \
          --form "ref=${CI_DEFAULT_BRANCH}" \
          --form "variables[ISSUE_IID]=${IID}" \
          --form "variables[GITLAB_TOKEN]=${GITLAB_ACCESS_TOKEN}" \
          --form "variables[ANTHROPIC_AUTH_TOKEN]=${ANTHROPIC_AUTH_TOKEN}" \
          "https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/trigger/pipeline"
      done
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
    - if: '$CI_PIPELINE_SOURCE == "web"'
      when: manual
  allow_failure: true
  timeout: 5m

claude:fix-issue:
  stage: ai_fix
  image: node:20
  variables:
    GIT_STRATEGY: clone
    GIT_DEPTH: 0
    ANTHROPIC_BASE_URL: "https://api.anthropic.com"
    ANTHROPIC_MODEL: "claude-sonnet-4-6"
    DISABLE_AUTOUPDATER: "1"
    DISABLE_PROMPT_CACHING: "1"
  before_script:
    - apt-get update && apt-get install -y git curl jq
    - npm install -g @anthropic-ai/claude-code
    - git config --global user.email "claude-bot@example.com"
    - git config --global user.name "Claude AI Bot"
  script:
    - |
      [ -z "$ISSUE_IID" ] && echo "ERROR: ISSUE_IID required." && exit 1
      [ -z "$GITLAB_TOKEN" ] && echo "ERROR: GITLAB_TOKEN required." && exit 1

      ISSUE_JSON=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID")
      ISSUE_TITLE=$(echo "$ISSUE_JSON" | jq -r '.title // empty')
      ISSUE_DESCRIPTION=$(echo "$ISSUE_JSON" | jq -r '.description // empty')
      [ -z "$ISSUE_TITLE" ] && echo "ERROR: Cannot fetch Issue" && exit 1
    - |
      git checkout "$CI_DEFAULT_BRANCH" && git pull origin "$CI_DEFAULT_BRANCH"
    - |
      export ANTHROPIC_API_KEY="${ANTHROPIC_AUTH_TOKEN}"

      PROMPT="你是一个代码修复助手。请使用中文回复。请分析并修复以下 GitLab Issue

      ## Issue #${ISSUE_IID}: ${ISSUE_TITLE}

      ${ISSUE_DESCRIPTION}

      请:
      1. 分析项目代码,定位问题根因
      2. 实施修复
      3. 确保代码能通过类型检查TypeScript 项目运行 npx tsc --noEmit
      4. 用中文输出修复摘要

      项目根目录已准备就绪。"

      RESULT=$(claude -p "$PROMPT" \
        --bare \
        --permission-mode acceptEdits \
        --allowedTools "Bash,Read,Edit,Write,Glob,Grep" \
        --max-turns 30 \
        --output-format text \
        2>&1) || true

      echo "$RESULT" > repair_summary.txt
    - |
      git add -A
      git reset -- repair_summary.txt claude_stderr.txt 2>/dev/null || true
      if git diff --cached --quiet; then
        COMMIT_STATUS="no_changes"
      else
        git commit -m "fix(auto): resolve Issue #${ISSUE_IID} - ${ISSUE_TITLE} [skip ci]"
        git push "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" \
          HEAD:"$CI_DEFAULT_BRANCH"
        COMMIT_STATUS="pushed"
      fi
    - |
      SUMMARY=$(cat repair_summary.txt | head -200 | \
        sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')

      if [ "$COMMIT_STATUS" = "pushed" ]; then
        BODY="## ✅ Claude Code 自动修复完成\n\n修复已推送到 \`${CI_DEFAULT_BRANCH}\`。\nPipeline: ${CI_PIPELINE_URL}\n\n<details><summary>修复详情</summary>\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n</details>"
      else
        BODY="## ⚠️ Claude Code 分析完成\n\n未检测到需要变更的文件。\nPipeline: ${CI_PIPELINE_URL}\n\n<details><summary>分析详情</summary>\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n</details>"
      fi

      curl -s --request POST \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"body\": \"${BODY}\"}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID/notes"
    - |
      curl -s --request PUT \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"remove_labels\": \"claude-processing\", \"add_labels\": \"claude-done\"}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$ISSUE_IID" > /dev/null
  rules:
    - if: '$CI_PIPELINE_SOURCE == "trigger" && $ISSUE_IID'
    - if: '$CI_PIPELINE_SOURCE == "web" && $ISSUE_IID'
      when: manual
  allow_failure: true
  timeout: 30m

总结

特性 实现方式
触发机制 GitLab Schedule 定时扫描 + Pipeline Trigger 触发修复
AI 引擎 Claude Code CLI (@anthropic-ai/claude-code)
权限控制 --permission-mode acceptEdits + --allowedTools 白名单
防重复 标签状态机 auto-fix → claude-processing → claude-done
防递归 commit message 中 [skip ci]
结果反馈 自动在 Issue 上发表评论,含修复摘要
项目上下文 CLAUDE.md 项目指南文件

这套方案已在实际项目中运行,成功自动修复了多个 Bug Issue。核心优势是零人工介入——开发者只需写好 Issue 描述并打上标签AI 自动完成从分析到修复到提交的全流程。