Repository navigation
Commit cb0a2fc
ci(ui-merge): Test UI runs only the ui tests a pull request or merge group affects — the root ci.yml wires ui/scripts/select-affected-tests.mjs (#25882)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6Jao47d4XTXUAPA2geTEJykbxK)_
Fixes #25868
Part of #25677
Clause-②: no
Metadata-protocol: none
## 维护者速读(草稿)
- **改了什么:** 根 `ci.yml` 的 Test UI(16 个分片)在 pull request 和 merge queue
上不再每次跑全量 ui 测试,而是先用 objectui 原有的 `ui/scripts/select-affected-tests.mjs`
选出本次改动影响到的测试文件,只跑这些。push 到 main、每小时的 schedule 和手动触发仍然跑全量。
- **为什么改:** 合并后每个 ui PR 都跑 16 个全量分片(每片 7–14 分钟,约 190 runner-min)。在
objectui 仓库时,小 PR 只跑受影响的测试,CI 3–8 分钟。
- **风险与代价(含回滚):** 选择器漏掉的测试,要等 main 上的全量运行(每小时一次)才会发现,这是 objectui
原来就接受的取舍。选择器出错、拿不到 diff 基点时一律回退到全量,不会跳过。ui/ 之外影响所有 ui 测试的改动(根目录的
lockfile、workspace、turbo.json 等非文档文件,`patches/`,以及 ui 测试读取其构建产物的 7 个
@objectstack 包)一律全量。回滚:revert 本 PR 即恢复每次全量。
- **席位意见:**
- **你要做的:** 这是 Tier H(改了 `.github/workflows/ci.yml`),需要你批准后由席位落地。
## What changed
1. **`.github/workflows/ci.yml`, job `test-ui`** — objectui's two-step
wiring, ported:
- `Select the tests this change affects` (id `select`): `pull_request`
and `merge_group` run the selector; every other event writes
`mode=full`. Fails open: no base, a non-zero exit or no verdict line
means `mode=full`, never a skip. The exit status is captured beside the
output, not through a command substitution.
- The PR diff base is `merge-base(origin/BASE_REF, HEAD)`, the same base
Test Core uses, not the payload's frozen `base.sha`. With the frozen
sha, every commit `main` gained while the PR was open (a lockfile bump
among them) would be charged to the PR and turn it into a full run. A
merge group diffs from `merge_group.base_sha`.
- `Run the ui tests (shard N/16)` reads the output's VALUE (`affected` /
`full`). On `affected` it runs `pnpm --dir ui exec vitest run
--shard=N/16 ... FILTERS` with the filters relative to `ui/` (the vitest
root), as positionals with no separator, which is the only form
`ui/scripts/vitest-invocation-guard.mjs` accepts. On `full` it runs the
command it ran before.
- The checkout takes `fetch-depth: 0` so the base's history is there
(Test Core and Type Check UI do the same).
2. **`ui/scripts/select-affected-tests.mjs`** — the git paths already
went through `--relative` (#25728). Its own diff dropped every changed
file outside `ui/`, though, so a lockfile bump, a root `tsconfig.json`
or a `packages/spec` change selected only the always-on set (measured
below). New: `changedOutsideTree()` lists the monorepo's own changes
(git at the workspace root, `--relative` again, the `ui/` prefix
dropped), and `outsideTreeReasons()` turns them into full-run reasons:
- a workspace-root file that is not documentation, or anything under
`patches/` (the rule the selector already applied to objectui's own
root, now applied to the root this tree installs from);
- a file in a monorepo package that a ui package depends on (any field),
or that such a package depends on at run time (`dependencies` /
`peerDependencies` / `optionalDependencies`). On this tree that set is
exactly the seven packages the `ui_consumers` filter names: spec,
client, core, types, lint, formula, sdui-parser.
- Everything else outside `ui/` (other packages, docs, `.changeset/`,
`.github/`, `scripts/`) reaches ui tests only through the always-on set,
as before.
3. **`ui/scripts/__tests__/select-affected-tests-wiring.test.ts`** now
reads the root `ci.yml` (located through `workspaceRoot()`) and runs
both steps there at the monorepo root. A `git` stand-in answers
`merge-base` as HEAD and records the call, so the legs assert the step
asks for `refs/remotes/origin/main` and `HEAD`. A new leg covers a
failing merge-base: full run. The controls are unchanged.
4. **`ui/scripts/__tests__/select-affected-tests.test.ts`**: the
`ci.yml` wiring block now reads the root job (including `fetch-depth: 0`
and the 16-wide matrix). A new nested-layout fixture (`ui/` under a
parent workspace) covers each outside-tree rule in both directions. One
case runs real git in a scratch repo to show that `changedFiles` and
`changedOutsideTree` split one diff between them.
The turbo parity case (`agrees with turbo on who depends on whom`) was
already green in the merged layout on `main`. It is unchanged and still
green.
`ui/.github/workflows/ci.yml` (objectui's copy, which runs nowhere) is
left as it is; the governance-workflow audit owns it.
## Measured
Selector verdicts on this tree (`c475b45b` + this diff), from scratch
commits in a detached worktree:
| change | verdict | selected test files |
|---|---|---|
| nothing under `ui/` (this PR's own shape: workflow + `ui/scripts`) |
affected | 686 of 5810 |
| one leaf, `ui/packages/plugin-gantt/src/index.ts` | affected | 1036 of
5810 |
| `ui/packages/plugin-kanban/src/KanbanColumnSummary.ts` (reaches
app-shell) | affected | 2647 of 5810 |
| `pnpm-lock.yaml` + `packages/spec/src/index.ts`, before this diff |
affected | 686 of 5810 (the hole) |
| the same, after | full | — |
Weighted by `ui/scripts/test-shard-timings.json` (the sequencer's
per-file dataset): always-on alone is 8.8% of the summed file time,
plugin-gantt 20.2%, plugin-kanban 54.2%, `ui/packages/fields` 88.9%.
Each shard still pays its fixed cost (checkout, install, building the
seven packages). The before/after shard wall times are read from this
PR's own Test UI run, which is the always-on shape, and posted on the
card.
## Verification
- `pnpm exec vitest run scripts/__tests__/select-affected-tests.test.ts
scripts/__tests__/select-affected-tests-wiring.test.ts` (in `ui/`): 2
files, 49 tests, all pass.
- Whole `ui/scripts/__tests__` suite (`pnpm exec vitest run
scripts/__tests__` in `ui/`, head `bc79c8aa`): 190 files, 5608 passed, 2
skipped, 1 failed. The failure is
`check-pre-install-import-graph.test.ts` > "finds no pre-install gate
reaching a package" (`unresolved: scripts/objectstack-pin.mjs`, which
the cutover deleted and `ui/.github/workflows/*` still name). It fails
the same way on `c475b45b` with this diff's four files restored (37
tests, 1 failed), so it is red on `main` already and not this PR's. It
is reported to the dispatcher. That file is in the always-on set, so it
keeps running on every affected Test UI run.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran`: 63 derived, 59 run with exit 0, 4 NOT MEASURED (exit 3, built
dists absent): `check:dts-closure`, `check:dual-build-cjs-loads`,
`check:lean-entry-closure`, `check:sourcemap-no-sources-content`. These
are Build Core's guards, and Build Core runs them on this PR (`ci.yml`
is in the `core` filter).
## Acceptance notes
- A spec-only PR still runs no Test UI (the `ui` filter decides that,
unchanged). On a merge group, Test UI runs today for every entry, and
this diff makes it full for an entry that touches the seven packages or
a root install input, and affected otherwise. #25867 (merge_group ui
path diff) is the card that decides whether such an entry runs Test UI
at all.
- Vitest import overhead (card's optional note): not measured here.
---
_Generated by [Claude
Code](https://claude.ai/code/session_015oJuSyTy7Y3cm91KJMEW2m)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 487056b commit cb0a2fc
5 files changed
Lines changed: 452 additions & 65 deletions
File tree
- .github/workflows
- ui/scripts
- __tests__
- helpers
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3315 | 3315 | | |
3316 | 3316 | | |
3317 | 3317 | | |
3318 | | - | |
3319 | | - | |
3320 | | - | |
3321 | | - | |
3322 | | - | |
| 3318 | + | |
| 3319 | + | |
| 3320 | + | |
| 3321 | + | |
| 3322 | + | |
| 3323 | + | |
| 3324 | + | |
| 3325 | + | |
| 3326 | + | |
| 3327 | + | |
3323 | 3328 | | |
3324 | 3329 | | |
3325 | 3330 | | |
| |||
3336 | 3341 | | |
3337 | 3342 | | |
3338 | 3343 | | |
| 3344 | + | |
| 3345 | + | |
| 3346 | + | |
| 3347 | + | |
3339 | 3348 | | |
3340 | 3349 | | |
3341 | 3350 | | |
| |||
3386 | 3395 | | |
3387 | 3396 | | |
3388 | 3397 | | |
| 3398 | + | |
| 3399 | + | |
| 3400 | + | |
| 3401 | + | |
| 3402 | + | |
| 3403 | + | |
| 3404 | + | |
| 3405 | + | |
| 3406 | + | |
| 3407 | + | |
| 3408 | + | |
| 3409 | + | |
| 3410 | + | |
| 3411 | + | |
| 3412 | + | |
| 3413 | + | |
| 3414 | + | |
| 3415 | + | |
| 3416 | + | |
| 3417 | + | |
| 3418 | + | |
| 3419 | + | |
| 3420 | + | |
| 3421 | + | |
| 3422 | + | |
| 3423 | + | |
| 3424 | + | |
| 3425 | + | |
| 3426 | + | |
| 3427 | + | |
| 3428 | + | |
| 3429 | + | |
| 3430 | + | |
| 3431 | + | |
| 3432 | + | |
| 3433 | + | |
| 3434 | + | |
| 3435 | + | |
| 3436 | + | |
| 3437 | + | |
| 3438 | + | |
| 3439 | + | |
| 3440 | + | |
| 3441 | + | |
| 3442 | + | |
| 3443 | + | |
| 3444 | + | |
| 3445 | + | |
| 3446 | + | |
| 3447 | + | |
| 3448 | + | |
| 3449 | + | |
| 3450 | + | |
| 3451 | + | |
| 3452 | + | |
| 3453 | + | |
| 3454 | + | |
| 3455 | + | |
| 3456 | + | |
| 3457 | + | |
| 3458 | + | |
| 3459 | + | |
| 3460 | + | |
3389 | 3461 | | |
3390 | 3462 | | |
3391 | 3463 | | |
3392 | 3464 | | |
3393 | 3465 | | |
3394 | 3466 | | |
3395 | | - | |
| 3467 | + | |
| 3468 | + | |
| 3469 | + | |
| 3470 | + | |
| 3471 | + | |
| 3472 | + | |
| 3473 | + | |
| 3474 | + | |
| 3475 | + | |
| 3476 | + | |
3396 | 3477 | | |
3397 | 3478 | | |
3398 | 3479 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
15 | | - | |
16 | | - | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
| |||
0 commit comments