ci(docs): fail OPEN when the Build Docs path gate cannot compute its diff (#3723) - #3744
Merged
Merged
Conversation
…diff (#3723) `ci.yml`'s `docs` job decided whether to build the site from CHANGED=$(git diff --name-only BASE...HEAD -- 'apps/site/' 'content/' 2>/dev/null || echo "") which collapses two different facts into one empty string: "the diff succeeded and nothing docs-related changed" (correctly a skip) and "the diff could not be computed at all" — a checkout that did not fetch deep enough, a transient git failure, a malformed sha. The second case skipped the entire site build and the job still reported success: no red step, no warning, nothing in the summary. objectstack#4928 named this the filter contract after the same shape produced a fully green, zero-job pull request: when the filter cannot tell, RUN. The capture is now the fail-open form the four gates PR #3722 added to this workflow already use — `if ! CHANGED=$(git diff …); then should_run=true; exit 0; fi`, with the revision range quoted so a malformed sha reaches git as one argument and is rejected rather than word-split. Measured by executing this step's own `run:` script (pulled out of the parsed YAML, `${{ … }}` substituted) against a fixture repository: unreachable base sha `should_run=false` -> `true`; docs changed `true` -> `true`; only code changed `false` -> `false`. Which pull requests pay for a site build is unchanged. Two things found while measuring, both now written into the step: - Failing open does NOT cover an empty revision range. With no `github.event.pull_request` payload the range interpolates to a bare `...`, which git reads as `HEAD...HEAD` and exits 0 with no output — so the `!= 'pull_request'` early return #3722 added is what covers the queue and push lanes, not the diff. - `2>/dev/null` is dropped as well as `|| echo ""`. It hid git's own explanation of the failure from the run log, which is the only diagnostic a reader of a skipped build gets. `merge-queue-reporting.test.ts`'s fail-open assertion was a single whole-file `toMatch` per workflow, so ci.yml's three fail-open captures satisfied it on the `docs` gate's behalf — the file was green with the defect in it (measured: 10/10 on the pre-fix tree). It is now per CAPTURE: every `CHANGED=$(git diff …)` in `ci.yml` and `lint.yml` must open as `if ! …`, with a per-file floor so deleting a gate's capture cannot make the check vacuously green, plus a second test rejecting `|| echo ""` and `2>/dev/null` anywhere in the gates — `if !` wrapped around a swallow is fail-closed with the safe spelling around it. No changeset: CI configuration only, no published package changes, in line with #3722 and the three `ci.yml` commits before it. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
yinlianghui
marked this pull request as ready for review
August 8, 2026 11:24
This was referenced Aug 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3723
问题
ci.yml的docsjob(Build Docs)用这一句决定要不要构建站点:CHANGED=$(git diff --name-only BASE...HEAD -- 'apps/site/' 'content/' 2>/dev/null || echo "")2>/dev/null || echo ""把两件完全不同的事压成同一个空串:apps/site/与content/下确实没变 —— 该跳过,正确;objectstack#4928 把这条命名为 filter 契约:filter 拿不准的时候必须 RUN。PR #3722 给本 workflow 新加的四个门禁(
type-check/test/e2e/lint)全是 fail-open 拼法,这一处成了唯一的例外。改法(
.github/workflows/ci.yml,docs job 一步)捕获改成与那四个门禁同一个形状:
if ! CHANGED=$(git diff …); then should_run=true; exit 0; fi,revision range 加单引号(畸形 sha 会作为一个参数递给 git 被拒,而不是被词法拆开),并沿用它们的说明性注释形状。验证方式不是手抄一遍逻辑,而是把这一步真实的
run:脚本从解析后的 YAML 里取出来、替换${{ … }}后在 fixture 仓库里执行:should_run=false(静默全跳)should_run=true(Could not diff against the merge base)truetruefalsefalsemerge_group队列构建truetruetruetrue也就是说:哪些 PR 需要付一次站点构建的代价没有变,只有"算不出来"这一格从静默跳过翻成了运行。
测量中另外确认了两件事,都已写进步骤注释:
github.event.pull_requestpayload 时,range 会插值成一个裸的...,git 把它读成HEAD...HEAD,exit 0 且无输出(已实测)—— 所以覆盖队列与 push 两条 lane 的是 ci: subscribe the four gate workflows to merge_group, and move ci/lint path filtering into the jobs (#3523 steps 1-2) #3722 加的!= 'pull_request'提前返回,不是 diff 本身。这一条本来容易被当成冗余删掉。2>/dev/null与|| echo ""一起删。 它把 git 自己对失败原因的说明从 run log 里抹掉了,而那是"构建为什么被跳过"的读者唯一能拿到的诊断。顺带修掉
type-checkjob 里那段注释:它原本写着"下面docsjob 的|| echo ""是 fail-CLOSED 拼法",本 PR 之后这句话就是错的——同一个文件里留一句与代码相反的断言,比不写更糟。钉面(
scripts/__tests__/merge-queue-reporting.test.ts)原来的 fail-open 断言是按文件的一条
toMatch,所以它看不见docs这一处:ci.yml 里三个 fail-open 捕获替docs门禁满足了正则,整份文件带着缺陷仍然全绿(实测:改前的树上 10/10 通过)。现在改成按捕获:ci.yml/lint.yml里每一处CHANGED=$(git diff …)(先剥注释——两个 workflow 现在都在正文里讨论这个形状)都必须以if !开头;新加的第六个门禁写成 closed 拼法会立刻红,不需要有人记得来改这个测试;type-check/test/e2e/docs;lint.yml 1 个:lint),否则"删掉某个门禁的捕获"会让上面那条断言拿到空列表——因为什么都没产出而绿,不是因为逻辑对;|| echo ""或2>/dev/null。if ! CHANGED=$(git diff … || echo "")形状上是 fail-open,实际不是——|| echo ""让命令无论 git 如何都成功,失败分支不可达,等于把安全拼法套在 fail-closed 外面。反向验证(方向先预测,后测量)
预测:把 ci.yml 的拼法回退到 origin/main,恰好 2 条测试变红,9 条仍绿(捕获数量仍是 4,下界那条应当保持绿)。实测一致:
门禁
scripts/全跑是刻意的:ci-cd-pipeline-doc.test.ts也读.github/workflows/(按 job 与按命令两个方向钉content/docs/guide/ci-cd-pipeline.md的表格),本改动没有增删任何 first-party 命令,它保持绿。仓库里没有 workflow linter(package.json与.github/workflows/均无 actionlint),所以 YAML 的合法性由上面那个"解析 YAML 取出run:再执行"的模拟顺带覆盖。content/docs/guide/ci-cd-pipeline.md不需要改:它第 116 行本来就写着 "The gate fails open — if the diff cannot be computed the job runs everything",而那一段同时点了docsjob 的名。本 PR 之前这句话对docs是过度声明,之后才真正成立。无 changeset:纯 CI 配置,无已发布包的行为变化——与 #3722 及它之前三个
ci.yml提交(#3659 / #3547 / #3550)的先例一致。Generated by Claude Code