前言

本文介绍如何在自建 GitLab 中实现基于 Claude Code 的自动代码评审,而无需依赖 GitLab 企业版的 AI 能力(GitLab Duo)。

只需:

  • 一个 Claude Code Max 订阅
  • 一个配置了代理的 GitLab Runner

就能为团队带来 AI 代码评审的能力,生成 Markdown 和 PDF 格式的评审报告。

前置准备

个人建议

不要在 CI 中使用个人订阅,应使用 Anthropic 的 API 服务而不是个人订阅,个人订阅会因为违反使用条款中的多人共享规则而被封禁,这是我个人被封禁 2 个 Max 帐号后的经验。

如果不方便接入 Anthropic API,可以考虑接入 OpenRouter 等第三方 API 服务商。 另外,阿里云的 Qwen3 也是一个可行的方案,但实测下来报告质量不如 Opus 4.5,表达不够简洁,内容相对价值下降。

订阅 Claude Code Max

为了保证代码评审报告的质量,我们选择了支持 Opus 模型的 Max 套餐。

对于在中国的用户,可通过 iOS 应用内购买完成订阅:

  1. 通过 giffgaff 获取英国手机号,使用 Google 账号登录 claude.ai 完成注册
  2. 准备美区 Apple ID,在 Apple 官网购买礼品卡并充值
  3. 在 iPhone 上下载 Claude App,使用应用内购买完成订阅
订阅方式 Max 套餐(5x) Max 套餐(20x)
官网直接订阅(需美国信用卡) $100/月 $200/月
iOS 应用内购买 $125/月 $250/月

网络环境要求

Claude Code 使用 OAuth Token 认证,需要访问 Anthropic 服务。如果 GitLab Runner 部署在中国大陆,需要配置透明代理,使流量通过美国等地区的代理服务器进行转发,也可直接使用美国地区的服务器作为 Runner。

实现步骤

构建 Docker 镜像

将 Claude Code 及依赖封装到 Docker 镜像中,避免每次 CI 都执行安装操作:

FROM ghcr.io/puppeteer/puppeteer:24

USER root
WORKDIR /root
RUN npm install -g @anthropic-ai/claude-code md-to-pdf

镜像包含 Claude Code 和 md-to-pdf 的运行环境。

配置 GitLab CI

获取并配置 Token

执行 claude setup-token 获取以 sk-ant-oat01- 开头的 Token。

在 GitLab 项目的 Settings -> CI/CD -> Variables 中添加:

  • Key: CLAUDE_CODE_OAUTH_TOKEN
  • Protected: 开启(只有保护分支可读取,确保 Token 安全)
  • Masked: 开启

配置 Markdown 转 PDF 的配置文件

这份配置文件可解决代码高亮和代码过长导致的显示不全问题。

在 GitLab 项目的 Settings -> CI/CD -> Variables 中添加:

  • Key: MD_TO_PDF_CONFIG_FILE
  • Protected: 开启
  • Masked: 关闭
  • Type: File
module.exports = {
stylesheet: [
    'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css'
],
highlight_style: 'atom-one-light',
body_class: 'markdown-body',

marked_options: {
    headerIds: true,
    smartypants: true,
    gfm: true,
    breaks: false,
},

pdf_options: {
    format: 'A4',
    margin: {
    top: '20mm',
    right: '20mm',
    bottom: '25mm',
    left: '20mm'
    },
    printBackground: true,
    displayHeaderFooter: true,
    headerTemplate: '<div></div>',
    footerTemplate: `
    <div style="font-size: 10px; width: 100%; text-align: center; color: #888;">
        <span class="pageNumber"></span> / <span class="totalPages"></span>
    </div>
    `,
},

launch_options: {
    args: [
        "--no-sandbox",
        "--disable-setuid-sandbox"
    ]
},

css: `
    pre,
    pre code,
    pre code.hljs,
    code,
    .hljs {
        white-space: pre-wrap !important;
        word-wrap: break-word !important;
        word-break: break-all !important;
        overflow-wrap: break-word !important;
    }

    pre {
        max-width: 100% !important;
        overflow-x: visible !important;
        padding: 12px;
        border-radius: 8px;
        font-size: 12px;
        line-height: 1;
        background-color: #f6f8fa !important;
        page-break-inside: avoid;
    }

    pre > code {
        display: block !important;
        max-width: 100% !important;
        overflow: visible !important;
    }

    code {
        font-family: 'Cascadia Code', 'JetBrains Mono', 'Fira Code', monospace;
    }

    @media print {
    pre, pre code, .hljs {
        white-space: pre-wrap !important;
        word-break: break-all !important;
        overflow: visible !important;
    }
    }

    .markdown-body {
        font-size: 12px;
        max-width: 100% !important;
        overflow: hidden;
    }
`
};

CI 配置

stages:
  - code-review
  - build-assets
  - build-docker-image
  - deploy

claude-code-review:
  image: registry.example.com/infrastructure/claude-code:v0.0.1
  tags:
    - us-proxy  # 配置了透明代理的 Runner
  stage: code-review
  variables:
    GIT_DEPTH: 100
  script:
    - git fetch --depth=20 origin main:main
    - |
      claude \
      --model opus \
      --permission-mode acceptEdits \
      --allowedTools "Bash(*) Read(*) Edit(*) Write(*)" \
      -p "$(cat << EOF
      对 main 到 ${CI_COMMIT_BRANCH} 的所有 commits 进行代码审查。

      要求:
      1. 将中文报告写入到 ${CI_PIPELINE_ID}_review.md 文件内,不要改动其他文件
      2. 分析当前代码状态中仍存在的问题
      3. 对于每个问题,必须包含以下内容:
         - 问题所在的文件路径和行号(基于当前代码状态)
         - 问题代码片段(使用 markdown 代码块)
         - 问题分析:解释为什么这是一个问题
         - 修复建议:给出具体的修复方案或代码示例
      4. 按严重程度分类:严重、高、中、低
      5. 不要使用 emoji
      6. 使用 markdown list 格式(避免 markdown table)
      7. 如果没有发现问题,说明代码质量良好即可

      重点关注:
      - 潜在的 bug 和逻辑错误
      - 安全漏洞
      - 性能问题
      - 未清理的调试代码
      - 类型错误或类型不安全

      分析策略:
      1. 按时间顺序(从旧到新)分析所有 commits
      2. 对于每个 commit 中发现的问题,检查后续 commits 是否已修复该问题
      3. 如果问题已被后续 commit 修复,则不要在最终报告中包含该问题
      4. 只报告在当前代码状态中仍然存在的问题

      判断问题已修复的标准:
      - 问题代码在后续 commit 中被删除或重写
      - 后续 commit 的改动明确解决了该问题(如修复了 bug、添加了缺失的校验等)
      - 同一位置的代码逻辑在后续 commit 中被优化或改进
      EOF
      )"
    - md2pdf --config-file ${MD_TO_PDF_CONFIG_FILE} ${CI_PIPELINE_ID}_review.md
    - |
      echo \
      "markdown: ${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/jobs/${CI_JOB_ID}/artifacts/raw/${CI_PIPELINE_ID}_review.md"
    - |
      echo \
      "pdf: ${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/jobs/${CI_JOB_ID}/artifacts/file/${CI_PIPELINE_ID}_review.pdf"
  artifacts:
    paths:
      - "*_review.md"
      - "*_review.pdf"
    when: always
  rules:
    - if: '$CI_COMMIT_BRANCH != "main"'

# 省略了后续的构建和部署阶段

工作流程

main → feature/* → release → 触发 CI 代码评审 → 审阅报告 → 测试环境验证通过 → main

开发者从 main 拉出 feature 分支进行开发,运维从 main 拉出 release 分支。开发完成后,将 feature 分支合并到 release 分支,此时触发代码评审并部署测试环境。评审报告通过且测试环境验证无误后,再将 release 分支合并回 main。

安全策略

将 release 分支设置为保护分支,配合 Protected Variable:

  • 只有保护分支的 CI 任务能读取 CLAUDE_CODE_OAUTH_TOKEN
  • 普通 feature 分支无法获取 Token,避免泄露风险
  • 保护分支只有运维可以删除

代码评审在开发分支合并到 release 分支时触发,作为 CI 的第一个 Stage 执行。

使用方式

CI 完成后,日志末尾会输出报告链接:

  • 通过 PDF 文件链接,直接在线预览报告
  • 通过 Markdown 文件链接,下载到本地后在 VSCode 中查看(方便复制黏贴)

报告作为 GitLab Artifacts 永久保存。

总结

这种方式的优势:

  • 低门槛:基于 GitLab CE 即可实现,无需企业版
  • 低成本:只需 Claude Code Max 订阅费用
  • 安全可控:Token 通过 Protected Variable 保护,代码和报告都在自建 GitLab 中
  • 灵活定制:Prompt 可根据团队需求调整评审重点