@smoothbricks/cli 0.10.2 → 0.10.3
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 +25 -13
- package/dist/cli.js +24 -0
- package/dist/github-ci/index.d.ts +17 -2
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +141 -11
- package/dist/github-ci/outputs.d.ts +22 -0
- package/dist/github-ci/outputs.d.ts.map +1 -0
- package/dist/github-ci/outputs.js +649 -0
- package/dist/monorepo/ci-workflow.js +1 -1
- package/dist/monorepo/managed-files.d.ts +1 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +38 -0
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +26 -0
- package/dist/monorepo/packs/index.d.ts +3 -0
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +5 -2
- package/dist/monorepo/publish-workflow.d.ts +1 -0
- package/dist/monorepo/publish-workflow.d.ts.map +1 -1
- package/dist/monorepo/publish-workflow.js +239 -2
- package/dist/nx/index.d.ts +6 -0
- package/dist/nx/index.d.ts.map +1 -1
- package/dist/nx/index.js +55 -5
- package/dist/release/github-release.d.ts +3 -0
- package/dist/release/github-release.d.ts.map +1 -1
- package/dist/release/github-release.js +11 -0
- package/dist/release/index.d.ts +19 -1
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +140 -31
- package/dist/release/orchestration.d.ts +8 -1
- package/dist/release/orchestration.d.ts.map +1 -1
- package/dist/release/orchestration.js +38 -1
- package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +5 -0
- package/managed/raw/tooling/direnv/setup-environment.ts +40 -3
- package/managed/templates/github/actions/cache-nix-devenv/action.yml +12 -10
- package/managed/templates/github/actions/cache-node-modules/action.yml +3 -2
- package/managed/templates/github/actions/cache-nx/action.yml +2 -2
- package/managed/templates/github/actions/save-nix-devenv/action.yml +11 -3
- package/package.json +7 -4
- package/src/cli.ts +30 -4
- package/src/github-ci/index.test.ts +486 -0
- package/src/github-ci/index.ts +172 -13
- package/src/github-ci/outputs.ts +506 -0
- package/src/monorepo/__tests__/ci-workflow.test.ts +11 -0
- package/src/monorepo/__tests__/publish-workflow.test.ts +222 -1
- package/src/monorepo/ci-workflow.ts +1 -1
- package/src/monorepo/managed-files.test.ts +62 -0
- package/src/monorepo/managed-files.ts +41 -0
- package/src/monorepo/package-policy.test.ts +50 -1
- package/src/monorepo/package-policy.ts +28 -0
- package/src/monorepo/packs/index.test.ts +18 -1
- package/src/monorepo/packs/index.ts +7 -3
- package/src/monorepo/publish-workflow.ts +479 -2
- package/src/nx/index.test.ts +39 -0
- package/src/nx/index.ts +65 -5
- package/src/release/__tests__/fixture-repo.test.ts +18 -16
- package/src/release/__tests__/github-release.test.ts +11 -0
- package/src/release/__tests__/orchestration.test.ts +57 -2
- package/src/release/__tests__/trust-publisher.test.ts +91 -2
- package/src/release/github-release.ts +12 -0
- package/src/release/index.ts +218 -40
- package/src/release/orchestration.ts +55 -3
package/dist/release/index.d.ts
CHANGED
|
@@ -11,6 +11,14 @@ export interface ReleasePublishOptions {
|
|
|
11
11
|
}
|
|
12
12
|
export interface ReleaseRepairPendingOptions {
|
|
13
13
|
dryRun?: boolean;
|
|
14
|
+
platformOutputs?: string;
|
|
15
|
+
ref?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ReleasePlatformOutputsOptions {
|
|
18
|
+
bump: string;
|
|
19
|
+
output: string;
|
|
20
|
+
ref?: string;
|
|
21
|
+
targets: string;
|
|
14
22
|
}
|
|
15
23
|
export interface ReleaseTrustPublisherOptions {
|
|
16
24
|
dryRun?: boolean;
|
|
@@ -37,7 +45,9 @@ export interface ReleaseRetagUnpublishedOptions {
|
|
|
37
45
|
export declare function releaseVersion(root: string, options: ReleaseVersionOptions): Promise<void>;
|
|
38
46
|
export declare function releasePublish(root: string, options: ReleasePublishOptions): Promise<void>;
|
|
39
47
|
export declare function releaseRepairPending(root: string, options: ReleaseRepairPendingOptions): Promise<void>;
|
|
48
|
+
export declare function releaseCollectPlatformOutputs(root: string, options: ReleasePlatformOutputsOptions): Promise<void>;
|
|
40
49
|
export declare function releaseTrustPublisher(root: string, options: ReleaseTrustPublisherOptions): Promise<void>;
|
|
50
|
+
export declare function npmTrustGithubArgs(packageName: string, repository: string, workflow: string, dryRun: boolean): string[];
|
|
41
51
|
export interface TrustPublisherShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
42
52
|
repository: string;
|
|
43
53
|
workflow: string;
|
|
@@ -45,7 +55,8 @@ export interface TrustPublisherShell<Package extends ReleasePackageInfo = Releas
|
|
|
45
55
|
packageExists(name: string): Promise<boolean>;
|
|
46
56
|
bootstrapNpmPackages(options: BootstrapNpmPackagesOptions): Promise<Package[]>;
|
|
47
57
|
trustPublisher(pkg: Package, dryRun: boolean, env?: Record<string, string>): Promise<TrustPublisherResult>;
|
|
48
|
-
trustedPublishers(pkg: Package): Promise<
|
|
58
|
+
trustedPublishers(pkg: Package): Promise<TrustedPublisherLookup>;
|
|
59
|
+
login(): Promise<void>;
|
|
49
60
|
log(message: string): void;
|
|
50
61
|
error(message: string): void;
|
|
51
62
|
}
|
|
@@ -56,9 +67,16 @@ export interface TrustedPublisher {
|
|
|
56
67
|
file?: string;
|
|
57
68
|
repository?: string;
|
|
58
69
|
}
|
|
70
|
+
export interface NpmTrustAccessDenied {
|
|
71
|
+
readonly status: 'access-denied';
|
|
72
|
+
readonly identity: string;
|
|
73
|
+
readonly owners: string;
|
|
74
|
+
}
|
|
75
|
+
export type TrustedPublisherLookup = TrustedPublisher[] | NpmTrustAccessDenied;
|
|
59
76
|
export declare function configureTrustedPublishers<Package extends ReleasePackageInfo>(shell: TrustPublisherShell<Package>, options: ReleaseTrustPublisherOptions): Promise<void>;
|
|
60
77
|
export declare function releaseBootstrapNpmPackages(root: string, options: ReleaseBootstrapNpmPackagesOptions): Promise<void>;
|
|
61
78
|
export declare function releaseRetagUnpublished(root: string, options: ReleaseRetagUnpublishedOptions): Promise<void>;
|
|
62
79
|
export declare function printReleaseState(root: string): Promise<void>;
|
|
80
|
+
export declare function npmTrustListAccessDenied(stdout: string, stderr: string): boolean;
|
|
63
81
|
export declare function parseTrustedPublishers(stdout: string, packageName: string): TrustedPublisher[];
|
|
64
82
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/release/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/release/index.ts"],"names":[],"mappings":"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"}
|
package/dist/release/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { appendFile, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
4
|
import { createInterface } from 'node:readline/promises';
|
|
5
5
|
import { Writable } from 'node:stream';
|
|
6
6
|
import { $ } from 'bun';
|
|
7
|
+
import { githubCiApplyOutputs, githubCiNxRunMany } from '../github-ci/index.js';
|
|
7
8
|
import { assertNoConflictMarkers } from '../lib/conflict-markers.js';
|
|
8
9
|
import { withDevenvEnv } from '../lib/devenv.js';
|
|
9
10
|
import { isRecord, readJsonObject, stringProperty } from '../lib/json.js';
|
|
10
|
-
import { decode, run, runInteractiveStatus, runResult
|
|
11
|
+
import { decode, run, runInteractiveStatus, runResult } from '../lib/run.js';
|
|
11
12
|
import { listReleasePackages, readPackageJson, repositoryInfo } from '../lib/workspace.js';
|
|
12
13
|
import { readPackedPackageJson, validatePackedWorkspaceDependencies } from '../monorepo/packed-manifest.js';
|
|
13
14
|
import { bootstrapNpmPackages, NPM_BOOTSTRAP_DIST_TAG, NPM_BOOTSTRAP_VERSION, } from './bootstrap-npm-packages.js';
|
|
14
15
|
import { autoReleaseCandidatePackages } from './candidates.js';
|
|
15
16
|
import { collectOwnedReleaseTagRecords, pendingReleaseTargets, releaseTag, releaseTagAliases, } from './core.js';
|
|
16
|
-
import { createOrUpdateGithubRelease, renderNxProjectChangelogContents, withNxWorkspaceRoot, } from './github-release.js';
|
|
17
|
+
import { createOrUpdateGithubRelease, githubReleaseLookupExists, renderNxProjectChangelogContents, withNxWorkspaceRoot, } from './github-release.js';
|
|
17
18
|
import { publishWithAuthDiagnostics } from './npm-auth.js';
|
|
18
|
-
import { bumpStableReleaseToNext, completeReleaseAtHead as completeReleaseAtHeadWithShell, repairPendingTargets, runReleaseVersion, } from './orchestration.js';
|
|
19
|
+
import { bumpStableReleaseToNext, collectRepairPlatformOutputs, completeReleaseAtHead as completeReleaseAtHeadWithShell, repairPendingTargets, runReleaseVersion, } from './orchestration.js';
|
|
19
20
|
import { retagUnpublished } from './retag-unpublished.js';
|
|
20
21
|
export async function releaseVersion(root, options) {
|
|
21
22
|
const bump = releaseBumpArg(options.bump);
|
|
@@ -78,23 +79,38 @@ export async function releasePublish(root, options) {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
export async function releaseRepairPending(root, options) {
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
console.log(`Repair pending releases:
|
|
84
|
-
await
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
const targets = await listPendingReleaseTargets(root, restoreRef);
|
|
89
|
-
console.log(targets.length === 0
|
|
90
|
-
? 'Repair pending releases: no pending durable state repairs found.'
|
|
91
|
-
: `Repair pending releases: ${targets.length} release target${targets.length === 1 ? '' : 's'} need repair.`);
|
|
92
|
-
for (const target of targets) {
|
|
93
|
-
console.log(`Repair pending releases: target ${target.sha.slice(0, 12)} needs ${repairTargetSummary(target)}.`);
|
|
94
|
-
}
|
|
95
|
-
const summaries = await repairPendingTargets(releaseRepairShell(root), targets, restoreRef, options.dryRun === true);
|
|
82
|
+
const repairRef = await fetchReleaseRepairRef(root, options.ref);
|
|
83
|
+
const restoreRef = options.ref ? await gitHead(root) : repairRef;
|
|
84
|
+
console.log(`Repair pending releases: planning from ${repairRef}.`);
|
|
85
|
+
const targets = await listPendingReleaseTargets(root, repairRef);
|
|
86
|
+
logPendingReleaseTargets(targets);
|
|
87
|
+
const platformOutputs = options.platformOutputs ? resolve(root, options.platformOutputs) : undefined;
|
|
88
|
+
const summaries = await repairPendingTargets(releaseRepairShell(root, platformOutputs), targets, restoreRef, options.dryRun === true);
|
|
96
89
|
await writeRepairSummary(summaries, options.dryRun === true);
|
|
97
90
|
}
|
|
91
|
+
export async function releaseCollectPlatformOutputs(root, options) {
|
|
92
|
+
const restoreRef = await gitHead(root);
|
|
93
|
+
const releaseRef = await fetchReleaseRepairRef(root, options.ref);
|
|
94
|
+
const packages = releasePackages(root);
|
|
95
|
+
const packagesAtHead = await releasePackagesAtHead(root, packages);
|
|
96
|
+
const currentPackages = packagesAtHead.length > 0
|
|
97
|
+
? packagesAtHead
|
|
98
|
+
: await releasePlatformPackages(root, packages, releaseBumpArg(options.bump));
|
|
99
|
+
console.log(currentPackages.length === 0
|
|
100
|
+
? 'Release platform outputs: no current release packages selected.'
|
|
101
|
+
: `Release platform outputs: building current outputs for ${packageSummary(currentPackages)}.`);
|
|
102
|
+
const outputRoot = resolve(root, options.output);
|
|
103
|
+
await githubCiNxRunMany(root, {
|
|
104
|
+
targets: options.targets,
|
|
105
|
+
projects: releasePackageProjects(currentPackages),
|
|
106
|
+
collectOutputs: join(outputRoot, 'current'),
|
|
107
|
+
allowEmptyProjects: true,
|
|
108
|
+
});
|
|
109
|
+
console.log(`Repair platform outputs: planning from ${releaseRef}.`);
|
|
110
|
+
const targets = await listPendingReleaseTargets(root, releaseRef);
|
|
111
|
+
logPendingReleaseTargets(targets);
|
|
112
|
+
await collectRepairPlatformOutputs(releaseRepairOutputsShell(root, options.targets, join(outputRoot, 'repairs')), targets, restoreRef);
|
|
113
|
+
}
|
|
98
114
|
export async function releaseTrustPublisher(root, options) {
|
|
99
115
|
const repository = githubRepositoryFromRootPackage(root);
|
|
100
116
|
const workflow = 'publish.yml';
|
|
@@ -111,18 +127,20 @@ export async function releaseTrustPublisher(root, options) {
|
|
|
111
127
|
promptOtp: (packageName) => promptForNpmOtp(packageName),
|
|
112
128
|
log: (message) => console.log(message),
|
|
113
129
|
}, bootstrapOptions),
|
|
114
|
-
trustPublisher: (pkg, dryRun, env) =>
|
|
115
|
-
const args = ['trust', 'github', pkg.name, '--file', workflow, '--repo', repository, '--yes'];
|
|
116
|
-
if (dryRun) {
|
|
117
|
-
args.push('--dry-run');
|
|
118
|
-
}
|
|
119
|
-
return runLatestNpmTrust(root, args, env);
|
|
120
|
-
},
|
|
130
|
+
trustPublisher: (pkg, dryRun, env) => runLatestNpmTrust(root, npmTrustGithubArgs(pkg.name, repository, workflow, dryRun), env),
|
|
121
131
|
trustedPublishers: (pkg) => listTrustedPublishers(root, pkg),
|
|
132
|
+
login: () => runLatestNpm(root, ['login', '--auth-type=web']),
|
|
122
133
|
log: (message) => console.log(message),
|
|
123
134
|
error: (message) => console.error(message),
|
|
124
135
|
}, options);
|
|
125
136
|
}
|
|
137
|
+
export function npmTrustGithubArgs(packageName, repository, workflow, dryRun) {
|
|
138
|
+
const args = ['trust', 'github', packageName, '--file', workflow, '--repo', repository, '--allow-publish', '--yes'];
|
|
139
|
+
if (dryRun) {
|
|
140
|
+
args.push('--dry-run');
|
|
141
|
+
}
|
|
142
|
+
return args;
|
|
143
|
+
}
|
|
126
144
|
export async function configureTrustedPublishers(shell, options) {
|
|
127
145
|
const packages = shell.listReleasePackages();
|
|
128
146
|
const selectedPackages = selectedTrustPublisherPackages(packages, options.packages ?? []);
|
|
@@ -149,7 +167,7 @@ export async function configureTrustedPublishers(shell, options) {
|
|
|
149
167
|
const failedPackages = [];
|
|
150
168
|
for (const pkg of selectedPackages) {
|
|
151
169
|
if (!options.dryRun) {
|
|
152
|
-
const trustedPublishers = await shell
|
|
170
|
+
const trustedPublishers = await trustedPublishersWithOwnerLogin(shell, pkg);
|
|
153
171
|
if (hasMatchingGithubTrustedPublisher(trustedPublishers, shell.repository, shell.workflow)) {
|
|
154
172
|
shell.log(`${pkg.name}: npm trusted publisher is already configured; skipping.`);
|
|
155
173
|
continue;
|
|
@@ -186,6 +204,23 @@ export async function configureTrustedPublishers(shell, options) {
|
|
|
186
204
|
shell.error(`Trusted publishing was not configured for: ${failedPackages.join(', ')}`);
|
|
187
205
|
}
|
|
188
206
|
}
|
|
207
|
+
async function trustedPublishersWithOwnerLogin(shell, pkg) {
|
|
208
|
+
let result = await shell.trustedPublishers(pkg);
|
|
209
|
+
if (Array.isArray(result)) {
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
shell.error(`${pkg.name}: npm trust access denied for npm account "${result.identity}". ` +
|
|
213
|
+
`npm trust requires package write access. Package owners:\n${result.owners}`);
|
|
214
|
+
shell.log(`${pkg.name}: opening npm browser login. Sign in as a listed package owner, then return here.`);
|
|
215
|
+
await shell.login();
|
|
216
|
+
result = await shell.trustedPublishers(pkg);
|
|
217
|
+
if (Array.isArray(result)) {
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
throw new Error(`${pkg.name}: npm trust access denied for npm account "${result.identity}". ` +
|
|
221
|
+
`npm trust requires package write access. Package owners:\n${result.owners}\n` +
|
|
222
|
+
'npm browser login completed, but the selected account still cannot manage this package.');
|
|
223
|
+
}
|
|
189
224
|
function selectedTrustPublisherPackages(packages, selections) {
|
|
190
225
|
if (selections.length === 0) {
|
|
191
226
|
return packages;
|
|
@@ -350,6 +385,14 @@ async function releaseVersionPackages(root, packages, bump) {
|
|
|
350
385
|
packageHasHistory: (packagePath) => packageHasHistory(root, packagePath),
|
|
351
386
|
}, packages);
|
|
352
387
|
}
|
|
388
|
+
async function releasePlatformPackages(root, packages, bump) {
|
|
389
|
+
const candidates = await releaseVersionPackages(root, packages, bump);
|
|
390
|
+
if (candidates.length === 0) {
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
// Nx may version additional reverse dependents, so use its dry-run result rather than only the direct candidates.
|
|
394
|
+
return runNxReleaseVersionPreview(root, releasePackageProjects(candidates), bump);
|
|
395
|
+
}
|
|
353
396
|
async function runNxReleaseVersion(root, projects, bump, dryRun) {
|
|
354
397
|
if (dryRun) {
|
|
355
398
|
return runNxReleaseVersionPreview(root, projects, bump);
|
|
@@ -392,6 +435,7 @@ async function runNxReleaseVersionPreview(root, projects, bump) {
|
|
|
392
435
|
gitPush: false,
|
|
393
436
|
stageChanges: false,
|
|
394
437
|
createRelease: false,
|
|
438
|
+
forceChangelogGeneration: true,
|
|
395
439
|
dryRun: true,
|
|
396
440
|
});
|
|
397
441
|
releasePreviewChangelogs.clear();
|
|
@@ -568,9 +612,8 @@ function releaseNextShell(root) {
|
|
|
568
612
|
},
|
|
569
613
|
};
|
|
570
614
|
}
|
|
571
|
-
function
|
|
615
|
+
function releaseTargetCheckoutShell(root) {
|
|
572
616
|
return {
|
|
573
|
-
...releaseCompletionShell(root),
|
|
574
617
|
checkout: (ref) => run('git', ['switch', '--detach', ref], root),
|
|
575
618
|
withDevenvEnv: (runWithEnv) => withDevenvEnv(root, runWithEnv),
|
|
576
619
|
beforeRepairTarget: (target) => {
|
|
@@ -581,6 +624,30 @@ function releaseRepairShell(root) {
|
|
|
581
624
|
},
|
|
582
625
|
};
|
|
583
626
|
}
|
|
627
|
+
function releaseRepairShell(root, platformOutputs) {
|
|
628
|
+
return {
|
|
629
|
+
...releaseCompletionShell(root),
|
|
630
|
+
...releaseTargetCheckoutShell(root),
|
|
631
|
+
prepareRepairTarget: async (target) => {
|
|
632
|
+
if (!platformOutputs || target.npmPackages.length === 0) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const output = join(platformOutputs, target.sha);
|
|
636
|
+
console.log(`Repair pending releases: applying cross-platform outputs from ${output}.`);
|
|
637
|
+
await githubCiApplyOutputs(root, [output], target.sha);
|
|
638
|
+
},
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
function releaseRepairOutputsShell(root, targetGlobs, outputRoot) {
|
|
642
|
+
return {
|
|
643
|
+
...releaseTargetCheckoutShell(root),
|
|
644
|
+
collectRepairTargetOutputs: (target) => githubCiNxRunMany(root, {
|
|
645
|
+
targets: targetGlobs,
|
|
646
|
+
projects: releasePackageProjects(target.npmPackages),
|
|
647
|
+
collectOutputs: join(outputRoot, target.sha),
|
|
648
|
+
}),
|
|
649
|
+
};
|
|
650
|
+
}
|
|
584
651
|
function releaseRetagShell(root, remote) {
|
|
585
652
|
return {
|
|
586
653
|
listReleasePackages: () => releasePackages(root),
|
|
@@ -596,6 +663,25 @@ function releaseRetagShell(root, remote) {
|
|
|
596
663
|
log: (message) => console.log(message),
|
|
597
664
|
};
|
|
598
665
|
}
|
|
666
|
+
async function fetchReleaseRepairRef(root, requestedRef) {
|
|
667
|
+
const branch = await releaseBranch(root);
|
|
668
|
+
const remote = await releaseRemote(root, branch);
|
|
669
|
+
console.log(`Repair pending releases: fetching ${remote}/${branch} and tags.`);
|
|
670
|
+
await fetchReleaseRefs(root, remote, branch);
|
|
671
|
+
if (requestedRef) {
|
|
672
|
+
return requestedRef;
|
|
673
|
+
}
|
|
674
|
+
const remoteRef = `${remote}/${branch}`;
|
|
675
|
+
return (await gitRefExists(root, remoteRef)) ? remoteRef : gitHead(root);
|
|
676
|
+
}
|
|
677
|
+
function logPendingReleaseTargets(targets) {
|
|
678
|
+
console.log(targets.length === 0
|
|
679
|
+
? 'Repair pending releases: no pending durable state repairs found.'
|
|
680
|
+
: `Repair pending releases: ${targets.length} release target${targets.length === 1 ? '' : 's'} need repair.`);
|
|
681
|
+
for (const target of targets) {
|
|
682
|
+
console.log(`Repair pending releases: target ${target.sha.slice(0, 12)} needs ${repairTargetSummary(target)}.`);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
599
685
|
async function listPendingReleaseTargets(root, ref) {
|
|
600
686
|
const head = await gitHead(root);
|
|
601
687
|
return pendingReleaseTargets(await listOwnedReleaseTagRecords(root, ref), head);
|
|
@@ -795,7 +881,8 @@ function repairReasons(target, pkg) {
|
|
|
795
881
|
return reasons;
|
|
796
882
|
}
|
|
797
883
|
async function fetchReleaseRefs(root, remote, branch) {
|
|
798
|
-
|
|
884
|
+
// `retag-unpublished` intentionally moves repairable tags, so the remote tag is authoritative.
|
|
885
|
+
await run('git', ['fetch', '--force', '--tags', remote, branch], root);
|
|
799
886
|
}
|
|
800
887
|
async function gitRefExists(root, ref) {
|
|
801
888
|
const result = await $ `git rev-parse --verify ${ref}`.cwd(root).quiet().nothrow();
|
|
@@ -1003,7 +1090,8 @@ async function pushRetaggedReleaseTags(root, remote, updates) {
|
|
|
1003
1090
|
await run('git', ['push', '--atomic', ...leases, remote, ...refspecs], root);
|
|
1004
1091
|
}
|
|
1005
1092
|
async function githubReleaseExists(root, tag) {
|
|
1006
|
-
|
|
1093
|
+
const result = await $ `gh release view ${tag} --json tagName`.cwd(root).quiet().nothrow();
|
|
1094
|
+
return githubReleaseLookupExists(tag, result.exitCode, decode(result.stdout), decode(result.stderr));
|
|
1007
1095
|
}
|
|
1008
1096
|
function githubReleaseUrl(root, tag) {
|
|
1009
1097
|
return `https://github.com/${githubRepositoryFromRootPackage(root)}/releases/tag/${encodeURIComponent(tag)}`;
|
|
@@ -1143,11 +1231,32 @@ async function listTrustedPublishers(root, pkg) {
|
|
|
1143
1231
|
}
|
|
1144
1232
|
result = await runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1145
1233
|
}
|
|
1234
|
+
if (result.exitCode !== 0 && npmTrustListAccessDenied(result.stdout, result.stderr)) {
|
|
1235
|
+
return npmTrustAccessDetails(root, pkg.name);
|
|
1236
|
+
}
|
|
1146
1237
|
if (result.exitCode !== 0) {
|
|
1147
1238
|
throw new Error(`nix shell nixpkgs#nodejs_latest -c npm ${args.join(' ')} failed with exit code ${result.exitCode}`);
|
|
1148
1239
|
}
|
|
1149
1240
|
return parseTrustedPublishers(result.stdout, pkg.name);
|
|
1150
1241
|
}
|
|
1242
|
+
export function npmTrustListAccessDenied(stdout, stderr) {
|
|
1243
|
+
return /\bE403\b/.test(`${stdout}\n${stderr}`);
|
|
1244
|
+
}
|
|
1245
|
+
async function npmTrustAccessDetails(root, packageName) {
|
|
1246
|
+
const [identityResult, ownersResult] = await Promise.all([
|
|
1247
|
+
runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', 'whoami'], root),
|
|
1248
|
+
runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', 'owner', 'ls', packageName], root),
|
|
1249
|
+
]);
|
|
1250
|
+
return {
|
|
1251
|
+
status: 'access-denied',
|
|
1252
|
+
identity: identityResult.exitCode === 0 && identityResult.stdout.trim().length > 0
|
|
1253
|
+
? identityResult.stdout.trim()
|
|
1254
|
+
: '(not authenticated)',
|
|
1255
|
+
owners: ownersResult.exitCode === 0 && ownersResult.stdout.trim().length > 0
|
|
1256
|
+
? ownersResult.stdout.trim()
|
|
1257
|
+
: '(owner lookup unavailable)',
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1151
1260
|
export function parseTrustedPublishers(stdout, packageName) {
|
|
1152
1261
|
if (stdout.trim().length === 0) {
|
|
1153
1262
|
return [];
|
|
@@ -27,12 +27,18 @@ export interface ReleaseCompletionShell<Package extends ReleasePackageInfo = Rel
|
|
|
27
27
|
export interface ReleaseNextShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
28
28
|
bumpStablePackagesToNext(packages: Package[]): Promise<void>;
|
|
29
29
|
}
|
|
30
|
-
export interface
|
|
30
|
+
export interface ReleaseTargetCheckoutShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
31
31
|
checkout(ref: string): Promise<void>;
|
|
32
32
|
withDevenvEnv<T>(runWithEnv: () => Promise<T>): Promise<T>;
|
|
33
33
|
beforeRepairTarget?(target: ReleaseTarget<Package>): void;
|
|
34
34
|
afterRepairTarget?(target: ReleaseTarget<Package>): void;
|
|
35
35
|
}
|
|
36
|
+
export interface ReleaseRepairShell<Package extends ReleasePackageInfo = ReleasePackageInfo> extends ReleaseCompletionShell<Package>, ReleaseTargetCheckoutShell<Package> {
|
|
37
|
+
prepareRepairTarget?(target: ReleaseTarget<Package>): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export interface ReleaseRepairOutputsShell<Package extends ReleasePackageInfo = ReleasePackageInfo> extends ReleaseTargetCheckoutShell<Package> {
|
|
40
|
+
collectRepairTargetOutputs(target: ReleaseTarget<Package>): Promise<void>;
|
|
41
|
+
}
|
|
36
42
|
export interface ReleaseVersionShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
37
43
|
releasePackagesAtHead(): Promise<Package[]>;
|
|
38
44
|
releaseVersionPackages(bump: string): Promise<Package[]>;
|
|
@@ -53,5 +59,6 @@ export declare function runReleaseVersion<Package extends ReleasePackageInfo>(sh
|
|
|
53
59
|
export declare function completeReleaseAtHead<Package extends ReleasePackageInfo>(shell: ReleaseCompletionShell<Package>, packages: Package[], dryRun: boolean, rerunRequired: boolean): Promise<ReleaseSummary<Package>>;
|
|
54
60
|
export declare function bumpStableReleaseToNext<Package extends ReleasePackageInfo>(shell: ReleaseNextShell<Package>, packages: Package[], dryRun: boolean, rerunRequired: boolean): Promise<Package[]>;
|
|
55
61
|
export declare function repairPendingTargets<Package extends ReleasePackageInfo>(shell: ReleaseRepairShell<Package>, targets: Array<ReleaseTarget<Package>>, restoreRef: string, dryRun: boolean): Promise<Array<ReleaseSummary<Package>>>;
|
|
62
|
+
export declare function collectRepairPlatformOutputs<Package extends ReleasePackageInfo>(shell: ReleaseRepairOutputsShell<Package>, targets: Array<ReleaseTarget<Package>>, restoreRef: string): Promise<void>;
|
|
56
63
|
export declare function completeRepairTargetAtHead<Package extends ReleasePackageInfo>(shell: ReleaseCompletionShell<Package>, target: ReleaseTarget<Package>, dryRun: boolean): Promise<ReleaseSummary<Package>>;
|
|
57
64
|
//# sourceMappingURL=orchestration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/release/orchestration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAGnE,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,cAAc,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IACrF,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,EAAE,CAAC;IACrB,gBAAgB,EAAE,OAAO,EAAE,CAAC;IAC5B,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,kBAAkB,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IAC7F,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,yBAAyB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IACvF,wBAAwB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/release/orchestration.ts"],"names":[],"mappings":"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"}
|
|
@@ -72,7 +72,10 @@ export async function repairPendingTargets(shell, targets, restoreRef, dryRun) {
|
|
|
72
72
|
}
|
|
73
73
|
shell.beforeRepairTarget?.(target);
|
|
74
74
|
try {
|
|
75
|
-
summaries.push(await shell.withDevenvEnv(() =>
|
|
75
|
+
summaries.push(await shell.withDevenvEnv(async () => {
|
|
76
|
+
await shell.prepareRepairTarget?.(target);
|
|
77
|
+
return completeRepairTargetAtHead(shell, target, dryRun);
|
|
78
|
+
}));
|
|
76
79
|
}
|
|
77
80
|
finally {
|
|
78
81
|
shell.afterRepairTarget?.(target);
|
|
@@ -81,9 +84,43 @@ export async function repairPendingTargets(shell, targets, restoreRef, dryRun) {
|
|
|
81
84
|
}
|
|
82
85
|
finally {
|
|
83
86
|
await shell.checkout(restoreRef);
|
|
87
|
+
if (targets.length > 0) {
|
|
88
|
+
// Loading devenv at a historical release can rebuild ignored tool outputs
|
|
89
|
+
// from that checkout. Refresh after restoring HEAD so later release phases
|
|
90
|
+
// cannot combine the current CLI with an older Nx plugin build.
|
|
91
|
+
await shell.withDevenvEnv(async () => undefined);
|
|
92
|
+
}
|
|
84
93
|
}
|
|
85
94
|
return summaries;
|
|
86
95
|
}
|
|
96
|
+
export async function collectRepairPlatformOutputs(shell, targets, restoreRef) {
|
|
97
|
+
const outputTargets = targets.filter((target) => target.npmPackages.length > 0);
|
|
98
|
+
if (outputTargets.length === 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
for (const target of outputTargets) {
|
|
103
|
+
await shell.checkout(target.sha);
|
|
104
|
+
if (target.packages.length === 0) {
|
|
105
|
+
// invariant throw: release target discovery must never yield a package-free target.
|
|
106
|
+
throw new Error(`Release commit ${target.sha} has no release packages after checkout.`);
|
|
107
|
+
}
|
|
108
|
+
shell.beforeRepairTarget?.(target);
|
|
109
|
+
try {
|
|
110
|
+
await shell.withDevenvEnv(() => shell.collectRepairTargetOutputs(target));
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
shell.afterRepairTarget?.(target);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await shell.checkout(restoreRef);
|
|
119
|
+
// Historical devenv activation may rebuild ignored tool outputs. Restore the
|
|
120
|
+
// dispatch environment before the macOS job performs any further work.
|
|
121
|
+
await shell.withDevenvEnv(async () => undefined);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
87
124
|
function repairDryRunSummary(target) {
|
|
88
125
|
return {
|
|
89
126
|
sha: target.sha,
|
|
@@ -46,6 +46,11 @@ install_devenv() {
|
|
|
46
46
|
|
|
47
47
|
build_devenv_shell() {
|
|
48
48
|
devenv shell --verbose -- date
|
|
49
|
+
# enterShell exports this for the bootstrap itself; persist it for the
|
|
50
|
+
# independent workflow step shells that run after this composite action.
|
|
51
|
+
if [ -n "${GITHUB_ENV:-}" ]; then
|
|
52
|
+
echo "TTSC_TSGO_BINARY=$repo_root/node_modules/@typescript/native/bin/tsc" >> "$GITHUB_ENV"
|
|
53
|
+
fi
|
|
49
54
|
# Add repo-local tools only after the shell exists; cleanup steps use an
|
|
50
55
|
# explicit PATH because failures before this point must still refresh caches.
|
|
51
56
|
add_repo_paths
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { mkdir, rmdir } from 'node:fs/promises';
|
|
3
|
+
import { mkdir, rmdir, stat } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { $ } from 'bun';
|
|
6
6
|
|
|
@@ -8,6 +8,13 @@ const devenvRoot = process.env.DEVENV_ROOT;
|
|
|
8
8
|
const projectRoot = path.resolve(`${devenvRoot}/../..`);
|
|
9
9
|
const startedWithoutNodeModules = !existsSync(path.join(projectRoot, 'node_modules'));
|
|
10
10
|
|
|
11
|
+
// A legitimate concurrent setup finishes well within this; anything older is a
|
|
12
|
+
// leftover from an interrupted run (CTRL-C/kill before the finally-cleanup) and
|
|
13
|
+
// would otherwise wedge every future shell load behind the 120s spin + EEXIST.
|
|
14
|
+
// NOTE: must be declared ABOVE the top-level setup block below — module consts
|
|
15
|
+
// are not hoisted, and the lock loop runs during that block.
|
|
16
|
+
const STALE_LOCK_MS = 10 * 60_000;
|
|
17
|
+
|
|
11
18
|
class CapturedCommandError extends Error {
|
|
12
19
|
constructor(
|
|
13
20
|
public readonly command: string,
|
|
@@ -67,7 +74,9 @@ try {
|
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
async function installLocalDependencies(): Promise<void> {
|
|
70
|
-
//
|
|
77
|
+
// bun install runs the root prepare script, which patches TypeScript with
|
|
78
|
+
// ts-patch. Multiple concurrent direnv activations can otherwise race while
|
|
79
|
+
// mutating the same files under node_modules.
|
|
71
80
|
await withSetupLock(async () => {
|
|
72
81
|
await runSetupCommand('bun install --no-summary', $`bun install --no-summary`);
|
|
73
82
|
});
|
|
@@ -104,14 +113,42 @@ async function acquireLock(lockDir: string): Promise<void> {
|
|
|
104
113
|
await mkdir(lockDir, { recursive: false });
|
|
105
114
|
return;
|
|
106
115
|
} catch (error) {
|
|
107
|
-
if (!(error
|
|
116
|
+
if (!isFileExistsError(error) || Date.now() > deadline) {
|
|
108
117
|
throw error;
|
|
109
118
|
}
|
|
119
|
+
if (await isStaleLock(lockDir)) {
|
|
120
|
+
// Surface the self-heal so an interrupted-run leftover is visible in
|
|
121
|
+
// the direnv log rather than silently absorbed.
|
|
122
|
+
console.error(`! Breaking stale setup lock (${lockDir}) left by an interrupted run`);
|
|
123
|
+
// Best-effort: if a concurrent process breaks it first, the rmdir
|
|
124
|
+
// fails silently and the next mkdir attempt settles the race.
|
|
125
|
+
await rmdir(lockDir).catch(() => undefined);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
110
128
|
await Bun.sleep(100);
|
|
111
129
|
}
|
|
112
130
|
}
|
|
113
131
|
}
|
|
114
132
|
|
|
133
|
+
async function isStaleLock(lockDir: string): Promise<boolean> {
|
|
134
|
+
try {
|
|
135
|
+
const info = await stat(lockDir);
|
|
136
|
+
return Date.now() - info.mtimeMs > STALE_LOCK_MS;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// Only "lock vanished" is expected here (a concurrent process released
|
|
139
|
+
// it); anything else must surface — a swallowed ReferenceError in this
|
|
140
|
+
// exact spot once disabled stale detection entirely.
|
|
141
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
142
|
+
return false; // gone — let the mkdir retry acquire it
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isFileExistsError(error: unknown): boolean {
|
|
149
|
+
return error instanceof Error && 'code' in error && error.code === 'EEXIST';
|
|
150
|
+
}
|
|
151
|
+
|
|
115
152
|
function replayCapturedOutput(error: unknown): void {
|
|
116
153
|
if (!(error instanceof CapturedCommandError)) {
|
|
117
154
|
return;
|
|
@@ -33,10 +33,10 @@ runs:
|
|
|
33
33
|
~/.local/state/nix/profiles
|
|
34
34
|
~/.cache/nix
|
|
35
35
|
key:
|
|
36
|
-
${{ runner.os }}-nix-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
37
|
-
'tooling/direnv/devenv.lock') }}
|
|
36
|
+
${{ runner.os }}-${{ runner.arch }}-nix-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
37
|
+
'tooling/direnv/devenv.nix', 'tooling/direnv/devenv.lock') }}
|
|
38
38
|
restore-keys: |
|
|
39
|
-
${{ runner.os }}-nix-v3-
|
|
39
|
+
${{ runner.os }}-${{ runner.arch }}-nix-v3-
|
|
40
40
|
|
|
41
41
|
- name: Save Nix profiles and store NAR
|
|
42
42
|
if: ${{ inputs.segment == 'nix' && inputs.mode == 'save' }}
|
|
@@ -48,8 +48,8 @@ runs:
|
|
|
48
48
|
~/.local/state/nix/profiles
|
|
49
49
|
~/.cache/nix
|
|
50
50
|
key:
|
|
51
|
-
${{ runner.os }}-nix-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
52
|
-
'tooling/direnv/devenv.lock') }}
|
|
51
|
+
${{ runner.os }}-${{ runner.arch }}-nix-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
52
|
+
'tooling/direnv/devenv.nix', 'tooling/direnv/devenv.lock') }}
|
|
53
53
|
|
|
54
54
|
# .devenv/.direnv are small, but they contain absolute /nix/store pointers.
|
|
55
55
|
# Workflows restore this segment only after an exact Nix cache hit.
|
|
@@ -62,10 +62,11 @@ runs:
|
|
|
62
62
|
${{ github.workspace }}/tooling/direnv/.devenv
|
|
63
63
|
${{ github.workspace }}/tooling/direnv/.direnv
|
|
64
64
|
key:
|
|
65
|
-
${{ runner.os }}-devenv-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
66
|
-
'tooling/direnv/devenv.
|
|
65
|
+
${{ runner.os }}-${{ runner.arch }}-devenv-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
66
|
+
'tooling/direnv/devenv.nix', 'tooling/direnv/devenv.lock', 'tooling/direnv/envrc.sh',
|
|
67
|
+
'tooling/direnv/setup-environment.ts') }}
|
|
67
68
|
restore-keys: |
|
|
68
|
-
${{ runner.os }}-devenv-v3-
|
|
69
|
+
${{ runner.os }}-${{ runner.arch }}-devenv-v3-
|
|
69
70
|
|
|
70
71
|
- name: Save devenv and direnv state
|
|
71
72
|
if: ${{ inputs.segment == 'devenv' && inputs.mode == 'save' }}
|
|
@@ -75,5 +76,6 @@ runs:
|
|
|
75
76
|
${{ github.workspace }}/tooling/direnv/.devenv
|
|
76
77
|
${{ github.workspace }}/tooling/direnv/.direnv
|
|
77
78
|
key:
|
|
78
|
-
${{ runner.os }}-devenv-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
79
|
-
'tooling/direnv/devenv.
|
|
79
|
+
${{ runner.os }}-${{ runner.arch }}-devenv-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
80
|
+
'tooling/direnv/devenv.nix', 'tooling/direnv/devenv.lock', 'tooling/direnv/envrc.sh',
|
|
81
|
+
'tooling/direnv/setup-environment.ts') }}
|
|
@@ -8,6 +8,7 @@ runs:
|
|
|
8
8
|
uses: actions/cache@v5.0.5
|
|
9
9
|
with:
|
|
10
10
|
path: node_modules
|
|
11
|
-
|
|
11
|
+
# prettier-ignore
|
|
12
|
+
key: ${{ runner.os }}-${{ runner.arch }}-node-{{NODE_MODULES_CACHE_KEY}}
|
|
12
13
|
restore-keys: |
|
|
13
|
-
${{ runner.os }}-node-
|
|
14
|
+
${{ runner.os }}-${{ runner.arch }}-node-
|
|
@@ -16,6 +16,6 @@ runs:
|
|
|
16
16
|
path: |
|
|
17
17
|
.nx/cache
|
|
18
18
|
.nx/workspace-data/*.db*
|
|
19
|
-
key: ${{ runner.os }}-nx-db-v1-${{ github.sha }}
|
|
19
|
+
key: ${{ runner.os }}-${{ runner.arch }}-nx-db-v1-${{ github.sha }}
|
|
20
20
|
restore-keys: |
|
|
21
|
-
${{ runner.os }}-nx-db-v1-
|
|
21
|
+
${{ runner.os }}-${{ runner.arch }}-nx-db-v1-
|
|
@@ -14,13 +14,21 @@ inputs:
|
|
|
14
14
|
runs:
|
|
15
15
|
using: composite
|
|
16
16
|
steps:
|
|
17
|
-
- name: 🧹
|
|
17
|
+
- name: 🧹 Prepare Nix/devenv cache save
|
|
18
18
|
id: cleanup-cache
|
|
19
19
|
shell: bash
|
|
20
20
|
working-directory: tooling/direnv
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
env:
|
|
22
|
+
NIX_CACHE_HIT: ${{ inputs.nix-cache-hit }}
|
|
23
|
+
# An exact Nix cache hit is immutable and cannot be overwritten by
|
|
24
|
+
# actions/cache. Avoid rebuilding its ~2 GB NAR just to discard it.
|
|
25
|
+
# build-shell normally adds repo paths to GITHUB_PATH, but cleanup must
|
|
26
|
+
# still run after a cache miss when build-shell fails before that happens.
|
|
23
27
|
run: |
|
|
28
|
+
if [[ "$NIX_CACHE_HIT" == 'true' ]]; then
|
|
29
|
+
echo 'cache-ready=true' >> "$GITHUB_OUTPUT"
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
24
32
|
export PATH="$(../../tooling/direnv/repo-path)"
|
|
25
33
|
smoo github-ci cleanup-cache
|
|
26
34
|
|