release-it 20.1.0 → 20.2.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/lib/plugin/npm/npm.js +21 -9
- package/package.json +1 -1
- package/test/npm.js +41 -0
package/lib/plugin/npm/npm.js
CHANGED
|
@@ -215,6 +215,16 @@ class npm extends Plugin {
|
|
|
215
215
|
return urlJoin(baseUrl, publicPath, this.getName());
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
getStagedPackagesUrl() {
|
|
219
|
+
const name = this.getName();
|
|
220
|
+
const entity = name.startsWith('@') ? name.slice(1).split('/')[0] : this.getContext('username');
|
|
221
|
+
return entity ? `https://www.npmjs.com/settings/${entity}/staged-packages` : 'https://www.npmjs.com';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
logWouldStage() {
|
|
225
|
+
this.log.log(`📦 Would stage (dry-run). Approve at ${this.getStagedPackagesUrl()} after a real run.`);
|
|
226
|
+
}
|
|
227
|
+
|
|
218
228
|
getRegistry() {
|
|
219
229
|
const { publishConfig } = this.getContext();
|
|
220
230
|
const registries = publishConfig
|
|
@@ -278,13 +288,19 @@ class npm extends Plugin {
|
|
|
278
288
|
...fixArgs(publishArgs)
|
|
279
289
|
].filter(Boolean);
|
|
280
290
|
const publishCommand = stage ? ['stage', 'publish'] : ['publish'];
|
|
281
|
-
const isInteractive = !this.config.isCI || Boolean(this.config.isPromptOnlyVersion);
|
|
291
|
+
const isInteractive = !stage && (!this.config.isCI || Boolean(this.config.isPromptOnlyVersion));
|
|
282
292
|
return this.exec([publishPackageManager, ...publishCommand, ...args], {
|
|
283
293
|
options: { ...getOptions(), interactive: isInteractive }
|
|
284
294
|
})
|
|
285
|
-
.then(
|
|
295
|
+
.then(output => {
|
|
286
296
|
if (stage) {
|
|
287
|
-
this.
|
|
297
|
+
if (this.config.isDryRun) {
|
|
298
|
+
this.logWouldStage();
|
|
299
|
+
} else {
|
|
300
|
+
const id = output?.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i)?.[0];
|
|
301
|
+
const approve = `${publishPackageManager} stage approve${id ? ` ${id}` : ''}`;
|
|
302
|
+
this.log.log(`📦 Staged, not yet published. Approve at ${this.getStagedPackagesUrl()} (or \`${approve}\`).`);
|
|
303
|
+
}
|
|
288
304
|
} else {
|
|
289
305
|
this.setContext({ isReleased: true });
|
|
290
306
|
this.config.setContext({ isReleased: true });
|
|
@@ -293,6 +309,7 @@ class npm extends Plugin {
|
|
|
293
309
|
.catch(err => {
|
|
294
310
|
this.debug(err);
|
|
295
311
|
if (this.config.isDryRun && /publish over the previously published version/.test(err)) {
|
|
312
|
+
if (stage) this.logWouldStage();
|
|
296
313
|
return Promise.resolve();
|
|
297
314
|
}
|
|
298
315
|
|
|
@@ -309,14 +326,9 @@ class npm extends Plugin {
|
|
|
309
326
|
}
|
|
310
327
|
|
|
311
328
|
afterRelease() {
|
|
312
|
-
const { isReleased
|
|
329
|
+
const { isReleased } = this.getContext();
|
|
313
330
|
if (isReleased) {
|
|
314
331
|
this.log.log(`🔗 ${this.getPackageUrl()}`);
|
|
315
|
-
} else if (isStaged) {
|
|
316
|
-
const pm = this.options.publishPackageManager || 'npm';
|
|
317
|
-
this.log.log(
|
|
318
|
-
`📦 Staged for publishing. Approve with \`${pm} stage approve\` (see \`${pm} stage list\`) or on npmjs.com. Requires 2FA.`
|
|
319
|
-
);
|
|
320
332
|
}
|
|
321
333
|
}
|
|
322
334
|
}
|
package/package.json
CHANGED
package/test/npm.js
CHANGED
|
@@ -377,6 +377,47 @@ describe('npm', async () => {
|
|
|
377
377
|
assert.deepEqual(exec.mock.calls.at(-1).arguments[0], ['pnpm', 'stage', 'publish', '.', '--tag', 'latest']);
|
|
378
378
|
});
|
|
379
379
|
|
|
380
|
+
test('should print the staged-packages approval URL after stage publish', async t => {
|
|
381
|
+
const unscoped = await factory(npm, { options: { npm: { stage: true } } });
|
|
382
|
+
unscoped.setContext({ name: 'pkg', username: 'webpro' });
|
|
383
|
+
t.mock.method(unscoped.shell, 'exec', () => Promise.resolve());
|
|
384
|
+
await unscoped.publish();
|
|
385
|
+
assert.match(unscoped.log.log.mock.calls.map(c => c.arguments[0]).join('\n'), /settings\/webpro\/staged-packages/);
|
|
386
|
+
|
|
387
|
+
const scoped = await factory(npm, { options: { npm: { stage: true } } });
|
|
388
|
+
scoped.setContext({ name: '@release-it/x', username: 'webpro' });
|
|
389
|
+
t.mock.method(scoped.shell, 'exec', () => Promise.resolve());
|
|
390
|
+
await scoped.publish();
|
|
391
|
+
assert.match(scoped.log.log.mock.calls.map(c => c.arguments[0]).join('\n'), /settings\/release-it\/staged-packages/);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test('should surface the stage id from publish output in the approval message', async t => {
|
|
395
|
+
const npmClient = await factory(npm, { options: { npm: { stage: true } } });
|
|
396
|
+
npmClient.setContext({ name: 'pkg', username: 'webpro' });
|
|
397
|
+
const id = '71289309-c232-432b-a2d4-32a14fa08177';
|
|
398
|
+
t.mock.method(npmClient.shell, 'exec', () => Promise.resolve(`+ pkg@1.0.0 (staged with id ${id})`));
|
|
399
|
+
await npmClient.publish();
|
|
400
|
+
const logged = npmClient.log.log.mock.calls.map(c => c.arguments[0]).join('\n');
|
|
401
|
+
assert.match(logged, new RegExp(`npm stage approve ${id}`));
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test('should describe a staged dry-run, whether npm resolves or rejects the un-bumped version', async t => {
|
|
405
|
+
const execs = [
|
|
406
|
+
() => Promise.resolve('staged with id 71289309-c232-432b-a2d4-32a14fa08177'),
|
|
407
|
+
() => Promise.reject(new Error('npm error You cannot publish over the previously published versions: 1.0.0.'))
|
|
408
|
+
];
|
|
409
|
+
for (const exec of execs) {
|
|
410
|
+
const npmClient = await factory(npm, { options: { 'dry-run': true, npm: { stage: true } } });
|
|
411
|
+
npmClient.setContext({ name: 'pkg', username: 'webpro' });
|
|
412
|
+
t.mock.method(npmClient.shell, 'exec', exec);
|
|
413
|
+
await npmClient.publish();
|
|
414
|
+
const logged = npmClient.log.log.mock.calls.map(c => c.arguments[0]).join('\n');
|
|
415
|
+
assert.match(logged, /Would stage \(dry-run\)/);
|
|
416
|
+
assert.match(logged, /settings\/webpro\/staged-packages/);
|
|
417
|
+
assert.doesNotMatch(logged, /stage approve 71289309/);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
380
421
|
test('should skip checks', async () => {
|
|
381
422
|
const options = { npm: { skipChecks: true } };
|
|
382
423
|
const npmClient = await factory(npm, { options });
|