> 本文记录了在 GitLab 项目中集成 Claude Code CLI,实现"给 Issue 打标签即可自动修复 Bug"的完整方案与实践过程。 --- ## 目录 - [方案概述](#方案概述) - [整体架构](#整体架构) - [前置条件](#前置条件) - [第一步:配置 CI/CD Variables](#第一步配置-cicd-variables) - [第二步:创建 Pipeline Trigger Token](#第二步创建-pipeline-trigger-token) - [第三步:编写 .gitlab-ci.yml](#第三步编写-gitlab-ciyml) - [Job 1: claude:scan-issues — 扫描 Issue](#job-1-claudescan-issues--扫描-issue) - [Job 2: claude:fix-issue — 执行修复](#job-2-claudefix-issue--执行修复) - [第四步:创建定时调度](#第四步创建定时调度) - [第五步:编写 CLAUDE.md 项目指南](#第五步编写-claudemd-项目指南) - [使用流程](#使用流程) - [手动触发脚本](#手动触发脚本) - [关键设计细节](#关键设计细节) - [踩坑记录与调试经验](#踩坑记录与调试经验) - [完整 .gitlab-ci.yml 参考](#完整-gitlab-ciyml-参考) --- ## 方案概述 核心思路:利用 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 Token(api scope),扫描 Job 使用 | | `ANTHROPIC_AUTH_TOKEN` | Masked | Anthropic API Key(或内部代理的 auth token) | | `TRIGGER_TOKEN` | 见下一步 | Pipeline 触发器 Token | > **安全提示**:`GITLAB_ACCESS_TOKEN` 和 `ANTHROPIC_AUTH_TOKEN` 务必勾选 **Masked**,防止在日志中泄露。 ### 关于 Anthropic API 访问 如果你直接使用 Anthropic 官方 API,需要设置: - `ANTHROPIC_AUTH_TOKEN` = 你的 Anthropic API Key 如果使用内部代理(如本项目使用 `openai.nie.netease.com`),则在 CI Job 中通过环境变量指定: ```yaml 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 调用: ```yaml 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¬%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-processing` 和 `claude-done` 的 Issue 2. 对每个 Issue 切换标签(防止重复处理) 3. 通过 Pipeline Trigger API 启动独立的修复 Pipeline,传入 `ISSUE_IID`、`GITLAB_TOKEN`、`ANTHROPIC_AUTH_TOKEN` ### Job 2: claude:fix-issue — 执行修复 这是核心修复 Job,使用 `node:20` 镜像,安装并运行 Claude Code: ```yaml 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
修复详情\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n
" else BODY="## ⚠️ Claude Code 分析完成\n\n未检测到需要变更的文件。\n\nPipeline: ${CI_PIPELINE_URL}\n\n
分析详情\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n
" 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.md`,Claude Code 在 CI 中运行时会自动读取此文件作为上下文指导: ```markdown # 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-done`,Issue 评论中会出现修复摘要 6. 如果有代码变更,commit 会自动推送到 `main` 分支 ### 手动模式(命令行触发) 项目提供了便捷脚本 `scripts/trigger-fix.sh`: ```bash # 设置环境变量 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: ```bash 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-processing` 和 `claude-done` - 保证每个 Issue **只被处理一次** ### 3. `[skip ci]` 避免递归触发 commit message 中包含 `[skip ci]`,防止修复 commit 触发新的 Pipeline,形成无限循环。 ### 4. 临时文件排除 `repair_summary.txt` 和 `claude_stderr.txt` 通过 `git reset` 排除暂存区,通过 `.gitignore` 排除版本控制: ```gitignore repair_summary.txt claude_stderr.txt ``` ### 5. Upload Job 与 Fix Job 互不干扰 Upload Job 的 rules 中明确排除 `schedule` 和 `trigger` 来源: ```yaml rules: - if: '$CI_PIPELINE_SOURCE == "schedule"' when: never - if: '$CI_PIPELINE_SOURCE == "trigger"' when: never ``` ### 6. 完整克隆 ```yaml variables: GIT_STRATEGY: clone GIT_DEPTH: 0 ``` Claude Code 需要完整的仓库来分析代码,不能使用浅克隆。 --- ## 踩坑记录与调试经验 ### 1. Anthropic API 配置 **问题**:Claude Code CLI 的环境变量名是 `ANTHROPIC_API_KEY`,但 CI 变量传递时用了别的名字。 **解决**:在 script 中显式映射: ```bash export ANTHROPIC_API_KEY="${ANTHROPIC_AUTH_TOKEN}" ``` 如果使用内部代理,还需设置 `ANTHROPIC_BASE_URL`。额外的 `ANTHROPIC_MODEL` 和 `ANTHROPIC_CUSTOM_MODEL_OPTION` 变量用于指定模型。 ### 2. Claude Code 自动更新 **问题**:CI 环境中 Claude Code 尝试自动更新,导致超时或失败。 **解决**:设置环境变量禁用: ```yaml DISABLE_AUTOUPDATER: "1" ``` ### 3. Issue 查询排除已处理的 Issue **问题**:早期版本未排除 `claude-processing`/`claude-done`,导致同一 Issue 被反复触发。 **解决**:使用 GitLab API 的 `not[labels]` 参数: ``` ?labels=auto-fix¬%5Blabels%5D=claude-processing,claude-done&state=opened ``` ### 4. Git Push 认证 **问题**:CI 环境默认的 git remote 可能不支持 push。 **解决**:使用 OAuth2 Token 方式构建 push URL: ```bash git push "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:main ``` ### 5. 中文输出 **问题**:Claude Code 默认可能以英文回复。 **解决**:在 Prompt 中明确要求 "请使用中文回复",确保修复摘要和 Issue 评论为中文。 ### 6. 评论中的特殊字符转义 **问题**:Claude 的输出可能包含 `"`、`\`、换行等字符,直接放入 JSON 会破坏格式。 **解决**:通过 `sed` 链式转义: ```bash 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` 中: ```yaml 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¬%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
修复详情\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n
" else BODY="## ⚠️ Claude Code 分析完成\n\n未检测到需要变更的文件。\nPipeline: ${CI_PIPELINE_URL}\n\n
分析详情\n\n\`\`\`\n${SUMMARY}\n\`\`\`\n
" 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 自动完成从分析到修复到提交的全流程。