Skip to content

Commit 994dab9

Browse files
committed
test: pin root-doc paths-ignore entries with a regression test
Addresses review feedback on #1791 from thymikee: the docs-only classifier for AGENTS.md/CHANGELOG.md/CONTEXT.md/CONTRIBUTING.md/ LICENSE/SECURITY.md across ios.yml/android.yml/linux.yml/macos.yml/ ci.yml/size.yml had no regression pin. Neither check:gate-manifest (only proves a *registered check* is reachable) nor actionlint (only validates YAML shape) nor generic Markdown coverage would catch a single dropped entry — e.g. LICENSE reappearing in one workflow's paths-ignore list but not another's would silently put a full 9-15 min device run back on prose-only PRs. test/ci/root-docs-paths-ignore.test.ts parses the six real workflow files and asserts, using the same matchesGlob the gate-manifest model uses to decide lane triggering, that each of the six root docs is ignored by each workflow's pull_request paths-ignore. Registered in vitest.config.ts's unit-core project next to its sibling upload-agent-device-artifacts.test.ts (parse-only, no device/subprocess lane needed). Verified red on main (all 36 file x doc assertions fail — confirmed via a throwaway script reading `git show main:.github/workflows/*.yml`) and green on this branch (6/6). Full unit-core project (873 files / 6641 tests) still passes; check:gate-manifest and check:gate-manifest:test unchanged (48 checks / 33 lanes, 28/28).
1 parent 73aad1a commit 994dab9

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Regression pin for #1781 A9: the six root-level docs files
2+
// (AGENTS.md, CHANGELOG.md, CONTEXT.md, CONTRIBUTING.md, LICENSE, SECURITY.md)
3+
// must stay in the `pull_request` `paths-ignore` list of every workflow that
4+
// also ignores `docs/**`/`website/**`/`README.md` — the four device lanes plus
5+
// `ci.yml` and `size.yml`. Nothing else derives this: `check:gate-manifest`
6+
// only asks whether a *registered check* is reachable, generic Markdown
7+
// coverage does not look at workflow trigger config at all, and `actionlint`
8+
// only validates YAML shape, not policy — so a PR that quietly drops one entry
9+
// (e.g. re-adds `LICENSE` to a device workflow while missing it in `size.yml`)
10+
// would pass every other gate and put a full 9-15 min device run back on
11+
// prose-only PRs. This test reads the real workflow files and asserts the
12+
// behavior directly, via the same glob matcher the gate-manifest model uses
13+
// to decide whether a lane triggers for a given path.
14+
15+
import fs from 'node:fs';
16+
import path from 'node:path';
17+
import { expect, test } from 'vitest';
18+
import { parse } from 'yaml';
19+
import { matchesGlob } from '../../scripts/gate/workflows.ts';
20+
21+
const repoRoot = path.resolve(import.meta.dirname, '../..');
22+
23+
const WORKFLOWS = ['ios.yml', 'android.yml', 'linux.yml', 'macos.yml', 'ci.yml', 'size.yml'];
24+
25+
const ROOT_DOCS = [
26+
'AGENTS.md',
27+
'CHANGELOG.md',
28+
'CONTEXT.md',
29+
'CONTRIBUTING.md',
30+
'LICENSE',
31+
'SECURITY.md',
32+
];
33+
34+
type WorkflowDoc = {
35+
// A bare `on:` key can parse as the boolean key `true` under YAML 1.1
36+
// semantics; scripts/gate/workflows.ts already guards against this, so this
37+
// test mirrors that fallback rather than trusting `on` alone.
38+
on?: Record<string, { 'paths-ignore'?: string[] }>;
39+
true?: Record<string, { 'paths-ignore'?: string[] }>;
40+
};
41+
42+
function pathsIgnore(file: string): string[] {
43+
const doc = parse(
44+
fs.readFileSync(path.join(repoRoot, '.github/workflows', file), 'utf8'),
45+
) as WorkflowDoc;
46+
const on = doc.on ?? doc.true ?? {};
47+
return on.pull_request?.['paths-ignore'] ?? [];
48+
}
49+
50+
test.each(WORKFLOWS)('%s skips a pull_request triggered by only a root doc', (file) => {
51+
const ignored = pathsIgnore(file);
52+
for (const rootDoc of ROOT_DOCS) {
53+
expect(
54+
ignored.some((pattern) => matchesGlob(pattern, rootDoc)),
55+
`${file}'s paths-ignore must match ${rootDoc} (got ${JSON.stringify(ignored)})`,
56+
).toBe(true);
57+
}
58+
});

vitest.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ export default defineConfig({
8686
'scripts/__tests__/package-closure-audit.test.ts',
8787
// Parses CI configuration only, so this action guard needs no device or subprocess lane.
8888
'test/ci/upload-agent-device-artifacts.test.ts',
89+
// #1781 A9: pins the root-doc paths-ignore entries directly against the
90+
// real workflow YAML, parse-only like its sibling above.
91+
'test/ci/root-docs-paths-ignore.test.ts',
8992
// The frozen replay-compat corpus (#1417): parse-only, no device or
9093
// subprocess work, so it belongs in the fast lane next to the
9194
// grammar it guards.

0 commit comments

Comments
 (0)