@smoothbricks/cli 0.2.0 → 0.3.0
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 +27 -23
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -3
- package/dist/generate/index.d.ts +20 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +47 -0
- package/dist/lib/run.d.ts +1 -0
- package/dist/lib/run.d.ts.map +1 -1
- package/dist/lib/run.js +19 -0
- package/dist/lib/workspace.d.ts +10 -0
- package/dist/lib/workspace.d.ts.map +1 -1
- package/dist/lib/workspace.js +55 -16
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +9 -0
- package/dist/monorepo/package-policy.d.ts +6 -17
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +63 -1127
- package/dist/monorepo/publish-workflow.js +2 -3
- package/dist/nx/index.d.ts +1 -0
- package/dist/nx/index.d.ts.map +1 -1
- package/dist/nx/index.js +23 -5
- package/dist/release/candidates.js +1 -1
- package/dist/release/core.d.ts +3 -1
- package/dist/release/core.d.ts.map +1 -1
- package/dist/release/core.js +76 -9
- package/dist/release/github-release.d.ts +1 -0
- package/dist/release/github-release.d.ts.map +1 -1
- package/dist/release/github-release.js +1 -1
- package/dist/release/index.d.ts +9 -3
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +265 -39
- package/dist/release/orchestration.d.ts +10 -2
- package/dist/release/orchestration.d.ts.map +1 -1
- package/dist/release/orchestration.js +33 -3
- package/managed/templates/github/workflows/ci.yml +3 -2
- package/package.json +7 -12
- package/src/cli.ts +21 -4
- package/src/generate/index.ts +92 -0
- package/src/lib/run.ts +25 -0
- package/src/lib/workspace.ts +72 -16
- package/src/monorepo/lockfile.ts +9 -0
- package/src/monorepo/package-policy.test.ts +250 -22
- package/src/monorepo/package-policy.ts +88 -1351
- package/src/monorepo/publish-workflow.ts +2 -3
- package/src/nx/index.test.ts +9 -0
- package/src/nx/index.ts +25 -5
- package/src/release/__tests__/candidates.test.ts +53 -8
- package/src/release/__tests__/core-properties.test.ts +2 -2
- package/src/release/__tests__/core-scenarios.test.ts +12 -15
- package/src/release/__tests__/core.test.ts +50 -3
- package/src/release/__tests__/fixture-repo.test.ts +68 -18
- package/src/release/__tests__/github-release.test.ts +9 -16
- package/src/release/__tests__/orchestration.test.ts +91 -5
- package/src/release/__tests__/retag-unpublished.test.ts +9 -9
- package/src/release/__tests__/trust-publisher.test.ts +65 -33
- package/src/release/candidates.ts +1 -1
- package/src/release/core.ts +95 -10
- package/src/release/github-release.ts +1 -1
- package/src/release/index.ts +343 -49
- package/src/release/orchestration.ts +50 -5
- package/dist/nx-version-actions.cjs +0 -25
- package/dist/nx-version-actions.d.cts +0 -6
- package/dist/nx-version-actions.d.cts.map +0 -1
- package/src/nx-version-actions.cts +0 -36
package/dist/release/index.js
CHANGED
|
@@ -6,15 +6,15 @@ import { Writable } from 'node:stream';
|
|
|
6
6
|
import { $ } from 'bun';
|
|
7
7
|
import { withDevenvEnv } from '../lib/devenv.js';
|
|
8
8
|
import { isRecord, readJsonObject, stringProperty } from '../lib/json.js';
|
|
9
|
-
import { decode, run, runResult, runStatus } from '../lib/run.js';
|
|
9
|
+
import { decode, run, runInteractiveStatus, runResult, runStatus } from '../lib/run.js';
|
|
10
10
|
import { listReleasePackages, readPackageJson, repositoryInfo } from '../lib/workspace.js';
|
|
11
11
|
import { readPackedPackageJson, validatePackedWorkspaceDependencies } from '../monorepo/packed-manifest.js';
|
|
12
12
|
import { bootstrapNpmPackages, NPM_BOOTSTRAP_DIST_TAG, NPM_BOOTSTRAP_VERSION, } from './bootstrap-npm-packages.js';
|
|
13
13
|
import { autoReleaseCandidatePackages } from './candidates.js';
|
|
14
|
-
import { collectOwnedReleaseTagRecords, pendingReleaseTargets, releaseTag, } from './core.js';
|
|
15
|
-
import { createOrUpdateGithubRelease, renderNxProjectChangelogContents } from './github-release.js';
|
|
14
|
+
import { collectOwnedReleaseTagRecords, pendingReleaseTargets, releaseTag, releaseTagAliases, } from './core.js';
|
|
15
|
+
import { createOrUpdateGithubRelease, renderNxProjectChangelogContents, withNxWorkspaceRoot, } from './github-release.js';
|
|
16
16
|
import { publishWithAuthDiagnostics } from './npm-auth.js';
|
|
17
|
-
import { completeReleaseAtHead as completeReleaseAtHeadWithShell, repairPendingTargets, runReleaseVersion, } from './orchestration.js';
|
|
17
|
+
import { bumpStableReleaseToNext, completeReleaseAtHead as completeReleaseAtHeadWithShell, repairPendingTargets, runReleaseVersion, } from './orchestration.js';
|
|
18
18
|
import { retagUnpublished } from './retag-unpublished.js';
|
|
19
19
|
export async function releaseVersion(root, options) {
|
|
20
20
|
const bump = releaseBumpArg(options.bump);
|
|
@@ -33,6 +33,9 @@ export async function releaseVersion(root, options) {
|
|
|
33
33
|
else if (result.status === 'no-release-needed') {
|
|
34
34
|
console.log('Nx did not create a release commit; no release needed.');
|
|
35
35
|
}
|
|
36
|
+
if (result.status === 'dry-run') {
|
|
37
|
+
await writeReleasePreviewSummary(root, packages, result.packages);
|
|
38
|
+
}
|
|
36
39
|
await writeReleaseGithubOutput(options.githubOutput, result.packages, result.mode);
|
|
37
40
|
}
|
|
38
41
|
export async function releasePublish(root, options) {
|
|
@@ -40,15 +43,20 @@ export async function releasePublish(root, options) {
|
|
|
40
43
|
const packages = await releasePackagesAtHead(root, releasePackages(root));
|
|
41
44
|
if (packages.length === 0) {
|
|
42
45
|
if (bump === 'auto') {
|
|
46
|
+
if (options.dryRun === true) {
|
|
47
|
+
console.log('No release tags found at HEAD because dry-run versioning does not create release commits or tags.');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
43
50
|
console.log('No release tags found at HEAD; no release to publish.');
|
|
44
51
|
const summary = {
|
|
45
52
|
sha: await gitHead(root),
|
|
46
|
-
dryRun:
|
|
53
|
+
dryRun: false,
|
|
47
54
|
packages,
|
|
48
55
|
pushed: false,
|
|
49
56
|
published: [],
|
|
50
57
|
alreadyPublished: [],
|
|
51
58
|
githubReleases: [],
|
|
59
|
+
githubReleaseLinks: [],
|
|
52
60
|
rerunRequired: false,
|
|
53
61
|
noRelease: true,
|
|
54
62
|
};
|
|
@@ -59,6 +67,10 @@ export async function releasePublish(root, options) {
|
|
|
59
67
|
}
|
|
60
68
|
const summary = await completeReleaseAtHeadWithShell(releaseCompletionShell(root), packages, options.dryRun === true, await newerCommitsRemain(root));
|
|
61
69
|
await writeReleaseSummary(summary);
|
|
70
|
+
const bumpedPackages = await bumpStableReleaseToNext(releaseNextShell(root), packages, options.dryRun === true, summary.rerunRequired);
|
|
71
|
+
if (bumpedPackages.length > 0) {
|
|
72
|
+
console.log(`Prepared next prerelease for ${packageSummary(bumpedPackages)}.`);
|
|
73
|
+
}
|
|
62
74
|
}
|
|
63
75
|
export async function releaseRepairPending(root, options) {
|
|
64
76
|
const branch = await releaseBranch(root);
|
|
@@ -72,6 +84,9 @@ export async function releaseRepairPending(root, options) {
|
|
|
72
84
|
console.log(targets.length === 0
|
|
73
85
|
? 'Repair pending releases: no pending durable state repairs found.'
|
|
74
86
|
: `Repair pending releases: ${targets.length} release target${targets.length === 1 ? '' : 's'} need repair.`);
|
|
87
|
+
for (const target of targets) {
|
|
88
|
+
console.log(`Repair pending releases: target ${target.sha.slice(0, 12)} needs ${repairTargetSummary(target)}.`);
|
|
89
|
+
}
|
|
75
90
|
const summaries = await repairPendingTargets(releaseRepairShell(root), targets, restoreRef, options.dryRun === true);
|
|
76
91
|
await writeRepairSummary(summaries, options.dryRun === true);
|
|
77
92
|
}
|
|
@@ -91,7 +106,6 @@ export async function releaseTrustPublisher(root, options) {
|
|
|
91
106
|
promptOtp: (packageName) => promptForNpmOtp(packageName),
|
|
92
107
|
log: (message) => console.log(message),
|
|
93
108
|
}, bootstrapOptions),
|
|
94
|
-
login: () => runLatestNpm(root, ['login', '--auth-type=web']),
|
|
95
109
|
trustPublisher: (pkg, dryRun, env) => {
|
|
96
110
|
const args = ['trust', 'github', pkg.name, '--file', workflow, '--repo', repository, '--yes'];
|
|
97
111
|
if (dryRun) {
|
|
@@ -99,28 +113,27 @@ export async function releaseTrustPublisher(root, options) {
|
|
|
99
113
|
}
|
|
100
114
|
return runLatestNpmTrust(root, args, env);
|
|
101
115
|
},
|
|
102
|
-
|
|
116
|
+
trustedPublishers: (pkg) => listTrustedPublishers(root, pkg),
|
|
103
117
|
log: (message) => console.log(message),
|
|
104
118
|
error: (message) => console.error(message),
|
|
105
119
|
}, options);
|
|
106
120
|
}
|
|
107
121
|
export async function configureTrustedPublishers(shell, options) {
|
|
108
122
|
const packages = shell.listReleasePackages();
|
|
109
|
-
|
|
123
|
+
const selectedPackages = selectedTrustPublisherPackages(packages, options.packages ?? []);
|
|
124
|
+
if (selectedPackages.length === 0) {
|
|
110
125
|
throw new Error('No owned release packages found.');
|
|
111
126
|
}
|
|
112
|
-
let bootstrapLoggedIn = false;
|
|
113
127
|
if (options.bootstrap) {
|
|
114
|
-
|
|
128
|
+
await shell.bootstrapNpmPackages({
|
|
115
129
|
dryRun: options.dryRun === true,
|
|
116
130
|
skipLogin: options.skipLogin === true,
|
|
117
131
|
otp: options.bootstrapOtp,
|
|
118
|
-
packages: [],
|
|
132
|
+
packages: options.packages ?? [],
|
|
119
133
|
});
|
|
120
|
-
bootstrapLoggedIn = bootstrapped.length > 0 && !options.dryRun && !options.skipLogin;
|
|
121
134
|
}
|
|
122
135
|
if (!options.dryRun) {
|
|
123
|
-
const packageStates = await Promise.all(
|
|
136
|
+
const packageStates = await Promise.all(selectedPackages.map(async (pkg) => ((await shell.packageExists(pkg.name)) ? null : pkg.name)));
|
|
124
137
|
const missingPackages = packageStates.filter((name) => name !== null);
|
|
125
138
|
if (missingPackages.length > 0) {
|
|
126
139
|
throw new Error('npm trusted publishing can only be configured after packages exist on the registry. ' +
|
|
@@ -128,16 +141,23 @@ export async function configureTrustedPublishers(shell, options) {
|
|
|
128
141
|
`Missing packages: ${missingPackages.join(', ')}`);
|
|
129
142
|
}
|
|
130
143
|
}
|
|
131
|
-
if (!options.dryRun && !options.skipLogin && !bootstrapLoggedIn) {
|
|
132
|
-
await shell.login();
|
|
133
|
-
}
|
|
134
144
|
const failedPackages = [];
|
|
135
|
-
for (const pkg of
|
|
145
|
+
for (const pkg of selectedPackages) {
|
|
146
|
+
if (!options.dryRun) {
|
|
147
|
+
const trustedPublishers = await shell.trustedPublishers(pkg);
|
|
148
|
+
if (hasMatchingGithubTrustedPublisher(trustedPublishers, shell.repository, shell.workflow)) {
|
|
149
|
+
shell.log(`${pkg.name}: npm trusted publisher is already configured; skipping.`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (trustedPublishers.length > 0) {
|
|
153
|
+
throw new Error(`${pkg.name}: npm trusted publisher exists but does not match GitHub Actions ${shell.repository}/${shell.workflow}. ` +
|
|
154
|
+
'Use npm trust list to inspect it and npm trust revoke --id <trust-id> before reconfiguring.');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
136
157
|
shell.log(`${pkg.name}: trusting GitHub Actions ${shell.repository}/${shell.workflow}`);
|
|
137
158
|
while (true) {
|
|
138
|
-
const otp = options.dryRun ? undefined : (options.otp ?? (await shell.promptOtp(pkg.name)));
|
|
139
159
|
try {
|
|
140
|
-
const result = await shell.trustPublisher(pkg, options.dryRun === true
|
|
160
|
+
const result = await shell.trustPublisher(pkg, options.dryRun === true);
|
|
141
161
|
if (result === 'already-configured') {
|
|
142
162
|
shell.log(`${pkg.name}: npm trusted publisher is already configured; skipping.`);
|
|
143
163
|
}
|
|
@@ -147,9 +167,9 @@ export async function configureTrustedPublishers(shell, options) {
|
|
|
147
167
|
shell.error(`${pkg.name}: npm trusted publisher setup failed.`);
|
|
148
168
|
shell.error(error instanceof Error ? error.message : String(error));
|
|
149
169
|
if (!options.dryRun) {
|
|
150
|
-
shell.error('npm
|
|
170
|
+
shell.error('npm owns trusted publishing authentication. Complete the npm browser challenge, then retry.');
|
|
151
171
|
}
|
|
152
|
-
if (options.
|
|
172
|
+
if (options.dryRun) {
|
|
153
173
|
failedPackages.push(pkg.name);
|
|
154
174
|
break;
|
|
155
175
|
}
|
|
@@ -159,10 +179,33 @@ export async function configureTrustedPublishers(shell, options) {
|
|
|
159
179
|
}
|
|
160
180
|
if (failedPackages.length > 0) {
|
|
161
181
|
shell.error(`Trusted publishing was not configured for: ${failedPackages.join(', ')}`);
|
|
162
|
-
|
|
163
|
-
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function selectedTrustPublisherPackages(packages, selections) {
|
|
185
|
+
if (selections.length === 0) {
|
|
186
|
+
return packages;
|
|
187
|
+
}
|
|
188
|
+
const byName = new Map(packages.map((pkg) => [pkg.name, pkg]));
|
|
189
|
+
const selected = [];
|
|
190
|
+
const unknown = [];
|
|
191
|
+
for (const name of selections) {
|
|
192
|
+
const pkg = byName.get(name);
|
|
193
|
+
if (pkg) {
|
|
194
|
+
selected.push(pkg);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
unknown.push(name);
|
|
164
198
|
}
|
|
165
199
|
}
|
|
200
|
+
if (unknown.length > 0) {
|
|
201
|
+
throw new Error(`Unknown owned release package selection: ${unknown.join(', ')}`);
|
|
202
|
+
}
|
|
203
|
+
return selected;
|
|
204
|
+
}
|
|
205
|
+
function hasMatchingGithubTrustedPublisher(trustedPublishers, repository, workflow) {
|
|
206
|
+
return trustedPublishers.some((trustedPublisher) => trustedPublisher.type === 'github' &&
|
|
207
|
+
trustedPublisher.repository === repository &&
|
|
208
|
+
trustedPublisher.file === workflow);
|
|
166
209
|
}
|
|
167
210
|
export async function releaseBootstrapNpmPackages(root, options) {
|
|
168
211
|
await bootstrapNpmPackages({
|
|
@@ -198,6 +241,7 @@ export async function releaseRetagUnpublished(root, options) {
|
|
|
198
241
|
export async function printReleaseState(root) {
|
|
199
242
|
console.log(JSON.stringify(await getReleaseState(root), null, 2));
|
|
200
243
|
}
|
|
244
|
+
const releasePreviewChangelogs = new Map();
|
|
201
245
|
async function getReleaseState(root) {
|
|
202
246
|
return getReleaseStateForPackages(root, listReleasePackages(root));
|
|
203
247
|
}
|
|
@@ -301,6 +345,9 @@ async function releaseVersionPackages(root, packages, bump) {
|
|
|
301
345
|
}, packages);
|
|
302
346
|
}
|
|
303
347
|
async function runNxReleaseVersion(root, projects, bump, dryRun) {
|
|
348
|
+
if (dryRun) {
|
|
349
|
+
return runNxReleaseVersionPreview(root, projects, bump);
|
|
350
|
+
}
|
|
304
351
|
// Nx owns local release mutation: package versions, bun.lock updates, the
|
|
305
352
|
// release commit, and annotated tags. smoo owns remote publication after the
|
|
306
353
|
// workflow validates the exact release commit Nx produced.
|
|
@@ -309,10 +356,66 @@ async function runNxReleaseVersion(root, projects, bump, dryRun) {
|
|
|
309
356
|
nxArgs.push(bump);
|
|
310
357
|
}
|
|
311
358
|
nxArgs.push(`--projects=${projects}`, '--git-commit=true', '--git-tag=true', '--git-push=false');
|
|
312
|
-
if (dryRun) {
|
|
313
|
-
nxArgs.push('--dry-run');
|
|
314
|
-
}
|
|
315
359
|
await run('nx', nxArgs, root);
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
async function runNxReleaseVersionPreview(root, projects, bump) {
|
|
363
|
+
return withNxWorkspaceRoot(root, async () => {
|
|
364
|
+
const { createAPI } = await import('nx/src/command-line/release/version.js');
|
|
365
|
+
const { createAPI: createChangelogAPI } = await import('nx/src/command-line/release/changelog.js');
|
|
366
|
+
const projectNames = projects.split(',').filter(Boolean);
|
|
367
|
+
const result = await createAPI({}, false)({
|
|
368
|
+
specifier: bump === 'auto' ? undefined : bump,
|
|
369
|
+
projects: projectNames,
|
|
370
|
+
gitCommit: true,
|
|
371
|
+
gitTag: true,
|
|
372
|
+
gitPush: false,
|
|
373
|
+
dryRun: true,
|
|
374
|
+
});
|
|
375
|
+
const changelogResult = await createChangelogAPI({
|
|
376
|
+
changelog: {
|
|
377
|
+
workspaceChangelog: false,
|
|
378
|
+
projectChangelogs: { createRelease: false, file: false },
|
|
379
|
+
},
|
|
380
|
+
}, false)({
|
|
381
|
+
projects: projectNames,
|
|
382
|
+
versionData: result.projectsVersionData,
|
|
383
|
+
releaseGraph: result.releaseGraph,
|
|
384
|
+
gitCommit: false,
|
|
385
|
+
gitTag: false,
|
|
386
|
+
gitPush: false,
|
|
387
|
+
stageChanges: false,
|
|
388
|
+
createRelease: false,
|
|
389
|
+
dryRun: true,
|
|
390
|
+
});
|
|
391
|
+
releasePreviewChangelogs.clear();
|
|
392
|
+
for (const [projectName, changelog] of Object.entries(changelogResult.projectChangelogs ?? {})) {
|
|
393
|
+
releasePreviewChangelogs.set(projectName, changelog.contents);
|
|
394
|
+
}
|
|
395
|
+
const packagesByProject = new Map(releasePackages(root).map((pkg) => [pkg.projectName, pkg]));
|
|
396
|
+
return Object.entries(result.projectsVersionData)
|
|
397
|
+
.map(([projectName, data]) => {
|
|
398
|
+
const pkg = packagesByProject.get(projectName);
|
|
399
|
+
if (!pkg || !data.newVersion) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
return { ...pkg, version: data.newVersion };
|
|
403
|
+
})
|
|
404
|
+
.filter((pkg) => pkg !== null);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
async function runNxNextPrereleaseVersion(root, projects) {
|
|
408
|
+
await run('nx', [
|
|
409
|
+
'release',
|
|
410
|
+
'version',
|
|
411
|
+
'prerelease',
|
|
412
|
+
`--projects=${projects}`,
|
|
413
|
+
'--preid=next',
|
|
414
|
+
'--git-commit=true',
|
|
415
|
+
'--git-tag=false',
|
|
416
|
+
'--git-push=false',
|
|
417
|
+
'--git-commit-message=chore(release): prepare next prerelease',
|
|
418
|
+
], root);
|
|
316
419
|
}
|
|
317
420
|
async function releasePackagesAtHead(root, packages) {
|
|
318
421
|
return releasePackagesAtRef(root, packages, 'HEAD');
|
|
@@ -381,7 +484,7 @@ async function gitTagsAtRef(root, ref) {
|
|
|
381
484
|
.filter(Boolean);
|
|
382
485
|
}
|
|
383
486
|
async function previousReleaseTag(root, pkg, currentTag) {
|
|
384
|
-
const result = await $ `git tag --list ${`${pkg.
|
|
487
|
+
const result = await $ `git tag --list ${`${pkg.projectName}@*`} --sort=-v:refname --merged ${currentTag}`
|
|
385
488
|
.cwd(root)
|
|
386
489
|
.quiet()
|
|
387
490
|
.nothrow();
|
|
@@ -429,6 +532,11 @@ async function pushReleaseRefs(root, packages) {
|
|
|
429
532
|
await run('git', ['push', '--atomic', remote, ...refspecs], root);
|
|
430
533
|
return true;
|
|
431
534
|
}
|
|
535
|
+
async function pushCurrentBranch(root) {
|
|
536
|
+
const branch = await releaseBranch(root);
|
|
537
|
+
const remote = await releaseRemote(root, branch);
|
|
538
|
+
await run('git', ['push', remote, `HEAD:refs/heads/${branch}`], root);
|
|
539
|
+
}
|
|
432
540
|
function releaseCompletionShell(root) {
|
|
433
541
|
return {
|
|
434
542
|
gitHead: () => gitHead(root),
|
|
@@ -446,6 +554,14 @@ function releaseCompletionShell(root) {
|
|
|
446
554
|
createGithubRelease: (pkg, dryRun) => createGithubRelease(root, pkg, dryRun),
|
|
447
555
|
};
|
|
448
556
|
}
|
|
557
|
+
function releaseNextShell(root) {
|
|
558
|
+
return {
|
|
559
|
+
bumpStablePackagesToNext: async (packages) => {
|
|
560
|
+
await runNxNextPrereleaseVersion(root, releasePackageProjects(packages));
|
|
561
|
+
await pushCurrentBranch(root);
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
}
|
|
449
565
|
function releaseRepairShell(root) {
|
|
450
566
|
return {
|
|
451
567
|
...releaseCompletionShell(root),
|
|
@@ -490,15 +606,23 @@ async function listOwnedReleaseTagRecords(root, ref) {
|
|
|
490
606
|
}
|
|
491
607
|
async function durableReleaseTagState(root, pkg, tag) {
|
|
492
608
|
const packageVersion = `${pkg.name}@${pkg.version}`;
|
|
609
|
+
const githubReleaseTags = releaseTagAliases({ ...pkg, projectName: projectNameFromReleaseTag(tag) });
|
|
493
610
|
const start = Date.now();
|
|
494
|
-
console.log(`${packageVersion}: checking durable state (npm + GitHub Release ${
|
|
611
|
+
console.log(`${packageVersion}: checking durable state (npm + GitHub Release ${githubReleaseTags.join(' or ')}).`);
|
|
495
612
|
const [npmPublished, githubReleasePresent] = await Promise.all([
|
|
496
613
|
npmVersionExists(root, pkg.name, pkg.version),
|
|
497
|
-
|
|
614
|
+
anyGithubReleaseExists(root, githubReleaseTags),
|
|
498
615
|
]);
|
|
499
616
|
console.log(`${packageVersion}: durable state npm=${yesNo(npmPublished)} github=${yesNo(githubReleasePresent)} (${Date.now() - start}ms).`);
|
|
500
617
|
return { npmPublished, githubReleaseExists: githubReleasePresent };
|
|
501
618
|
}
|
|
619
|
+
function projectNameFromReleaseTag(tag) {
|
|
620
|
+
const versionSeparator = tag.lastIndexOf('@');
|
|
621
|
+
if (versionSeparator <= 0) {
|
|
622
|
+
return tag;
|
|
623
|
+
}
|
|
624
|
+
return tag.slice(0, versionSeparator);
|
|
625
|
+
}
|
|
502
626
|
async function gitReleaseTagsByCreatorDate(root) {
|
|
503
627
|
const result = await $ `git for-each-ref --sort=-creatordate --format=${'%(refname:short)%09%(creatordate:unix)%09%(*objectname)%09%(objectname)'} refs/tags`
|
|
504
628
|
.cwd(root)
|
|
@@ -537,7 +661,7 @@ async function createGithubRelease(root, pkg, dryRun) {
|
|
|
537
661
|
const previousTag = await previousReleaseTag(root, pkg, currentTag);
|
|
538
662
|
if (dryRun) {
|
|
539
663
|
await renderNxProjectChangelogContents({ root, pkg, previousTag, dryRun });
|
|
540
|
-
return;
|
|
664
|
+
return null;
|
|
541
665
|
}
|
|
542
666
|
const contents = await renderNxProjectChangelogContents({ root, pkg, previousTag, dryRun });
|
|
543
667
|
await createOrUpdateGithubRelease(pkg, contents, {
|
|
@@ -545,6 +669,7 @@ async function createGithubRelease(root, pkg, dryRun) {
|
|
|
545
669
|
runGhRelease: (args) => run('gh', args, root),
|
|
546
670
|
log: (message) => console.log(message),
|
|
547
671
|
});
|
|
672
|
+
return githubReleaseUrl(root, currentTag);
|
|
548
673
|
}
|
|
549
674
|
function envPresence(name) {
|
|
550
675
|
return `${name}=${process.env[name] ? 'present' : 'missing'}`;
|
|
@@ -579,7 +704,7 @@ async function writeReleaseSummary(summary) {
|
|
|
579
704
|
lines.push(`- Git refs pushed: ${summary.pushed ? 'yes' : 'already current'}`);
|
|
580
705
|
lines.push(`- npm published: ${packageSummary(summary.published)}`);
|
|
581
706
|
lines.push(`- npm already published: ${packageSummary(summary.alreadyPublished)}`);
|
|
582
|
-
lines.push(`- GitHub Releases created/updated: ${
|
|
707
|
+
lines.push(`- GitHub Releases created/updated: ${githubReleaseSummary(summary)}`);
|
|
583
708
|
}
|
|
584
709
|
if (summary.rerunRequired) {
|
|
585
710
|
const message = 'A previous incomplete release was repaired; newer commits remain. Run Publish again.';
|
|
@@ -593,6 +718,32 @@ async function writeReleaseSummary(summary) {
|
|
|
593
718
|
await appendFile(summaryPath, `${text}\n`);
|
|
594
719
|
}
|
|
595
720
|
}
|
|
721
|
+
async function writeReleasePreviewSummary(root, currentPackages, previewPackages) {
|
|
722
|
+
const lines = ['## Release Preview', '', `- Commit: \`${(await gitHead(root)).slice(0, 12)}\``, '- Mode: dry run'];
|
|
723
|
+
if (previewPackages.length === 0) {
|
|
724
|
+
lines.push('- Result: no release needed');
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
lines.push('- Packages:');
|
|
728
|
+
const currentByName = new Map(currentPackages.map((pkg) => [pkg.name, pkg]));
|
|
729
|
+
for (const pkg of previewPackages) {
|
|
730
|
+
lines.push(` - \`${pkg.name}\`: \`${currentByName.get(pkg.name)?.version ?? 'unknown'}\` -> \`${pkg.version}\``);
|
|
731
|
+
}
|
|
732
|
+
for (const pkg of previewPackages) {
|
|
733
|
+
const contents = releasePreviewChangelogs.get(pkg.projectName);
|
|
734
|
+
if (!contents) {
|
|
735
|
+
throw new Error(`Nx did not generate a project changelog for ${pkg.projectName}.`);
|
|
736
|
+
}
|
|
737
|
+
lines.push('', `### ${pkg.name} ${pkg.version}`, '', contents.trim());
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const text = `${lines.join('\n')}\n`;
|
|
741
|
+
console.log(text.trimEnd());
|
|
742
|
+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
743
|
+
if (summaryPath) {
|
|
744
|
+
await appendFile(summaryPath, `${text}\n`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
596
747
|
async function writeRepairSummary(summaries, dryRun) {
|
|
597
748
|
const lines = ['## Pending Release Repair', '', `- Mode: ${dryRun ? 'dry run' : 'release'}`];
|
|
598
749
|
if (summaries.length === 0) {
|
|
@@ -600,7 +751,7 @@ async function writeRepairSummary(summaries, dryRun) {
|
|
|
600
751
|
}
|
|
601
752
|
else {
|
|
602
753
|
for (const summary of summaries) {
|
|
603
|
-
lines.push(`- Repaired \`${summary.sha.slice(0, 12)}\`: ${packageSummary(summary.packages)}`);
|
|
754
|
+
lines.push(`- ${dryRun ? 'Would repair' : 'Repaired'} \`${summary.sha.slice(0, 12)}\`: ${packageSummary(summary.packages)}`);
|
|
604
755
|
}
|
|
605
756
|
}
|
|
606
757
|
const text = `${lines.join('\n')}\n`;
|
|
@@ -616,6 +767,27 @@ function packageSummary(packages) {
|
|
|
616
767
|
}
|
|
617
768
|
return packages.map((pkg) => `${pkg.name}@${pkg.version}`).join(', ');
|
|
618
769
|
}
|
|
770
|
+
function githubReleaseSummary(summary) {
|
|
771
|
+
if (summary.githubReleaseLinks.length > 0) {
|
|
772
|
+
return summary.githubReleaseLinks.map(({ pkg, url }) => `[${pkg.name}@${pkg.version}](${url})`).join(', ');
|
|
773
|
+
}
|
|
774
|
+
return packageSummary(summary.githubReleases);
|
|
775
|
+
}
|
|
776
|
+
function repairTargetSummary(target) {
|
|
777
|
+
return target.packages
|
|
778
|
+
.map((pkg) => `${pkg.name}@${pkg.version} (${repairReasons(target, pkg).join(' + ')})`)
|
|
779
|
+
.join(', ');
|
|
780
|
+
}
|
|
781
|
+
function repairReasons(target, pkg) {
|
|
782
|
+
const reasons = [];
|
|
783
|
+
if (target.npmPackages.includes(pkg)) {
|
|
784
|
+
reasons.push('npm missing');
|
|
785
|
+
}
|
|
786
|
+
if (target.githubPackages.includes(pkg)) {
|
|
787
|
+
reasons.push('GitHub Release missing');
|
|
788
|
+
}
|
|
789
|
+
return reasons;
|
|
790
|
+
}
|
|
619
791
|
async function fetchReleaseRefs(root, remote, branch) {
|
|
620
792
|
await run('git', ['fetch', '--tags', remote, branch], root);
|
|
621
793
|
}
|
|
@@ -806,6 +978,17 @@ async function pushRetaggedReleaseTags(root, remote, updates) {
|
|
|
806
978
|
async function githubReleaseExists(root, tag) {
|
|
807
979
|
return (await runStatus('gh', ['release', 'view', tag, '--json', 'tagName'], root, true)) === 0;
|
|
808
980
|
}
|
|
981
|
+
function githubReleaseUrl(root, tag) {
|
|
982
|
+
return `https://github.com/${githubRepositoryFromRootPackage(root)}/releases/tag/${encodeURIComponent(tag)}`;
|
|
983
|
+
}
|
|
984
|
+
async function anyGithubReleaseExists(root, tags) {
|
|
985
|
+
for (const tag of tags) {
|
|
986
|
+
if (await githubReleaseExists(root, tag)) {
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
809
992
|
async function assertRemoteTagExists(root, tag) {
|
|
810
993
|
const branch = await releaseBranch(root);
|
|
811
994
|
const remote = await releaseRemote(root, branch);
|
|
@@ -917,15 +1100,58 @@ async function runLatestNpm(root, npmArgs, env) {
|
|
|
917
1100
|
await run('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...npmArgs], root, env);
|
|
918
1101
|
}
|
|
919
1102
|
async function runLatestNpmTrust(root, npmArgs, env) {
|
|
920
|
-
const
|
|
921
|
-
if (
|
|
1103
|
+
const status = await runInteractiveStatus('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...npmArgs], root, env);
|
|
1104
|
+
if (status === 0) {
|
|
922
1105
|
return 'configured';
|
|
923
1106
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1107
|
+
throw new Error(`nix shell nixpkgs#nodejs_latest -c npm ${npmArgs.join(' ')} failed with exit code ${status}`);
|
|
1108
|
+
}
|
|
1109
|
+
async function listTrustedPublishers(root, pkg) {
|
|
1110
|
+
const args = ['trust', 'list', pkg.name, '--json'];
|
|
1111
|
+
let result = await runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1112
|
+
if (result.exitCode !== 0 && /\bEOTP\b/.test(`${result.stdout}\n${result.stderr}`)) {
|
|
1113
|
+
const status = await runInteractiveStatus('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1114
|
+
if (status !== 0) {
|
|
1115
|
+
throw new Error(`nix shell nixpkgs#nodejs_latest -c npm ${args.join(' ')} failed with exit code ${status}`);
|
|
1116
|
+
}
|
|
1117
|
+
result = await runResult('nix', ['shell', 'nixpkgs#nodejs_latest', '-c', 'npm', ...args], root);
|
|
1118
|
+
}
|
|
1119
|
+
if (result.exitCode !== 0) {
|
|
1120
|
+
throw new Error(`nix shell nixpkgs#nodejs_latest -c npm ${args.join(' ')} failed with exit code ${result.exitCode}`);
|
|
1121
|
+
}
|
|
1122
|
+
return parseTrustedPublishers(result.stdout, pkg.name);
|
|
1123
|
+
}
|
|
1124
|
+
export function parseTrustedPublishers(stdout, packageName) {
|
|
1125
|
+
if (stdout.trim().length === 0) {
|
|
1126
|
+
return [];
|
|
1127
|
+
}
|
|
1128
|
+
const parsed = JSON.parse(stdout);
|
|
1129
|
+
if (parsed === null) {
|
|
1130
|
+
return [];
|
|
1131
|
+
}
|
|
1132
|
+
if (Array.isArray(parsed)) {
|
|
1133
|
+
return parsed.map((value) => parseTrustedPublisher(value, packageName));
|
|
1134
|
+
}
|
|
1135
|
+
if (isRecord(parsed)) {
|
|
1136
|
+
return [parseTrustedPublisher(parsed, packageName)];
|
|
927
1137
|
}
|
|
928
|
-
throw new Error(
|
|
1138
|
+
throw new Error(`${packageName}: npm trust list returned invalid JSON.`);
|
|
1139
|
+
}
|
|
1140
|
+
function parseTrustedPublisher(value, packageName) {
|
|
1141
|
+
if (!isRecord(value)) {
|
|
1142
|
+
throw new Error(`${packageName}: npm trust list returned invalid trusted publisher entry.`);
|
|
1143
|
+
}
|
|
1144
|
+
const id = stringProperty(value, 'id');
|
|
1145
|
+
const type = stringProperty(value, 'type');
|
|
1146
|
+
if (!id || !type) {
|
|
1147
|
+
throw new Error(`${packageName}: npm trust list returned a trusted publisher without id or type.`);
|
|
1148
|
+
}
|
|
1149
|
+
return {
|
|
1150
|
+
id,
|
|
1151
|
+
type,
|
|
1152
|
+
file: stringProperty(value, 'file') ?? undefined,
|
|
1153
|
+
repository: stringProperty(value, 'repository') ?? undefined,
|
|
1154
|
+
};
|
|
929
1155
|
}
|
|
930
1156
|
async function runLatestNpmPublish(root, npmArgs) {
|
|
931
1157
|
await runLatestNpm(root, npmArgs, { NODE_AUTH_TOKEN: '', NPM_TOKEN: '' });
|
|
@@ -935,7 +1161,7 @@ function missingNpmPackagePublishGuidance(pkg) {
|
|
|
935
1161
|
}
|
|
936
1162
|
async function promptForNpmOtp(packageName) {
|
|
937
1163
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
938
|
-
throw new Error(`npm
|
|
1164
|
+
throw new Error(`npm requires a one-time password for ${packageName}. Pass --otp <code> in non-interactive shells.`);
|
|
939
1165
|
}
|
|
940
1166
|
const mutedOutput = new Writable({
|
|
941
1167
|
write(_chunk, _encoding, callback) {
|
|
@@ -8,6 +8,10 @@ export interface ReleaseSummary<Package extends ReleasePackageInfo = ReleasePack
|
|
|
8
8
|
published: Package[];
|
|
9
9
|
alreadyPublished: Package[];
|
|
10
10
|
githubReleases: Package[];
|
|
11
|
+
githubReleaseLinks: Array<{
|
|
12
|
+
pkg: Package;
|
|
13
|
+
url: string;
|
|
14
|
+
}>;
|
|
11
15
|
rerunRequired: boolean;
|
|
12
16
|
noRelease: boolean;
|
|
13
17
|
}
|
|
@@ -18,7 +22,10 @@ export interface ReleaseCompletionShell<Package extends ReleasePackageInfo = Rel
|
|
|
18
22
|
buildReleaseCandidate(packages: Package[]): Promise<void>;
|
|
19
23
|
publishPackage(pkg: Package, distTag: string, dryRun: boolean): Promise<void>;
|
|
20
24
|
listGithubMissingPackages(packages: Package[]): Promise<Package[]>;
|
|
21
|
-
createGithubRelease(pkg: Package, dryRun: boolean): Promise<
|
|
25
|
+
createGithubRelease(pkg: Package, dryRun: boolean): Promise<string | null>;
|
|
26
|
+
}
|
|
27
|
+
export interface ReleaseNextShell<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
28
|
+
bumpStablePackagesToNext(packages: Package[]): Promise<void>;
|
|
22
29
|
}
|
|
23
30
|
export interface ReleaseRepairShell<Package extends ReleasePackageInfo = ReleasePackageInfo> extends ReleaseCompletionShell<Package> {
|
|
24
31
|
checkout(ref: string): Promise<void>;
|
|
@@ -31,7 +38,7 @@ export interface ReleaseVersionShell<Package extends ReleasePackageInfo = Releas
|
|
|
31
38
|
releaseVersionPackages(bump: string): Promise<Package[]>;
|
|
32
39
|
ensureLocalReleaseTags(packages: Package[]): Promise<void>;
|
|
33
40
|
gitHead(): Promise<string>;
|
|
34
|
-
runNxReleaseVersion(packages: Package[], bump: string, dryRun: boolean): Promise<
|
|
41
|
+
runNxReleaseVersion(packages: Package[], bump: string, dryRun: boolean): Promise<Package[]>;
|
|
35
42
|
assertCleanGitTree(): Promise<void>;
|
|
36
43
|
}
|
|
37
44
|
export interface ReleaseVersionResult<Package extends ReleasePackageInfo = ReleasePackageInfo> {
|
|
@@ -44,6 +51,7 @@ export declare function runReleaseVersion<Package extends ReleasePackageInfo>(sh
|
|
|
44
51
|
dryRun: boolean;
|
|
45
52
|
}): Promise<ReleaseVersionResult<Package>>;
|
|
46
53
|
export declare function completeReleaseAtHead<Package extends ReleasePackageInfo>(shell: ReleaseCompletionShell<Package>, packages: Package[], dryRun: boolean, rerunRequired: boolean): Promise<ReleaseSummary<Package>>;
|
|
54
|
+
export declare function bumpStableReleaseToNext<Package extends ReleasePackageInfo>(shell: ReleaseNextShell<Package>, packages: Package[], dryRun: boolean, rerunRequired: boolean): Promise<Package[]>;
|
|
47
55
|
export declare function repairPendingTargets<Package extends ReleasePackageInfo>(shell: ReleaseRepairShell<Package>, targets: Array<ReleaseTarget<Package>>, restoreRef: string, dryRun: boolean): Promise<Array<ReleaseSummary<Package>>>;
|
|
48
56
|
export declare function completeRepairTargetAtHead<Package extends ReleasePackageInfo>(shell: ReleaseCompletionShell<Package>, target: ReleaseTarget<Package>, dryRun: boolean): Promise<ReleaseSummary<Package>>;
|
|
49
57
|
//# 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,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,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/release/orchestration.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,9 +16,9 @@ export async function runReleaseVersion(shell, options) {
|
|
|
16
16
|
return { mode: 'none', packages: [], status: 'no-release-needed' };
|
|
17
17
|
}
|
|
18
18
|
const headBeforeVersioning = await shell.gitHead();
|
|
19
|
-
await shell.runNxReleaseVersion(versionPackages, options.bump, options.dryRun);
|
|
19
|
+
const dryRunPackages = await shell.runNxReleaseVersion(versionPackages, options.bump, options.dryRun);
|
|
20
20
|
if (options.dryRun) {
|
|
21
|
-
return { mode: 'none', packages:
|
|
21
|
+
return { mode: 'none', packages: dryRunPackages, status: 'dry-run' };
|
|
22
22
|
}
|
|
23
23
|
await shell.assertCleanGitTree();
|
|
24
24
|
const headAfterVersioning = await shell.gitHead();
|
|
@@ -51,7 +51,18 @@ export async function completeReleaseAtHead(shell, packages, dryRun, rerunRequir
|
|
|
51
51
|
rerunRequired,
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
+
export async function bumpStableReleaseToNext(shell, packages, dryRun, rerunRequired) {
|
|
55
|
+
const stablePackages = packages.filter((pkg) => !pkg.version.includes('-'));
|
|
56
|
+
if (dryRun || rerunRequired || stablePackages.length === 0) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
await shell.bumpStablePackagesToNext(stablePackages);
|
|
60
|
+
return stablePackages;
|
|
61
|
+
}
|
|
54
62
|
export async function repairPendingTargets(shell, targets, restoreRef, dryRun) {
|
|
63
|
+
if (dryRun) {
|
|
64
|
+
return targets.map((target) => repairDryRunSummary(target));
|
|
65
|
+
}
|
|
55
66
|
const summaries = [];
|
|
56
67
|
try {
|
|
57
68
|
for (const target of targets) {
|
|
@@ -73,6 +84,20 @@ export async function repairPendingTargets(shell, targets, restoreRef, dryRun) {
|
|
|
73
84
|
}
|
|
74
85
|
return summaries;
|
|
75
86
|
}
|
|
87
|
+
function repairDryRunSummary(target) {
|
|
88
|
+
return {
|
|
89
|
+
sha: target.sha,
|
|
90
|
+
dryRun: true,
|
|
91
|
+
packages: target.packages,
|
|
92
|
+
pushed: false,
|
|
93
|
+
published: [],
|
|
94
|
+
alreadyPublished: target.packages.filter((pkg) => !target.npmPackages.includes(pkg)),
|
|
95
|
+
githubReleases: [],
|
|
96
|
+
githubReleaseLinks: [],
|
|
97
|
+
rerunRequired: false,
|
|
98
|
+
noRelease: false,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
76
101
|
export async function completeRepairTargetAtHead(shell, target, dryRun) {
|
|
77
102
|
return completePlannedRelease(shell, {
|
|
78
103
|
sha: await shell.gitHead(),
|
|
@@ -96,8 +121,12 @@ async function completePlannedRelease(shell, input) {
|
|
|
96
121
|
for (const { pkg, distTag } of plan.publishPackages) {
|
|
97
122
|
await shell.publishPackage(pkg, distTag, input.dryRun);
|
|
98
123
|
}
|
|
124
|
+
const githubReleaseLinks = [];
|
|
99
125
|
for (const pkg of plan.githubReleasePackages) {
|
|
100
|
-
await shell.createGithubRelease(pkg, input.dryRun);
|
|
126
|
+
const url = await shell.createGithubRelease(pkg, input.dryRun);
|
|
127
|
+
if (url) {
|
|
128
|
+
githubReleaseLinks.push({ pkg, url });
|
|
129
|
+
}
|
|
101
130
|
}
|
|
102
131
|
return {
|
|
103
132
|
sha: input.sha,
|
|
@@ -107,6 +136,7 @@ async function completePlannedRelease(shell, input) {
|
|
|
107
136
|
published: input.dryRun ? [] : plan.publishPackages.map((action) => action.pkg),
|
|
108
137
|
alreadyPublished: input.packages.filter((pkg) => !input.npmMissingPackages.includes(pkg)),
|
|
109
138
|
githubReleases: input.dryRun ? [] : plan.githubReleasePackages,
|
|
139
|
+
githubReleaseLinks,
|
|
110
140
|
rerunRequired: input.rerunRequired,
|
|
111
141
|
noRelease: false,
|
|
112
142
|
};
|