@smoothbricks/cli 0.10.7 โ†’ 0.10.8

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.
Files changed (56) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +23 -1
  3. package/dist/github-ci/index.d.ts +43 -3
  4. package/dist/github-ci/index.d.ts.map +1 -1
  5. package/dist/github-ci/index.js +219 -34
  6. package/dist/monorepo/ci-workflow.js +16 -6
  7. package/dist/monorepo/managed-files.d.ts.map +1 -1
  8. package/dist/monorepo/managed-files.js +19 -1
  9. package/dist/monorepo/pr-preview-cleanup-workflow.d.ts +5 -0
  10. package/dist/monorepo/pr-preview-cleanup-workflow.d.ts.map +1 -0
  11. package/dist/monorepo/pr-preview-cleanup-workflow.js +38 -0
  12. package/dist/monorepo/publish-workflow.js +2 -2
  13. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  14. package/dist/monorepo/tool-validation.js +85 -5
  15. package/dist/playwright/index.d.ts +22 -0
  16. package/dist/playwright/index.d.ts.map +1 -0
  17. package/dist/playwright/index.js +44 -0
  18. package/dist/release/bootstrap-npm-packages.d.ts +3 -0
  19. package/dist/release/bootstrap-npm-packages.d.ts.map +1 -1
  20. package/dist/release/bootstrap-npm-packages.js +21 -0
  21. package/dist/release/index.d.ts.map +1 -1
  22. package/dist/release/index.js +17 -0
  23. package/dist/wrangler/cloudflare.d.ts +85 -0
  24. package/dist/wrangler/cloudflare.d.ts.map +1 -0
  25. package/dist/wrangler/cloudflare.js +235 -0
  26. package/dist/wrangler/deploy-environment.d.ts +48 -0
  27. package/dist/wrangler/deploy-environment.d.ts.map +1 -0
  28. package/dist/wrangler/deploy-environment.js +383 -0
  29. package/dist/wrangler/environment.d.ts +58 -0
  30. package/dist/wrangler/environment.d.ts.map +1 -0
  31. package/dist/wrangler/environment.js +297 -0
  32. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +3 -4
  33. package/package.json +8 -1
  34. package/src/cli.ts +25 -2
  35. package/src/github-ci/index.test.ts +171 -0
  36. package/src/github-ci/index.ts +272 -30
  37. package/src/monorepo/__tests__/ci-workflow.test.ts +10 -4
  38. package/src/monorepo/__tests__/pr-preview-cleanup-workflow.test.ts +23 -0
  39. package/src/monorepo/__tests__/publish-workflow.test.ts +1 -1
  40. package/src/monorepo/ci-workflow.ts +16 -6
  41. package/src/monorepo/managed-files.test.ts +56 -1
  42. package/src/monorepo/managed-files.ts +20 -1
  43. package/src/monorepo/pr-preview-cleanup-workflow.ts +44 -0
  44. package/src/monorepo/publish-workflow.ts +2 -2
  45. package/src/monorepo/tool-validation.test.ts +85 -0
  46. package/src/monorepo/tool-validation.ts +94 -5
  47. package/src/playwright/index.test.ts +90 -0
  48. package/src/playwright/index.ts +73 -0
  49. package/src/release/__tests__/bootstrap-npm-packages.test.ts +63 -2
  50. package/src/release/bootstrap-npm-packages.ts +34 -0
  51. package/src/release/index.ts +18 -0
  52. package/src/wrangler/cloudflare.ts +289 -0
  53. package/src/wrangler/deploy-environment.test.ts +354 -0
  54. package/src/wrangler/deploy-environment.ts +445 -0
  55. package/src/wrangler/environment.test.ts +173 -0
  56. package/src/wrangler/environment.ts +366 -0
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,wBAAsB,MAAM,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AASA,wBAAsB,MAAM,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
package/dist/cli.js CHANGED
@@ -2,7 +2,9 @@ import { Command, CommanderError } from 'commander';
2
2
  import { variants } from './generate/index.js';
3
3
  import { cliPackageVersion } from './lib/cli-package.js';
4
4
  import { findRepoRoot } from './lib/run.js';
5
+ import { ensureChromium } from './playwright/index.js';
5
6
  import { resolvePrConflicts } from './pr/index.js';
7
+ import { cleanupPullRequest, deployEnvironment } from './wrangler/deploy-environment.js';
6
8
  import { scaffold } from './wrangler/scaffold.js';
7
9
  export async function runCli(argv = process.argv.slice(2)) {
8
10
  const program = buildProgram();
@@ -307,7 +309,7 @@ function buildProgram() {
307
309
  });
308
310
  githubCi
309
311
  .command('nx-deploy')
310
- .requiredOption('--configuration <configuration>')
312
+ .option('--environment <environment>', 'explicit staging, production, or prN override')
311
313
  .option('--mode <mode>', 'auto, affected, or run-many', 'run-many')
312
314
  .option('--name <name>')
313
315
  .option('--step <step>')
@@ -327,6 +329,14 @@ function buildProgram() {
327
329
  process.exitCode = exitCode;
328
330
  }
329
331
  });
332
+ const playwright = program.command('playwright').description('Manage Playwright browsers');
333
+ const playwrightEnsure = playwright.command('ensure').description('Ensure a Playwright browser is available');
334
+ playwrightEnsure
335
+ .command('chromium')
336
+ .description('Ensure Chromium is available for browser tests')
337
+ .action(async () => {
338
+ await ensureChromium();
339
+ });
330
340
  const wrangler = program.command('wrangler').description('Cloudflare wrangler project helpers');
331
341
  wrangler
332
342
  .command('scaffold <project>')
@@ -335,6 +345,18 @@ function buildProgram() {
335
345
  .action(async (project, options) => {
336
346
  scaffold(await findRepoRoot(), project, { force: options.force });
337
347
  });
348
+ wrangler
349
+ .command('deploy-environment')
350
+ .requiredOption('--environment <environment>', 'staging, production, or prN')
351
+ .action(async (options) => {
352
+ await deployEnvironment(process.cwd(), options.environment);
353
+ });
354
+ wrangler
355
+ .command('cleanup-pr')
356
+ .requiredOption('--pr <number>', 'pull-request number')
357
+ .action(async (options) => {
358
+ await cleanupPullRequest(process.cwd(), Number(options.pr));
359
+ });
338
360
  return program;
339
361
  }
340
362
  function booleanOption(value) {
@@ -1,5 +1,21 @@
1
1
  import { type ProjectTargets } from '../nx/index.js';
2
+ import { type EnvironmentToken } from '../wrangler/environment.js';
2
3
  import type { NxTargetRun } from './outputs.js';
4
+ export interface GithubActionsEventPayload {
5
+ action?: string;
6
+ repository?: {
7
+ default_branch?: string;
8
+ full_name?: string;
9
+ };
10
+ pull_request?: {
11
+ number?: number;
12
+ head?: {
13
+ repo?: {
14
+ full_name?: string;
15
+ };
16
+ };
17
+ };
18
+ }
3
19
  type NxSmartMode = 'auto' | 'affected' | 'run-many';
4
20
  export declare function cleanupGithubCiCache(root: string): Promise<void>;
5
21
  export declare function nxSmartArgs(target: string, mode: 'affected' | 'run-many', configuration?: string): string[];
@@ -28,12 +44,36 @@ export declare function nxRunManyArgs(run: NxTargetRun, configuration?: string):
28
44
  export declare function readGitHeadSha(root: string): Promise<string>;
29
45
  export declare function githubCiNxRunMany(root: string, options: NxRunManyOptions): Promise<void>;
30
46
  export declare function githubCiApplyOutputs(root: string, directories: string[], expectedSourceSha: string): Promise<void>;
31
- export declare function githubCiNxDeploy(root: string, options: {
32
- configuration: string;
47
+ export interface GithubCiNxDeployOptions {
48
+ environment?: string;
33
49
  mode?: NxSmartMode;
34
50
  name?: string;
35
51
  step?: string;
36
52
  verify?: boolean;
37
- }): Promise<void>;
53
+ }
54
+ export interface GithubCiNxDeployDependencies {
55
+ listProjects?: (root: string, target: string, mode: 'affected' | 'run-many') => Promise<string[]>;
56
+ runNx?: (args: string[], root: string) => Promise<number>;
57
+ appendSummary?: (summaryPath: string, content: string) => Promise<void>;
58
+ publishDeployment?: (environment: `pr${number}`, url: string) => Promise<void>;
59
+ setStatus?: (state: 'pending' | 'success' | 'failure') => Promise<void>;
60
+ processEnv?: NodeJS.ProcessEnv;
61
+ eventPayload?: GithubActionsEventPayload;
62
+ }
63
+ export declare function githubCiNxDeploy(root: string, options: GithubCiNxDeployOptions, dependencies?: GithubCiNxDeployDependencies): Promise<void>;
64
+ export declare function resolveDeploymentEnvironment(explicit: string | undefined, environment: NodeJS.ProcessEnv, event: GithubActionsEventPayload | undefined): EnvironmentToken;
65
+ export declare function selectEnvironmentDeployProjects(candidates: string[], loadProject: (project: string) => Promise<unknown>): Promise<string[]>;
66
+ export interface GithubApiProcessResult {
67
+ exitCode: number;
68
+ stdout: string;
69
+ stderr: string;
70
+ }
71
+ export interface GithubApiProcessRunner {
72
+ run(args: string[], input: string, cwd: string): Promise<GithubApiProcessResult>;
73
+ }
74
+ export declare class NodeGithubApiProcessRunner implements GithubApiProcessRunner {
75
+ run(args: string[], input: string, cwd: string): Promise<GithubApiProcessResult>;
76
+ }
77
+ export declare function publishGithubDeployment(environment: `pr${number}`, url: string, processEnvironment: NodeJS.ProcessEnv, runner?: GithubApiProcessRunner): Promise<void>;
38
78
  export {};
39
79
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAmBhD,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAKpD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE;AAmFD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAO3G;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACpG,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,oBAAoB,CAmD9G;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAwC/E;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAehF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9F;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAGf;AA0CD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrG,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { spawn } from 'node:child_process';
1
2
  import { existsSync, readFileSync } from 'node:fs';
2
3
  import { appendFile, mkdtemp, realpath, rename, rm } from 'node:fs/promises';
3
4
  import { dirname, join } from 'node:path';
@@ -6,22 +7,35 @@ import typia from 'typia';
6
7
  import { parseStringArrayText } from '../lib/json.js';
7
8
  import { decode, run, runStatus } from '../lib/run.js';
8
9
  import { readProjectTargets } from '../nx/index.js';
10
+ import { isPullRequestEnvironment, parseEnvironmentToken, pullRequestEnvironment, } from '../wrangler/environment.js';
9
11
  const parseGithubActionsEvent = (() => {
10
- const _io0 = input => undefined === input.repository || "object" === typeof input.repository && null !== input.repository && false === Array.isArray(input.repository) && _io1(input.repository);
11
- const _io1 = input => undefined === input.default_branch || "string" === typeof input.default_branch;
12
+ const _ip0 = input => undefined === input["full_name"] || "string" === typeof input["full_name"];
13
+ const _io0 = input => (undefined === input.action || "string" === typeof input.action) && (undefined === input.repository || "object" === typeof input.repository && null !== input.repository && false === Array.isArray(input.repository) && _io1(input.repository)) && (undefined === input.pull_request || "object" === typeof input.pull_request && null !== input.pull_request && false === Array.isArray(input.pull_request) && _io2(input.pull_request));
14
+ const _io1 = input => (undefined === input.default_branch || "string" === typeof input.default_branch) && _ip0(input);
15
+ const _io2 = input => (undefined === input.number || "number" === typeof input.number) && (undefined === input.head || "object" === typeof input.head && null !== input.head && false === Array.isArray(input.head) && _io3(input.head));
16
+ const _io3 = input => undefined === input.repo || "object" === typeof input.repo && null !== input.repo && false === Array.isArray(input.repo) && _io4(input.repo);
17
+ const _io4 = input => _ip0(input);
12
18
  const __is = input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
13
19
  return input => { input = JSON.parse(input); return __is(input) ? input : null; };
14
20
  })();
15
- const parseNxProjectDeployConfigurations = (() => {
21
+ const isGithubDeployment = (() => {
22
+ const _io0 = input => "number" === typeof input.id;
23
+ return input => "object" === typeof input && null !== input && _io0(input);
24
+ })();
25
+ const isNxProjectDeployTarget = (() => {
26
+ const _ip0 = input => true;
16
27
  const _io0 = input => undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets);
17
28
  const _io1 = input => undefined === input.deploy || "object" === typeof input.deploy && null !== input.deploy && false === Array.isArray(input.deploy) && _io2(input.deploy);
18
- const _io2 = input => undefined === input.configurations || "object" === typeof input.configurations && null !== input.configurations && false === Array.isArray(input.configurations) && _io3(input.configurations);
19
- const _io3 = input => Object.keys(input).every(key => {
20
- const value = input[key];
21
- if (undefined === value)
22
- return true;
23
- return true;
24
- });
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
+ const _io3 = input => _ip0(input);
31
+ return input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
32
+ })();
33
+ const parseNxProjectDeployTarget = (() => {
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);
36
+ const _io1 = input => undefined === input.deploy || "object" === typeof input.deploy && null !== input.deploy && false === Array.isArray(input.deploy) && _io2(input.deploy);
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
+ const _io3 = input => _ip0(input);
25
39
  const __is = input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
26
40
  return input => { input = JSON.parse(input); return __is(input) ? input : null; };
27
41
  })();
@@ -300,31 +314,74 @@ function commaSeparatedValues(value) {
300
314
  .map((entry) => entry.trim())
301
315
  .filter(Boolean);
302
316
  }
303
- export async function githubCiNxDeploy(root, options) {
304
- const name = options.name ?? `Deploy ${options.configuration}`;
317
+ export async function githubCiNxDeploy(root, options, dependencies = {}) {
318
+ const processEnv = dependencies.processEnv ?? process.env;
319
+ const eventPayload = dependencies.eventPayload ?? readGithubActionsEvent(processEnv);
320
+ const environment = resolveDeploymentEnvironment(options.environment, processEnv, eventPayload);
321
+ const name = options.name ?? 'Deploy Environment';
305
322
  const step = options.step ?? '';
306
- await createGithubStatus(name, step);
323
+ const setStatus = dependencies.setStatus ??
324
+ ((state) => state === 'pending' ? createGithubStatus(name, step) : updateGithubStatus(name, state, step));
325
+ await setStatus('pending');
307
326
  const mode = resolveNxSmartMode(options.mode ?? 'run-many');
308
- const projects = await deployProjectsWithConfiguration(root, options.configuration, mode);
327
+ const listProjects = dependencies.listProjects ?? listNxProjectsWithTarget;
328
+ const runNx = dependencies.runNx ?? ((args, commandRoot) => runStatus('nx', args, commandRoot));
329
+ const projects = await listProjects(root, 'deploy', mode);
309
330
  if (projects.length === 0) {
310
- console.log(`No ${mode} deploy projects with configuration ${options.configuration}; skipping.`);
311
- await updateGithubStatus(name, 'success', step);
331
+ console.log(`No ${mode} deploy projects; skipping ${environment}.`);
332
+ await setStatus('success');
312
333
  return;
313
334
  }
314
335
  const projectList = projects.join(',');
315
336
  const targets = options.verify === true ? ['build', 'lint', 'test', 'deploy'] : ['deploy'];
316
337
  for (const target of targets) {
317
- const nxArgs = ['run-many', '-t', target, `--projects=${projectList}`, `--parallel=${NX_PARALLEL}`];
338
+ const nxArgs = [
339
+ 'run-many',
340
+ '-t',
341
+ target,
342
+ `--projects=${projectList}`,
343
+ '--exclude=tag:permanent-deploy-target',
344
+ `--parallel=${NX_PARALLEL}`,
345
+ ];
318
346
  if (target === 'deploy') {
319
- nxArgs.push(`--configuration=${options.configuration}`);
347
+ nxArgs.push(`--environment=${environment}`);
320
348
  }
321
- const status = await runStatus('nx', nxArgs, root);
349
+ const status = await runNx(nxArgs, root);
322
350
  if (status !== 0) {
323
- await updateGithubStatus(name, 'failure', step);
351
+ await setStatus('failure');
324
352
  throw new Error(`nx ${nxArgs.join(' ')} failed with exit code ${status}`);
325
353
  }
326
354
  }
327
- await updateGithubStatus(name, 'success', step);
355
+ if (isPullRequestEnvironment(environment)) {
356
+ const url = `https://app.${environment}.conloca.com`;
357
+ const summaryPath = processEnv.GITHUB_STEP_SUMMARY;
358
+ if (summaryPath) {
359
+ const appendSummary = dependencies.appendSummary ?? appendFile;
360
+ await appendSummary(summaryPath, `## ${environment} deployment\n\n[View deployment](${url})\n`);
361
+ }
362
+ const publishDeployment = dependencies.publishDeployment ??
363
+ ((token, deploymentUrl) => publishGithubDeployment(token, deploymentUrl, processEnv));
364
+ await publishDeployment(environment, url);
365
+ }
366
+ if (environment !== 'production') {
367
+ const e2eProjects = await listProjects(root, 'e2e-deployed', 'run-many');
368
+ if (e2eProjects.length > 0) {
369
+ const nxArgs = [
370
+ 'run-many',
371
+ '-t',
372
+ 'e2e-deployed',
373
+ `--projects=${e2eProjects.join(',')}`,
374
+ `--parallel=${NX_PARALLEL}`,
375
+ `--environment=${environment}`,
376
+ ];
377
+ const status = await runNx(nxArgs, root);
378
+ if (status !== 0) {
379
+ await setStatus('failure');
380
+ throw new Error(`nx ${nxArgs.join(' ')} failed with exit code ${status}`);
381
+ }
382
+ }
383
+ }
384
+ await setStatus('success');
328
385
  }
329
386
  function resolveNxSmartMode(mode) {
330
387
  if (mode === 'affected' || mode === 'run-many') {
@@ -357,24 +414,152 @@ function eventDefaultBranch() {
357
414
  return undefined;
358
415
  }
359
416
  }
360
- async function deployProjectsWithConfiguration(root, configuration, mode) {
361
- const listArgs = mode === 'affected'
362
- ? ['show', 'projects', '--affected', '--withTarget', 'deploy', '--json']
363
- : ['show', 'projects', '--withTarget', 'deploy', '--json'];
417
+ export function resolveDeploymentEnvironment(explicit, environment, event) {
418
+ if (explicit !== undefined)
419
+ return parseEnvironmentToken(explicit);
420
+ if (environment.GITHUB_EVENT_NAME === 'pull_request') {
421
+ if (!event?.action || !['opened', 'reopened', 'synchronize'].includes(event.action)) {
422
+ throw new Error('Pull-request deployment runs only for opened, reopened, or synchronize events.');
423
+ }
424
+ const repository = event.repository?.full_name;
425
+ const headRepository = event.pull_request?.head?.repo?.full_name;
426
+ if (!repository || !headRepository || repository !== headRepository) {
427
+ throw new Error('Pull-request deployment is restricted to same-repository pull requests.');
428
+ }
429
+ const number = event.pull_request?.number;
430
+ if (number === undefined)
431
+ throw new Error('GitHub pull_request event is missing its PR number.');
432
+ return pullRequestEnvironment(number);
433
+ }
434
+ if (environment.GITHUB_EVENT_NAME === 'push' && environment.GITHUB_REF_NAME === 'private') {
435
+ return 'staging';
436
+ }
437
+ if (environment.GITHUB_EVENT_NAME === 'release') {
438
+ return 'production';
439
+ }
440
+ throw new Error('Cannot resolve a deployment environment from this GitHub event; pass --environment explicitly.');
441
+ }
442
+ function readGithubActionsEvent(environment) {
443
+ const eventPath = environment.GITHUB_EVENT_PATH;
444
+ if (!eventPath)
445
+ return undefined;
446
+ try {
447
+ return parseGithubActionsEvent(readFileSync(eventPath, 'utf8')) || undefined;
448
+ }
449
+ catch {
450
+ return undefined;
451
+ }
452
+ }
453
+ async function listNxProjectsWithTarget(root, target, mode) {
454
+ const listArgs = ['show', 'projects'];
455
+ if (mode === 'affected')
456
+ listArgs.push('--affected');
457
+ listArgs.push('--withTarget', target);
458
+ if (target === 'deploy')
459
+ listArgs.push('--exclude=tag:permanent-deploy-target');
460
+ listArgs.push('--json');
364
461
  const result = await $ `nx ${listArgs}`.cwd(root).quiet();
365
- const candidates = nxProjectList(decode(result.stdout));
366
- const projects = [];
462
+ const candidates = nxProjectList(decode(result.stdout)).sort((left, right) => left.localeCompare(right));
463
+ if (target !== 'deploy')
464
+ return candidates;
465
+ return selectEnvironmentDeployProjects(candidates, async (project) => {
466
+ const projectResult = await $ `nx show project ${project} --json`.cwd(root).quiet();
467
+ const parsed = parseNxProjectDeployTarget(decode(projectResult.stdout));
468
+ if (!parsed)
469
+ throw new Error(`nx show project ${project} returned invalid JSON.`);
470
+ return parsed;
471
+ });
472
+ }
473
+ export async function selectEnvironmentDeployProjects(candidates, loadProject) {
474
+ const selected = [];
367
475
  for (const project of candidates) {
368
- if (await deployTargetHasConfiguration(root, project, configuration)) {
369
- projects.push(project);
476
+ const definition = await loadProject(project);
477
+ if (!isNxProjectDeployTarget(definition))
478
+ continue;
479
+ const deploy = definition.targets?.deploy;
480
+ const commandValue = deploy?.options?.command ?? deploy?.command;
481
+ if (typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-environment')) {
482
+ selected.push(project);
370
483
  }
371
484
  }
372
- return projects.sort((a, b) => a.localeCompare(b));
485
+ return selected;
486
+ }
487
+ export class NodeGithubApiProcessRunner {
488
+ run(args, input, cwd) {
489
+ const { promise, resolve, reject } = Promise.withResolvers();
490
+ const child = spawn('gh', args, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
491
+ let stdout = '';
492
+ let stderr = '';
493
+ child.stdout.setEncoding('utf8');
494
+ child.stderr.setEncoding('utf8');
495
+ child.stdout.on('data', (chunk) => {
496
+ stdout += chunk;
497
+ });
498
+ child.stderr.on('data', (chunk) => {
499
+ stderr += chunk;
500
+ });
501
+ child.once('error', reject);
502
+ child.once('close', (code) => {
503
+ resolve({ exitCode: code ?? -1, stdout, stderr });
504
+ });
505
+ child.stdin.end(input);
506
+ return promise;
507
+ }
373
508
  }
374
- async function deployTargetHasConfiguration(root, project, configuration) {
375
- const result = await $ `nx show project ${project} --json`.cwd(root).quiet();
376
- const parsed = parseNxProjectDeployConfigurations(decode(result.stdout));
377
- return parsed?.targets?.deploy?.configurations?.[configuration] !== undefined;
509
+ export async function publishGithubDeployment(environment, url, processEnvironment, runner = new NodeGithubApiProcessRunner()) {
510
+ const repository = processEnvironment.GITHUB_REPOSITORY;
511
+ const sha = processEnvironment.GITHUB_SHA;
512
+ if (!repository || !sha)
513
+ throw new Error('GITHUB_REPOSITORY and GITHUB_SHA are required to publish a deployment.');
514
+ const createBody = JSON.stringify({
515
+ ref: sha,
516
+ environment,
517
+ auto_merge: false,
518
+ required_contexts: [],
519
+ transient_environment: true,
520
+ production_environment: false,
521
+ });
522
+ const createResult = await runner.run([
523
+ 'api',
524
+ '--method',
525
+ 'POST',
526
+ '-H',
527
+ 'Accept: application/vnd.github+json',
528
+ `/repos/${repository}/deployments`,
529
+ '--input',
530
+ '-',
531
+ ], createBody, process.cwd());
532
+ if (createResult.exitCode !== 0) {
533
+ throw new Error(`GitHub deployment creation failed with exit code ${createResult.exitCode}: ${createResult.stderr.trim()}`);
534
+ }
535
+ let deployment;
536
+ try {
537
+ deployment = JSON.parse(createResult.stdout);
538
+ }
539
+ catch {
540
+ throw new Error('GitHub returned invalid JSON while creating a deployment.');
541
+ }
542
+ if (!isGithubDeployment(deployment))
543
+ throw new Error('GitHub returned an invalid deployment response.');
544
+ const statusBody = JSON.stringify({
545
+ state: 'success',
546
+ environment,
547
+ environment_url: url,
548
+ auto_inactive: false,
549
+ });
550
+ const statusResult = await runner.run([
551
+ 'api',
552
+ '--method',
553
+ 'POST',
554
+ '-H',
555
+ 'Accept: application/vnd.github+json',
556
+ `/repos/${repository}/deployments/${deployment.id}/statuses`,
557
+ '--input',
558
+ '-',
559
+ ], statusBody, process.cwd());
560
+ if (statusResult.exitCode !== 0) {
561
+ throw new Error(`GitHub deployment status failed with exit code ${statusResult.exitCode}: ${statusResult.stderr.trim()}`);
562
+ }
378
563
  }
379
564
  function nxProjectList(output) {
380
565
  return parseStringArrayText(output) ?? [];
@@ -29,7 +29,7 @@ export function defineCiWorkflow(options) {
29
29
  { kind: CiWorkflowStepKind.ManagedFilesDispatch, name: '๐Ÿ” Dispatch managed-file drift healing' },
30
30
  ];
31
31
  if (options.deploy) {
32
- steps.push({ kind: CiWorkflowStepKind.Deploy, name: '๐Ÿš€ Deploy Staging' });
32
+ steps.push({ kind: CiWorkflowStepKind.Deploy, name: '๐Ÿš€ Deploy Environment' });
33
33
  }
34
34
  steps.push({ kind: CiWorkflowStepKind.SaveNxCache, name: '๐Ÿ’พ Save Nx cache' }, { kind: CiWorkflowStepKind.UploadTraceDbs, name: '๐Ÿ“Ž Upload trace DBs' }, { kind: CiWorkflowStepKind.SaveNixDevenv, name: '๐Ÿงน Cleanup and cache Nix/devenv' });
35
35
  return steps.map((step, index) => ({ ...step, number: index + 2 }));
@@ -51,7 +51,7 @@ permissions:
51
51
  # actions:write lets the drift step dispatch the managed-files workflow.
52
52
  actions: write
53
53
  contents: read
54
- statuses: write
54
+ ${options.deploy ? ' deployments: write\n' : ''} statuses: write
55
55
 
56
56
  defaults:
57
57
  run:
@@ -167,11 +167,15 @@ function yamlLinesForStep(step, options) {
167
167
  case CiWorkflowStepKind.Deploy:
168
168
  return [
169
169
  ` - name: ${step.name}`,
170
- ' if:',
171
- " ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}',",
172
- ' github.event.repository.default_branch) }}',
170
+ ' if: >-',
171
+ ' ${{',
172
+ " (github.event_name == 'pull_request' &&",
173
+ ' contains(fromJSON(\'["opened","reopened","synchronize"]\'), github.event.action) &&',
174
+ ' github.event.pull_request.head.repo.full_name == github.repository) ||',
175
+ " (github.event_name == 'push' && github.ref == 'refs/heads/private')",
176
+ ' }}',
173
177
  ...deployEnvLines(options),
174
- ` run: smoo github-ci nx-deploy --configuration staging --mode affected --name "Deploy Staging" --step ${step.number}`,
178
+ ` run: smoo github-ci nx-deploy --mode run-many --name "Deploy Environment" --step ${step.number}`,
175
179
  ];
176
180
  case CiWorkflowStepKind.SaveNxCache:
177
181
  return [
@@ -220,6 +224,12 @@ function deployEnvLines(options) {
220
224
  ' env:',
221
225
  ' CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}',
222
226
  ' CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}',
227
+ ' GITHUB_CLIENT_SECRET: ${{ secrets.GITHUB_CLIENT_SECRET }}',
228
+ ' GITHUB_APP_PRIVATE_KEY: ${{ secrets.GITHUB_APP_PRIVATE_KEY }}',
229
+ ' GITHUB_APP_PRIVATE_KEY_PEM: ${{ secrets.GITHUB_APP_PRIVATE_KEY_PEM }}',
230
+ ' OAUTH_STATE_SIGNING_KEY: ${{ secrets.OAUTH_STATE_SIGNING_KEY }}',
231
+ ' MAIL_CAPTURE_CONTROL_TOKEN: ${{ secrets.MAIL_CAPTURE_CONTROL_TOKEN }}',
232
+ ' TOKEN_ENCRYPTION_KEY: ${{ secrets.TOKEN_ENCRYPTION_KEY }}',
223
233
  ];
224
234
  }
225
235
  function nxSmartStep(step, target, name) {
@@ -1 +1 @@
1
- {"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,UAAU,EAA2B,MAAM,gBAAgB,CAAC;AAM1F;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,yEAAyE,CAAC;AAU3G,sFAAsF;AACtF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAIlF;AAED,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AAE1D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;8BAE8B;AAC9B,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAkCxG;AAED,wCAAwC;AACxC,eAAO,MAAM,+BAA+B,iCAA2B,CAAC;AAExE;+EAC+E;AAC/E,iBAAS,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAqBtF;AAED,yCAAyC;AACzC,eAAO,MAAM,gCAAgC,kCAA4B,CAAC;AAE1E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AAeD,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AA4GD,eAAO,MAAM,yBAAyB;;;GAAyE,CAAC;AAIhH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAG9G;AAmGD,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAMlF;AAED,0EAA0E;AAC1E,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,gBAAgB,CAY1G;AAsDD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAIxD;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxE"}
1
+ {"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,UAAU,EAA2B,MAAM,gBAAgB,CAAC;AAO1F;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,yEAAyE,CAAC;AAW3G,sFAAsF;AACtF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAIlF;AAED,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AAE1D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;8BAE8B;AAC9B,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAkCxG;AAED,wCAAwC;AACxC,eAAO,MAAM,+BAA+B,iCAA2B,CAAC;AAExE;+EAC+E;AAC/E,iBAAS,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAqBtF;AAED,yCAAyC;AACzC,eAAO,MAAM,gCAAgC,kCAA4B,CAAC;AAE1E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AAeD,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAkHD,eAAO,MAAM,yBAAyB;;;GAAyE,CAAC;AAIhH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAG9G;AAyGD,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAMlF;AAED,0EAA0E;AAC1E,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,gBAAgB,CAY1G;AA2DD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAIxD;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxE"}
@@ -5,6 +5,7 @@ import { PLATFORM_TARGET_GLOBS } from '@smoothbricks/nx-plugin/workspace-config-
5
5
  import { listReleasePackages, readPackageJson } from '../lib/workspace.js';
6
6
  import { loadNxProjects, targetNamesFromProjects } from '../nx/index.js';
7
7
  import { renderCiWorkflowYaml } from './ci-workflow.js';
8
+ import { renderPrPreviewCleanupWorkflowYaml } from './pr-preview-cleanup-workflow.js';
8
9
  import { renderPublishWorkflowYaml } from './publish-workflow.js';
9
10
  /**
10
11
  * Repos may append their own content to a managed file below this marker โ€”
@@ -156,6 +157,12 @@ const managedFiles = [
156
157
  source: 'ci-workflow',
157
158
  target: '.github/workflows/ci.yml',
158
159
  },
160
+ {
161
+ kind: 'generated',
162
+ source: 'pr-preview-cleanup-workflow',
163
+ target: '.github/workflows/pr-preview-cleanup.yml',
164
+ cloudflareDeployOnly: true,
165
+ },
159
166
  {
160
167
  kind: 'generated',
161
168
  source: 'publish-workflow',
@@ -208,6 +215,9 @@ function applyManagedFile(root, file, mode, context) {
208
215
  if (file.releasePackagesOnly === true && !context.hasReleasePackages && !context.hasProductionDeployTargets) {
209
216
  return { target: file.target, action: 'skipped' };
210
217
  }
218
+ if (file.cloudflareDeployOnly === true && context.stagingDeployProvider !== 'cloudflare') {
219
+ return { target: file.target, action: 'skipped' };
220
+ }
211
221
  const target = resolve(root, file.target);
212
222
  const content = getManagedContent(file, context);
213
223
  if (existsSync(target)) {
@@ -257,6 +267,9 @@ function getManagedContent(file, context) {
257
267
  runsOn: context.ciRunsOn,
258
268
  });
259
269
  }
270
+ if (file.source === 'pr-preview-cleanup-workflow') {
271
+ return renderPrPreviewCleanupWorkflowYaml({ runsOn: context.ciRunsOn });
272
+ }
260
273
  throw new Error(`Unknown generated managed file source ${file.source}`);
261
274
  }
262
275
  const sourceRoot = file.kind === 'raw' ? 'managed/raw' : 'managed/templates';
@@ -319,11 +332,16 @@ function deployTargetInfoFromTargets(targets, configuration) {
319
332
  if (!deploy) {
320
333
  return { exists: false };
321
334
  }
335
+ const baseCommandValue = deploy.options?.command ?? deploy.command;
336
+ const baseCommand = typeof baseCommandValue === 'string' ? baseCommandValue : '';
337
+ if (baseCommand.includes('smoo wrangler deploy-environment')) {
338
+ return { exists: true, provider: 'cloudflare' };
339
+ }
322
340
  const config = deploy.configurations?.[configuration];
323
341
  if (!config) {
324
342
  return { exists: false };
325
343
  }
326
- const commandValue = config.command ?? config.options?.command ?? deploy.options?.command ?? deploy.command;
344
+ const commandValue = config.command ?? config.options?.command ?? baseCommand;
327
345
  const command = typeof commandValue === 'string' ? commandValue : '';
328
346
  return { exists: true, provider: command.includes('wrangler ') ? 'cloudflare' : undefined };
329
347
  }
@@ -0,0 +1,5 @@
1
+ export interface PrPreviewCleanupWorkflowOptions {
2
+ runsOn?: string | string[];
3
+ }
4
+ export declare function renderPrPreviewCleanupWorkflowYaml(options?: PrPreviewCleanupWorkflowOptions): string;
5
+ //# sourceMappingURL=pr-preview-cleanup-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-preview-cleanup-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/pr-preview-cleanup-workflow.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,+BAA+B;IAC9C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,kCAAkC,CAAC,OAAO,GAAE,+BAAoC,GAAG,MAAM,CAmCxG"}
@@ -0,0 +1,38 @@
1
+ /* biome-ignore-all lint/suspicious/noTemplateCurlyInString: GitHub Actions expressions are emitted literally. */
2
+ import { renderRunsOnLine } from './github-runs-on.js';
3
+ export function renderPrPreviewCleanupWorkflowYaml(options = {}) {
4
+ return `name: PR Preview Cleanup
5
+
6
+ on:
7
+ pull_request:
8
+ types: [closed]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ cleanup:
15
+ name: Cleanup PR environment
16
+ if: github.event.pull_request.head.repo.full_name == github.repository
17
+ ${renderRunsOnLine(options.runsOn)}
18
+ timeout-minutes: 15
19
+ defaults:
20
+ run:
21
+ working-directory: tooling/direnv
22
+ steps:
23
+ - name: Checkout
24
+ uses: actions/checkout@v6.0.2
25
+ with:
26
+ filter: blob:none
27
+ fetch-depth: 1
28
+
29
+ - name: Setup Nix/devenv
30
+ uses: ./.github/actions/setup-devenv
31
+
32
+ - name: Cleanup PR environment
33
+ env:
34
+ CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
35
+ CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
36
+ run: smoo wrangler cleanup-pr --pr \${{ github.event.pull_request.number }}
37
+ `;
38
+ }
@@ -380,7 +380,7 @@ function deployProductionStep(step, options) {
380
380
  " ${{ steps.version.outputs.mode != 'none' && inputs.deploy_environment == 'production' && inputs.dry_run !=",
381
381
  " 'true' }}",
382
382
  ...deployEnvLines(options),
383
- ' run: smoo github-ci nx-deploy --configuration production --mode run-many --verify --name "Deploy Production"',
383
+ ' run: smoo github-ci nx-deploy --environment production --mode run-many --verify --name "Deploy Production"',
384
384
  ];
385
385
  }
386
386
  function deployEnvLines(options) {
@@ -606,7 +606,7 @@ function renderFinalLinuxPublishSteps(options) {
606
606
  }
607
607
  lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐ŸŽ Apply verified macOS outputs', ` if: ${mode} != 'none'`, ' run:', ` smoo github-ci apply-outputs --source-sha "${githubExpression('github.sha')}"`, ` "${githubExpression('runner.temp')}/publish-artifacts/publish-macos-outputs-${githubExpression('github.run_id')}/current"`, '', ` # Step ${stepNumber++}`, ` - name: โœ… Validate restored release (${githubExpression(mode)})`, ` if: ${mode} != 'none'`, ' run: smoo monorepo validate', '', ' # --- Release ------------------------------------------------------------', '', ` # Step ${stepNumber++}`, ` - name: ๐Ÿ“ฆ Publish release (${githubExpression(mode)})`, ' # smoo packs with Bun, then publishes tarballs with npm. Existing', ' # packages must already exist on npm and use trusted publishing/OIDC.', ' # Missing package names are bootstrapped locally before trust setup.', ` run: smoo release publish --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}"`);
608
608
  if (options.deploy === true) {
609
- lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿš€ Deploy production', ' if:', " ${{ needs.linux-release-candidate.outputs.mode != 'none' && inputs.deploy_environment == 'production' &&", " inputs.dry_run != 'true' }}", ...deployEnvLines(options), ' run: smoo github-ci nx-deploy --configuration production --mode run-many --verify --name "Deploy Production"');
609
+ lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿš€ Deploy production', ' if:', " ${{ needs.linux-release-candidate.outputs.mode != 'none' && inputs.deploy_environment == 'production' &&", " inputs.dry_run != 'true' }}", ...deployEnvLines(options), ' run: smoo github-ci nx-deploy --environment production --mode run-many --verify --name "Deploy Production"');
610
610
  }
611
611
  lines.push('', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ' # success() is default; always() still saves GH Nix cache after a red job.', ' if: always()', ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
612
612
  return lines.join('\n').trimEnd();
@@ -1 +1 @@
1
- {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AAgDD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAStE;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG;AAqCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAyBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAsED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQxE"}
1
+ {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AA4DD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAStE;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG;AAqCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiC7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAyBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6B3D;AAoID,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQxE"}