上一篇我们讨论了 OpenCodeReview 在 GitHub Actions 中的最短接入路径——一行uses即可启动 AI 审查。但对于大量运行 Jenkins 的团队来说,真正的战场在 Jenkinsfile 里。这篇文章从零开始,在 Jenkins 上搭建一条完整的 AI 审查闭环:从安装ocrCLI、配置 LLM 凭据、编写 Jenkinsfile,到把审查结果以 SARIF 格式落盘并接入 Warnings NG 插件,最终让“审查”从一个人的主观判断变成流水线中一条可追溯、可版本化、可度量的结构化产物。
一、为什么是 Jenkins + SARIF 这个组合
先说清楚一个前提:OpenCodeReview 不是 Jenkins 插件,它是一个 CLI 工具。它的设计哲学是“ocr二进制只负责评审,平台侧的发布逻辑全部下沉到 CI 层”。这意味着在 GitHub Actions 中,官方提供了一个 composite action 来封装安装、配置、运行、回帖的全过程;但在 Jenkins 中,你需要自己写 Jenkinsfile 来完成同样的编排。
这看起来是劣势,实际上是优势。Jenkins 的灵活性意味着你可以精确控制审查在流水线中的位置、结果的消费方式、以及门禁策略。而 SARIF(Static Analysis Results Interchange Format)是 OASIS 标准,Jenkins 的 Warnings Next Generation 插件可以直接消费,让审查结果进入 Jenkins 原生的趋势图表和构建门禁体系。
组合起来的工作流是这样的:
Gerrit Trigger / GitHub PR 事件 → Jenkins Pipeline 触发 → ocr review --format sarif --output ocr-report.sarif → Warnings NG 插件解析 SARIF → 行内评论回写到代码托管平台 → 构建门禁:error 级别告警阻断合并每一步都有明确的工程意义,我们逐一拆解。
二、环境准备:安装与凭据
2.1 安装 ocr CLI
OCR 通过 npm 分发,推荐在 Jenkins agent 上全局安装:
npm install -g @alibaba-group/open-code-review安装后ocr命令即可全局调用。在 Jenkins 中,由于 agent 可能是临时容器或共享节点,更稳妥的做法是在 Pipeline 的environment块中通过npm install -g在每次构建时安装,或者使用 Jenkins 的“全局工具配置”预先安装好。
2.2 配置 LLM 凭据
OCR 需要 LLM 端点、认证令牌和模型名称三项配置。在 Jenkins 中,这些应该通过凭据管理来注入,而不是硬编码在 Jenkinsfile 中。
需要在 Jenkins 凭据系统中创建两个 Secret text:
ocr-llm-token:LLM API key。注意这里有一个容易踩坑的细节:CI 环境变量名习惯使用OCR_LLM_AUTH_TOKEN,但 OCR 二进制真正读取的环境变量是OCR_LLM_TOKEN。官方文档明确指出了这个映射关系,流水线内部通过ocr config set llm.auth_token_cmd 'printf "%s" "$OCR_LLM_TOKEN"'这类方式桥接。排查认证问题时,先确认这一层转换是否生效。code-review-token:用于将审查结果回写到 Gerrit 或 GitLab/GitHub 的写令牌。在 Gerrit 场景下,这就是 bot 账号的 HTTP 密码。
此外还需要一个普通环境变量来指定 LLM 端点和模型:
environment { OCR_LLM_URL = 'https://api.anthropic.com/v1/messages' OCR_LLM_MODEL = 'claude-opus-4-6' OCR_USE_ANTHROPIC = 'true' }三、Jenkinsfile 编写:从触发到审查
以下是一个完整的 Jenkinsfile 骨架,适用于 Gerrit Trigger 触发的 patchset-created 事件。整体链路参考了 OCR 仓库中examples/gerrit_ci/的设计模式。
3.1 触发配置
在 Jenkins 任务中配置 Gerrit Trigger 插件,选择Patchset Created事件。这等价于 Gerrit 的post-receivehook,每次新的 patchset 推入时触发构建。
3.2 完整的 Jenkinsfile
pipeline { agent any environment { OCR_LLM_URL = 'https://api.anthropic.com/v1/messages' OCR_LLM_MODEL = 'claude-opus-4-6' OCR_USE_ANTHROPIC = 'true' } stages { stage('Install OCR') { steps { sh 'npm install -g @alibaba-group/open-code-review' sh 'ocr --version' } } stage('Configure LLM') { steps { withCredentials([ string(credentialsId: 'ocr-llm-token', variable: 'OCR_LLM_TOKEN') ]) { sh ''' ocr config set llm.url "$OCR_LLM_URL" ocr config set llm.auth_token_cmd 'printf "%s" "$OCR_LLM_TOKEN"' ocr config set llm.model "$OCR_LLM_MODEL" ocr llm test ''' } } } stage('Fetch & Review') { steps { withCredentials([ string(credentialsId: 'ocr-llm-token', variable: 'OCR_LLM_TOKEN') ]) { sh ''' git fetch origin "+refs/heads/*:refs/remotes/origin/*" ocr review \ --from "origin/$GERRIT_BRANCH" \ --to "$GERRIT_PATCHSET_REVISION" \ --format sarif \ --audience agent \ --output ocr-report.sarif ''' } } } stage('Publish Results') { steps { recordIssues( tools: [sarif(pattern: 'ocr-report.sarif')], qualityGates: [[threshold: 1, type: 'TOTAL', unstable: false]] ) } } } }几个关键设计决策的解释:
--audience agent抑制进度输出,让 stdout 只包含结构化结果。--audience human时进度流向 stderr 供人观看,而 CI 场景需要静默的机器可读输出。
--from origin/$GERRIT_BRANCH使用远端引用而非本地分支,确保 diff 基准是远端最新状态。Gerrit Trigger 注入的GERRIT_BRANCH和GERRIT_PATCHSET_REVISION环境变量保证了审查范围精确到当前 patchset。
ocr llm test在正式审查前验证 LLM 端点连通性。如果这一步失败,问题定位会清晰得多,而不是等到审查阶段才发现认证错误。
四、规则文件:让审查标准跟着团队走
OCR 的规则解析遵循四级优先级链:CLI--rule标志 > 仓库根目录的.opencodereview/rule.json> 用户级配置 > 内置规则集。
在 Jenkins 实践中,把.opencodereview/rule.json提交到仓库是最重要的习惯。它让审查标准成为代码的一部分,新成员不需要问“我们的审查标准是什么”,rule.json本身就是文档。
一个最小可用的规则文件结构如下:
{ "rules": [ { "path": "src/api/**", "text": "检查所有 API handler 是否对请求体做了空值校验。未校验的入参是 P0 级风险。" }, { "path": "src/frontend/**", "text": "检查是否存在敏感信息硬编码(API key、token、密码)。任何硬编码凭据都是 error 级别。" } ] }每条规则的path字段支持 glob 模式,text字段可以是内联文本,也可以指向一个 Markdown 检查清单文件——只要值以.md/.txt/.markdown结尾的单行路径,OCR 会自动读取文件内容作为规则文本。
对于大型项目,可以拆分成多个规则文件,在 Jenkinsfile 中按需加载:
ocr review --rule .opencodereview/rules/security.json \
--rule .opencodereview/rules/performance.json \
--format sarif
一个需要注意的细节:规则文件的RepoDir锚定在 git 顶层。从 monorepo 子目录执行ocr review时,加载的是仓库根目录的rule.json,子目录下的局部rule.json不会被读取。如果需要在 monorepo 中按子项目区分规则,应该通过--rule标志显式指定不同路径的文件。
五、结果回写与门禁
5.1 SARIF 进入 Warnings NG
recordIssues步骤让 SARIF 中的每条发现进入 Jenkins 的 Warnings NG 仪表盘。OCR 的 SARIF 输出将严重级别映射为:critical/high → error,medium → warning,low/空/未知 → note。
qualityGates 配置为threshold: 1, type: 'TOTAL'意味着:只要出现 1 条 error 级别的告警,构建即标记为失败。这是“从一条 SARIF 告警开始”的最直接落地——一条 NPE 风险或 SQL 注入告警,就足以阻断合并。
5.2 行内评论回写
SARIF 解决的是“持久化告警追踪”和“构建门禁”,但开发者仍然希望在 PR 页面上看到具体的行内评论。对于 Gerrit 场景,OCR 仓库提供了examples/gerrit_ci/post_review.py——一个仅依赖 Python 标准库的脚本,读取ocr review --format json的输出,将其作为一次批量 ReviewInput 原子提交到 Gerrit 的 set-review 接口。
在 Jenkinsfile 中增加一个并行阶段来同时产出 JSON 和 SARIF:
stage('Review & Publish') { parallel { stage('SARIF for Gates') { steps { sh 'ocr review --format sarif --output ocr-report.sarif' } } stage('JSON for Comments') { steps { withCredentials([ string(credentialsId: 'code-review-token', variable: 'GERRIT_HTTP_PASSWORD') ]) { sh ''' ocr review --format json --audience agent --output ocr-review.json python3 post_review.py --input ocr-review.json ''' } } } } }post_review.py处理了 Gerrit 特有的几个坑:在/a/端点上预发式 HTTP Basic 认证、剥离响应中的)]}'反 XSSI 前缀、把“返回 200 但实际是 HTML 登录页”识别为配置错误而非成功,以及在批量请求收到 HTTP 400 时重试一次并将行内评论折叠进总结消息。
六、规则迭代与效能度量
审查闭环转起来之后,真正的工作才开始:规则需要迭代,误报需要校准。
OCR 的 session 持久化机制提供了度量基础。每次ocr review会生成一条 session 记录,包含触发的规则、产出的意见、消耗的 token 等元数据。通过ocr session list和ocr session compare可以追踪:
哪些规则触发频率最高?
随着规则文本的迭代,误报率是否下降?
不同规则对 LLM token 的消耗差异有多大?
这些数据在 Jenkins 中的落地方式很简单——把 session 列表和统计输出作为构建产物归档:
post { always { archiveArtifacts artifacts: 'ocr-report.sarif, ocr-review.json', allowEmptyArchive: true sh 'ocr session list > ocr-sessions.txt || true' archiveArtifacts artifacts: 'ocr-sessions.txt', allowEmptyArchive: true } }归档的 SARIF 文件本身也是一条时间线。Warnings NG 插件会自动生成趋势图,展示每个构建中 error/warning/note 数量的变化。如果某条规则被调整后 error 数量骤降,趋势图会直接反映出来。
七、关于两种输出格式的选择
OCR 当前支持 text、json 和 sarif 三种输出格式。在 Jenkins 场景下,选择取决于消费方:
JSON是“发布胶水”的输入。它包含完整的评论结构(文件路径、行号、内容、severity),适合用脚本解析后通过平台 API 回写为行内评论。--audience agent确保 stdout 干净可解析。
SARIF是“持久化告警”的载体。它让审查结果进入 Jenkins 的 Warnings NG 仪表盘和分支保护门禁,获得与 CodeQL、Semgrep 等 SAST 工具同等的告警生命周期管理能力——open → fixed → dismissed。
两者不互斥。在流水线中同时产出两种格式,各行其职,是推荐的做法。
结语
回到上一篇文章的结尾:工具已经就绪,瓶颈在流程。在 GitHub Actions 中,官方 action 把编排封装到了一行uses里,接入门槛极低。在 Jenkins 中,你需要自己写 Jenkinsfile,但这恰恰给了你更大的控制权——精确控制审查在流水线中的位置、结果的消费方式、以及门禁的严格程度。
从一个 PR 开始,从一个.opencodereview/rule.json开始,从一条 SARIF 告警开始。当recordIssues因为第一条 error 级别告警把构建标红时,审查闭环就真正转起来了。剩下的,是规则迭代和度量校准的持续工作——那是另一个故事的开始。