@smoothbricks/cli 0.11.12 → 0.11.14
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/README.md +104 -20
- package/dist/cli.js +6 -1
- package/dist/lib/json.d.ts +51 -0
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/json.js +111 -67
- package/dist/monorepo/ci-workflow.d.ts +27 -2
- package/dist/monorepo/ci-workflow.d.ts.map +1 -1
- package/dist/monorepo/ci-workflow.js +151 -11
- package/dist/monorepo/index.d.ts +2 -0
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +1 -1
- package/dist/monorepo/managed-files.d.ts +3 -1
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +3 -0
- package/dist/monorepo/packed-package.d.ts +3 -3
- package/dist/monorepo/packed-package.d.ts.map +1 -1
- package/dist/monorepo/packed-package.js +11 -6
- package/dist/monorepo/packs/index.d.ts +8 -0
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +6 -5
- package/dist/monorepo/publish-workflow.d.ts +8 -1
- package/dist/monorepo/publish-workflow.d.ts.map +1 -1
- package/dist/monorepo/publish-workflow.js +20 -6
- package/managed/raw/tooling/direnv/devenv.smoo.nix +28 -4
- package/managed/raw/tooling/direnv/secret-references.ts +138 -53
- package/managed/templates/github/actions/save-nix-devenv/action.yml +2 -2
- package/managed/templates/github/actions/setup-devenv/action.yml +54 -5
- package/package.json +2 -2
- package/src/cli.ts +10 -1
- package/src/lib/json.ts +52 -0
- package/src/monorepo/__tests__/ci-workflow.test.ts +183 -0
- package/src/monorepo/__tests__/publish-workflow.test.ts +32 -0
- package/src/monorepo/ci-workflow.ts +180 -11
- package/src/monorepo/index.ts +6 -1
- package/src/monorepo/managed-files.ts +6 -0
- package/src/monorepo/packed-package.ts +21 -6
- package/src/monorepo/packs/index.ts +14 -5
- package/src/monorepo/publish-workflow.ts +32 -5
- package/src/monorepo/secret-references.test.ts +28 -2
|
@@ -36,6 +36,14 @@ export interface MonorepoContext {
|
|
|
36
36
|
root: string;
|
|
37
37
|
syncRuntime: boolean;
|
|
38
38
|
verbose?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Nx project names the validation is about, when a caller knows: the
|
|
41
|
+
* release's candidates. The build phase and the packed-package packs scope
|
|
42
|
+
* to them; manifest-level packs still see the whole repository, because a
|
|
43
|
+
* package's hygiene does not depend on which packages ship today. Absent,
|
|
44
|
+
* everything is validated and everything is built.
|
|
45
|
+
*/
|
|
46
|
+
projects?: readonly string[];
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export interface ValidatePackOptions {
|
|
@@ -174,19 +182,19 @@ const packs: MonorepoPack[] = [
|
|
|
174
182
|
{
|
|
175
183
|
name: 'packed-package-publint',
|
|
176
184
|
validatePostBuild(ctx) {
|
|
177
|
-
return validatePackedPublishablePackagePublint(ctx.root);
|
|
185
|
+
return validatePackedPublishablePackagePublint(ctx.root, ctx.projects);
|
|
178
186
|
},
|
|
179
187
|
},
|
|
180
188
|
{
|
|
181
189
|
name: 'packed-package-manifest',
|
|
182
190
|
validatePostBuild(ctx) {
|
|
183
|
-
return validatePackedPublishablePackageManifest(ctx.root);
|
|
191
|
+
return validatePackedPublishablePackageManifest(ctx.root, ctx.projects);
|
|
184
192
|
},
|
|
185
193
|
},
|
|
186
194
|
{
|
|
187
195
|
name: 'packed-package-types',
|
|
188
196
|
validatePostBuild(ctx) {
|
|
189
|
-
return validatePackedPublishablePackageTypes(ctx.root);
|
|
197
|
+
return validatePackedPublishablePackageTypes(ctx.root, ctx.projects);
|
|
190
198
|
},
|
|
191
199
|
},
|
|
192
200
|
{
|
|
@@ -369,9 +377,10 @@ async function runBuild(ctx: MonorepoContext, options: ValidatePackOptions = {})
|
|
|
369
377
|
if (options.verbose) {
|
|
370
378
|
printCheckHeading('build', true);
|
|
371
379
|
}
|
|
380
|
+
const args = ['run-many', '-t', 'build', ...(ctx.projects?.length ? ['-p', ctx.projects.join(',')] : [])];
|
|
372
381
|
const result = options.verbose
|
|
373
|
-
? { exitCode: await runStatus('nx',
|
|
374
|
-
: await runResult('nx',
|
|
382
|
+
? { exitCode: await runStatus('nx', args, ctx.root, false), stdout: '', stderr: '' }
|
|
383
|
+
: await runResult('nx', args, ctx.root);
|
|
375
384
|
const status = result.exitCode;
|
|
376
385
|
if (status !== 0) {
|
|
377
386
|
if (!options.verbose) {
|
|
@@ -11,6 +11,7 @@ import { isSmoothBricksCodebasePackageName } from '../lib/cli-package.js';
|
|
|
11
11
|
import type {
|
|
12
12
|
PackageCargoCredentialsConfig,
|
|
13
13
|
PackagePrivateNpmConfig,
|
|
14
|
+
PackageRemoteCacheConfig,
|
|
14
15
|
PackageSmooGithub,
|
|
15
16
|
PackageSourceCheckoutConfig,
|
|
16
17
|
} from '../lib/json.js';
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
cargoCredentialStepLines,
|
|
22
23
|
type DeployStepSecretConfig,
|
|
23
24
|
deployStepSecretEnvLines,
|
|
25
|
+
remoteCacheJobEnvLines,
|
|
24
26
|
sourceCheckoutsStepLines,
|
|
25
27
|
} from './ci-workflow.js';
|
|
26
28
|
import { GITHUB_HOSTED_LINUX_RUNNER, renderRunsOnLine, type WorkflowRunsOn } from './github-runs-on.js';
|
|
@@ -125,6 +127,13 @@ export interface PublishWorkflowDefinitionOptions extends DeployStepSecretConfig
|
|
|
125
127
|
* become job env because every later cargo fetch resolves them.
|
|
126
128
|
*/
|
|
127
129
|
cargoCredentials?: PackageCargoCredentialsConfig;
|
|
130
|
+
/**
|
|
131
|
+
* Declared self-hosted Nx remote cache. Every job here runs Nx targets —
|
|
132
|
+
* the release-candidate build, the platform build, the publish gate — so
|
|
133
|
+
* each carries the server and access token and reuses what CI already
|
|
134
|
+
* built for the same hashes.
|
|
135
|
+
*/
|
|
136
|
+
remoteCache?: PackageRemoteCacheConfig;
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
export interface PublishWorkflowInputs {
|
|
@@ -466,7 +475,7 @@ jobs:
|
|
|
466
475
|
publish:
|
|
467
476
|
${options.release === false ? renderRunsOnLine(options.runsOn) : publishJobRunsOnLine(options)}
|
|
468
477
|
env:
|
|
469
|
-
GH_TOKEN: ${githubExpression('github.token')}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
478
|
+
GH_TOKEN: ${githubExpression('github.token')}${remoteCacheJobEnv(options)}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
470
479
|
steps:
|
|
471
480
|
`;
|
|
472
481
|
}
|
|
@@ -605,7 +614,14 @@ function yamlLinesForStep(step: PublishWorkflowStep, options: PublishWorkflowDef
|
|
|
605
614
|
'failure()',
|
|
606
615
|
);
|
|
607
616
|
case PublishWorkflowStepKind.ValidateMonorepoConfig:
|
|
608
|
-
|
|
617
|
+
// Scoped to the release's candidates: the build phase and the packed-package
|
|
618
|
+
// checks cover what ships. Unscoped, validate compiled every project - on a
|
|
619
|
+
// release touching no Rust that was 3m30 of the cowshed CLI on the critical
|
|
620
|
+
// path, for a binary the release did not contain.
|
|
621
|
+
return conditionalRunStep(
|
|
622
|
+
step,
|
|
623
|
+
`smoo monorepo validate --projects "${githubExpression('steps.version.outputs.projects')}"`,
|
|
624
|
+
);
|
|
609
625
|
case PublishWorkflowStepKind.TagRelease:
|
|
610
626
|
return tagReleaseStepLines(step.name);
|
|
611
627
|
case PublishWorkflowStepKind.PublishRelease:
|
|
@@ -717,6 +733,17 @@ function cargoCredentialsJobEnv(options: PublishWorkflowDefinitionOptions): stri
|
|
|
717
733
|
return rendered === '' ? '' : `\n${rendered}`;
|
|
718
734
|
}
|
|
719
735
|
|
|
736
|
+
/**
|
|
737
|
+
* The remote cache is job env for the same reason: every Nx target in the job
|
|
738
|
+
* reads it, and a release build that missed the cache would rebuild what CI
|
|
739
|
+
* already built for the identical hashes. Only `${{ secrets.NAME }}` is
|
|
740
|
+
* rendered for the token. Malformed declarations throw here, not in CI.
|
|
741
|
+
*/
|
|
742
|
+
function remoteCacheJobEnv(options: PublishWorkflowDefinitionOptions): string {
|
|
743
|
+
const rendered = remoteCacheJobEnvLines(options.remoteCache).trimEnd();
|
|
744
|
+
return rendered === '' ? '' : `\n${rendered}`;
|
|
745
|
+
}
|
|
746
|
+
|
|
720
747
|
function renderSingleJobPublishWorkflowSteps(
|
|
721
748
|
steps: PublishWorkflowStep[],
|
|
722
749
|
options: PublishWorkflowDefinitionOptions,
|
|
@@ -796,7 +823,7 @@ ${renderRunsOnLine(options.runsOn)}
|
|
|
796
823
|
mode: ${githubExpression('steps.version.outputs.mode')}
|
|
797
824
|
release-sha: ${githubExpression('steps.release-state.outputs.sha')}
|
|
798
825
|
env:
|
|
799
|
-
GH_TOKEN: ${githubExpression('github.token')}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
826
|
+
GH_TOKEN: ${githubExpression('github.token')}${remoteCacheJobEnv(options)}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
800
827
|
steps:
|
|
801
828
|
${renderLinuxReleaseCandidateSteps(steps, options)}
|
|
802
829
|
|
|
@@ -806,7 +833,7 @@ ${renderMacosJobHeaderLines(options)}
|
|
|
806
833
|
contents: read
|
|
807
834
|
id-token: none
|
|
808
835
|
env:
|
|
809
|
-
GH_TOKEN: ${githubExpression('github.token')}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
836
|
+
GH_TOKEN: ${githubExpression('github.token')}${remoteCacheJobEnv(options)}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
810
837
|
${Object.entries(options.platformProducer?.env ?? {})
|
|
811
838
|
.map(([name, value]) => ` ${name}: ${JSON.stringify(value)}`)
|
|
812
839
|
.join('\n')}
|
|
@@ -821,7 +848,7 @@ ${publishJobRunsOnLine(options)}
|
|
|
821
848
|
id-token: write
|
|
822
849
|
env:
|
|
823
850
|
TTSC_TSGO_BINARY: ${githubExpression('github.workspace')}/node_modules/@typescript/native/bin/tsc
|
|
824
|
-
GH_TOKEN: ${githubExpression('github.token')}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
851
|
+
GH_TOKEN: ${githubExpression('github.token')}${remoteCacheJobEnv(options)}${cargoCredentialsJobEnv(options)}${privateNpmInstallJobEnv(options)}
|
|
825
852
|
steps:
|
|
826
853
|
${renderFinalLinuxPublishSteps(options)}
|
|
827
854
|
`;
|
|
@@ -136,14 +136,18 @@ async function resolveInBootstrap(options: {
|
|
|
136
136
|
|
|
137
137
|
/** Builds a fixture repository whose package.json and .npmrc are the resolver's real inputs. */
|
|
138
138
|
async function withFixture(
|
|
139
|
-
options: { secrets: Record<string, SecretSpec>; npmrc?: string },
|
|
139
|
+
options: { secrets: Record<string, SecretSpec>; npmrc?: string; remoteCache?: unknown },
|
|
140
140
|
run: (root: string) => Promise<void>,
|
|
141
141
|
): Promise<void> {
|
|
142
142
|
const root = await mkdtemp(join(tmpdir(), 'smoo-secret-references-'));
|
|
143
143
|
try {
|
|
144
144
|
await writeFile(
|
|
145
145
|
join(root, 'package.json'),
|
|
146
|
-
JSON.stringify({
|
|
146
|
+
JSON.stringify({
|
|
147
|
+
name: 'fixture',
|
|
148
|
+
version: '0.0.0',
|
|
149
|
+
smoo: { secrets: options.secrets, remoteCache: options.remoteCache },
|
|
150
|
+
}),
|
|
147
151
|
);
|
|
148
152
|
if (options.npmrc !== undefined) {
|
|
149
153
|
await writeFile(join(root, '.npmrc'), options.npmrc);
|
|
@@ -249,6 +253,28 @@ describe('resolveSecretEnvironment', () => {
|
|
|
249
253
|
});
|
|
250
254
|
});
|
|
251
255
|
|
|
256
|
+
it('an unreachable cache-token provider does not block the install, while other secrets still refuse', async () => {
|
|
257
|
+
await withFixture(
|
|
258
|
+
{
|
|
259
|
+
secrets: {
|
|
260
|
+
NX_REMOTE_CACHE_TOKEN: { command: ['definitely-not-a-real-smoo-binary-xyz'] },
|
|
261
|
+
SMOO_TOKEN: { command: emit('tok-from-provider') },
|
|
262
|
+
},
|
|
263
|
+
remoteCache: { server: 'https://nx-cache.example.net', tokenSecret: 'NX_REMOTE_CACHE_TOKEN' },
|
|
264
|
+
},
|
|
265
|
+
async (root) => {
|
|
266
|
+
// A cache is an optimization: its provider being down installs
|
|
267
|
+
// dependencies anyway. Every other declared secret keeps its refusal.
|
|
268
|
+
expect(await resolveInBootstrap({ root, env: {} })).toEqual({
|
|
269
|
+
resolved: { SMOO_TOKEN: 'tok-from-provider' },
|
|
270
|
+
});
|
|
271
|
+
const withoutCacheDeclaration = await resolveInBootstrap({ root, env: { CI: 'true' } });
|
|
272
|
+
expect(withoutCacheDeclaration.error).toContain('SMOO_TOKEN');
|
|
273
|
+
expect(withoutCacheDeclaration.error).not.toContain('NX_REMOTE_CACHE_TOKEN');
|
|
274
|
+
},
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
252
278
|
it('a present variable is not reported while another refuses in CI', async () => {
|
|
253
279
|
await withFixture(
|
|
254
280
|
{
|