@smoothbricks/cli 0.10.13 → 0.10.15
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/dist/cli.js +1 -0
- package/dist/github-ci/index.d.ts +4 -3
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +25 -11
- package/dist/monorepo/ci-workflow.js +3 -3
- package/package.json +1 -1
- package/src/cli.ts +2 -0
- package/src/github-ci/index.test.ts +29 -11
- package/src/github-ci/index.ts +39 -8
- package/src/monorepo/__tests__/ci-workflow.test.ts +3 -3
- package/src/monorepo/ci-workflow.ts +3 -3
package/dist/cli.js
CHANGED
|
@@ -286,6 +286,7 @@ function buildProgram() {
|
|
|
286
286
|
.option('--mode <mode>', 'auto, affected, or run-many', 'auto')
|
|
287
287
|
.option('--configuration <configuration>')
|
|
288
288
|
.option('--stage <stage>')
|
|
289
|
+
.option('--stream-output', 'stream Nx task output without prefixes')
|
|
289
290
|
.action(async (options) => {
|
|
290
291
|
const { githubCiNxSmart } = await import('./github-ci/index.js');
|
|
291
292
|
await githubCiNxSmart(await findRepoRoot(), options);
|
|
@@ -18,7 +18,7 @@ export interface GithubActionsEventPayload {
|
|
|
18
18
|
}
|
|
19
19
|
type NxSmartMode = 'auto' | 'affected' | 'run-many';
|
|
20
20
|
export declare function cleanupGithubCiCache(root: string): Promise<void>;
|
|
21
|
-
export declare function nxSmartArgs(target: string, mode: 'affected' | 'run-many', configuration?: string, stage?: string): string[];
|
|
21
|
+
export declare function nxSmartArgs(target: string, mode: 'affected' | 'run-many', configuration?: string, stage?: string, streamOutput?: boolean): string[];
|
|
22
22
|
export declare function githubCiNxSmart(root: string, options: {
|
|
23
23
|
target: string;
|
|
24
24
|
name?: string;
|
|
@@ -26,6 +26,7 @@ export declare function githubCiNxSmart(root: string, options: {
|
|
|
26
26
|
mode?: NxSmartMode;
|
|
27
27
|
configuration?: string;
|
|
28
28
|
stage?: string;
|
|
29
|
+
streamOutput?: boolean;
|
|
29
30
|
}): Promise<void>;
|
|
30
31
|
export interface NxRunManyOptions {
|
|
31
32
|
targets: string;
|
|
@@ -53,7 +54,7 @@ export interface GithubCiNxDeployOptions {
|
|
|
53
54
|
verify?: boolean;
|
|
54
55
|
}
|
|
55
56
|
export interface GithubCiNxDeployDependencies {
|
|
56
|
-
listProjects?: (root: string, target: string, mode: 'affected' | 'run-many') => Promise<string[]>;
|
|
57
|
+
listProjects?: (root: string, target: string, mode: 'affected' | 'run-many', stage: DeploymentStage) => Promise<string[]>;
|
|
57
58
|
runNx?: (args: string[], root: string) => Promise<number>;
|
|
58
59
|
appendSummary?: (summaryPath: string, content: string) => Promise<void>;
|
|
59
60
|
appendOutput?: (outputPath: string, content: string) => Promise<void>;
|
|
@@ -64,7 +65,7 @@ export interface GithubCiNxDeployDependencies {
|
|
|
64
65
|
}
|
|
65
66
|
export declare function githubCiNxDeploy(root: string, options: GithubCiNxDeployOptions, dependencies?: GithubCiNxDeployDependencies): Promise<void>;
|
|
66
67
|
export declare function resolveDeploymentStage(explicit: string | undefined, environment: NodeJS.ProcessEnv, event: GithubActionsEventPayload | undefined): DeploymentStage;
|
|
67
|
-
export declare function selectStageDeployProjects(candidates: string[], loadProject: (project: string) => Promise<unknown>): Promise<string[]>;
|
|
68
|
+
export declare function selectStageDeployProjects(candidates: string[], stage: DeploymentStage, loadProject: (project: string) => Promise<unknown>): Promise<string[]>;
|
|
68
69
|
export interface GithubApiProcessResult {
|
|
69
70
|
exitCode: number;
|
|
70
71
|
stdout: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,KAAK,eAAe,EAA8D,MAAM,sBAAsB,CAAC;AACxH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE;QACX,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,YAAY,CAAC,EAAE;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE;YACL,IAAI,CAAC,EAAE;gBACL,SAAS,CAAC,EAAE,MAAM,CAAC;aACpB,CAAC;SACH,CAAC;KACH,CAAC;CACH;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"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"}
|
package/dist/github-ci/index.js
CHANGED
|
@@ -24,7 +24,7 @@ const isGithubDeployment = (() => {
|
|
|
24
24
|
})();
|
|
25
25
|
const isNxProjectDeployTarget = (() => {
|
|
26
26
|
const _ip0 = input => true;
|
|
27
|
-
const _io0 = input => undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets);
|
|
27
|
+
const _io0 = input => true && (undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets));
|
|
28
28
|
const _io1 = input => undefined === input.deploy || "object" === typeof input.deploy && null !== input.deploy && false === Array.isArray(input.deploy) && _io2(input.deploy);
|
|
29
29
|
const _io2 = input => _ip0(input) && (undefined === input.options || "object" === typeof input.options && null !== input.options && false === Array.isArray(input.options) && _io3(input.options));
|
|
30
30
|
const _io3 = input => _ip0(input);
|
|
@@ -32,7 +32,7 @@ const isNxProjectDeployTarget = (() => {
|
|
|
32
32
|
})();
|
|
33
33
|
const parseNxProjectDeployTarget = (() => {
|
|
34
34
|
const _ip0 = input => true;
|
|
35
|
-
const _io0 = input => undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets);
|
|
35
|
+
const _io0 = input => true && (undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets));
|
|
36
36
|
const _io1 = input => undefined === input.deploy || "object" === typeof input.deploy && null !== input.deploy && false === Array.isArray(input.deploy) && _io2(input.deploy);
|
|
37
37
|
const _io2 = input => _ip0(input) && (undefined === input.options || "object" === typeof input.options && null !== input.options && false === Array.isArray(input.options) && _io3(input.options));
|
|
38
38
|
const _io3 = input => _ip0(input);
|
|
@@ -138,7 +138,7 @@ async function addReferencesFrom(roots, path, cwd) {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
export function nxSmartArgs(target, mode, configuration, stage) {
|
|
141
|
+
export function nxSmartArgs(target, mode, configuration, stage, streamOutput = false) {
|
|
142
142
|
const args = [mode, '-t', target];
|
|
143
143
|
if (configuration) {
|
|
144
144
|
args.push(`--configuration=${configuration}`);
|
|
@@ -146,6 +146,9 @@ export function nxSmartArgs(target, mode, configuration, stage) {
|
|
|
146
146
|
if (stage) {
|
|
147
147
|
args.push(`--stage=${stage}`);
|
|
148
148
|
}
|
|
149
|
+
if (streamOutput) {
|
|
150
|
+
args.push('--outputStyle=stream-without-prefixes');
|
|
151
|
+
}
|
|
149
152
|
args.push(`--exclude=tag:ci:skip:${target}`, `--parallel=${NX_PARALLEL}`);
|
|
150
153
|
return args;
|
|
151
154
|
}
|
|
@@ -154,7 +157,7 @@ export async function githubCiNxSmart(root, options) {
|
|
|
154
157
|
const step = options.step ?? '';
|
|
155
158
|
await createGithubStatus(name, step);
|
|
156
159
|
const mode = resolveNxSmartMode(options.mode ?? 'auto');
|
|
157
|
-
const nxArgs = nxSmartArgs(options.target, mode, options.configuration, options.stage);
|
|
160
|
+
const nxArgs = nxSmartArgs(options.target, mode, options.configuration, options.stage, options.streamOutput);
|
|
158
161
|
const status = await runStatus('nx', nxArgs, root);
|
|
159
162
|
await updateGithubStatus(name, status === 0 ? 'success' : 'failure', step);
|
|
160
163
|
if (status !== 0) {
|
|
@@ -330,7 +333,7 @@ export async function githubCiNxDeploy(root, options, dependencies = {}) {
|
|
|
330
333
|
const mode = resolveNxSmartMode(options.mode ?? 'run-many');
|
|
331
334
|
const listProjects = dependencies.listProjects ?? listNxProjectsWithTarget;
|
|
332
335
|
const runNx = dependencies.runNx ?? ((args, commandRoot) => runStatus('nx', args, commandRoot));
|
|
333
|
-
const projects = await listProjects(root, 'deploy', mode);
|
|
336
|
+
const projects = await listProjects(root, 'deploy', mode, stage);
|
|
334
337
|
if (projects.length === 0) {
|
|
335
338
|
console.log(`No ${mode} deploy projects; skipping ${stage}.`);
|
|
336
339
|
await setStatus('success');
|
|
@@ -344,7 +347,7 @@ export async function githubCiNxDeploy(root, options, dependencies = {}) {
|
|
|
344
347
|
'-t',
|
|
345
348
|
target,
|
|
346
349
|
`--projects=${projectList}`,
|
|
347
|
-
|
|
350
|
+
`--exclude=${deployExclusions(stage)}`,
|
|
348
351
|
`--parallel=${NX_PARALLEL}`,
|
|
349
352
|
];
|
|
350
353
|
if (target === 'deploy') {
|
|
@@ -451,19 +454,25 @@ function readGithubActionsEvent(environment) {
|
|
|
451
454
|
return undefined;
|
|
452
455
|
}
|
|
453
456
|
}
|
|
454
|
-
|
|
457
|
+
function deployExclusions(stage) {
|
|
458
|
+
const tags = ['tag:permanent-deploy-target'];
|
|
459
|
+
if (stage !== 'staging')
|
|
460
|
+
tags.push('tag:staging-deploy-target');
|
|
461
|
+
return tags.join(',');
|
|
462
|
+
}
|
|
463
|
+
async function listNxProjectsWithTarget(root, target, mode, stage) {
|
|
455
464
|
const listArgs = ['show', 'projects'];
|
|
456
465
|
if (mode === 'affected')
|
|
457
466
|
listArgs.push('--affected');
|
|
458
467
|
listArgs.push('--withTarget', target);
|
|
459
468
|
if (target === 'deploy')
|
|
460
|
-
listArgs.push(
|
|
469
|
+
listArgs.push(`--exclude=${deployExclusions(stage)}`);
|
|
461
470
|
listArgs.push('--json');
|
|
462
471
|
const result = await $ `nx ${listArgs}`.cwd(root).quiet();
|
|
463
472
|
const candidates = nxProjectList(decode(result.stdout)).sort((left, right) => left.localeCompare(right));
|
|
464
473
|
if (target !== 'deploy')
|
|
465
474
|
return candidates;
|
|
466
|
-
return selectStageDeployProjects(candidates, async (project) => {
|
|
475
|
+
return selectStageDeployProjects(candidates, stage, async (project) => {
|
|
467
476
|
const projectResult = await $ `nx show project ${project} --json`.cwd(root).quiet();
|
|
468
477
|
const parsed = parseNxProjectDeployTarget(decode(projectResult.stdout));
|
|
469
478
|
if (!parsed)
|
|
@@ -471,7 +480,7 @@ async function listNxProjectsWithTarget(root, target, mode) {
|
|
|
471
480
|
return parsed;
|
|
472
481
|
});
|
|
473
482
|
}
|
|
474
|
-
export async function selectStageDeployProjects(candidates, loadProject) {
|
|
483
|
+
export async function selectStageDeployProjects(candidates, stage, loadProject) {
|
|
475
484
|
const selected = [];
|
|
476
485
|
for (const project of candidates) {
|
|
477
486
|
const definition = await loadProject(project);
|
|
@@ -479,7 +488,12 @@ export async function selectStageDeployProjects(candidates, loadProject) {
|
|
|
479
488
|
continue;
|
|
480
489
|
const deploy = definition.targets?.deploy;
|
|
481
490
|
const commandValue = deploy?.options?.command ?? deploy?.command;
|
|
482
|
-
|
|
491
|
+
const tags = Array.isArray(definition.tags)
|
|
492
|
+
? definition.tags.filter((tag) => typeof tag === 'string')
|
|
493
|
+
: [];
|
|
494
|
+
const isStageDerived = typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage');
|
|
495
|
+
const isStagingOnly = tags.includes('staging-deploy-target');
|
|
496
|
+
if (isStageDerived || (stage === 'staging' && isStagingOnly)) {
|
|
483
497
|
selected.push(project);
|
|
484
498
|
}
|
|
485
499
|
}
|
|
@@ -253,7 +253,7 @@ function renderE2eDeploymentJob(options) {
|
|
|
253
253
|
return '';
|
|
254
254
|
return `
|
|
255
255
|
e2e-deployment:
|
|
256
|
-
name:
|
|
256
|
+
name: E2E Tests (Deployed Stage)
|
|
257
257
|
needs: main
|
|
258
258
|
${renderRunsOnLine(options.runsOn)}
|
|
259
259
|
timeout-minutes: 15
|
|
@@ -275,9 +275,9 @@ ${renderRunsOnLine(options.runsOn)}
|
|
|
275
275
|
uses: ./.github/actions/setup-devenv
|
|
276
276
|
|
|
277
277
|
# Step 4
|
|
278
|
-
- name:
|
|
278
|
+
- name: E2E Tests (Deployed Stage)
|
|
279
279
|
# prettier-ignore
|
|
280
|
-
run: smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "\${{ needs.main.outputs.deployment-stage }}" --name "
|
|
280
|
+
run: smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "\${{ needs.main.outputs.deployment-stage }}" --stream-output --name "E2E Tests (Deployed Stage)" --step 4
|
|
281
281
|
|
|
282
282
|
# Step 5
|
|
283
283
|
- name: 🧹 Cleanup and cache Nix/devenv
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -336,6 +336,7 @@ function buildProgram(): Command {
|
|
|
336
336
|
.option('--mode <mode>', 'auto, affected, or run-many', 'auto')
|
|
337
337
|
.option('--configuration <configuration>')
|
|
338
338
|
.option('--stage <stage>')
|
|
339
|
+
.option('--stream-output', 'stream Nx task output without prefixes')
|
|
339
340
|
.action(
|
|
340
341
|
async (options: {
|
|
341
342
|
target: string;
|
|
@@ -344,6 +345,7 @@ function buildProgram(): Command {
|
|
|
344
345
|
mode?: 'auto' | 'affected' | 'run-many';
|
|
345
346
|
configuration?: string;
|
|
346
347
|
stage?: string;
|
|
348
|
+
streamOutput?: boolean;
|
|
347
349
|
}) => {
|
|
348
350
|
const { githubCiNxSmart } = await import('./github-ci/index.js');
|
|
349
351
|
await githubCiNxSmart(await findRepoRoot(), options);
|
|
@@ -134,12 +134,13 @@ describe('GitHub CI Nx target expansion', () => {
|
|
|
134
134
|
).toEqual(['native:package-linux', 'native:compile-linux', 'native:build']);
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
it('adds optional stage before the generic target skip tag only to nx-smart', () => {
|
|
138
|
-
expect(nxSmartArgs('e2e-deployment', 'run-many', undefined, 'pr123')).toEqual([
|
|
137
|
+
it('adds optional stage and streaming before the generic target skip tag only to nx-smart', () => {
|
|
138
|
+
expect(nxSmartArgs('e2e-deployment', 'run-many', undefined, 'pr123', true)).toEqual([
|
|
139
139
|
'run-many',
|
|
140
140
|
'-t',
|
|
141
141
|
'e2e-deployment',
|
|
142
142
|
'--stage=pr123',
|
|
143
|
+
'--outputStyle=stream-without-prefixes',
|
|
143
144
|
'--exclude=tag:ci:skip:e2e-deployment',
|
|
144
145
|
'--parallel=100%',
|
|
145
146
|
]);
|
|
@@ -572,7 +573,7 @@ describe('event-aware stage deployment', () => {
|
|
|
572
573
|
).toThrow(/same-repository/);
|
|
573
574
|
});
|
|
574
575
|
|
|
575
|
-
it('selects
|
|
576
|
+
it('selects stage-derived deploy targets plus staging-only infrastructure on staging', async () => {
|
|
576
577
|
const definitions: Record<string, unknown> = {
|
|
577
578
|
'conloca-app': {
|
|
578
579
|
targets: {
|
|
@@ -582,17 +583,34 @@ describe('event-aware stage deployment', () => {
|
|
|
582
583
|
'conloca-app-backend': {
|
|
583
584
|
targets: { deploy: { command: 'smoo wrangler deploy-stage --stage {args.stage}' } },
|
|
584
585
|
},
|
|
586
|
+
'conloca-e2e-mail-capture': {
|
|
587
|
+
tags: ['staging-deploy-target'],
|
|
588
|
+
targets: { deploy: { options: { command: 'bun scripts/deploy.ts --stage={args.stage}' } } },
|
|
589
|
+
},
|
|
585
590
|
'conloca-oauth-redirect': {
|
|
591
|
+
tags: ['permanent-deploy-target'],
|
|
586
592
|
targets: { deploy: { options: { command: 'wrangler deploy --config wrangler.toml' } } },
|
|
587
593
|
},
|
|
588
594
|
'conloca-website': {
|
|
589
595
|
targets: { deploy: { options: { command: 'bun scripts/deploy-website.ts' } } },
|
|
590
596
|
},
|
|
591
597
|
};
|
|
598
|
+
const candidates = Object.keys(definitions);
|
|
599
|
+
const loadProject = async (project: string) => definitions[project];
|
|
592
600
|
|
|
593
|
-
await expect(
|
|
594
|
-
|
|
595
|
-
|
|
601
|
+
await expect(selectStageDeployProjects(candidates, 'staging', loadProject)).resolves.toEqual([
|
|
602
|
+
'conloca-app',
|
|
603
|
+
'conloca-app-backend',
|
|
604
|
+
'conloca-e2e-mail-capture',
|
|
605
|
+
]);
|
|
606
|
+
await expect(selectStageDeployProjects(candidates, 'pr123', loadProject)).resolves.toEqual([
|
|
607
|
+
'conloca-app',
|
|
608
|
+
'conloca-app-backend',
|
|
609
|
+
]);
|
|
610
|
+
await expect(selectStageDeployProjects(candidates, 'production', loadProject)).resolves.toEqual([
|
|
611
|
+
'conloca-app',
|
|
612
|
+
'conloca-app-backend',
|
|
613
|
+
]);
|
|
596
614
|
});
|
|
597
615
|
|
|
598
616
|
it('publishes GitHub deployment JSON through a real stdin process seam', async () => {
|
|
@@ -657,7 +675,7 @@ describe('event-aware stage deployment', () => {
|
|
|
657
675
|
|
|
658
676
|
it('deploys app/backend, publishes PR metadata, and emits the resolved stage', async () => {
|
|
659
677
|
const nxCalls: string[][] = [];
|
|
660
|
-
const listCalls: Array<[string, string]> = [];
|
|
678
|
+
const listCalls: Array<[string, string, string]> = [];
|
|
661
679
|
const summaries: string[] = [];
|
|
662
680
|
const deployments: Array<[string, string]> = [];
|
|
663
681
|
const outputs: string[] = [];
|
|
@@ -677,8 +695,8 @@ describe('event-aware stage deployment', () => {
|
|
|
677
695
|
repository: { full_name: 'owner/repo' },
|
|
678
696
|
pull_request: { number: 123, head: { repo: { full_name: 'owner/repo' } } },
|
|
679
697
|
},
|
|
680
|
-
listProjects: async (_root, target, mode) => {
|
|
681
|
-
listCalls.push([target, mode]);
|
|
698
|
+
listProjects: async (_root, target, mode, stage) => {
|
|
699
|
+
listCalls.push([target, mode, stage]);
|
|
682
700
|
return ['conloca-app', 'conloca-app-backend'];
|
|
683
701
|
},
|
|
684
702
|
runNx: async (args) => {
|
|
@@ -697,10 +715,10 @@ describe('event-aware stage deployment', () => {
|
|
|
697
715
|
},
|
|
698
716
|
);
|
|
699
717
|
|
|
700
|
-
expect(listCalls).toEqual([['deploy', 'run-many']]);
|
|
718
|
+
expect(listCalls).toEqual([['deploy', 'run-many', 'pr123']]);
|
|
701
719
|
expect(nxCalls).toHaveLength(1);
|
|
702
720
|
expect(nxCalls[0]).toContain('--projects=conloca-app,conloca-app-backend');
|
|
703
|
-
expect(nxCalls[0]).toContain('--exclude=tag:permanent-deploy-target');
|
|
721
|
+
expect(nxCalls[0]).toContain('--exclude=tag:permanent-deploy-target,tag:staging-deploy-target');
|
|
704
722
|
expect(nxCalls[0]).toContain('--stage=pr123');
|
|
705
723
|
expect(nxCalls[0]).not.toContain('e2e-deployment');
|
|
706
724
|
expect(summaries).toEqual(['## pr123 deployment\n\n[View deployment](https://app.pr123.conloca.com)\n']);
|
package/src/github-ci/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface GithubActionsEventPayload {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
interface NxProjectDeployTarget {
|
|
30
|
+
tags?: unknown;
|
|
30
31
|
targets?: {
|
|
31
32
|
deploy?: {
|
|
32
33
|
command?: unknown;
|
|
@@ -159,6 +160,7 @@ export function nxSmartArgs(
|
|
|
159
160
|
mode: 'affected' | 'run-many',
|
|
160
161
|
configuration?: string,
|
|
161
162
|
stage?: string,
|
|
163
|
+
streamOutput = false,
|
|
162
164
|
): string[] {
|
|
163
165
|
const args = [mode, '-t', target];
|
|
164
166
|
if (configuration) {
|
|
@@ -167,19 +169,30 @@ export function nxSmartArgs(
|
|
|
167
169
|
if (stage) {
|
|
168
170
|
args.push(`--stage=${stage}`);
|
|
169
171
|
}
|
|
172
|
+
if (streamOutput) {
|
|
173
|
+
args.push('--outputStyle=stream-without-prefixes');
|
|
174
|
+
}
|
|
170
175
|
args.push(`--exclude=tag:ci:skip:${target}`, `--parallel=${NX_PARALLEL}`);
|
|
171
176
|
return args;
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
export async function githubCiNxSmart(
|
|
175
180
|
root: string,
|
|
176
|
-
options: {
|
|
181
|
+
options: {
|
|
182
|
+
target: string;
|
|
183
|
+
name?: string;
|
|
184
|
+
step?: string;
|
|
185
|
+
mode?: NxSmartMode;
|
|
186
|
+
configuration?: string;
|
|
187
|
+
stage?: string;
|
|
188
|
+
streamOutput?: boolean;
|
|
189
|
+
},
|
|
177
190
|
): Promise<void> {
|
|
178
191
|
const name = options.name ?? options.target;
|
|
179
192
|
const step = options.step ?? '';
|
|
180
193
|
await createGithubStatus(name, step);
|
|
181
194
|
const mode = resolveNxSmartMode(options.mode ?? 'auto');
|
|
182
|
-
const nxArgs = nxSmartArgs(options.target, mode, options.configuration, options.stage);
|
|
195
|
+
const nxArgs = nxSmartArgs(options.target, mode, options.configuration, options.stage, options.streamOutput);
|
|
183
196
|
const status = await runStatus('nx', nxArgs, root);
|
|
184
197
|
await updateGithubStatus(name, status === 0 ? 'success' : 'failure', step);
|
|
185
198
|
if (status !== 0) {
|
|
@@ -392,7 +405,12 @@ export interface GithubCiNxDeployOptions {
|
|
|
392
405
|
}
|
|
393
406
|
|
|
394
407
|
export interface GithubCiNxDeployDependencies {
|
|
395
|
-
listProjects?: (
|
|
408
|
+
listProjects?: (
|
|
409
|
+
root: string,
|
|
410
|
+
target: string,
|
|
411
|
+
mode: 'affected' | 'run-many',
|
|
412
|
+
stage: DeploymentStage,
|
|
413
|
+
) => Promise<string[]>;
|
|
396
414
|
runNx?: (args: string[], root: string) => Promise<number>;
|
|
397
415
|
appendSummary?: (summaryPath: string, content: string) => Promise<void>;
|
|
398
416
|
appendOutput?: (outputPath: string, content: string) => Promise<void>;
|
|
@@ -420,7 +438,7 @@ export async function githubCiNxDeploy(
|
|
|
420
438
|
const mode = resolveNxSmartMode(options.mode ?? 'run-many');
|
|
421
439
|
const listProjects = dependencies.listProjects ?? listNxProjectsWithTarget;
|
|
422
440
|
const runNx = dependencies.runNx ?? ((args: string[], commandRoot: string) => runStatus('nx', args, commandRoot));
|
|
423
|
-
const projects = await listProjects(root, 'deploy', mode);
|
|
441
|
+
const projects = await listProjects(root, 'deploy', mode, stage);
|
|
424
442
|
if (projects.length === 0) {
|
|
425
443
|
console.log(`No ${mode} deploy projects; skipping ${stage}.`);
|
|
426
444
|
await setStatus('success');
|
|
@@ -435,7 +453,7 @@ export async function githubCiNxDeploy(
|
|
|
435
453
|
'-t',
|
|
436
454
|
target,
|
|
437
455
|
`--projects=${projectList}`,
|
|
438
|
-
|
|
456
|
+
`--exclude=${deployExclusions(stage)}`,
|
|
439
457
|
`--parallel=${NX_PARALLEL}`,
|
|
440
458
|
];
|
|
441
459
|
if (target === 'deploy') {
|
|
@@ -553,20 +571,27 @@ function readGithubActionsEvent(environment: NodeJS.ProcessEnv): GithubActionsEv
|
|
|
553
571
|
}
|
|
554
572
|
}
|
|
555
573
|
|
|
574
|
+
function deployExclusions(stage: DeploymentStage): string {
|
|
575
|
+
const tags = ['tag:permanent-deploy-target'];
|
|
576
|
+
if (stage !== 'staging') tags.push('tag:staging-deploy-target');
|
|
577
|
+
return tags.join(',');
|
|
578
|
+
}
|
|
579
|
+
|
|
556
580
|
async function listNxProjectsWithTarget(
|
|
557
581
|
root: string,
|
|
558
582
|
target: string,
|
|
559
583
|
mode: 'affected' | 'run-many',
|
|
584
|
+
stage: DeploymentStage,
|
|
560
585
|
): Promise<string[]> {
|
|
561
586
|
const listArgs = ['show', 'projects'];
|
|
562
587
|
if (mode === 'affected') listArgs.push('--affected');
|
|
563
588
|
listArgs.push('--withTarget', target);
|
|
564
|
-
if (target === 'deploy') listArgs.push(
|
|
589
|
+
if (target === 'deploy') listArgs.push(`--exclude=${deployExclusions(stage)}`);
|
|
565
590
|
listArgs.push('--json');
|
|
566
591
|
const result = await $`nx ${listArgs}`.cwd(root).quiet();
|
|
567
592
|
const candidates = nxProjectList(decode(result.stdout)).sort((left, right) => left.localeCompare(right));
|
|
568
593
|
if (target !== 'deploy') return candidates;
|
|
569
|
-
return selectStageDeployProjects(candidates, async (project) => {
|
|
594
|
+
return selectStageDeployProjects(candidates, stage, async (project) => {
|
|
570
595
|
const projectResult = await $`nx show project ${project} --json`.cwd(root).quiet();
|
|
571
596
|
const parsed = parseNxProjectDeployTarget(decode(projectResult.stdout));
|
|
572
597
|
if (!parsed) throw new Error(`nx show project ${project} returned invalid JSON.`);
|
|
@@ -576,6 +601,7 @@ async function listNxProjectsWithTarget(
|
|
|
576
601
|
|
|
577
602
|
export async function selectStageDeployProjects(
|
|
578
603
|
candidates: string[],
|
|
604
|
+
stage: DeploymentStage,
|
|
579
605
|
loadProject: (project: string) => Promise<unknown>,
|
|
580
606
|
): Promise<string[]> {
|
|
581
607
|
const selected: string[] = [];
|
|
@@ -584,7 +610,12 @@ export async function selectStageDeployProjects(
|
|
|
584
610
|
if (!isNxProjectDeployTarget(definition)) continue;
|
|
585
611
|
const deploy = definition.targets?.deploy;
|
|
586
612
|
const commandValue = deploy?.options?.command ?? deploy?.command;
|
|
587
|
-
|
|
613
|
+
const tags = Array.isArray(definition.tags)
|
|
614
|
+
? definition.tags.filter((tag): tag is string => typeof tag === 'string')
|
|
615
|
+
: [];
|
|
616
|
+
const isStageDerived = typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage');
|
|
617
|
+
const isStagingOnly = tags.includes('staging-deploy-target');
|
|
618
|
+
if (isStageDerived || (stage === 'staging' && isStagingOnly)) {
|
|
588
619
|
selected.push(project);
|
|
589
620
|
}
|
|
590
621
|
}
|
|
@@ -77,7 +77,7 @@ describe('CI workflow definition', () => {
|
|
|
77
77
|
const rendered = renderCiWorkflowYaml(options({ deploy: true, e2eDeployment: true, runsOn: [...nixosRunsOn] }));
|
|
78
78
|
|
|
79
79
|
expect(rendered).toContain('deployment-stage: ${{ steps.deploy.outputs.stage }}');
|
|
80
|
-
expect(rendered).toContain(' e2e-deployment:\n name:
|
|
80
|
+
expect(rendered).toContain(' e2e-deployment:\n name: E2E Tests (Deployed Stage)\n needs: main');
|
|
81
81
|
expect(rendered).not.toContain('\n\n\n e2e-deployment:');
|
|
82
82
|
expect(rendered).toContain(
|
|
83
83
|
"if: ${{ needs.main.result == 'success' && needs.main.outputs.deployment-stage != '' }}",
|
|
@@ -88,9 +88,9 @@ describe('CI workflow definition', () => {
|
|
|
88
88
|
);
|
|
89
89
|
expect(rendered).toContain('# prettier-ignore\n run: smoo github-ci nx-smart --target e2e-deployment');
|
|
90
90
|
expect(rendered).toContain(
|
|
91
|
-
'smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "${{ needs.main.outputs.deployment-stage }}" --name "
|
|
91
|
+
'smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "${{ needs.main.outputs.deployment-stage }}" --stream-output --name "E2E Tests (Deployed Stage)" --step 4',
|
|
92
92
|
);
|
|
93
|
-
expect(rendered.match(/name:
|
|
93
|
+
expect(rendered.match(/name: E2E Tests \(Deployed Stage\)/g)).toHaveLength(2);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
it('omits optional browser and deployment-E2E lanes when disabled', () => {
|
|
@@ -295,7 +295,7 @@ function renderE2eDeploymentJob(options: CiWorkflowDefinitionOptions): string {
|
|
|
295
295
|
if (!options.e2eDeployment) return '';
|
|
296
296
|
return `
|
|
297
297
|
e2e-deployment:
|
|
298
|
-
name:
|
|
298
|
+
name: E2E Tests (Deployed Stage)
|
|
299
299
|
needs: main
|
|
300
300
|
${renderRunsOnLine(options.runsOn)}
|
|
301
301
|
timeout-minutes: 15
|
|
@@ -317,9 +317,9 @@ ${renderRunsOnLine(options.runsOn)}
|
|
|
317
317
|
uses: ./.github/actions/setup-devenv
|
|
318
318
|
|
|
319
319
|
# Step 4
|
|
320
|
-
- name:
|
|
320
|
+
- name: E2E Tests (Deployed Stage)
|
|
321
321
|
# prettier-ignore
|
|
322
|
-
run: smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "\${{ needs.main.outputs.deployment-stage }}" --name "
|
|
322
|
+
run: smoo github-ci nx-smart --target e2e-deployment --mode run-many --stage "\${{ needs.main.outputs.deployment-stage }}" --stream-output --name "E2E Tests (Deployed Stage)" --step 4
|
|
323
323
|
|
|
324
324
|
# Step 5
|
|
325
325
|
- name: 🧹 Cleanup and cache Nix/devenv
|