cistack 5.5.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/analyzers/codebase.js +53 -0
- package/src/detectors/framework.js +6 -6
- package/src/detectors/testing.js +37 -5
- package/src/generators/workflow.js +3 -63
- package/tests/run.js +38 -63
package/package.json
CHANGED
|
@@ -127,25 +127,78 @@ class CodebaseAnalyzer {
|
|
|
127
127
|
'composer.json',
|
|
128
128
|
// Build tools
|
|
129
129
|
'vite.config.js',
|
|
130
|
+
'vite.config.cjs',
|
|
131
|
+
'vite.config.mjs',
|
|
130
132
|
'vite.config.ts',
|
|
133
|
+
'vite.config.cts',
|
|
134
|
+
'vite.config.mts',
|
|
131
135
|
'webpack.config.js',
|
|
136
|
+
'webpack.config.cjs',
|
|
137
|
+
'webpack.config.mjs',
|
|
132
138
|
'webpack.config.ts',
|
|
139
|
+
'webpack.config.cts',
|
|
140
|
+
'webpack.config.mts',
|
|
133
141
|
'rollup.config.js',
|
|
142
|
+
'rollup.config.cjs',
|
|
143
|
+
'rollup.config.mjs',
|
|
144
|
+
'rollup.config.ts',
|
|
145
|
+
'rollup.config.cts',
|
|
146
|
+
'rollup.config.mts',
|
|
147
|
+
'next.config.js',
|
|
148
|
+
'next.config.cjs',
|
|
149
|
+
'next.config.mjs',
|
|
150
|
+
'next.config.ts',
|
|
151
|
+
'next.config.cts',
|
|
152
|
+
'next.config.mts',
|
|
153
|
+
'nuxt.config.js',
|
|
154
|
+
'nuxt.config.cjs',
|
|
155
|
+
'nuxt.config.mjs',
|
|
156
|
+
'nuxt.config.ts',
|
|
157
|
+
'nuxt.config.cts',
|
|
158
|
+
'nuxt.config.mts',
|
|
159
|
+
'svelte.config.js',
|
|
160
|
+
'svelte.config.cjs',
|
|
161
|
+
'svelte.config.mjs',
|
|
162
|
+
'svelte.config.ts',
|
|
163
|
+
'svelte.config.cts',
|
|
164
|
+
'svelte.config.mts',
|
|
165
|
+
'astro.config.js',
|
|
166
|
+
'astro.config.cjs',
|
|
134
167
|
'turbo.json',
|
|
135
168
|
'nx.json',
|
|
136
169
|
'lerna.json',
|
|
137
170
|
'rush.json',
|
|
138
171
|
// Test
|
|
139
172
|
'jest.config.js',
|
|
173
|
+
'jest.config.cjs',
|
|
174
|
+
'jest.config.mjs',
|
|
140
175
|
'jest.config.ts',
|
|
176
|
+
'jest.config.cts',
|
|
177
|
+
'jest.config.mts',
|
|
141
178
|
'vitest.config.js',
|
|
179
|
+
'vitest.config.cjs',
|
|
180
|
+
'vitest.config.mjs',
|
|
142
181
|
'vitest.config.ts',
|
|
182
|
+
'vitest.config.cts',
|
|
183
|
+
'vitest.config.mts',
|
|
143
184
|
'cypress.config.js',
|
|
185
|
+
'cypress.config.cjs',
|
|
186
|
+
'cypress.config.mjs',
|
|
144
187
|
'cypress.config.ts',
|
|
188
|
+
'cypress.config.cts',
|
|
189
|
+
'cypress.config.mts',
|
|
145
190
|
'playwright.config.js',
|
|
191
|
+
'playwright.config.cjs',
|
|
192
|
+
'playwright.config.mjs',
|
|
146
193
|
'playwright.config.ts',
|
|
194
|
+
'playwright.config.cts',
|
|
195
|
+
'playwright.config.mts',
|
|
147
196
|
'.mocharc.js',
|
|
197
|
+
'.mocharc.cjs',
|
|
198
|
+
'.mocharc.mjs',
|
|
148
199
|
'.mocharc.yml',
|
|
200
|
+
'.mocharc.yaml',
|
|
201
|
+
'.mocharc.json',
|
|
149
202
|
'phpunit.xml',
|
|
150
203
|
'pytest.ini',
|
|
151
204
|
'conftest.py',
|
|
@@ -19,16 +19,16 @@ class FrameworkDetector {
|
|
|
19
19
|
async detect() {
|
|
20
20
|
const results = [
|
|
21
21
|
// JS / TS frontend
|
|
22
|
-
this._check('Next.js', ['next'], ['next.config.js', 'next.config.
|
|
23
|
-
this._check('Nuxt', ['nuxt', 'nuxt3'], ['nuxt.config.js', 'nuxt.config.ts'], { buildDir: '.nuxt', priority: 10 }),
|
|
24
|
-
this._check('SvelteKit', ['@sveltejs/kit'], ['svelte.config.js'], { buildDir: '.svelte-kit', priority: 10 }),
|
|
22
|
+
this._check('Next.js', ['next'], ['next.config.js', 'next.config.cjs', 'next.config.mjs', 'next.config.ts', 'next.config.cts', 'next.config.mts'], { buildDir: '.next', priority: 10 }),
|
|
23
|
+
this._check('Nuxt', ['nuxt', 'nuxt3'], ['nuxt.config.js', 'nuxt.config.cjs', 'nuxt.config.mjs', 'nuxt.config.ts', 'nuxt.config.cts', 'nuxt.config.mts'], { buildDir: '.nuxt', priority: 10 }),
|
|
24
|
+
this._check('SvelteKit', ['@sveltejs/kit'], ['svelte.config.js', 'svelte.config.cjs', 'svelte.config.mjs', 'svelte.config.ts', 'svelte.config.cts', 'svelte.config.mts'], { buildDir: '.svelte-kit', priority: 10 }),
|
|
25
25
|
this._check('Remix', ['@remix-run/react', '@remix-run/node'], [], { priority: 10 }),
|
|
26
|
-
this._check('Astro', ['astro'], ['astro.config.mjs', 'astro.config.ts'], { buildDir: 'dist', priority: 10 }),
|
|
27
|
-
this._check('Vite', ['vite'], ['vite.config.js', 'vite.config.ts'], { buildDir: 'dist', priority: 5 }),
|
|
26
|
+
this._check('Astro', ['astro'], ['astro.config.js', 'astro.config.cjs', 'astro.config.mjs', 'astro.config.ts'], { buildDir: 'dist', priority: 10 }),
|
|
27
|
+
this._check('Vite', ['vite'], ['vite.config.js', 'vite.config.cjs', 'vite.config.mjs', 'vite.config.ts', 'vite.config.cts', 'vite.config.mts'], { buildDir: 'dist', priority: 5 }),
|
|
28
28
|
this._check('React', ['react', 'react-dom'], [], { buildDir: 'build', priority: 1 }),
|
|
29
29
|
this._check('Vue', ['vue'], [], { buildDir: 'dist', priority: 1 }),
|
|
30
30
|
this._check('Angular', ['@angular/core'], [], { buildDir: 'dist', priority: 1 }),
|
|
31
|
-
this._check('Svelte', ['svelte'], ['svelte.config.js'], { buildDir: 'public', priority: 1 }),
|
|
31
|
+
this._check('Svelte', ['svelte'], ['svelte.config.js', 'svelte.config.cjs', 'svelte.config.mjs', 'svelte.config.ts', 'svelte.config.cts', 'svelte.config.mts'], { buildDir: 'public', priority: 1 }),
|
|
32
32
|
this._check('Gatsby', ['gatsby'], [], { buildDir: 'public', priority: 1 }),
|
|
33
33
|
this._check('Ember', ['ember-cli'], [], { priority: 1 }),
|
|
34
34
|
// Node / backend
|
package/src/detectors/testing.js
CHANGED
|
@@ -46,7 +46,14 @@ class TestingDetector {
|
|
|
46
46
|
_checkJest() {
|
|
47
47
|
let conf = 0;
|
|
48
48
|
if (this.deps['jest'] || this.deps['@jest/core']) conf += 0.5;
|
|
49
|
-
if (this.
|
|
49
|
+
if (this._hasConfig([
|
|
50
|
+
'jest.config.js',
|
|
51
|
+
'jest.config.cjs',
|
|
52
|
+
'jest.config.mjs',
|
|
53
|
+
'jest.config.ts',
|
|
54
|
+
'jest.config.cts',
|
|
55
|
+
'jest.config.mts',
|
|
56
|
+
])) conf += 0.4;
|
|
50
57
|
if (this.scripts.test && this.scripts.test.includes('jest')) conf += 0.2;
|
|
51
58
|
return { name: 'Jest', confidence: Math.min(conf, 1), command: this._testScript('jest') || 'npx jest --coverage', type: 'unit' };
|
|
52
59
|
}
|
|
@@ -54,21 +61,35 @@ class TestingDetector {
|
|
|
54
61
|
_checkVitest() {
|
|
55
62
|
let conf = 0;
|
|
56
63
|
if (this.deps['vitest']) conf += 0.6;
|
|
57
|
-
if (this.
|
|
64
|
+
if (this._hasConfig([
|
|
65
|
+
'vitest.config.js',
|
|
66
|
+
'vitest.config.cjs',
|
|
67
|
+
'vitest.config.mjs',
|
|
68
|
+
'vitest.config.ts',
|
|
69
|
+
'vitest.config.cts',
|
|
70
|
+
'vitest.config.mts',
|
|
71
|
+
])) conf += 0.4;
|
|
58
72
|
return { name: 'Vitest', confidence: Math.min(conf, 1), command: this._testScript('vitest') || 'npx vitest run --coverage', type: 'unit' };
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
_checkMocha() {
|
|
62
76
|
let conf = 0;
|
|
63
77
|
if (this.deps['mocha']) conf += 0.5;
|
|
64
|
-
if (this.
|
|
78
|
+
if (this._hasConfig(['.mocharc.js', '.mocharc.cjs', '.mocharc.mjs', '.mocharc.yml', '.mocharc.yaml', '.mocharc.json'])) conf += 0.4;
|
|
65
79
|
return { name: 'Mocha', confidence: Math.min(conf, 1), command: 'npx mocha', type: 'unit' };
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
_checkCypress() {
|
|
69
83
|
let conf = 0;
|
|
70
84
|
if (this.deps['cypress']) conf += 0.6;
|
|
71
|
-
if (this.
|
|
85
|
+
if (this._hasConfig([
|
|
86
|
+
'cypress.config.js',
|
|
87
|
+
'cypress.config.cjs',
|
|
88
|
+
'cypress.config.mjs',
|
|
89
|
+
'cypress.config.ts',
|
|
90
|
+
'cypress.config.cts',
|
|
91
|
+
'cypress.config.mts',
|
|
92
|
+
])) conf += 0.4;
|
|
72
93
|
if (this.files.has('cypress/e2e') || [...this.files].some((f) => f.startsWith('cypress/'))) conf += 0.2;
|
|
73
94
|
return { name: 'Cypress', confidence: Math.min(conf, 1), command: 'npx cypress run', type: 'e2e' };
|
|
74
95
|
}
|
|
@@ -76,7 +97,14 @@ class TestingDetector {
|
|
|
76
97
|
_checkPlaywright() {
|
|
77
98
|
let conf = 0;
|
|
78
99
|
if (this.deps['@playwright/test']) conf += 0.6;
|
|
79
|
-
if (this.
|
|
100
|
+
if (this._hasConfig([
|
|
101
|
+
'playwright.config.js',
|
|
102
|
+
'playwright.config.cjs',
|
|
103
|
+
'playwright.config.mjs',
|
|
104
|
+
'playwright.config.ts',
|
|
105
|
+
'playwright.config.cts',
|
|
106
|
+
'playwright.config.mts',
|
|
107
|
+
])) conf += 0.4;
|
|
80
108
|
return { name: 'Playwright', confidence: Math.min(conf, 1), command: 'npx playwright test', type: 'e2e' };
|
|
81
109
|
}
|
|
82
110
|
|
|
@@ -148,6 +176,10 @@ class TestingDetector {
|
|
|
148
176
|
if (this.packageManager === 'bun') return `bun run ${name}`;
|
|
149
177
|
return `npm run ${name}`;
|
|
150
178
|
}
|
|
179
|
+
|
|
180
|
+
_hasConfig(candidates) {
|
|
181
|
+
return candidates.some((candidate) => this.configs.has(candidate));
|
|
182
|
+
}
|
|
151
183
|
}
|
|
152
184
|
|
|
153
185
|
module.exports = TestingDetector;
|
|
@@ -188,29 +188,6 @@ class WorkflowGenerator {
|
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
// ── lighthouse job ──────────────────────────────────────────────────
|
|
192
|
-
if (jobs.build && this.frameworks.some(f => ['Next.js', 'React', 'Vue', 'Svelte', 'Nuxt'].includes(f.name))) {
|
|
193
|
-
jobs.lighthouse = {
|
|
194
|
-
name: '⚡ Lighthouse Audit',
|
|
195
|
-
'runs-on': 'ubuntu-latest',
|
|
196
|
-
needs: ['build'],
|
|
197
|
-
if: "github.event_name == 'pull_request'",
|
|
198
|
-
steps: [
|
|
199
|
-
this._stepCheckout(),
|
|
200
|
-
{
|
|
201
|
-
name: 'Run Lighthouse on build output',
|
|
202
|
-
uses: 'treosh/lighthouse-ci-action@v11',
|
|
203
|
-
with: {
|
|
204
|
-
uploadArtifacts: true,
|
|
205
|
-
temporaryPublicStorage: true,
|
|
206
|
-
...this._lighthouseActionConfig(),
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
|
-
],
|
|
210
|
-
'continue-on-error': true,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
191
|
// ── e2e job ───────────────────────────────────────────────────────────
|
|
215
192
|
if (this.e2eTests.length > 0) {
|
|
216
193
|
const e2eTest = this.e2eTests[0];
|
|
@@ -339,38 +316,6 @@ class WorkflowGenerator {
|
|
|
339
316
|
},
|
|
340
317
|
};
|
|
341
318
|
|
|
342
|
-
if (buildablePackages.length > 0 && this.frameworks.some(f => ['Next.js', 'React', 'Vue', 'Svelte', 'Nuxt'].includes(f.name))) {
|
|
343
|
-
workflow.jobs.lighthouse = {
|
|
344
|
-
name: '⚡ Lighthouse (Root)',
|
|
345
|
-
'runs-on': 'ubuntu-latest',
|
|
346
|
-
strategy: {
|
|
347
|
-
matrix: {
|
|
348
|
-
include: buildablePackages,
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
steps: [
|
|
352
|
-
this._stepCheckout(),
|
|
353
|
-
...this._setupSteps(lang),
|
|
354
|
-
{
|
|
355
|
-
...this._stepInstallDeps(lang),
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
name: 'Build workspace',
|
|
359
|
-
run: this._workspaceRunCommand(lang, '${{ matrix.buildScript }}'),
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
name: 'Lighthouse',
|
|
363
|
-
uses: 'treosh/lighthouse-ci-action@v11',
|
|
364
|
-
with: {
|
|
365
|
-
uploadArtifacts: true,
|
|
366
|
-
temporaryPublicStorage: true,
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
],
|
|
370
|
-
'continue-on-error': true,
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
|
|
374
319
|
return this._toYaml(
|
|
375
320
|
workflow,
|
|
376
321
|
`# Generated by cistack v${version} — https://github.com/cistack\n# Monorepo CI — matrix over all workspaces\n\n`
|
|
@@ -698,11 +643,6 @@ class WorkflowGenerator {
|
|
|
698
643
|
return steps;
|
|
699
644
|
}
|
|
700
645
|
|
|
701
|
-
_lighthouseActionConfig() {
|
|
702
|
-
const configPath = path.join(this.projectPath, '.lighthouserc.json');
|
|
703
|
-
return fs.existsSync(configPath) ? { configPath: './.lighthouserc.json' } : {};
|
|
704
|
-
}
|
|
705
|
-
|
|
706
646
|
_stepInstallDeps(lang) {
|
|
707
647
|
const pm = lang.packageManager;
|
|
708
648
|
if (pm === 'npm') return { name: 'Install dependencies', run: this.lockFiles.has('package-lock.json') ? 'npm ci' : 'npm install' };
|
|
@@ -890,9 +830,9 @@ class WorkflowGenerator {
|
|
|
890
830
|
{
|
|
891
831
|
name: 'Validate Vercel credentials',
|
|
892
832
|
run: [
|
|
893
|
-
'test -n "$VERCEL_TOKEN" || (echo "Missing VERCEL_TOKEN secret. Add it in GitHub Actions secrets." && exit 1)',
|
|
894
|
-
'test -n "$VERCEL_ORG_ID" || (echo "Missing VERCEL_ORG_ID secret. Add it in GitHub Actions secrets." && exit 1)',
|
|
895
|
-
'test -n "$VERCEL_PROJECT_ID" || (echo "Missing VERCEL_PROJECT_ID secret. Add it in GitHub Actions secrets." && exit 1)',
|
|
833
|
+
'test -n "$VERCEL_TOKEN" || (echo "Missing VERCEL_TOKEN secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs." && exit 1)',
|
|
834
|
+
'test -n "$VERCEL_ORG_ID" || (echo "Missing VERCEL_ORG_ID secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs." && exit 1)',
|
|
835
|
+
'test -n "$VERCEL_PROJECT_ID" || (echo "Missing VERCEL_PROJECT_ID secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs." && exit 1)',
|
|
896
836
|
].join('\n'),
|
|
897
837
|
env: vercelEnv,
|
|
898
838
|
},
|
package/tests/run.js
CHANGED
|
@@ -151,6 +151,22 @@ test('FrameworkDetector detects Spring Boot from build.gradle.kts', async () =>
|
|
|
151
151
|
assert(frameworks.some((framework) => framework.name === 'Spring Boot'));
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
+
test('FrameworkDetector recognizes modern framework config files like next.config.mjs', async () => {
|
|
155
|
+
const projectDir = makeTempDir();
|
|
156
|
+
writeFiles(projectDir, {
|
|
157
|
+
'package.json': json({
|
|
158
|
+
name: 'next-config-mjs-app',
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
}),
|
|
161
|
+
'next.config.mjs': 'export default {};\n',
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const info = await new CodebaseAnalyzer(projectDir).analyse();
|
|
165
|
+
const frameworks = await new FrameworkDetector(projectDir, info).detect();
|
|
166
|
+
|
|
167
|
+
assert(frameworks.some((framework) => framework.name === 'Next.js'));
|
|
168
|
+
});
|
|
169
|
+
|
|
154
170
|
test('HostingDetector recognizes Azure pipelines in azure/pipelines.yml', async () => {
|
|
155
171
|
const projectDir = makeTempDir();
|
|
156
172
|
writeFiles(projectDir, {
|
|
@@ -274,6 +290,24 @@ test('ReleaseDetector reads release-it CJS config and honors npm.publish false',
|
|
|
274
290
|
assert.equal(release.requiresNpmToken, false);
|
|
275
291
|
});
|
|
276
292
|
|
|
293
|
+
test('TestingDetector recognizes modern config file extensions like vitest.config.mjs', async () => {
|
|
294
|
+
const projectDir = makeTempDir();
|
|
295
|
+
writeFiles(projectDir, {
|
|
296
|
+
'package.json': json({
|
|
297
|
+
name: 'modern-vitest-app',
|
|
298
|
+
version: '1.0.0',
|
|
299
|
+
}),
|
|
300
|
+
'vitest.config.mjs': 'export default {};\n',
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const info = await new CodebaseAnalyzer(projectDir).analyse();
|
|
304
|
+
const testing = await new TestingDetector(projectDir, info).detect();
|
|
305
|
+
const vitest = testing.find((entry) => entry.name === 'Vitest');
|
|
306
|
+
|
|
307
|
+
assert(vitest);
|
|
308
|
+
assert(vitest.confidence > 0);
|
|
309
|
+
});
|
|
310
|
+
|
|
277
311
|
test('bun.lock is recognized as Bun across codebase, testing, and release detection', async () => {
|
|
278
312
|
const projectDir = makeTempDir();
|
|
279
313
|
writeFiles(projectDir, {
|
|
@@ -440,9 +474,9 @@ test('Vercel deploy workflows validate secrets before running vercel pull', () =
|
|
|
440
474
|
const pullStep = deploySteps.find((step) => step.name === 'Pull Vercel environment');
|
|
441
475
|
|
|
442
476
|
assert(validateStep);
|
|
443
|
-
assert(validateStep.run.includes('Missing VERCEL_TOKEN secret'));
|
|
444
|
-
assert(validateStep.run.includes('Missing VERCEL_ORG_ID secret'));
|
|
445
|
-
assert(validateStep.run.includes('Missing VERCEL_PROJECT_ID secret'));
|
|
477
|
+
assert(validateStep.run.includes('Missing VERCEL_TOKEN secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs.'));
|
|
478
|
+
assert(validateStep.run.includes('Missing VERCEL_ORG_ID secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs.'));
|
|
479
|
+
assert(validateStep.run.includes('Missing VERCEL_PROJECT_ID secret. Add it in GitHub Actions secrets, or Dependabot secrets for Dependabot PRs.'));
|
|
446
480
|
assert.equal(pullStep.run, 'vercel pull --yes --environment=production --token="$VERCEL_TOKEN"');
|
|
447
481
|
});
|
|
448
482
|
|
|
@@ -494,64 +528,6 @@ test('Frontend Lighthouse is omitted when no build job exists', () => {
|
|
|
494
528
|
assert(!parsed.jobs.lighthouse);
|
|
495
529
|
});
|
|
496
530
|
|
|
497
|
-
test('Lighthouse job does not require .lighthouserc.json when the file is absent', () => {
|
|
498
|
-
const projectDir = makeTempDir();
|
|
499
|
-
writeFiles(projectDir, {
|
|
500
|
-
'package.json': json({
|
|
501
|
-
name: 'lighthouse-default-app',
|
|
502
|
-
version: '1.0.0',
|
|
503
|
-
scripts: {
|
|
504
|
-
build: 'echo build',
|
|
505
|
-
},
|
|
506
|
-
}),
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
const generator = new WorkflowGenerator(
|
|
510
|
-
makeJsProject({
|
|
511
|
-
frameworks: [{ name: 'React', confidence: 1, buildDir: 'dist' }],
|
|
512
|
-
}),
|
|
513
|
-
projectDir
|
|
514
|
-
);
|
|
515
|
-
|
|
516
|
-
const parsed = parseWorkflow(generator._buildCIWorkflow());
|
|
517
|
-
const lighthouseStep = parsed.jobs.lighthouse.steps.find((step) => step.name === 'Run Lighthouse on build output');
|
|
518
|
-
|
|
519
|
-
assert(lighthouseStep);
|
|
520
|
-
assert(!('configPath' in lighthouseStep.with));
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
test('Lighthouse job uses .lighthouserc.json when the file exists', () => {
|
|
524
|
-
const projectDir = makeTempDir();
|
|
525
|
-
writeFiles(projectDir, {
|
|
526
|
-
'package.json': json({
|
|
527
|
-
name: 'lighthouse-config-app',
|
|
528
|
-
version: '1.0.0',
|
|
529
|
-
scripts: {
|
|
530
|
-
build: 'echo build',
|
|
531
|
-
},
|
|
532
|
-
}),
|
|
533
|
-
'.lighthouserc.json': json({
|
|
534
|
-
ci: {
|
|
535
|
-
collect: {
|
|
536
|
-
numberOfRuns: 1,
|
|
537
|
-
},
|
|
538
|
-
},
|
|
539
|
-
}),
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
const generator = new WorkflowGenerator(
|
|
543
|
-
makeJsProject({
|
|
544
|
-
frameworks: [{ name: 'React', confidence: 1, buildDir: 'dist' }],
|
|
545
|
-
}),
|
|
546
|
-
projectDir
|
|
547
|
-
);
|
|
548
|
-
|
|
549
|
-
const parsed = parseWorkflow(generator._buildCIWorkflow());
|
|
550
|
-
const lighthouseStep = parsed.jobs.lighthouse.steps.find((step) => step.name === 'Run Lighthouse on build output');
|
|
551
|
-
|
|
552
|
-
assert.equal(lighthouseStep.with.configPath, './.lighthouserc.json');
|
|
553
|
-
});
|
|
554
|
-
|
|
555
531
|
test('E2E jobs fall back to existing jobs instead of depending on a missing build job', () => {
|
|
556
532
|
const projectDir = makeTempDir();
|
|
557
533
|
const generator = new WorkflowGenerator(
|
|
@@ -929,7 +905,6 @@ test('Monorepo root CI installs dependencies at the repo root and does not hide
|
|
|
929
905
|
const lintStep = ciSteps.find((step) => step.name === 'Lint');
|
|
930
906
|
const testStep = ciSteps.find((step) => step.name === 'Test');
|
|
931
907
|
const buildStep = ciSteps.find((step) => step.name === 'Build');
|
|
932
|
-
const lighthouseBuildStep = rootWorkflow.jobs.lighthouse.steps.find((step) => step.name === 'Build workspace');
|
|
933
908
|
|
|
934
909
|
assert.equal(installStep.run, 'yarn install --frozen-lockfile');
|
|
935
910
|
assert.equal(lintStep.if, '${{ matrix.lintScript != \'\' }}');
|
|
@@ -938,7 +913,7 @@ test('Monorepo root CI installs dependencies at the repo root and does not hide
|
|
|
938
913
|
assert(!lintStep.run.includes('|| true'));
|
|
939
914
|
assert(!testStep.run.includes('|| true'));
|
|
940
915
|
assert(!buildStep.run.includes('|| true'));
|
|
941
|
-
assert
|
|
916
|
+
assert(!rootWorkflow.jobs.lighthouse);
|
|
942
917
|
});
|
|
943
918
|
|
|
944
919
|
test('Bun monorepo matrix commands are scoped to the workspace path', () => {
|