@smoothbricks/cli 0.10.2 → 0.10.4
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 +31 -23
- package/dist/bun/preload.d.ts +13 -0
- package/dist/bun/preload.d.ts.map +1 -0
- package/dist/bun/preload.js +12 -0
- package/dist/cli.js +36 -4
- package/dist/generate/index.d.ts.map +1 -1
- package/dist/generate/index.js +0 -6
- 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 +192 -26
- 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 +648 -0
- package/dist/lib/cli-package.js +2 -2
- package/dist/lib/json.d.ts +118 -11
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/json.js +317 -29
- package/dist/lib/workspace.d.ts +7 -14
- package/dist/lib/workspace.d.ts.map +1 -1
- package/dist/lib/workspace.js +76 -82
- package/dist/monorepo/ci-workflow.d.ts +2 -0
- package/dist/monorepo/ci-workflow.d.ts.map +1 -1
- package/dist/monorepo/ci-workflow.js +28 -2
- package/dist/monorepo/git-config.js +2 -2
- package/dist/monorepo/index.d.ts +3 -1
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +6 -2
- package/dist/monorepo/lockfile.d.ts +13 -1
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +33 -21
- package/dist/monorepo/managed-files.d.ts +12 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +86 -28
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +78 -45
- package/dist/monorepo/packed-manifest.d.ts +5 -2
- package/dist/monorepo/packed-manifest.d.ts.map +1 -1
- package/dist/monorepo/packed-manifest.js +16 -47
- package/dist/monorepo/packed-package.d.ts.map +1 -1
- package/dist/monorepo/packed-package.js +28 -16
- 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 +18 -6
- 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 +242 -3
- package/dist/monorepo/runtime.d.ts +15 -0
- package/dist/monorepo/runtime.d.ts.map +1 -1
- package/dist/monorepo/runtime.js +66 -12
- package/dist/monorepo/tool-validation.d.ts.map +1 -1
- package/dist/monorepo/tool-validation.js +32 -23
- package/dist/monorepo/wrangler.d.ts.map +1 -1
- package/dist/monorepo/wrangler.js +13 -13
- package/dist/nx/index.d.ts +12 -4
- package/dist/nx/index.d.ts.map +1 -1
- package/dist/nx/index.js +86 -19
- package/dist/pr/index.d.ts.map +1 -1
- package/dist/pr/index.js +28 -32
- package/dist/release/candidates.d.ts +3 -2
- package/dist/release/candidates.d.ts.map +1 -1
- package/dist/release/candidates.js +4 -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 +20 -1
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +221 -89
- 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/dist/wrangler/prepare-env.d.ts +0 -1
- package/dist/wrangler/prepare-env.d.ts.map +1 -1
- package/dist/wrangler/prepare-env.js +100 -51
- package/dist/wrangler/scaffold.d.ts.map +1 -1
- package/dist/wrangler/scaffold.js +12 -12
- package/managed/raw/git-format-staged.yml +19 -1
- package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +6 -0
- package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
- package/managed/raw/tooling/direnv/setup-environment.ts +187 -19
- package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
- package/managed/templates/github/actions/cache-nix-devenv/action.yml +12 -10
- package/managed/templates/github/actions/cache-node-modules/action.yml +6 -2
- package/managed/templates/github/actions/cache-nx/action.yml +2 -2
- package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
- package/managed/templates/github/actions/save-nix-devenv/action.yml +11 -3
- package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
- package/managed/templates/github/workflows/managed-files.yml +80 -0
- package/package.json +18 -4
- package/src/bun/preload.ts +12 -0
- package/src/cli.ts +49 -11
- package/src/generate/index.ts +0 -6
- package/src/github-ci/index.test.ts +486 -0
- package/src/github-ci/index.ts +220 -30
- package/src/github-ci/outputs.ts +505 -0
- package/src/lib/cli-package.ts +2 -2
- package/src/lib/json.ts +291 -32
- package/src/lib/workspace.ts +88 -100
- package/src/monorepo/__tests__/ci-workflow.test.ts +14 -3
- package/src/monorepo/__tests__/publish-workflow.test.ts +222 -1
- package/src/monorepo/ci-workflow.ts +28 -2
- package/src/monorepo/git-config.ts +2 -2
- package/src/monorepo/index.ts +6 -2
- package/src/monorepo/lockfile.test.ts +35 -36
- package/src/monorepo/lockfile.ts +48 -24
- package/src/monorepo/managed-files.test.ts +63 -0
- package/src/monorepo/managed-files.ts +94 -34
- package/src/monorepo/package-policy.test.ts +70 -51
- package/src/monorepo/package-policy.ts +104 -59
- package/src/monorepo/packed-manifest.ts +18 -52
- package/src/monorepo/packed-package.ts +43 -22
- package/src/monorepo/packs/index.test.ts +18 -1
- package/src/monorepo/packs/index.ts +20 -7
- package/src/monorepo/publish-workflow.ts +482 -3
- package/src/monorepo/runtime.test.ts +42 -3
- package/src/monorepo/runtime.ts +90 -12
- package/src/monorepo/tool-validation.ts +35 -25
- package/src/monorepo/wrangler.test.ts +11 -15
- package/src/monorepo/wrangler.ts +15 -15
- package/src/nx/index.test.ts +43 -0
- package/src/nx/index.ts +110 -23
- package/src/pr/index.ts +42 -36
- package/src/release/__tests__/candidates.test.ts +5 -4
- 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 +98 -2
- package/src/release/candidates.ts +10 -17
- package/src/release/github-release.ts +12 -0
- package/src/release/index.ts +321 -112
- package/src/release/orchestration.ts +55 -3
- package/src/wrangler/prepare-env.ts +75 -54
- package/src/wrangler/scaffold.test.ts +9 -12
- package/src/wrangler/scaffold.ts +13 -13
package/src/release/index.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
1
2
|
import { appendFile, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
3
|
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
4
5
|
import { createInterface } from 'node:readline/promises';
|
|
5
6
|
import { Writable } from 'node:stream';
|
|
6
7
|
import { $ } from 'bun';
|
|
8
|
+
import typia from 'typia';
|
|
9
|
+
import { githubCiApplyOutputs, githubCiNxRunMany } from '../github-ci/index.js';
|
|
7
10
|
import { assertNoConflictMarkers } from '../lib/conflict-markers.js';
|
|
8
11
|
import { withDevenvEnv } from '../lib/devenv.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
12
|
+
import {
|
|
13
|
+
type NxJson,
|
|
14
|
+
type NxProjectJson,
|
|
15
|
+
type NxTargetConfig,
|
|
16
|
+
type PackageJson,
|
|
17
|
+
parseNxJsonText,
|
|
18
|
+
parseNxProjectJsonText,
|
|
19
|
+
parsePackageJsonText,
|
|
20
|
+
} from '../lib/json.js';
|
|
21
|
+
import { decode, run, runInteractiveStatus, runResult } from '../lib/run.js';
|
|
11
22
|
import { listReleasePackages, readPackageJson, repositoryInfo } from '../lib/workspace.js';
|
|
12
23
|
import { readPackedPackageJson, validatePackedWorkspaceDependencies } from '../monorepo/packed-manifest.js';
|
|
13
24
|
import {
|
|
@@ -29,14 +40,18 @@ import {
|
|
|
29
40
|
} from './core.js';
|
|
30
41
|
import {
|
|
31
42
|
createOrUpdateGithubRelease,
|
|
43
|
+
githubReleaseLookupExists,
|
|
32
44
|
renderNxProjectChangelogContents,
|
|
33
45
|
withNxWorkspaceRoot,
|
|
34
46
|
} from './github-release.js';
|
|
35
47
|
import { publishWithAuthDiagnostics } from './npm-auth.js';
|
|
36
48
|
import {
|
|
37
49
|
bumpStableReleaseToNext,
|
|
50
|
+
collectRepairPlatformOutputs,
|
|
38
51
|
completeReleaseAtHead as completeReleaseAtHeadWithShell,
|
|
39
52
|
type ReleaseCompletionShell,
|
|
53
|
+
type ReleaseRepairOutputsShell,
|
|
54
|
+
type ReleaseRepairShell,
|
|
40
55
|
type ReleaseSummary,
|
|
41
56
|
type ReleaseVersionMode,
|
|
42
57
|
repairPendingTargets,
|
|
@@ -57,6 +72,15 @@ export interface ReleasePublishOptions {
|
|
|
57
72
|
|
|
58
73
|
export interface ReleaseRepairPendingOptions {
|
|
59
74
|
dryRun?: boolean;
|
|
75
|
+
platformOutputs?: string;
|
|
76
|
+
ref?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ReleasePlatformOutputsOptions {
|
|
80
|
+
bump: string;
|
|
81
|
+
output: string;
|
|
82
|
+
ref?: string;
|
|
83
|
+
targets: string;
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
export interface ReleaseTrustPublisherOptions {
|
|
@@ -162,26 +186,56 @@ export async function releasePublish(root: string, options: ReleasePublishOption
|
|
|
162
186
|
}
|
|
163
187
|
|
|
164
188
|
export async function releaseRepairPending(root: string, options: ReleaseRepairPendingOptions): Promise<void> {
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
console.log(`Repair pending releases:
|
|
168
|
-
await
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
: `Repair pending releases: ${targets.length} release target${targets.length === 1 ? '' : 's'} need repair.`,
|
|
189
|
+
const repairRef = await fetchReleaseRepairRef(root, options.ref);
|
|
190
|
+
const restoreRef = options.ref ? await gitHead(root) : repairRef;
|
|
191
|
+
console.log(`Repair pending releases: planning from ${repairRef}.`);
|
|
192
|
+
const targets = await listPendingReleaseTargets(root, repairRef);
|
|
193
|
+
logPendingReleaseTargets(targets);
|
|
194
|
+
const platformOutputs = options.platformOutputs ? resolve(root, options.platformOutputs) : undefined;
|
|
195
|
+
const summaries = await repairPendingTargets(
|
|
196
|
+
releaseRepairShell(root, platformOutputs),
|
|
197
|
+
targets,
|
|
198
|
+
restoreRef,
|
|
199
|
+
options.dryRun === true,
|
|
177
200
|
);
|
|
178
|
-
for (const target of targets) {
|
|
179
|
-
console.log(`Repair pending releases: target ${target.sha.slice(0, 12)} needs ${repairTargetSummary(target)}.`);
|
|
180
|
-
}
|
|
181
|
-
const summaries = await repairPendingTargets(releaseRepairShell(root), targets, restoreRef, options.dryRun === true);
|
|
182
201
|
await writeRepairSummary(summaries, options.dryRun === true);
|
|
183
202
|
}
|
|
184
203
|
|
|
204
|
+
export async function releaseCollectPlatformOutputs(
|
|
205
|
+
root: string,
|
|
206
|
+
options: ReleasePlatformOutputsOptions,
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
const restoreRef = await gitHead(root);
|
|
209
|
+
const releaseRef = await fetchReleaseRepairRef(root, options.ref);
|
|
210
|
+
const packages = releasePackages(root);
|
|
211
|
+
const packagesAtHead = await releasePackagesAtHead(root, packages);
|
|
212
|
+
const currentPackages =
|
|
213
|
+
packagesAtHead.length > 0
|
|
214
|
+
? packagesAtHead
|
|
215
|
+
: await releasePlatformPackages(root, packages, releaseBumpArg(options.bump));
|
|
216
|
+
console.log(
|
|
217
|
+
currentPackages.length === 0
|
|
218
|
+
? 'Release platform outputs: no current release packages selected.'
|
|
219
|
+
: `Release platform outputs: building current outputs for ${packageSummary(currentPackages)}.`,
|
|
220
|
+
);
|
|
221
|
+
const outputRoot = resolve(root, options.output);
|
|
222
|
+
await githubCiNxRunMany(root, {
|
|
223
|
+
targets: options.targets,
|
|
224
|
+
projects: releasePackageProjects(currentPackages),
|
|
225
|
+
collectOutputs: join(outputRoot, 'current'),
|
|
226
|
+
allowEmptyProjects: true,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
console.log(`Repair platform outputs: planning from ${releaseRef}.`);
|
|
230
|
+
const targets = await listPendingReleaseTargets(root, releaseRef);
|
|
231
|
+
logPendingReleaseTargets(targets);
|
|
232
|
+
await collectRepairPlatformOutputs(
|
|
233
|
+
releaseRepairOutputsShell(root, options.targets, join(outputRoot, 'repairs')),
|
|
234
|
+
targets,
|
|
235
|
+
restoreRef,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
185
239
|
export async function releaseTrustPublisher(root: string, options: ReleaseTrustPublisherOptions): Promise<void> {
|
|
186
240
|
const repository = githubRepositoryFromRootPackage(root);
|
|
187
241
|
const workflow = 'publish.yml';
|
|
@@ -203,14 +257,10 @@ export async function releaseTrustPublisher(root: string, options: ReleaseTrustP
|
|
|
203
257
|
},
|
|
204
258
|
bootstrapOptions,
|
|
205
259
|
),
|
|
206
|
-
trustPublisher: (pkg, dryRun, env) =>
|
|
207
|
-
|
|
208
|
-
if (dryRun) {
|
|
209
|
-
args.push('--dry-run');
|
|
210
|
-
}
|
|
211
|
-
return runLatestNpmTrust(root, args, env);
|
|
212
|
-
},
|
|
260
|
+
trustPublisher: (pkg, dryRun, env) =>
|
|
261
|
+
runLatestNpmTrust(root, npmTrustGithubArgs(pkg.name, repository, workflow, dryRun), env),
|
|
213
262
|
trustedPublishers: (pkg) => listTrustedPublishers(root, pkg),
|
|
263
|
+
login: () => runLatestNpm(root, ['login', '--auth-type=web']),
|
|
214
264
|
log: (message) => console.log(message),
|
|
215
265
|
error: (message) => console.error(message),
|
|
216
266
|
},
|
|
@@ -218,6 +268,19 @@ export async function releaseTrustPublisher(root: string, options: ReleaseTrustP
|
|
|
218
268
|
);
|
|
219
269
|
}
|
|
220
270
|
|
|
271
|
+
export function npmTrustGithubArgs(
|
|
272
|
+
packageName: string,
|
|
273
|
+
repository: string,
|
|
274
|
+
workflow: string,
|
|
275
|
+
dryRun: boolean,
|
|
276
|
+
): string[] {
|
|
277
|
+
const args = ['trust', 'github', packageName, '--file', workflow, '--repo', repository, '--allow-publish', '--yes'];
|
|
278
|
+
if (dryRun) {
|
|
279
|
+
args.push('--dry-run');
|
|
280
|
+
}
|
|
281
|
+
return args;
|
|
282
|
+
}
|
|
283
|
+
|
|
221
284
|
export interface TrustPublisherShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
222
285
|
repository: string;
|
|
223
286
|
workflow: string;
|
|
@@ -225,7 +288,8 @@ export interface TrustPublisherShell<Package extends ReleasePackageInfo = Releas
|
|
|
225
288
|
packageExists(name: string): Promise<boolean>;
|
|
226
289
|
bootstrapNpmPackages(options: BootstrapNpmPackagesOptions): Promise<Package[]>;
|
|
227
290
|
trustPublisher(pkg: Package, dryRun: boolean, env?: Record<string, string>): Promise<TrustPublisherResult>;
|
|
228
|
-
trustedPublishers(pkg: Package): Promise<
|
|
291
|
+
trustedPublishers(pkg: Package): Promise<TrustedPublisherLookup>;
|
|
292
|
+
login(): Promise<void>;
|
|
229
293
|
log(message: string): void;
|
|
230
294
|
error(message: string): void;
|
|
231
295
|
}
|
|
@@ -239,6 +303,14 @@ export interface TrustedPublisher {
|
|
|
239
303
|
repository?: string;
|
|
240
304
|
}
|
|
241
305
|
|
|
306
|
+
export interface NpmTrustAccessDenied {
|
|
307
|
+
readonly status: 'access-denied';
|
|
308
|
+
readonly identity: string;
|
|
309
|
+
readonly owners: string;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export type TrustedPublisherLookup = TrustedPublisher[] | NpmTrustAccessDenied;
|
|
313
|
+
|
|
242
314
|
export async function configureTrustedPublishers<Package extends ReleasePackageInfo>(
|
|
243
315
|
shell: TrustPublisherShell<Package>,
|
|
244
316
|
options: ReleaseTrustPublisherOptions,
|
|
@@ -275,7 +347,7 @@ export async function configureTrustedPublishers<Package extends ReleasePackageI
|
|
|
275
347
|
const failedPackages: string[] = [];
|
|
276
348
|
for (const pkg of selectedPackages) {
|
|
277
349
|
if (!options.dryRun) {
|
|
278
|
-
const trustedPublishers = await shell
|
|
350
|
+
const trustedPublishers = await trustedPublishersWithOwnerLogin(shell, pkg);
|
|
279
351
|
if (hasMatchingGithubTrustedPublisher(trustedPublishers, shell.repository, shell.workflow)) {
|
|
280
352
|
shell.log(`${pkg.name}: npm trusted publisher is already configured; skipping.`);
|
|
281
353
|
continue;
|
|
@@ -315,6 +387,33 @@ export async function configureTrustedPublishers<Package extends ReleasePackageI
|
|
|
315
387
|
}
|
|
316
388
|
}
|
|
317
389
|
|
|
390
|
+
async function trustedPublishersWithOwnerLogin<Package extends ReleasePackageInfo>(
|
|
391
|
+
shell: TrustPublisherShell<Package>,
|
|
392
|
+
pkg: Package,
|
|
393
|
+
): Promise<TrustedPublisher[]> {
|
|
394
|
+
let result = await shell.trustedPublishers(pkg);
|
|
395
|
+
if (Array.isArray(result)) {
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
shell.error(
|
|
400
|
+
`${pkg.name}: npm trust access denied for npm account "${result.identity}". ` +
|
|
401
|
+
`npm trust requires package write access. Package owners:\n${result.owners}`,
|
|
402
|
+
);
|
|
403
|
+
shell.log(`${pkg.name}: opening npm browser login. Sign in as a listed package owner, then return here.`);
|
|
404
|
+
await shell.login();
|
|
405
|
+
|
|
406
|
+
result = await shell.trustedPublishers(pkg);
|
|
407
|
+
if (Array.isArray(result)) {
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
throw new Error(
|
|
411
|
+
`${pkg.name}: npm trust access denied for npm account "${result.identity}". ` +
|
|
412
|
+
`npm trust requires package write access. Package owners:\n${result.owners}\n` +
|
|
413
|
+
'npm browser login completed, but the selected account still cannot manage this package.',
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
318
417
|
function selectedTrustPublisherPackages<Package extends ReleasePackageInfo>(
|
|
319
418
|
packages: Package[],
|
|
320
419
|
selections: string[],
|
|
@@ -483,7 +582,7 @@ async function publishPlaceholderPackage(
|
|
|
483
582
|
name: pkg.name,
|
|
484
583
|
version: NPM_BOOTSTRAP_VERSION,
|
|
485
584
|
description: `Bootstrap placeholder for ${pkg.name}. Real releases are published by SmoothBricks CI.`,
|
|
486
|
-
license:
|
|
585
|
+
license: pkg.json.license ?? 'UNLICENSED',
|
|
487
586
|
repository: pkg.json.repository,
|
|
488
587
|
publishConfig: { access: 'public' },
|
|
489
588
|
},
|
|
@@ -507,7 +606,7 @@ function safeTarballPrefix(name: string): string {
|
|
|
507
606
|
|
|
508
607
|
async function assertPackedWorkspaceDependencies(root: string, tarball: string, pkg: ReleasePackage): Promise<void> {
|
|
509
608
|
const manifest = await readPackedPackageJson(root, tarball, pkg.name);
|
|
510
|
-
const failures = validatePackedWorkspaceDependencies(root, pkg, manifest);
|
|
609
|
+
const failures = validatePackedWorkspaceDependencies(root, pkg, manifest, { mode: 'publish' });
|
|
511
610
|
if (failures.length > 0) {
|
|
512
611
|
throw new Error(failures.join('\n'));
|
|
513
612
|
}
|
|
@@ -548,6 +647,19 @@ async function releaseVersionPackages(
|
|
|
548
647
|
);
|
|
549
648
|
}
|
|
550
649
|
|
|
650
|
+
async function releasePlatformPackages(
|
|
651
|
+
root: string,
|
|
652
|
+
packages: ReleasePackage[],
|
|
653
|
+
bump: string,
|
|
654
|
+
): Promise<ReleasePackage[]> {
|
|
655
|
+
const candidates = await releaseVersionPackages(root, packages, bump);
|
|
656
|
+
if (candidates.length === 0) {
|
|
657
|
+
return [];
|
|
658
|
+
}
|
|
659
|
+
// Nx may version additional reverse dependents, so use its dry-run result rather than only the direct candidates.
|
|
660
|
+
return runNxReleaseVersionPreview(root, releasePackageProjects(candidates), bump);
|
|
661
|
+
}
|
|
662
|
+
|
|
551
663
|
async function runNxReleaseVersion(
|
|
552
664
|
root: string,
|
|
553
665
|
projects: string,
|
|
@@ -603,6 +715,7 @@ async function runNxReleaseVersionPreview(root: string, projects: string, bump:
|
|
|
603
715
|
gitPush: false,
|
|
604
716
|
stageChanges: false,
|
|
605
717
|
createRelease: false,
|
|
718
|
+
forceChangelogGeneration: true,
|
|
606
719
|
dryRun: true,
|
|
607
720
|
});
|
|
608
721
|
releasePreviewChangelogs.clear();
|
|
@@ -680,8 +793,7 @@ async function packageVersionAtRef(root: string, packagePath: string, ref: strin
|
|
|
680
793
|
return null;
|
|
681
794
|
}
|
|
682
795
|
try {
|
|
683
|
-
|
|
684
|
-
return isRecord(parsed) ? stringProperty(parsed, 'version') : null;
|
|
796
|
+
return parsePackageJsonText(decode(result.stdout))?.version ?? null;
|
|
685
797
|
} catch {
|
|
686
798
|
return null;
|
|
687
799
|
}
|
|
@@ -808,17 +920,11 @@ function releaseNextShell(root: string): { bumpStablePackagesToNext(packages: Re
|
|
|
808
920
|
};
|
|
809
921
|
}
|
|
810
922
|
|
|
811
|
-
function
|
|
812
|
-
checkout(ref: string): Promise<void>;
|
|
813
|
-
withDevenvEnv<T>(runWithEnv: () => Promise<T>): Promise<T>;
|
|
814
|
-
beforeRepairTarget(target: ReleaseTarget): void;
|
|
815
|
-
afterRepairTarget(target: ReleaseTarget): void;
|
|
816
|
-
} {
|
|
923
|
+
function releaseTargetCheckoutShell(root: string) {
|
|
817
924
|
return {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
beforeRepairTarget: (target) => {
|
|
925
|
+
checkout: (ref: string) => run('git', ['switch', '--detach', ref], root),
|
|
926
|
+
withDevenvEnv: <T>(runWithEnv: () => Promise<T>) => withDevenvEnv(root, runWithEnv),
|
|
927
|
+
beforeRepairTarget: (target: ReleaseTarget) => {
|
|
822
928
|
console.log(`::group::Repair pending release ${target.sha.slice(0, 12)} (${packageSummary(target.packages)})`);
|
|
823
929
|
},
|
|
824
930
|
afterRepairTarget: () => {
|
|
@@ -827,6 +933,37 @@ function releaseRepairShell(root: string): ReleaseCompletionShell<ReleasePackage
|
|
|
827
933
|
};
|
|
828
934
|
}
|
|
829
935
|
|
|
936
|
+
function releaseRepairShell(root: string, platformOutputs?: string): ReleaseRepairShell<ReleasePackage> {
|
|
937
|
+
return {
|
|
938
|
+
...releaseCompletionShell(root),
|
|
939
|
+
...releaseTargetCheckoutShell(root),
|
|
940
|
+
prepareRepairTarget: async (target) => {
|
|
941
|
+
if (!platformOutputs || target.npmPackages.length === 0) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
const output = join(platformOutputs, target.sha);
|
|
945
|
+
console.log(`Repair pending releases: applying cross-platform outputs from ${output}.`);
|
|
946
|
+
await githubCiApplyOutputs(root, [output], target.sha);
|
|
947
|
+
},
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function releaseRepairOutputsShell(
|
|
952
|
+
root: string,
|
|
953
|
+
targetGlobs: string,
|
|
954
|
+
outputRoot: string,
|
|
955
|
+
): ReleaseRepairOutputsShell<ReleasePackage> {
|
|
956
|
+
return {
|
|
957
|
+
...releaseTargetCheckoutShell(root),
|
|
958
|
+
collectRepairTargetOutputs: (target) =>
|
|
959
|
+
githubCiNxRunMany(root, {
|
|
960
|
+
targets: targetGlobs,
|
|
961
|
+
projects: releasePackageProjects(target.npmPackages),
|
|
962
|
+
collectOutputs: join(outputRoot, target.sha),
|
|
963
|
+
}),
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
|
|
830
967
|
function releaseRetagShell(root: string, remote: string) {
|
|
831
968
|
return {
|
|
832
969
|
listReleasePackages: () => releasePackages(root),
|
|
@@ -844,6 +981,29 @@ function releaseRetagShell(root: string, remote: string) {
|
|
|
844
981
|
};
|
|
845
982
|
}
|
|
846
983
|
|
|
984
|
+
async function fetchReleaseRepairRef(root: string, requestedRef?: string): Promise<string> {
|
|
985
|
+
const branch = await releaseBranch(root);
|
|
986
|
+
const remote = await releaseRemote(root, branch);
|
|
987
|
+
console.log(`Repair pending releases: fetching ${remote}/${branch} and tags.`);
|
|
988
|
+
await fetchReleaseRefs(root, remote, branch);
|
|
989
|
+
if (requestedRef) {
|
|
990
|
+
return requestedRef;
|
|
991
|
+
}
|
|
992
|
+
const remoteRef = `${remote}/${branch}`;
|
|
993
|
+
return (await gitRefExists(root, remoteRef)) ? remoteRef : gitHead(root);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
function logPendingReleaseTargets(targets: ReleaseTarget[]): void {
|
|
997
|
+
console.log(
|
|
998
|
+
targets.length === 0
|
|
999
|
+
? 'Repair pending releases: no pending durable state repairs found.'
|
|
1000
|
+
: `Repair pending releases: ${targets.length} release target${targets.length === 1 ? '' : 's'} need repair.`,
|
|
1001
|
+
);
|
|
1002
|
+
for (const target of targets) {
|
|
1003
|
+
console.log(`Repair pending releases: target ${target.sha.slice(0, 12)} needs ${repairTargetSummary(target)}.`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
847
1007
|
async function listPendingReleaseTargets(root: string, ref: string): Promise<ReleaseTarget[]> {
|
|
848
1008
|
const head = await gitHead(root);
|
|
849
1009
|
return pendingReleaseTargets(await listOwnedReleaseTagRecords(root, ref), head);
|
|
@@ -1069,7 +1229,8 @@ function repairReasons(target: ReleaseTarget, pkg: ReleasePackage): string[] {
|
|
|
1069
1229
|
}
|
|
1070
1230
|
|
|
1071
1231
|
async function fetchReleaseRefs(root: string, remote: string, branch: string): Promise<void> {
|
|
1072
|
-
|
|
1232
|
+
// `retag-unpublished` intentionally moves repairable tags, so the remote tag is authoritative.
|
|
1233
|
+
await run('git', ['fetch', '--force', '--tags', remote, branch], root);
|
|
1073
1234
|
}
|
|
1074
1235
|
|
|
1075
1236
|
async function gitRefExists(root: string, ref: string): Promise<boolean> {
|
|
@@ -1112,74 +1273,83 @@ async function packageChangedFilesSince(root: string, ref: string, packagePath:
|
|
|
1112
1273
|
.map((path) => (path.startsWith(packagePrefix) ? path.slice(packagePrefix.length) : path));
|
|
1113
1274
|
}
|
|
1114
1275
|
|
|
1115
|
-
async function packageJsonAtRef(
|
|
1116
|
-
root: string,
|
|
1117
|
-
ref: string,
|
|
1118
|
-
packagePath: string,
|
|
1119
|
-
): Promise<Record<string, unknown> | null> {
|
|
1276
|
+
async function packageJsonAtRef(root: string, ref: string, packagePath: string): Promise<PackageJson | null> {
|
|
1120
1277
|
const result = await $`git show ${`${ref}:${packagePath}/package.json`}`.cwd(root).quiet().nothrow();
|
|
1121
1278
|
if (result.exitCode !== 0) {
|
|
1122
1279
|
return null;
|
|
1123
1280
|
}
|
|
1124
1281
|
try {
|
|
1125
|
-
|
|
1126
|
-
return isRecord(parsed) ? parsed : null;
|
|
1282
|
+
return parsePackageJsonText(decode(result.stdout));
|
|
1127
1283
|
} catch {
|
|
1128
1284
|
return null;
|
|
1129
1285
|
}
|
|
1130
1286
|
}
|
|
1131
1287
|
|
|
1132
|
-
async function currentPackageJson(root: string, packagePath: string): Promise<
|
|
1288
|
+
async function currentPackageJson(root: string, packagePath: string): Promise<PackageJson | null> {
|
|
1133
1289
|
return readPackageJson(join(root, packagePath, 'package.json'))?.json ?? null;
|
|
1134
1290
|
}
|
|
1135
1291
|
|
|
1136
1292
|
async function packageBuildInputPatterns(root: string, projectName: string, _packagePath: string): Promise<string[]> {
|
|
1137
1293
|
const project = await nxProjectJson(root, projectName);
|
|
1138
|
-
|
|
1139
|
-
return resolveBuildInputPatterns(project, nxJson);
|
|
1294
|
+
return resolveBuildInputPatterns(project, readNxJson(join(root, 'nx.json')));
|
|
1140
1295
|
}
|
|
1141
1296
|
|
|
1142
|
-
async function nxProjectJson(root: string, projectName: string): Promise<
|
|
1297
|
+
async function nxProjectJson(root: string, projectName: string): Promise<NxProjectJson> {
|
|
1143
1298
|
const result = await $`nx show project ${projectName} --json`.cwd(root).quiet();
|
|
1144
|
-
const parsed =
|
|
1145
|
-
if (!
|
|
1299
|
+
const parsed = parseNxProjectJsonText(decode(result.stdout));
|
|
1300
|
+
if (!parsed) {
|
|
1146
1301
|
throw new Error(`Unable to inspect Nx project ${projectName}.`);
|
|
1147
1302
|
}
|
|
1148
1303
|
return parsed;
|
|
1149
1304
|
}
|
|
1150
1305
|
|
|
1151
|
-
function
|
|
1152
|
-
|
|
1306
|
+
function readNxJson(path: string): NxJson {
|
|
1307
|
+
if (!existsSync(path)) {
|
|
1308
|
+
return {};
|
|
1309
|
+
}
|
|
1310
|
+
try {
|
|
1311
|
+
return parseNxJsonText(readFileSync(path, 'utf8')) ?? {};
|
|
1312
|
+
} catch {
|
|
1313
|
+
return {};
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
function resolveBuildInputPatterns(project: NxProjectJson, nxJson: NxJson): string[] {
|
|
1318
|
+
const targets = project.targets;
|
|
1153
1319
|
if (!targets) {
|
|
1154
1320
|
return [];
|
|
1155
1321
|
}
|
|
1156
1322
|
return normalizeInputPatterns(collectBuildInputs(targets), nxJson);
|
|
1157
1323
|
}
|
|
1158
1324
|
|
|
1159
|
-
function collectBuildInputs(targets: Record<string,
|
|
1160
|
-
const build =
|
|
1325
|
+
function collectBuildInputs(targets: Record<string, NxTargetConfig>): string[] {
|
|
1326
|
+
const build = targets.build;
|
|
1161
1327
|
if (!build) {
|
|
1162
1328
|
return ['production'];
|
|
1163
1329
|
}
|
|
1164
|
-
const directInputs =
|
|
1330
|
+
const directInputs = stringInputs(build.inputs);
|
|
1165
1331
|
if (directInputs.length > 0) {
|
|
1166
1332
|
return directInputs;
|
|
1167
1333
|
}
|
|
1168
1334
|
const inputs: string[] = [];
|
|
1169
|
-
for (const dependency of
|
|
1170
|
-
if (dependency.startsWith('^')) {
|
|
1335
|
+
for (const dependency of build.dependsOn ?? []) {
|
|
1336
|
+
if (typeof dependency !== 'string' || dependency.startsWith('^')) {
|
|
1171
1337
|
continue;
|
|
1172
1338
|
}
|
|
1173
1339
|
const targetName = dependency.includes(':') ? dependency.split(':')[1] : dependency;
|
|
1174
1340
|
if (!targetName) {
|
|
1175
1341
|
continue;
|
|
1176
1342
|
}
|
|
1177
|
-
inputs.push(...
|
|
1343
|
+
inputs.push(...stringInputs(targets[targetName]?.inputs));
|
|
1178
1344
|
}
|
|
1179
1345
|
return inputs.length > 0 ? inputs : ['production'];
|
|
1180
1346
|
}
|
|
1181
1347
|
|
|
1182
|
-
function
|
|
1348
|
+
function stringInputs(inputs: NxTargetConfig['inputs'] | undefined): string[] {
|
|
1349
|
+
return Array.isArray(inputs) ? inputs.filter((entry): entry is string => typeof entry === 'string') : [];
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
function normalizeInputPatterns(inputs: string[], nxJson: NxJson): string[] {
|
|
1183
1353
|
const patterns: string[] = [];
|
|
1184
1354
|
const seen = new Set<string>();
|
|
1185
1355
|
for (const input of inputs) {
|
|
@@ -1190,14 +1360,13 @@ function normalizeInputPatterns(inputs: string[], nxJson: Record<string, unknown
|
|
|
1190
1360
|
return patterns;
|
|
1191
1361
|
}
|
|
1192
1362
|
|
|
1193
|
-
function expandInputPattern(input: string, nxJson:
|
|
1363
|
+
function expandInputPattern(input: string, nxJson: NxJson, seen: Set<string>): string[] {
|
|
1194
1364
|
if (seen.has(input)) {
|
|
1195
1365
|
return [];
|
|
1196
1366
|
}
|
|
1197
1367
|
seen.add(input);
|
|
1198
1368
|
if (!input.includes('{')) {
|
|
1199
|
-
const
|
|
1200
|
-
const namedInput = namedInputs?.[input];
|
|
1369
|
+
const namedInput = nxJson.namedInputs?.[input];
|
|
1201
1370
|
if (Array.isArray(namedInput)) {
|
|
1202
1371
|
return namedInput.flatMap((entry) => (typeof entry === 'string' ? expandInputPattern(entry, nxJson, seen) : []));
|
|
1203
1372
|
}
|
|
@@ -1212,19 +1381,6 @@ function expandInputPattern(input: string, nxJson: Record<string, unknown>, seen
|
|
|
1212
1381
|
return [`${excluded ? '!' : ''}${packageRelative}`];
|
|
1213
1382
|
}
|
|
1214
1383
|
|
|
1215
|
-
function recordProperty(record: Record<string, unknown> | null, key: string): Record<string, unknown> | null {
|
|
1216
|
-
if (!record) {
|
|
1217
|
-
return null;
|
|
1218
|
-
}
|
|
1219
|
-
const value = record[key];
|
|
1220
|
-
return isRecord(value) ? value : null;
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
function stringArrayProperty(record: Record<string, unknown> | null, key: string): string[] {
|
|
1224
|
-
const value = record?.[key];
|
|
1225
|
-
return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
1384
|
async function packageHasHistory(root: string, packagePath: string): Promise<boolean> {
|
|
1229
1385
|
const result = await $`git log --format=%H -- ${packagePath}`.cwd(root).quiet().nothrow();
|
|
1230
1386
|
if (result.exitCode !== 0) {
|
|
@@ -1309,7 +1465,8 @@ async function pushRetaggedReleaseTags(
|
|
|
1309
1465
|
}
|
|
1310
1466
|
|
|
1311
1467
|
async function githubReleaseExists(root: string, tag: string): Promise<boolean> {
|
|
1312
|
-
|
|
1468
|
+
const result = await $`gh release view ${tag} --json tagName`.cwd(root).quiet().nothrow();
|
|
1469
|
+
return githubReleaseLookupExists(tag, result.exitCode, decode(result.stdout), decode(result.stderr));
|
|
1313
1470
|
}
|
|
1314
1471
|
|
|
1315
1472
|
function githubReleaseUrl(root: string, tag: string): string {
|
|
@@ -1462,61 +1619,113 @@ async function runLatestNpmTrust(
|
|
|
1462
1619
|
if (status === 0) {
|
|
1463
1620
|
return 'configured';
|
|
1464
1621
|
}
|
|
1465
|
-
throw new Error(
|
|
1622
|
+
throw new Error(npmCommandFailedMessage(npmArgs, status));
|
|
1466
1623
|
}
|
|
1467
1624
|
|
|
1468
|
-
async function listTrustedPublishers(root: string, pkg: Pick<ReleasePackage, 'name'>): Promise<
|
|
1625
|
+
async function listTrustedPublishers(root: string, pkg: Pick<ReleasePackage, 'name'>): Promise<TrustedPublisherLookup> {
|
|
1469
1626
|
const args = ['trust', 'list', pkg.name, '--json'];
|
|
1470
1627
|
let result = await runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1471
1628
|
if (result.exitCode !== 0 && /\bEOTP\b/.test(`${result.stdout}\n${result.stderr}`)) {
|
|
1472
1629
|
const status = await runInteractiveStatus('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1473
1630
|
if (status !== 0) {
|
|
1474
|
-
throw new Error(
|
|
1631
|
+
throw new Error(npmCommandFailedMessage(args, status));
|
|
1475
1632
|
}
|
|
1476
1633
|
result = await runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1477
1634
|
}
|
|
1635
|
+
if (result.exitCode !== 0 && npmTrustListAccessDenied(result.stdout, result.stderr)) {
|
|
1636
|
+
return npmTrustAccessDetails(root, pkg.name);
|
|
1637
|
+
}
|
|
1478
1638
|
if (result.exitCode !== 0) {
|
|
1479
|
-
throw new Error(
|
|
1480
|
-
`nix shell nixpkgs#nodejs_latest -c npm ${args.join(' ')} failed with exit code ${result.exitCode}`,
|
|
1481
|
-
);
|
|
1639
|
+
throw new Error(npmCommandFailedMessage(args, result.exitCode, result.stdout, result.stderr));
|
|
1482
1640
|
}
|
|
1483
1641
|
return parseTrustedPublishers(result.stdout, pkg.name);
|
|
1484
1642
|
}
|
|
1485
1643
|
|
|
1644
|
+
/** npm trust list/setup requires an authenticated package owner. */
|
|
1645
|
+
export function npmTrustListAccessDenied(stdout: string, stderr: string): boolean {
|
|
1646
|
+
const output = `${stdout}\n${stderr}`;
|
|
1647
|
+
// E403: authenticated but not an owner. E401 / login-required: no usable session.
|
|
1648
|
+
return (
|
|
1649
|
+
/\bE403\b/.test(output) ||
|
|
1650
|
+
/\bE401\b/.test(output) ||
|
|
1651
|
+
/You must be logged in to publish packages/i.test(output) ||
|
|
1652
|
+
/npm error 401 Unauthorized/i.test(output)
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
function npmCommandFailedMessage(npmArgs: string[], exitCode: number, stdout = '', stderr = ''): string {
|
|
1657
|
+
const command = `nix shell nixpkgs#nodejs_latest -c npm ${npmArgs.join(' ')}`;
|
|
1658
|
+
const detail = npmFailureDetail(stdout, stderr);
|
|
1659
|
+
return detail.length > 0
|
|
1660
|
+
? `${command} failed with exit code ${exitCode}\n${detail}`
|
|
1661
|
+
: `${command} failed with exit code ${exitCode}`;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
function npmFailureDetail(stdout: string, stderr: string): string {
|
|
1665
|
+
const chunks = [stderr.trim(), stdout.trim()].filter((chunk) => chunk.length > 0);
|
|
1666
|
+
if (chunks.length === 0) {
|
|
1667
|
+
return '';
|
|
1668
|
+
}
|
|
1669
|
+
// Prefer the actionable npm error line over notice spam when present.
|
|
1670
|
+
const joined = chunks.join('\n');
|
|
1671
|
+
const errorLines = joined
|
|
1672
|
+
.split('\n')
|
|
1673
|
+
.map((line) => line.trimEnd())
|
|
1674
|
+
.filter((line) => /npm error|error code|401 Unauthorized|403 Forbidden|E401|E403|logged in/i.test(line));
|
|
1675
|
+
if (errorLines.length > 0) {
|
|
1676
|
+
return errorLines.slice(0, 8).join('\n');
|
|
1677
|
+
}
|
|
1678
|
+
// Fall back to a short tail of combined output.
|
|
1679
|
+
return joined.split('\n').slice(-12).join('\n');
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
async function npmTrustAccessDetails(root: string, packageName: string): Promise<NpmTrustAccessDenied> {
|
|
1683
|
+
const [identityResult, ownersResult] = await Promise.all([
|
|
1684
|
+
runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', 'whoami'], root),
|
|
1685
|
+
runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', 'owner', 'ls', packageName], root),
|
|
1686
|
+
]);
|
|
1687
|
+
return {
|
|
1688
|
+
status: 'access-denied',
|
|
1689
|
+
identity:
|
|
1690
|
+
identityResult.exitCode === 0 && identityResult.stdout.trim().length > 0
|
|
1691
|
+
? identityResult.stdout.trim()
|
|
1692
|
+
: '(not authenticated)',
|
|
1693
|
+
owners:
|
|
1694
|
+
ownersResult.exitCode === 0 && ownersResult.stdout.trim().length > 0
|
|
1695
|
+
? ownersResult.stdout.trim()
|
|
1696
|
+
: '(owner lookup unavailable)',
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1486
1700
|
export function parseTrustedPublishers(stdout: string, packageName: string): TrustedPublisher[] {
|
|
1487
1701
|
if (stdout.trim().length === 0) {
|
|
1488
1702
|
return [];
|
|
1489
1703
|
}
|
|
1490
|
-
|
|
1704
|
+
// createIsParse returns null for non-matching shapes and bare `null`.
|
|
1705
|
+
const parsed = parseTrustedPublisherJson(stdout);
|
|
1491
1706
|
if (parsed === null) {
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
if (isRecord(parsed)) {
|
|
1498
|
-
return [parseTrustedPublisher(parsed, packageName)];
|
|
1707
|
+
if (stdout.trim() === 'null') {
|
|
1708
|
+
return [];
|
|
1709
|
+
}
|
|
1710
|
+
throw new Error(`${packageName}: npm trust list returned invalid trusted publisher JSON.`);
|
|
1499
1711
|
}
|
|
1500
|
-
|
|
1712
|
+
return (Array.isArray(parsed) ? parsed : [parsed]).map((value) => ({
|
|
1713
|
+
id: value.id,
|
|
1714
|
+
type: value.type,
|
|
1715
|
+
file: value.file,
|
|
1716
|
+
repository: value.repository,
|
|
1717
|
+
}));
|
|
1501
1718
|
}
|
|
1502
1719
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
const type = stringProperty(value, 'type');
|
|
1509
|
-
if (!id || !type) {
|
|
1510
|
-
throw new Error(`${packageName}: npm trust list returned a trusted publisher without id or type.`);
|
|
1511
|
-
}
|
|
1512
|
-
return {
|
|
1513
|
-
id,
|
|
1514
|
-
type,
|
|
1515
|
-
file: stringProperty(value, 'file') ?? undefined,
|
|
1516
|
-
repository: stringProperty(value, 'repository') ?? undefined,
|
|
1517
|
-
};
|
|
1720
|
+
interface TrustedPublisherJson {
|
|
1721
|
+
id: string;
|
|
1722
|
+
type: string;
|
|
1723
|
+
file?: string;
|
|
1724
|
+
repository?: string;
|
|
1518
1725
|
}
|
|
1519
1726
|
|
|
1727
|
+
const parseTrustedPublisherJson = typia.json.createIsParse<TrustedPublisherJson | TrustedPublisherJson[]>();
|
|
1728
|
+
|
|
1520
1729
|
async function runLatestNpmPublish(root: string, npmArgs: string[]): Promise<void> {
|
|
1521
1730
|
await runLatestNpm(root, npmArgs, { NODE_AUTH_TOKEN: '', NPM_TOKEN: '' });
|
|
1522
1731
|
}
|