mopub 0.0.1 → 0.0.2
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 +34 -0
- package/dist/publish.js +17 -40
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# mopub
|
|
2
|
+
|
|
3
|
+
Publish every package in a pnpm monorepo with one command. It builds, packs, diffs against what's on the registry, prompts for the new version(s), and publishes.
|
|
4
|
+
|
|
5
|
+
## Use it
|
|
6
|
+
|
|
7
|
+
Dry-run first (packs everything into a temp folder so you can inspect):
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npx mopub
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
It'll figure out when you last published, calculate a changelog based on git history in each sub-package, prompt you for version number(s) you'd like to publish, and write a ready-to-publish package + changelog to a staging folder under `/tmp`. It'll print out the command for actually publishing at your leisure:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npx mopub prebuilt /tmp/mopub/your-repo-name-will-be-here/1777048359189
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Once the publish succeeds, it prints a command for drafting a GitHub release (opens the "new release" page with the changelog prefilled — no side effects until you click "Create release"):
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
npx mopub release-notes --comparison 0.0.3-7...0.0.3-8
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Other commands:
|
|
26
|
+
|
|
27
|
+
- `npx mopub local` replaces workspace deps with `file:` paths and prints `pnpm add` commands so you can test installs in another project.
|
|
28
|
+
- `npx mopub --help` for the full option list.
|
|
29
|
+
|
|
30
|
+
## Caveats
|
|
31
|
+
|
|
32
|
+
- pnpm only. It shells out to `pnpm list` and `pnpm recursive exec`, and looks for a `pnpm-workspace.yaml` or `pnpm-lock.yaml` at the workspace root.
|
|
33
|
+
- For monorepos. A single-package repo works, but there's no real reason to reach for this over `np`.
|
|
34
|
+
- Rough and ready. Expect to answer a few prompts and read some output before trusting `--publish`. The dry-run folder it prints (`/tmp/mopub/...`) is the source of truth for what will be shipped.
|
package/dist/publish.js
CHANGED
|
@@ -17,7 +17,10 @@ export const PublishInput = z
|
|
|
17
17
|
.boolean()
|
|
18
18
|
.describe('actually publish packages - if not provided the tool will run in dry-run mode and create a directory containing the packages to be published.')
|
|
19
19
|
.optional(),
|
|
20
|
-
otp: z
|
|
20
|
+
otp: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe('npm OTP to pass through to `npm publish --otp`. Only needed for registries that still require OTP-based 2FA. Leave unset to use npm\'s default browser-based auth flow.')
|
|
23
|
+
.optional(),
|
|
21
24
|
bump: z
|
|
22
25
|
.enum(['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'other', 'independent'])
|
|
23
26
|
.describe('semver "bump" strategy - if not provided you will be prompted for it. Do not use with --version.')
|
|
@@ -62,7 +65,7 @@ export const setupContextTasks = [
|
|
|
62
65
|
}
|
|
63
66
|
if (!projectName)
|
|
64
67
|
throw new Error(`Couldn't get package name from pnpm list output: ${list.stdout}`);
|
|
65
|
-
ctx.tempDir = path.join('/tmp/
|
|
68
|
+
ctx.tempDir = path.join('/tmp/mopub', projectName, Date.now().toString());
|
|
66
69
|
task.output = ctx.tempDir;
|
|
67
70
|
fs.mkdirSync(ctx.tempDir, { recursive: true });
|
|
68
71
|
},
|
|
@@ -437,18 +440,7 @@ export const publish = async (input) => {
|
|
|
437
440
|
rendererOptions: { persistentOutput: true },
|
|
438
441
|
task: async (ctx, task) => {
|
|
439
442
|
const shouldActuallyPublish = input.publish;
|
|
440
|
-
|
|
441
|
-
if (shouldActuallyPublish) {
|
|
442
|
-
otp ||= await task.prompt(ListrEnquirerPromptAdapter).run({
|
|
443
|
-
message: 'Enter npm OTP (press enter to try publishing without MFA)',
|
|
444
|
-
type: 'Input',
|
|
445
|
-
validate: v => v === '' || (typeof v === 'string' && /^\d{6}$/.test(v)),
|
|
446
|
-
});
|
|
447
|
-
if (otp.length === 0) {
|
|
448
|
-
task.output = 'No OTP provided - publish will likely error unless you have disabled MFA.';
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
const publishTasks = createPublishTasks(ctx, { otp });
|
|
443
|
+
const publishTasks = createPublishTasks(ctx, { otp: input.otp });
|
|
452
444
|
if (!shouldActuallyPublish)
|
|
453
445
|
publishTasks.forEach(t => (t.skip = true));
|
|
454
446
|
return task.newListr(publishTasks, { rendererOptions: { collapseSubtasks: false } });
|
|
@@ -461,7 +453,7 @@ export const publish = async (input) => {
|
|
|
461
453
|
task: async (ctx, task) => {
|
|
462
454
|
task.output = `To publish, run the following command:`;
|
|
463
455
|
task.output += `\n\n`;
|
|
464
|
-
task.output += `
|
|
456
|
+
task.output += `npx mopub prebuilt ${ctx.tempDir}`;
|
|
465
457
|
},
|
|
466
458
|
},
|
|
467
459
|
], { ctx: {} });
|
|
@@ -483,7 +475,10 @@ function loadContext(folderPath) {
|
|
|
483
475
|
export const PrebuiltInput = z.tuple([
|
|
484
476
|
z.string().describe('Path to the prebuilt publishable folder'),
|
|
485
477
|
z.object({
|
|
486
|
-
otp: z
|
|
478
|
+
otp: z
|
|
479
|
+
.string()
|
|
480
|
+
.describe('npm OTP to pass through to `npm publish --otp`. Only needed for registries that still require OTP-based 2FA. Leave unset to use npm\'s default browser-based auth flow.')
|
|
481
|
+
.optional(),
|
|
487
482
|
}),
|
|
488
483
|
]);
|
|
489
484
|
export async function publishPrebuilt([folder, options]) {
|
|
@@ -492,29 +487,7 @@ export async function publishPrebuilt([folder, options]) {
|
|
|
492
487
|
throw new Error(`Failed to get npm username: ${me.stderr}`);
|
|
493
488
|
console.log(me.stdout, '<<<<<<< npm whoami');
|
|
494
489
|
const ctx = loadContext(folder);
|
|
495
|
-
const tasks = new Listr(
|
|
496
|
-
{
|
|
497
|
-
title: 'Get OTP',
|
|
498
|
-
enabled: !options.otp,
|
|
499
|
-
task: async (_ctx, task) => {
|
|
500
|
-
options.otp = await task.prompt(ListrEnquirerPromptAdapter).run({
|
|
501
|
-
message: 'Enter npm OTP',
|
|
502
|
-
type: 'Input',
|
|
503
|
-
validate: v => v === '' || (typeof v === 'string' && /^\d{6}$/.test(v)),
|
|
504
|
-
});
|
|
505
|
-
if (options.otp === '') {
|
|
506
|
-
const confirmed = await task.prompt(ListrEnquirerPromptAdapter).run({
|
|
507
|
-
message: 'This will fail unless you have disabled MFA, which is not recommended.',
|
|
508
|
-
type: 'confirm',
|
|
509
|
-
});
|
|
510
|
-
if (!confirmed) {
|
|
511
|
-
throw new Error('OTP not provided');
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
},
|
|
515
|
-
},
|
|
516
|
-
...createPublishTasks(ctx, options),
|
|
517
|
-
], { ctx });
|
|
490
|
+
const tasks = new Listr(createPublishTasks(ctx, options), { ctx });
|
|
518
491
|
await tasks.run();
|
|
519
492
|
}
|
|
520
493
|
function createPublishTasks(ctx, options) {
|
|
@@ -548,9 +521,13 @@ function createPublishTasks(ctx, options) {
|
|
|
548
521
|
title: 'Publish complete',
|
|
549
522
|
rendererOptions: { persistentOutput: true },
|
|
550
523
|
task: async (_ctx, task) => {
|
|
524
|
+
const firstPkg = ctx.packages[0];
|
|
525
|
+
const left = loadLHSPackageJson(firstPkg)?.version || firstPkg?.shas?.left;
|
|
526
|
+
const right = firstPkg?.targetVersion || firstPkg?.shas?.right;
|
|
527
|
+
const comparison = left && right ? ` --comparison ${left}...${right}` : '';
|
|
551
528
|
task.output = `To open a release draft, run the following command:`;
|
|
552
529
|
task.output += `\n\n`;
|
|
553
|
-
task.output += `
|
|
530
|
+
task.output += `npx mopub release-notes${comparison}`;
|
|
554
531
|
},
|
|
555
532
|
},
|
|
556
533
|
];
|