Skip to content

Commit dcd0594

Browse files
committed
test: add CI workflow validation tests
1 parent 74cde20 commit dcd0594

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

tests/scripts/ci-workflow.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { describe, expect, test } from 'bun:test';
2+
import { readFileSync } from 'node:fs';
3+
4+
const REQUIRED_CI_INPUT_PATHS = [
5+
'.github/workflows/**',
6+
'src/**',
7+
'scripts/**',
8+
'tests/**',
9+
'bun.lock',
10+
'tsconfig.json',
11+
'tsconfig.build.json',
12+
'biome.json',
13+
'knip.ts',
14+
'sgconfig.yml',
15+
'ast-grep/**',
16+
] as const;
17+
18+
function readWorkflow(): string {
19+
return readFileSync(new URL('../../.github/workflows/ci.yml', import.meta.url), 'utf8');
20+
}
21+
22+
function extractPaths(workflow: string, eventName: 'push' | 'pull_request'): string[] {
23+
const lines = workflow.split('\n');
24+
const eventIndex = lines.findIndex((line) => line.trim() === `${eventName}:`);
25+
if (eventIndex === -1) {
26+
throw new Error(`Missing ${eventName} event in ci workflow`);
27+
}
28+
29+
const eventIndent = lines[eventIndex]?.match(/^\s*/)?.[0].length ?? 0;
30+
const eventLines: string[] = [];
31+
32+
for (const line of lines.slice(eventIndex + 1)) {
33+
const trimmed = line.trim();
34+
const indent = line.match(/^\s*/)?.[0].length ?? 0;
35+
if (trimmed && indent <= eventIndent) {
36+
break;
37+
}
38+
eventLines.push(line);
39+
}
40+
41+
const pathsIndex = eventLines.findIndex((line) => line.trim() === 'paths:');
42+
if (pathsIndex === -1) {
43+
throw new Error(`Missing paths filter for ${eventName} in ci workflow`);
44+
}
45+
46+
const pathsIndent = eventLines[pathsIndex]?.match(/^\s*/)?.[0].length ?? 0;
47+
const paths: string[] = [];
48+
49+
for (const line of eventLines.slice(pathsIndex + 1)) {
50+
const trimmed = line.trim();
51+
const indent = line.match(/^\s*/)?.[0].length ?? 0;
52+
if (trimmed && indent <= pathsIndent) {
53+
break;
54+
}
55+
if (trimmed.startsWith('- ')) {
56+
paths.push(trimmed.slice(2).replaceAll('"', ''));
57+
}
58+
}
59+
60+
return paths;
61+
}
62+
63+
describe('CI workflow trigger filters', () => {
64+
test('push still validates all build and static-analysis inputs', () => {
65+
const pushPaths = extractPaths(readWorkflow(), 'push');
66+
67+
for (const requiredPath of REQUIRED_CI_INPUT_PATHS) {
68+
expect(pushPaths).toContain(requiredPath);
69+
}
70+
});
71+
72+
test('push does not include generated release artifacts', () => {
73+
const pushPaths = extractPaths(readWorkflow(), 'push');
74+
75+
expect(pushPaths).not.toContain('assets/**');
76+
expect(pushPaths).not.toContain('package.json');
77+
});
78+
79+
test('pull requests still validate workflow and package changes', () => {
80+
const pullRequestPaths = extractPaths(readWorkflow(), 'pull_request');
81+
82+
for (const requiredPath of REQUIRED_CI_INPUT_PATHS) {
83+
expect(pullRequestPaths).toContain(requiredPath);
84+
}
85+
86+
expect(pullRequestPaths).toContain('assets/**');
87+
expect(pullRequestPaths).toContain('package.json');
88+
});
89+
});

0 commit comments

Comments
 (0)