在 GitLab CI/CD 里用 Claude Code:把 issue 变成 MR 的作业怎么写,走中转站和国内 Runner 要改的几处
按 Claude Code 官方的 GitLab 文档整理:在 .gitlab-ci.yml 里加一个跑 claude -p 的作业,让它改代码、开 MR。讲清最小的作业怎么写、评论触发和开 MR 靠什么、走中转站和国内 Runner 要改哪几处;作业里那条命令本站在服务器上照样跑了四遍。
本文根据公开分享整理,本站尚未实测。操作前请对照文末的原始来源。
本页目录(9 节)
这篇解决一个问题:代码在 GitLab 上(包括公司自建的),想让 Claude Code 像在 GitHub 上那样,评论里 @ 一下就去改代码、开 MR,该怎么配。
GitLab 没有 GitHub 那样的现成 Action。做法是在 .gitlab-ci.yml 里加一个作业,作业里装好 Claude Code、跑一条 claude -p。官方文档注明这个集成还是测试版,由 GitLab 一方维护,有问题要去 GitLab 的 issue 里反馈。
本站没有 GitLab 实例,GitLab 一侧(Runner、触发、评论、开 MR)都是按文档整理的。能测的是作业里那条命令:本站在服务器上用一个干净的配置目录、只靠环境变量给凭据(和 CI 容器里一样),照官方的写法跑了四遍,结果在第五节。用 GitHub 的看《用 GitHub Actions 让 Claude Code 审 PR、修 issue》。
一、它是怎么工作的
按官方文档:
- 触发。 GitLab 等你选定的事件,比如 issue、MR 或审查线程里出现
@claude的评论。作业从这个线程和仓库里收集上下文,拼成提示词,交给 Claude Code。 - 跑在你的 Runner 上。 每次都在一个容器里跑,网络和文件系统按你的规则限制;Claude Code 只能在工作区里写。
- 改动走 MR。 所有改动都通过 MR 交回来,审查和审批照旧。
模型可以走 Claude API,也可以走 Amazon Bedrock 或 Google Cloud。云平台那两种本站不写,只讲 Claude API 和中转站。
文档举的用法:在 issue 里评论 @claude implement this feature based on the issue description,它分析 issue 和代码、在分支上改、开 MR;在 MR 讨论里让它给出具体方案并改进 MR;在评论里让它修某个报错。
二、最小的作业
两步:在 Settings → CI/CD → Variables 加一个 masked 的变量 ANTHROPIC_API_KEY;在 .gitlab-ci.yml 里加这个作业(官方示例原样):
stages:
- ai
claude:
stage: ai
image: node:24-alpine3.21
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
GIT_STRATEGY: fetch
before_script:
- apk update
- apk add --no-cache git curl bash
- curl -fsSL https://claude.ai/install.sh | bash
- export PATH="$HOME/.local/bin:$PATH"
script:
- /bin/gitlab-mcp-server || true
- echo "$AI_FLOW_INPUT for $AI_FLOW_CONTEXT on $AI_FLOW_EVENT"
- >
claude
-p "${AI_FLOW_INPUT:-'Review this MR and implement the requested changes'}"
--permission-mode acceptEdits
--allowedTools "Bash Read Edit Write mcp__gitlab"
--debug
逐行说一下:
| 部分 | 做什么 |
|---|---|
rules |
什么时候跑:这里是在网页上手动跑,和 MR 事件。按需要改 |
before_script |
在 Alpine 镜像里装 git、curl、bash,再用官方安装脚本装 Claude Code,把 ~/.local/bin 加进 PATH |
/bin/gitlab-mcp-server |
启动 GitLab 的 MCP 服务器,Claude 靠它读 issue、发评论、开 MR。没有就跳过(` |
AI_FLOW_INPUT 等 |
从网页或接口触发时带进来的上下文:要做的事、来自哪个 issue 或 MR、什么事件。由触发流水线的一方(比如第三节说的监听程序)传入 |
-p "..." |
提示词。没有 AI_FLOW_INPUT 时用后面那句默认的 |
--permission-mode acceptEdits |
改文件不用确认。-p 从 2.1.302 起默认是 Manual,不写这个就改不了文件 |
--allowedTools |
放行 Bash、读写文件和 GitLab 的 MCP 工具 |
--debug |
打出调试信息 |
加好之后,可以在 CI/CD → Pipelines 里手动跑一次,或者开一个 MR 触发。
生产环境文档建议手动配:凭据用 masked 变量;读写 GitLab 用默认的 CI_JOB_TOKEN,权限不够就建一个带 api 范围的项目访问令牌,存成 GITLAB_ACCESS_TOKEN。
三、评论里 @claude 怎么触发
这一点容易误会:示例作业的 rules 只管手动运行和 MR 事件。按文档手动配置的第 4 步,要让评论里的 @claude 触发,得给项目加一个 “Comments (notes)” 的 webhook,指向你的事件监听程序;监听程序看到评论里有 @claude,就调 GitLab 的流水线触发接口,把 AI_FLOW_INPUT、AI_FLOW_CONTEXT 这些变量带过去。文档把这一步标为可选,监听程序要自己准备。
文档的排错里也写了:评论里要写 @claude,不是 /claude;没反应时先看流水线有没有被触发、凭据变量在不在、监听程序配了没有。
四、走中转站、在国内的 Runner 上要改的几处
官方文档没有讲中转站。作业里跑的就是 Claude Code 命令行,它认的环境变量和平时一样,见《Claude Code 接入中转站》。
1. 凭据换成两个变量。 不用 ANTHROPIC_API_KEY,在 CI/CD 变量里加:
| 变量 | 值 | 设置 |
|---|---|---|
ANTHROPIC_BASE_URL |
中转站给的地址,不带 /v1 |
可以不 mask |
ANTHROPIC_AUTH_TOKEN |
中转站给的 key | masked,按需要设成 protected |
本站第五节的四次运行就是这样:配置目录是空的,凭据只来自这两个环境变量,都正常。中转站要的是 x-api-key 的,把 key 放进 ANTHROPIC_API_KEY 而不是 ANTHROPIC_AUTH_TOKEN,两个不要同时设。
2. 模型名要这把 key 有的。 不指定时用的是 Claude Code 的默认模型(本站这次是 Opus 5.5)。key 没开这个模型的,在命令里加 --model,或者设 ANTHROPIC_MODEL。
3. 安装脚本可能下不来。 示例用 curl https://claude.ai/install.sh 安装,国内的 Runner 访问这个地址不一定顺。安装文档给了另一条路:用 npm 装 npm install -g @anthropic-ai/claude-code,装的是同一个二进制,支持 linux-x64-musl 这类平台。示例的 node 镜像里本来就有 npm,配上国内的 npm 镜像源就行。镜像本身从 Docker Hub 拉,国内也可能要配镜像加速。
4. Alpine 镜像要多装几样。 安装文档说,在 Alpine 这类 musl 系统上,运行时还要 libgcc、libstdc++ 和 ripgrep,并且在设置里把 USE_BUILTIN_RIPGREP 设成 0。官方的 GitLab 示例只装了 git、curl、bash。照安装文档补上:
before_script:
- apk update
- apk add --no-cache git curl bash libgcc libstdc++ ripgrep
- export USE_BUILTIN_RIPGREP=0
ripgrep 在 Alpine 的 community 仓库里。这一条是本站对照两页官方文档补的,服务器上没有 Docker,没有在 Alpine 镜像里测过。
5. 网络要放行。 Runner 要能连上你的中转站地址。文档建议限制作业的出网,放行的时候别漏了它。
五、实测:作业里这条命令到底做了什么
| 项目 | 内容 |
|---|---|
| 日期 | 2026-10-21 |
| 版本 | Claude Code 2.1.304 |
| 环境 | 本站测试服务器,Ubuntu 24.04;不是容器,也没有 GitLab |
| 凭据 | 空的配置目录,只有 ANTHROPIC_BASE_URL 和 ANTHROPIC_AUTH_TOKEN 两个环境变量,通过酷站AI 中转站 |
| 示例仓库 | 一个很小的 Python 项目:list_available() 把库存为 0 的商品也返回了。仓库里有一份 CLAUDE.md:改完要跑 python3 -m unittest,提交说明用中文、第一行不超过 50 个字,不要推送 |
| 命令 | 官方示例那一条,去掉了 --debug,没有 GitLab 的 MCP 服务器 |
AI_FLOW_INPUT 设成“实现 issue #12:库存为 0 的商品不应该出现在 list_available() 的结果里,补上测试。”
| 运行 | 结果 | 用时 | Claude Code 估算的花费 |
|---|---|---|---|
| 照官方原样 | 改对了,补了 3 个测试,4 个测试全过。没有提交,最后说“要提交的话我按 CLAUDE.md 的规矩写中文说明,不推送” | 22 秒 | 0.08 美元 |
| 提示词末尾加“改完在新分支 claude/issue-12 上提交” | 建了分支 claude/issue-12,提交说明是中文、第一行不超过 50 个字,没有推送 |
21 秒 | 0.08 美元 |
照官方原样,加 --max-turns 2 |
输出 Error: Reached max turns (2),退出码 1,什么也没改 |
9 秒 | 0.04 美元 |
几件值得知道的事:
- 这条命令本身不提交,也不开 MR。 没有 GitLab 的 MCP 服务器时,它只改了工作区。要它提交,提示词里得说;要开 MR,靠
mcp__gitlab工具,或者在作业的script里自己git push再调 GitLab 的接口。 - 它会试着用
glab去读 issue。 两次都先试着用glab读 issue #12(有一次还试了gh),机器上没装,就按提示词里的描述做了。想让它看到 issue 原文和讨论,装好 GitLab 的 MCP 服务器,或者把 issue 内容拼进提示词。 - CLAUDE.md 的规矩它照着做了:跑了测试,提交说明的格式对,没有推送。
- 提交里会带一行
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>。 这是 Claude Code 的默认做法,不想要就在设置里把attribution.commit设成空字符串。设置文档还说,认不出模型版本时写Claude,模型 ID 对不上任何 Claude 模型(比如通过自定义地址用别家的模型)时写Claude Code。本站经中转站用的是claude-opus-5-5,写的是完整的名字。 - 容器里要先配 git 身份。 本站的测试机上已经配过
user.name和user.email,所以提交成功了。CI 容器里一般没有,在before_script里先git config一下,不然提交会失败。 --max-turns到了上限,作业就算失败。 文档把它列为控制花费的办法,值别设得太小。- 回复的语言不固定。 同样的中文提示词,三次里两次用英文汇报,一次用中文。要它在 MR 里用中文,写进
CLAUDE.md。 - 那条默认提示词会带着引号。 没有
AI_FLOW_INPUT时,"${AI_FLOW_INPUT:-'Review this MR ...'}"在 bash 和 sh 里都会把那对单引号原样带进提示词。不影响它理解,嫌难看就把单引号去掉。 --debug排查完就去掉。 它会把大量调试信息打进作业日志,能看作业日志的人都看得到。本站测试时没有加。
六、安全和花费
文档的建议:
- key 和云凭据只放在 CI/CD 变量里,设成 masked,绝不提交进仓库;云平台优先用 OIDC,不用长期的 key。
- 限制作业的权限和出网。
- Claude 开的 MR 和别人的一样审。示例里放行了整个 Bash,又是
acceptEdits,它在容器里基本什么命令都能跑,靠的是容器和 Runner 的隔离。
花费分两块:Runner 的计算时间,和模型的 token。控制的办法:@claude 后面把要做的事说具体;设 --max-turns 和作业的 timeout(比如 timeout: 30m);限制同时跑几个。本站这个小仓库每次 4 到 8 美分(Opus 5.5,按官方价估算),真实项目的上下文大得多,会贵不少。
七、出了问题先查
| 现象 | 先查什么 |
|---|---|
| 评论里 @claude 没反应 | 流水线有没有被触发;评论里是 @claude 而不是 /claude;webhook 和监听程序配了没有;凭据变量在不在 |
| 作业发不了评论、开不了 MR | CI_JOB_TOKEN 的权限够不够,不够就用带 api 范围的项目访问令牌;--allowedTools 里有没有 mcp__gitlab;作业是不是在 MR 的上下文里跑,或者 AI_FLOW_* 带够了上下文 |
| 认证失败 | 走 Claude API 的,看 ANTHROPIC_API_KEY 有没有过期;走中转站的,看地址和 key 是不是放对了变量,见《Claude Code 常见报错怎么查》 |
Error: Reached max turns |
--max-turns 设小了(本站实测,退出码 1) |
| 提交失败 | 容器里没配 git 身份 |
| 装不上 | 安装脚本下载不了就改用 npm;Alpine 上缺运行库见第四节 |
文档还提醒:命令行参数可能随版本变,在作业里跑一下 claude --help 看当前支持什么。
这次没有覆盖到的
- GitLab 一侧全部没有测:Runner、
@claude的触发、GitLab 的 MCP 服务器、发评论和开 MR、CI_JOB_TOKEN的权限。 - Alpine 镜像和 npm 安装没有测,第四节是对照安装文档写的。
- Amazon Bedrock 和 Google Cloud 两种接法不写,本站不写云平台接入。
- 实测的仓库很小,四次运行,只说明这条命令在这个版本上的行为。