@smoothbricks/cli 0.11.14 → 0.11.16

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 (35) hide show
  1. package/dist/lib/json.d.ts +9 -0
  2. package/dist/lib/json.d.ts.map +1 -1
  3. package/dist/lib/json.js +65 -53
  4. package/dist/monorepo/managed-files.d.ts +9 -0
  5. package/dist/monorepo/managed-files.d.ts.map +1 -1
  6. package/dist/monorepo/managed-files.js +28 -2
  7. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  8. package/dist/monorepo/publish-workflow.js +52 -2
  9. package/dist/release/github-release.d.ts +16 -0
  10. package/dist/release/github-release.d.ts.map +1 -1
  11. package/dist/release/github-release.js +11 -2
  12. package/dist/release/index.d.ts +1 -1
  13. package/dist/release/index.d.ts.map +1 -1
  14. package/dist/release/index.js +29 -7
  15. package/dist/release/private-npm.d.ts +5 -0
  16. package/dist/release/private-npm.d.ts.map +1 -1
  17. package/dist/release/private-npm.js +26 -5
  18. package/managed/raw/tooling/direnv/devenv.smoo.nix +4 -2
  19. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +38 -0
  20. package/managed/raw/tooling/direnv/secret-references.ts +66 -0
  21. package/managed/raw/tooling/direnv/setup-environment.ts +81 -26
  22. package/managed/raw/tooling/direnv/toolchain-stamp.ts +88 -0
  23. package/managed/templates/github/actions/setup-devenv/action.yml +4 -2
  24. package/package.json +2 -2
  25. package/src/lib/json.ts +9 -0
  26. package/src/monorepo/__tests__/publish-workflow.test.ts +54 -0
  27. package/src/monorepo/managed-files.test.ts +26 -0
  28. package/src/monorepo/managed-files.ts +36 -2
  29. package/src/monorepo/publish-workflow.ts +70 -2
  30. package/src/monorepo/secret-references.test.ts +68 -0
  31. package/src/release/__tests__/private-npm-status.test.ts +37 -0
  32. package/src/release/__tests__/private-npm-workflow.test.ts +20 -0
  33. package/src/release/github-release.ts +31 -2
  34. package/src/release/index.ts +30 -4
  35. package/src/release/private-npm.ts +30 -5
@@ -48,6 +48,7 @@ export {
48
48
  type PrivateNpmRegistryConfigErrorKind,
49
49
  type PublishDestination,
50
50
  privateNpmPublishArgs,
51
+ privateNpmTokenEnvForMode,
51
52
  privateNpmUserconfigContent,
52
53
  publishPrivateWithDiagnostics,
53
54
  type Result as PrivateNpmResult,
@@ -58,6 +59,7 @@ export {
58
59
  withPrivateNpmUserconfig,
59
60
  } from './private-npm.js';
60
61
 
62
+ import { PLATFORM_TARGET_GLOBS } from '@smoothbricks/nx-plugin/workspace-config-policy';
61
63
  import { ciApiContext } from '../github-ci/api.js';
62
64
  import { readProjectTargets } from '../nx/index.js';
63
65
  import {
@@ -88,6 +90,7 @@ import {
88
90
  import {
89
91
  createOrUpdateGithubRelease,
90
92
  githubReleaseLookupExists,
93
+ importWorkspaceNx,
91
94
  renderNxProjectChangelogContents,
92
95
  withNxWorkspaceRoot,
93
96
  } from './github-release.js';
@@ -113,6 +116,7 @@ import {
113
116
  npmPublishedVersionExists as npmPublishedVersionExistsOnRegistry,
114
117
  type PrivateNpmRegistry,
115
118
  privateNpmPublishArgs,
119
+ privateNpmTokenEnvForMode,
116
120
  publishPrivateWithDiagnostics,
117
121
  selectPublishDestination,
118
122
  selectRegistryForPackage,
@@ -753,7 +757,13 @@ async function publishPrivatePackedPackage(
753
757
  await publishPrivateWithDiagnostics(
754
758
  pkg,
755
759
  {
756
- publish: () => runNpm(root, args, { NPM_CONFIG_USERCONFIG: userconfig }),
760
+ publish: () =>
761
+ runNpm(root, args, {
762
+ NPM_CONFIG_USERCONFIG: userconfig,
763
+ // Env config outranks a committed project `.npmrc` auth line; see
764
+ // npmStatusEnv in private-npm.ts for why that matters here.
765
+ [`npm_config_${registry.authKey}`]: process.env[privateNpmTokenEnvForMode(registry, 'publish')] ?? '',
766
+ }),
757
767
  // The open publish userconfig already authenticates this registry,
758
768
  // so the failure probe reuses it. Opening a second read-mode
759
769
  // userconfig here demanded a read credential the publishing job need
@@ -763,6 +773,7 @@ async function publishPrivatePackedPackage(
763
773
  npmPublishedVersionExistsOnRegistry(root, pkg.name, pkg.version, {
764
774
  registry: registry.registry,
765
775
  userconfig,
776
+ credential: { authKey: registry.authKey, tokenEnv: privateNpmTokenEnvForMode(registry, 'publish') },
766
777
  }),
767
778
  log: (message) => console.log(message),
768
779
  error: (message) => console.error(message),
@@ -881,8 +892,8 @@ async function runNxReleaseVersion(
881
892
 
882
893
  async function runNxReleaseVersionPreview(root: string, projects: string, bump: string): Promise<ReleasePackage[]> {
883
894
  return withNxWorkspaceRoot(root, async () => {
884
- const { createAPI } = await import('nx/src/command-line/release/version.js');
885
- const { createAPI: createChangelogAPI } = await import('nx/src/command-line/release/changelog.js');
895
+ const { createAPI } = await importWorkspaceNx(root, 'src/command-line/release/version.js');
896
+ const { createAPI: createChangelogAPI } = await importWorkspaceNx(root, 'src/command-line/release/changelog.js');
886
897
  const projectNames = projects.split(',').filter(Boolean);
887
898
  const result = await createAPI(
888
899
  {},
@@ -1196,6 +1207,17 @@ function releaseRepairShell(root: string, platformOutputs: readonly string[]): R
1196
1207
  const sourceSha = await gitHead(root);
1197
1208
  const outputs = platformOutputs.map((base) => join(base, sourceSha));
1198
1209
  if (outputs.length === 0) {
1210
+ // No producer job handed outputs over, so this runner is the producer:
1211
+ // build the platform legs at the checked-out ref. `build` alone gives a
1212
+ // package only the legs its own graph depends on — the host one and
1213
+ // whatever it declares — and the release gate demands the whole declared
1214
+ // native closure, so a foreign leg it never asked for was simply absent.
1215
+ console.log('Repair pending releases: building cross-platform outputs on this runner.');
1216
+ await githubCiNxRunMany(root, {
1217
+ targets: PLATFORM_TARGET_GLOBS.join(','),
1218
+ projects: releasePackageProjects(packages),
1219
+ allowEmptyProjects: true,
1220
+ });
1199
1221
  return;
1200
1222
  }
1201
1223
  console.log(`Repair pending releases: applying cross-platform outputs from ${outputs.join(', ')}.`);
@@ -1864,7 +1886,11 @@ async function npmVersionExists(root: string, name: string, version: string): Pr
1864
1886
  return npmPublishedVersionExistsOnRegistry(root, name, version);
1865
1887
  }
1866
1888
  return withPrivateNpmUserconfig(registry, 'read', (userconfig) =>
1867
- npmPublishedVersionExistsOnRegistry(root, name, version, { registry: registry.registry, userconfig }),
1889
+ npmPublishedVersionExistsOnRegistry(root, name, version, {
1890
+ registry: registry.registry,
1891
+ userconfig,
1892
+ credential: { authKey: registry.authKey, tokenEnv: privateNpmTokenEnvForMode(registry, 'read') },
1893
+ }),
1868
1894
  );
1869
1895
  }
1870
1896
 
@@ -247,7 +247,12 @@ export function resolvePrivateNpmWorkflowConfig(root: string): PackagePrivateNpm
247
247
  return undefined;
248
248
  }
249
249
  const npmrcEnv = npmrcAuthTokenEnv(root, declared.scope);
250
- const readTokenEnv = consumes ? (declared.readTokenEnv ?? npmrcEnv) : undefined;
250
+ // A publishing workspace reads the registry too: every release after the
251
+ // first checks the previous tag's durable state, and that check runs in the
252
+ // producer jobs that never see the publish credential. A declared read token
253
+ // therefore always renders; only the .npmrc fallback stays consumer-only, so
254
+ // a publish token is never promoted into a read role by inference.
255
+ const readTokenEnv = declared.readTokenEnv ?? (consumes ? npmrcEnv : undefined);
251
256
  const publishTokenEnv = publishes ? (declared.publishTokenEnv ?? npmrcEnv) : undefined;
252
257
  if (!readTokenEnv && !publishTokenEnv) {
253
258
  return undefined;
@@ -412,10 +417,30 @@ export async function withPrivateNpmUserconfig<T>(
412
417
  export interface NpmStatusOptions {
413
418
  registry?: string;
414
419
  userconfig?: string;
420
+ /** Path-scoped auth key and token env, so the credential can ride env config. */
421
+ credential?: { authKey: string; tokenEnv: string };
415
422
  }
416
423
 
417
- function npmStatusEnv(userconfig: string | undefined): Record<string, string> | undefined {
418
- return userconfig ? { NPM_CONFIG_USERCONFIG: userconfig } : undefined;
424
+ /**
425
+ * npm config precedence is cli > env > project `.npmrc` > userconfig. A
426
+ * repository that commits its own `//host/path:_authToken=${SOME_ENV}` line
427
+ * therefore OVERRIDES the userconfig this module writes, and when that env is
428
+ * unset npm sends the unexpanded value: the registry answers 401 on reads with
429
+ * a perfectly good read credential, naming nothing. So the credential also
430
+ * rides as env config, which the project file cannot outrank, and the token
431
+ * value stays out of every file on disk.
432
+ */
433
+ function npmStatusEnv(
434
+ userconfig: string | undefined,
435
+ credential?: { authKey: string; tokenEnv: string },
436
+ ): Record<string, string> | undefined {
437
+ if (!userconfig) return undefined;
438
+ const env: Record<string, string> = { NPM_CONFIG_USERCONFIG: userconfig };
439
+ const token = credential ? process.env[credential.tokenEnv] : undefined;
440
+ if (credential && token) {
441
+ env[`npm_config_${credential.authKey}`] = token;
442
+ }
443
+ return env;
419
444
  }
420
445
 
421
446
  function npmCommandFailedMessage(npmArgs: string[], exitCode: number, stdout = '', stderr = ''): string {
@@ -439,7 +464,7 @@ export async function npmPublishedVersionExists(
439
464
  if (options.registry) {
440
465
  args.push('--registry', options.registry);
441
466
  }
442
- const result = await runResult('npm', args, root, npmStatusEnv(options.userconfig));
467
+ const result = await runResult('npm', args, root, npmStatusEnv(options.userconfig, options.credential));
443
468
  if (result.exitCode === 0) {
444
469
  return true;
445
470
  }
@@ -455,7 +480,7 @@ export async function npmPackageExists(root: string, name: string, options: NpmS
455
480
  if (options.registry) {
456
481
  args.push('--registry', options.registry);
457
482
  }
458
- const result = await runResult('npm', args, root, npmStatusEnv(options.userconfig));
483
+ const result = await runResult('npm', args, root, npmStatusEnv(options.userconfig, options.credential));
459
484
  if (result.exitCode === 0) {
460
485
  return true;
461
486
  }