@smoothbricks/cli 0.3.4 โ†’ 0.4.1

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 (42) hide show
  1. package/dist/cli.js +14 -0
  2. package/dist/github-ci/index.d.ts +12 -0
  3. package/dist/github-ci/index.d.ts.map +1 -1
  4. package/dist/github-ci/index.js +72 -4
  5. package/dist/lib/run.d.ts +1 -0
  6. package/dist/lib/run.d.ts.map +1 -1
  7. package/dist/lib/run.js +11 -0
  8. package/dist/monorepo/ci-workflow.d.ts +26 -0
  9. package/dist/monorepo/ci-workflow.d.ts.map +1 -0
  10. package/dist/monorepo/ci-workflow.js +201 -0
  11. package/dist/monorepo/managed-files.d.ts.map +1 -1
  12. package/dist/monorepo/managed-files.js +97 -5
  13. package/dist/monorepo/nx-sync.d.ts.map +1 -1
  14. package/dist/monorepo/nx-sync.js +18 -4
  15. package/dist/monorepo/package-hygiene.d.ts +5 -0
  16. package/dist/monorepo/package-hygiene.d.ts.map +1 -1
  17. package/dist/monorepo/package-hygiene.js +18 -4
  18. package/dist/monorepo/package-policy.d.ts.map +1 -1
  19. package/dist/monorepo/package-policy.js +4 -2
  20. package/dist/monorepo/packed-package.js +5 -4
  21. package/dist/monorepo/packs/index.js +6 -2
  22. package/dist/monorepo/publish-workflow.d.ts +7 -1
  23. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  24. package/dist/monorepo/publish-workflow.js +59 -15
  25. package/managed/raw/git-format-staged.yml +4 -0
  26. package/package.json +2 -2
  27. package/src/cli.ts +35 -5
  28. package/src/github-ci/index.ts +94 -8
  29. package/src/lib/run.ts +13 -0
  30. package/src/monorepo/__tests__/ci-workflow.test.ts +34 -0
  31. package/src/monorepo/__tests__/publish-workflow.test.ts +65 -2
  32. package/src/monorepo/ci-workflow.ts +229 -0
  33. package/src/monorepo/managed-files.ts +115 -5
  34. package/src/monorepo/nx-sync.ts +18 -4
  35. package/src/monorepo/package-hygiene.test.ts +54 -1
  36. package/src/monorepo/package-hygiene.ts +34 -4
  37. package/src/monorepo/package-policy.test.ts +16 -6
  38. package/src/monorepo/package-policy.ts +4 -2
  39. package/src/monorepo/packed-package.ts +5 -5
  40. package/src/monorepo/packs/index.ts +6 -2
  41. package/src/monorepo/publish-workflow.ts +73 -16
  42. package/managed/templates/github/workflows/ci.yml +0 -102
@@ -1,11 +1,20 @@
1
- import { run, runStatus } from '../lib/run.js';
1
+ import { printCommandOutput, run, runResult, runStatus } from '../lib/run.js';
2
2
 
3
3
  export interface PackageHygieneShell {
4
4
  run(command: string, args: string[], cwd: string): Promise<void>;
5
+ runResult?(
6
+ command: string,
7
+ args: string[],
8
+ cwd: string,
9
+ ): Promise<{
10
+ exitCode: number;
11
+ stdout: string;
12
+ stderr: string;
13
+ }>;
5
14
  runStatus(command: string, args: string[], cwd: string, quiet?: boolean): Promise<number>;
6
15
  }
7
16
 
8
- const defaultShell: PackageHygieneShell = { run, runStatus };
17
+ const defaultShell: PackageHygieneShell = { run, runResult, runStatus };
9
18
 
10
19
  export async function fixPackageHygiene(
11
20
  root: string,
@@ -14,8 +23,12 @@ export async function fixPackageHygiene(
14
23
  ): Promise<void> {
15
24
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
16
25
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
17
- const status = await shell.runStatus('sherif', ['-f', '--select', 'highest'], root, !verbose);
26
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['-f', '--select', 'highest'], root, verbose);
27
+ const status = result.exitCode;
18
28
  if (status !== 0) {
29
+ if (!verbose) {
30
+ printCommandOutput(result.stdout, result.stderr);
31
+ }
19
32
  throw new Error(`sherif -f --select highest failed with exit code ${status}`);
20
33
  }
21
34
  }
@@ -27,10 +40,27 @@ export async function validatePackageHygiene(
27
40
  ): Promise<number> {
28
41
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
29
42
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
30
- const status = await shell.runStatus('sherif', ['--fail-on-warnings'], root, !verbose);
43
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['--fail-on-warnings'], root, verbose);
44
+ const status = result.exitCode;
31
45
  if (status !== 0) {
46
+ if (!verbose) {
47
+ printCommandOutput(result.stdout, result.stderr);
48
+ }
32
49
  console.error('sherif package hygiene validation failed');
33
50
  return 1;
34
51
  }
35
52
  return 0;
36
53
  }
54
+
55
+ async function runPackageHygieneCommand(
56
+ shell: PackageHygieneShell,
57
+ command: string,
58
+ args: string[],
59
+ root: string,
60
+ verbose: boolean,
61
+ ): Promise<{ exitCode: number; stdout: string; stderr: string }> {
62
+ if (!verbose && shell.runResult) {
63
+ return shell.runResult(command, args, root);
64
+ }
65
+ return { exitCode: await shell.runStatus(command, args, root, !verbose), stdout: '', stderr: '' };
66
+ }
@@ -51,14 +51,17 @@ describe('root smoo monorepo policy', () => {
51
51
  );
52
52
  await writeJson(join(root, 'nx.json'), validNxJson());
53
53
 
54
- expect(validateRootPackagePolicy(root)).toBe(5);
55
- expect(validateNxReleaseConfig(root)).toBe(6);
54
+ expect(validateRootPackagePolicy(root)).toBe(7);
55
+ expect(validateNxReleaseConfig(root)).toBe(8);
56
56
 
57
57
  applyFixableMonorepoDefaults(root);
58
58
 
59
59
  const rootPackage = await readJson(join(root, 'package.json'));
60
60
  const nxJson = await readJson(join(root, 'nx.json'));
61
61
  expect(rootPackage.scripts).toEqual({
62
+ clean: 'nx run-many -t clean; nx reset',
63
+ 'clean:node_modules':
64
+ 'rm -rf node_modules && find e* t* p* -type d -name node_modules -print0 | xargs -0 rm -rvf',
62
65
  'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
63
66
  'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
64
67
  lint: 'nx run-many -t lint',
@@ -66,7 +69,7 @@ describe('root smoo monorepo policy', () => {
66
69
  });
67
70
  expect(rootPackage).toMatchObject({ nx: { includedScripts: [] } });
68
71
  expect(nxJson.namedInputs).toEqual(validNamedInputs());
69
- expect(nxJson.targetDefaults).toEqual({ build: { cache: true, outputs: ['{projectRoot}/dist'] } });
72
+ expect(nxJson.targetDefaults).toEqual(validTargetDefaults());
70
73
  expect(nxJson.plugins).toEqual([
71
74
  {
72
75
  plugin: '@nx/js/typescript',
@@ -152,12 +155,12 @@ describe('root smoo monorepo policy', () => {
152
155
  },
153
156
  });
154
157
 
155
- expect(validateNxReleaseConfig(root)).toBe(4);
158
+ expect(validateNxReleaseConfig(root)).toBe(6);
156
159
 
157
160
  applyFixableMonorepoDefaults(root);
158
161
 
159
162
  const nxJson = await readJson(join(root, 'nx.json'));
160
- expect(nxJson.targetDefaults).toEqual({ build: { cache: true, outputs: ['{projectRoot}/dist'] } });
163
+ expect(nxJson.targetDefaults).toEqual(validTargetDefaults());
161
164
  expect(validateNxReleaseConfig(root)).toBe(0);
162
165
  } finally {
163
166
  await rm(root, { recursive: true, force: true });
@@ -1096,7 +1099,7 @@ function validConfiguredNxJson(): Record<string, unknown> {
1096
1099
  return {
1097
1100
  ...validNxJson(),
1098
1101
  namedInputs: validNamedInputs(),
1099
- targetDefaults: { build: { cache: true, outputs: ['{projectRoot}/dist'] } },
1102
+ targetDefaults: validTargetDefaults(),
1100
1103
  plugins: [
1101
1104
  {
1102
1105
  plugin: '@nx/js/typescript',
@@ -1115,6 +1118,13 @@ function validConfiguredNxJson(): Record<string, unknown> {
1115
1118
  };
1116
1119
  }
1117
1120
 
1121
+ function validTargetDefaults(): Record<string, unknown> {
1122
+ return {
1123
+ build: { cache: true, outputs: ['{projectRoot}/dist'] },
1124
+ clean: { executor: '@smoothbricks/nx-plugin:clean-outputs', cache: false },
1125
+ };
1126
+ }
1127
+
1118
1128
  function validNamedInputs(): Record<string, unknown> {
1119
1129
  return {
1120
1130
  default: ['{projectRoot}/**/*', 'sharedGlobals'],
@@ -48,10 +48,12 @@ export { SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS };
48
48
 
49
49
  const extraCommitScopes = ['release'];
50
50
  const rootScriptPolicy: Record<string, string> = {
51
+ clean: 'nx run-many -t clean; nx reset',
52
+ 'clean:node_modules': 'rm -rf node_modules && find e* t* p* -type d -name node_modules -print0 | xargs -0 rm -rvf',
53
+ 'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
54
+ 'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
51
55
  lint: 'nx run-many -t lint',
52
56
  'lint:fix': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --unstaged',
53
- 'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
54
- 'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
55
57
  };
56
58
 
57
59
  export function applyFixableMonorepoDefaults(root: string): void {
@@ -3,7 +3,7 @@ import { join } from 'node:path';
3
3
  import { publint } from 'publint';
4
4
  import { formatMessage } from 'publint/utils';
5
5
  import { isRecord } from '../lib/json.js';
6
- import { runResult, runStatus } from '../lib/run.js';
6
+ import { printCommandOutput, runResult } from '../lib/run.js';
7
7
  import type { PackageInfo } from '../lib/workspace.js';
8
8
  import { listPublicPackages } from '../lib/workspace.js';
9
9
  import { readPackedPackageJson, validatePackedWorkspaceDependencies } from './packed-manifest.js';
@@ -142,14 +142,14 @@ async function packPackage(root: string, pkg: PackageInfo): Promise<{ path: stri
142
142
  const tarballName = `.smoo-${process.pid}-${Date.now()}.tgz`;
143
143
  const tarballPath = join(root, tarballName);
144
144
  try {
145
- const status = await runStatus(
145
+ const result = await runResult(
146
146
  'bun',
147
147
  ['pm', 'pack', '--filename', tarballName, '--ignore-scripts', '--quiet'],
148
148
  packageDir,
149
- true,
150
149
  );
151
- if (status !== 0) {
152
- throw new Error(`bun pm pack failed with exit code ${status}`);
150
+ if (result.exitCode !== 0) {
151
+ printCommandOutput(result.stdout, result.stderr);
152
+ throw new Error(`bun pm pack failed with exit code ${result.exitCode}`);
153
153
  }
154
154
  const bytes = new Uint8Array(readFileSync(tarballPath));
155
155
  return { path: tarballPath, arrayBuffer: bytes.slice().buffer };
@@ -1,6 +1,6 @@
1
1
  import { chmodSync, existsSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { runStatus } from '../../lib/run.js';
3
+ import { printCommandOutput, runResult, runStatus } from '../../lib/run.js';
4
4
  import { readProjectTargets } from '../../nx/index.js';
5
5
  import { syncBunLockfileVersions, validateBunLockfileVersions } from '../lockfile.js';
6
6
  import { validateManagedFiles } from '../managed-files.js';
@@ -315,10 +315,14 @@ async function runBuild(ctx: MonorepoContext, options: ValidatePackOptions = {})
315
315
  if (options.verbose) {
316
316
  printCheckHeading('build', true);
317
317
  }
318
- const status = await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, options.verbose !== true);
318
+ const result = options.verbose
319
+ ? { exitCode: await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, false), stdout: '', stderr: '' }
320
+ : await runResult('nx', ['run-many', '-t', 'build'], ctx.root);
321
+ const status = result.exitCode;
319
322
  if (status !== 0) {
320
323
  if (!options.verbose) {
321
324
  printCheckHeading('build', true);
325
+ printCommandOutput(result.stdout, result.stderr);
322
326
  }
323
327
  console.error('nx run-many -t build failed');
324
328
  printCheckStatus('build', 1);
@@ -1,8 +1,9 @@
1
1
  import { isSmoothBricksCodebasePackageName } from '../lib/cli-package.js';
2
2
 
3
3
  export type PublishWorkflowBump = 'auto' | 'patch' | 'minor' | 'major' | 'prerelease';
4
- export type PublishWorkflowCondition = 'version-mode-not-none' | 'failure' | 'always';
4
+ export type PublishWorkflowCondition = 'version-mode-not-none' | 'deploy-production' | 'failure' | 'always';
5
5
  export type PublishWorkflowNxTarget = 'build' | 'lint' | 'test';
6
+ export type PublishWorkflowDeployEnvironment = 'none' | 'production';
6
7
 
7
8
  export enum PublishWorkflowStepKind {
8
9
  Checkout = 'checkout',
@@ -18,6 +19,7 @@ export enum PublishWorkflowStepKind {
18
19
  UploadTraceDbs = 'upload-trace-dbs',
19
20
  ValidateMonorepoConfig = 'validate-monorepo-config',
20
21
  PublishRelease = 'publish-release',
22
+ DeployProduction = 'deploy-production',
21
23
  SaveNixDevenv = 'save-nix-devenv',
22
24
  }
23
25
 
@@ -35,11 +37,14 @@ export interface PublishWorkflowDefinition {
35
37
  }
36
38
 
37
39
  export interface PublishWorkflowDefinitionOptions {
40
+ deploy?: boolean;
41
+ deployProvider?: 'cloudflare';
38
42
  repoName?: string;
39
43
  }
40
44
 
41
45
  export interface PublishWorkflowInputs {
42
46
  bump: PublishWorkflowBump;
47
+ deployEnvironment: PublishWorkflowDeployEnvironment;
43
48
  dryRun: boolean;
44
49
  }
45
50
 
@@ -65,6 +70,7 @@ export interface PublishWorkflowCallbacks {
65
70
  uploadTraceDbs(): Promise<void>;
66
71
  validateMonorepoConfig(): Promise<void>;
67
72
  publishRelease(input: { bump: PublishWorkflowBump; dryRun: boolean }): Promise<void>;
73
+ deployProduction(): Promise<void>;
68
74
  saveNixDevenv(input: PublishWorkflowSetupOutputs): Promise<void>;
69
75
  }
70
76
 
@@ -90,6 +96,19 @@ export function definePublishWorkflow(options: PublishWorkflowDefinitionOptions
90
96
  if (isSmoothBricksCodebasePackageName(options.repoName)) {
91
97
  setupSteps.push({ kind: PublishWorkflowStepKind.BuildSelfHostedCli, name: '๐Ÿ—๏ธ Build self-hosted smoo' });
92
98
  }
99
+ const releaseSteps: PublishWorkflowStepInput[] = [
100
+ {
101
+ kind: PublishWorkflowStepKind.PublishRelease,
102
+ name: `๐Ÿ“ฆ Publish release (${versionMode})`,
103
+ },
104
+ ];
105
+ if (options.deploy === true) {
106
+ releaseSteps.push({
107
+ kind: PublishWorkflowStepKind.DeployProduction,
108
+ name: '๐Ÿš€ Deploy production',
109
+ condition: 'deploy-production',
110
+ });
111
+ }
93
112
  return {
94
113
  steps: numberWorkflowSteps([
95
114
  ...setupSteps,
@@ -127,10 +146,7 @@ export function definePublishWorkflow(options: PublishWorkflowDefinitionOptions
127
146
  name: `โœ… Validate monorepo config (${versionMode})`,
128
147
  condition: 'version-mode-not-none',
129
148
  },
130
- {
131
- kind: PublishWorkflowStepKind.PublishRelease,
132
- name: `๐Ÿ“ฆ Publish release (${versionMode})`,
133
- },
149
+ ...releaseSteps,
134
150
  {
135
151
  kind: PublishWorkflowStepKind.SaveNixDevenv,
136
152
  name: '๐Ÿงน Cleanup and cache Nix/devenv',
@@ -153,7 +169,7 @@ export async function runPublishWorkflow(
153
169
  let failed = false;
154
170
  let failure: unknown;
155
171
  for (const step of workflow.steps) {
156
- if (!shouldRunStep(step, version, failed)) {
172
+ if (!shouldRunStep(step, version, failed, context.inputs)) {
157
173
  continue;
158
174
  }
159
175
  try {
@@ -201,6 +217,9 @@ export async function runPublishWorkflow(
201
217
  dryRun: context.inputs.dryRun,
202
218
  });
203
219
  break;
220
+ case PublishWorkflowStepKind.DeployProduction:
221
+ await context.callbacks.deployProduction();
222
+ break;
204
223
  case PublishWorkflowStepKind.SaveNixDevenv:
205
224
  await context.callbacks.saveNixDevenv(setupOutputs);
206
225
  break;
@@ -216,10 +235,18 @@ export async function runPublishWorkflow(
216
235
  return { version, failed };
217
236
  }
218
237
 
219
- function shouldRunStep(step: PublishWorkflowStep, version: PublishWorkflowVersionOutputs, failed: boolean): boolean {
238
+ function shouldRunStep(
239
+ step: PublishWorkflowStep,
240
+ version: PublishWorkflowVersionOutputs,
241
+ failed: boolean,
242
+ inputs: PublishWorkflowInputs,
243
+ ): boolean {
220
244
  if (step.condition === 'version-mode-not-none') {
221
245
  return version.mode !== 'none';
222
246
  }
247
+ if (step.condition === 'deploy-production') {
248
+ return version.mode !== 'none' && inputs.deployEnvironment === 'production' && !inputs.dryRun;
249
+ }
223
250
  if (step.condition === 'failure') {
224
251
  return failed;
225
252
  }
@@ -228,10 +255,19 @@ function shouldRunStep(step: PublishWorkflowStep, version: PublishWorkflowVersio
228
255
 
229
256
  export function renderPublishWorkflowYaml(options: PublishWorkflowDefinitionOptions = {}): string {
230
257
  const steps = definePublishWorkflow(options).steps;
231
- return `${renderPublishWorkflowHeader()}${renderPublishWorkflowSteps(steps)}`;
258
+ return `${renderPublishWorkflowHeader(options)}${renderPublishWorkflowSteps(steps, options)}`;
232
259
  }
233
260
 
234
- function renderPublishWorkflowHeader(): string {
261
+ function renderPublishWorkflowHeader(options: PublishWorkflowDefinitionOptions): string {
262
+ const deployInput =
263
+ options.deploy === true
264
+ ? `
265
+ deploy_environment:
266
+ type: choice
267
+ description: Deploy live systems after a successful publish.
268
+ options: [none, production]
269
+ default: none`
270
+ : '';
235
271
  return `name: Publish
236
272
 
237
273
  on:
@@ -247,7 +283,7 @@ on:
247
283
  dry_run:
248
284
  type: boolean
249
285
  description: Run release commands without writing versions, tags, publishes, or GitHub Releases.
250
- default: false
286
+ default: false${deployInput}
251
287
 
252
288
  permissions:
253
289
  contents: write
@@ -271,12 +307,12 @@ jobs:
271
307
  `;
272
308
  }
273
309
 
274
- function renderPublishWorkflowSteps(steps: PublishWorkflowStep[]): string {
310
+ function renderPublishWorkflowSteps(steps: PublishWorkflowStep[], options: PublishWorkflowDefinitionOptions): string {
275
311
  const lines: string[] = [];
276
312
  for (const step of steps) {
277
313
  lines.push(...sectionLinesBefore(step));
278
314
  lines.push(...commentLinesForStep(step));
279
- lines.push(...yamlLinesForStep(step));
315
+ lines.push(...yamlLinesForStep(step, options));
280
316
  lines.push('');
281
317
  }
282
318
  return `${lines.join('\n').trimEnd()}\n`;
@@ -319,7 +355,7 @@ function commentLinesForStep(step: PublishWorkflowStep): string[] {
319
355
  return [` # Step ${step.number}`];
320
356
  }
321
357
 
322
- function yamlLinesForStep(step: PublishWorkflowStep): string[] {
358
+ function yamlLinesForStep(step: PublishWorkflowStep, options: PublishWorkflowDefinitionOptions): string[] {
323
359
  switch (step.kind) {
324
360
  case PublishWorkflowStepKind.Checkout:
325
361
  return [
@@ -396,6 +432,8 @@ function yamlLinesForStep(step: PublishWorkflowStep): string[] {
396
432
  ' # Missing package names are bootstrapped locally before trust setup.',
397
433
  ` run: smoo release publish --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}"`,
398
434
  ];
435
+ case PublishWorkflowStepKind.DeployProduction:
436
+ return deployProductionStep(step, options);
399
437
  case PublishWorkflowStepKind.SaveNixDevenv:
400
438
  return [
401
439
  ` - name: ${step.name}`,
@@ -408,14 +446,33 @@ function yamlLinesForStep(step: PublishWorkflowStep): string[] {
408
446
  }
409
447
  }
410
448
 
411
- function conditionalRunStep(step: PublishWorkflowStep, run: string): string[] {
449
+ function deployProductionStep(step: PublishWorkflowStep, options: PublishWorkflowDefinitionOptions): string[] {
412
450
  return [
413
451
  ` - name: ${step.name}`,
414
- ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`,
415
- ` run: ${run}`,
452
+ ' if:',
453
+ " ${{ steps.version.outputs.mode != 'none' && inputs.deploy_environment == 'production' && inputs.dry_run !=",
454
+ " 'true' }}",
455
+ ...deployEnvLines(options),
456
+ ' run: smoo github-ci nx-deploy --configuration production --mode run-many --verify --name "Deploy Production"',
416
457
  ];
417
458
  }
418
459
 
460
+ function deployEnvLines(options: PublishWorkflowDefinitionOptions): string[] {
461
+ if (options.deployProvider !== 'cloudflare') {
462
+ return [];
463
+ }
464
+ return [
465
+ ' env:',
466
+ ' CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}',
467
+ ' CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}',
468
+ ];
469
+ }
470
+
471
+ function conditionalRunStep(step: PublishWorkflowStep, run: string): string[] {
472
+ const condition = "steps.version.outputs.mode != 'none'";
473
+ return [` - name: ${step.name}`, ` if: ${githubExpression(condition)}`, ` run: ${run}`];
474
+ }
475
+
419
476
  function githubExpression(expression: string): string {
420
477
  return ['$', '{{ ', expression, ' }}'].join('');
421
478
  }
@@ -1,102 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches:
6
- - '**'
7
- pull_request:
8
-
9
- permissions:
10
- actions: read
11
- contents: read
12
- statuses: write
13
-
14
- defaults:
15
- run:
16
- working-directory: tooling/direnv
17
-
18
- jobs:
19
- main:
20
- name: Validate
21
- runs-on: ubuntu-latest
22
- timeout-minutes: 45
23
- env:
24
- NIX_STORE_NAR: ${{ github.workspace }}/nix-store.nar
25
- GH_TOKEN: ${{ github.token }}
26
- steps:
27
- # Step 1: GitHub adds "Set up job" automatically
28
- # Step 2
29
- - name: ๐Ÿ“ฅ Checkout
30
- uses: actions/checkout@v6.0.2
31
- with:
32
- filter: blob:none
33
- fetch-depth: 0
34
-
35
- # Step 3. Composite action internals do not affect top-level job step
36
- # anchors; update the nx-smart --step values below if top-level steps move.
37
- - name: ๐Ÿงฑ Setup Nix/devenv
38
- id: setup
39
- uses: ./.github/actions/setup-devenv
40
-
41
- # --- Nx -----------------------------------------------------------------
42
-
43
- # Step 4
44
- # Sets the base and head SHAs required for the nx affected commands
45
- - name: ๐Ÿงญ Set Nx SHAs
46
- uses: nrwl/nx-set-shas@v5.0.1
47
- with:
48
- workflow-id: ci.yml
49
-
50
- # Step 5
51
- - name: ๐Ÿง  Restore Nx cache
52
- id: nx-cache
53
- uses: ./.github/actions/cache-nx
54
-
55
- # Step 6
56
- - name: ๐Ÿ”จ Build
57
- run: smoo github-ci nx-smart --target build --name "Build" --step 6
58
-
59
- # Step 7
60
- - name: ๐Ÿ” Lint
61
- run: smoo github-ci nx-smart --target lint --name "Lint" --step 7
62
-
63
- # Step 8
64
- - name: ๐Ÿงช Unit Tests
65
- run: smoo github-ci nx-smart --target test --name "Unit Tests" --step 8
66
-
67
- # Step 9
68
- # Nx's database cache needs artifact files and .nx/workspace-data DB
69
- # metadata restored together; GitHub Actions cache is only the archive
70
- # transport. Save runs only after build/lint/test succeed on the default
71
- # branch, so PRs may restore shared cache but cannot publish it.
72
- - name: ๐Ÿ’พ Save Nx cache
73
- if:
74
- ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}',
75
- github.event.repository.default_branch) && steps.nx-cache.outputs.cache-hit != 'true' }}
76
- uses: actions/cache/save@v5.0.5
77
- with:
78
- path: |
79
- .nx/cache
80
- .nx/workspace-data/*.db*
81
- key: ${{ runner.os }}-nx-db-v1-${{ github.sha }}
82
-
83
- # Step 10
84
- - name: ๐Ÿ“Ž Upload trace DBs
85
- if: ${{ always() }}
86
- uses: actions/upload-artifact@v7.0.1
87
- with:
88
- name: trace-results-${{ github.run_id }}
89
- path: packages/*/.trace-results.db
90
- if-no-files-found: ignore
91
- retention-days: 14
92
- include-hidden-files: true
93
-
94
- # --- Cleanup ------------------------------------------------------------
95
-
96
- # Step 11
97
- - name: ๐Ÿงน Cleanup and cache Nix/devenv
98
- if: ${{ always() }}
99
- uses: ./.github/actions/save-nix-devenv
100
- with:
101
- nix-cache-hit: ${{ steps.setup.outputs.nix-cache-hit }}
102
- devenv-cache-hit: ${{ steps.setup.outputs.devenv-cache-hit }}