指南
在 CI 中运行
CI 门控 介绍发布策略以及每个退出码的含义。本页讲的是 CI 作业内部发生的部分:如何在其中安装 Oloproof,作业运行期间证据存放在哪里,如何在不解析表格的情况下读取结果,以及如何将拉取请求与其目标分支进行比较。
退出码就是门控
oloproof run 以其门控结果退出。运行它的 CI 步骤会在门控阻止时失败,这通常正是你想要的,无需额外配置:
| 退出码 | CI 步骤应当 |
|---|---|
| 0 | 通过 |
| 1 | 失败:某条规则未通过 |
| 2 | 作为构建损坏而失败:配置有误,未进行任何度量 |
| 3 | 失败或警告:测试套件无法作出判定 |
| 4 | 失败并转交给人处理 |
| 5 | 作为构建损坏而失败:运行未完成 |
退出码 3 是团队争论最多的。默认策略会在此时阻止,因为规模太小、无法作出判定的测试套件并未证明变更是安全的。如果团队希望在扩充测试套件期间让作业保持绿色,可以在策略中明确声明,而不是忽略退出码:
version: 1
block_on: [FAIL, MANUAL_REVIEW]
warn_on: [INSUFFICIENT_EVIDENCE]
rules:
- id: exact-label-floor
metric: exact_label
min: 0.70examples/support_bot/ 的同一个已存储运行,在其自身策略下以 3 阻止,在这份策略下的结果如下:
oloproof gate RUN_ID --policy advisory.yamlexact-label-floor: INSUFFICIENT_EVIDENCE (interval_overlaps_threshold)
about 1614 more cases would decide it, if the observed rate holds (1632 in total)它以 0 退出。判定没有改变。改变的只有发布动作,而它之所以改变,是因为一个经过评审的文件如此规定。
以数据形式读取结果
--json 会向标准输出每行写入一个 JSON 事件,并将面向人的表格写入标准错误,这样 CI 日志保留表格,脚本读取事件。保存为 run.ndjson 后,每一行都带有运行的 id,最后一行带有退出码:
jq -r 'select(.type == "run_started") | .run_id' run.ndjson
jq -c 'select(.type == "run_finished")' run.ndjsonrun_01M3C3WS0SBTFAG55M7ECM1EZ4
{"run_id":"run_01M3C3WS0SBTFAG55M7ECM1EZ4","timestamp":"2026-09-25T11:06:03.646415Z","type":"run_finished","status":"DECIDED","completeness":"COMPLETE","exit_code":3}进度与并发 列出了所有事件类型。
证据存放在哪里
运行存储在发起它的 oloproof.yaml 旁边的 .oloproof/store.sqlite 中,并且 oloproof init 会把 .oloproof/ 加入 .gitignore。CI 作业从一个空的存储开始,因此每个作业都会重新执行每个用例,一个作业的内容对下一个作业不可见。
这对比较影响最大,因为比较需要两个运行位于同一个存储中。一个项目的两份检出各自拥有自己的存储,因此从其中一份发起的基线运行无法在另一份中找到:
Configuration error: unknown run 'run_01M3C3XSX9KY5T8VFZXA1CVBES'OLOPROOF_HOME 让所有命令指向同一个存储,无论其 oloproof.yaml 在哪里。它所指定的目录中存放 .oloproof/store.sqlite。
在作业中安装 Oloproof
Oloproof 未发布到任何包索引,因此不存在按名称获取它的 pip install 命令。作业从 Oloproof 仓库的检出中安装它,与开发者的做法相同:使用 actions/checkout,用 repository: 指向你们团队的该仓库副本所在位置;如果仓库是私有的,再提供一个可以读取它的 token:。仓库根目录会构建该包,而该包提供 oloproof 命令。
将拉取请求与其基准分支比较
将基准分支和拉取请求并排检出,把两者都运行到同一个存储中,然后比较:
name: oloproof
on: pull_request
jobs:
evaluate:
runs-on: ubuntu-latest
env:
OLOPROOF_HOME: ${{ github.workspace }}/evidence
steps:
- uses: actions/checkout@v4
with:
path: pr
- uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
path: main
- uses: actions/checkout@v4
with:
repository: YOUR_ORG/Oloproof
token: ${{ secrets.OLOPROOF_REPO_TOKEN }}
path: oloproof-src
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install ./oloproof-src
- run: mkdir -p "$OLOPROOF_HOME"
- run: oloproof run --config main/oloproof.yaml --json > base.ndjson || true
- run: oloproof run --config pr/oloproof.yaml --json > cand.ndjson || true
- name: compare
run: |
candidate=$(jq -r 'select(.type == "run_started") | .run_id' cand.ndjson)
baseline=$(jq -r 'select(.type == "run_started") | .run_id' base.ndjson)
oloproof compare "$candidate" "$baseline" --config pr/oloproof.yaml --policy pr/compare.yamlYOUR_ORG/Oloproof 和 OLOPROOF_REPO_TOKEN 是占位符,分别代表你们的仓库副本和一个可以读取它的密钥。两个运行都带有 || true,因为这里关心的不是它们各自的门控,而是比较的退出码。
在笔记本电脑上执行相同的步骤,将脚手架生成的项目检出两次:
Comparison sha256:31ac104779bda1726ba55b661107cbe256fae5f1d831c79b1283a07651b58cbf of run_01M3C3XX4TM0WSZW8K81PHRGAW against run_01M3C3XW7X64B0Z0ACZV27WSW6 · 30 paired cases
exact_label: +0.0 points [-16.5, +16.5] · 30 paired · 0 missing · 0 excluded
Decisions
no-regression exact_label non-inferiority, margin 5.0 points INSUFFICIENT_EVIDENCE interval_overlaps_margin
Gate: BLOCK (exit 3)两个运行必须基于同一个测试套件。修改了某个用例的拉取请求会改变测试套件的摘要,此时比较会拒绝执行,而不是去配对已经不再是同一个用例的用例:
Configuration error: runs 'run_01M3C3XXVZ1X0J2PR1ZW1WVGVZ' and 'run_01M3C3XW7X64B0Z0ACZV27WSW6' used different suites (sha256:baff4f101901d9a37cd440f99b9a70032f9488891b4f590f18a81017c26ba794 and sha256:2011286a7ec00c8c31560bb6d037b54a501a15f6251ac7c2d578d0c40e226d72); comparisons pair scenario by scenario over one suite对未完成的运行进行比较会以 5 退出,与对未完成运行执行门控相同:没有可供判定的配对结果。