mopub 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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,14 @@ 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.string().describe('npm otp - needed with --publish. If not provided you will be prompted for it').optional(),
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(),
24
+ tag: z
25
+ .string()
26
+ .describe('tag to publish to. Leave unset to use the last tag from the registry.')
27
+ .optional(),
21
28
  bump: z
22
29
  .enum(['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'other', 'independent'])
23
30
  .describe('semver "bump" strategy - if not provided you will be prompted for it. Do not use with --version.')
@@ -62,7 +69,7 @@ export const setupContextTasks = [
62
69
  }
63
70
  if (!projectName)
64
71
  throw new Error(`Couldn't get package name from pnpm list output: ${list.stdout}`);
65
- ctx.tempDir = path.join('/tmp/npmono', projectName, Date.now().toString());
72
+ ctx.tempDir = path.join('/tmp/mopub', projectName, Date.now().toString());
66
73
  task.output = ctx.tempDir;
67
74
  fs.mkdirSync(ctx.tempDir, { recursive: true });
68
75
  },
@@ -437,18 +444,7 @@ export const publish = async (input) => {
437
444
  rendererOptions: { persistentOutput: true },
438
445
  task: async (ctx, task) => {
439
446
  const shouldActuallyPublish = input.publish;
440
- let otp = input.otp;
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 });
447
+ const publishTasks = createPublishTasks(ctx, { otp: input.otp, tag: input.tag });
452
448
  if (!shouldActuallyPublish)
453
449
  publishTasks.forEach(t => (t.skip = true));
454
450
  return task.newListr(publishTasks, { rendererOptions: { collapseSubtasks: false } });
@@ -461,7 +457,7 @@ export const publish = async (input) => {
461
457
  task: async (ctx, task) => {
462
458
  task.output = `To publish, run the following command:`;
463
459
  task.output += `\n\n`;
464
- task.output += `pnpm npmono prebuilt ${ctx.tempDir}`;
460
+ task.output += `npx mopub prebuilt ${ctx.tempDir}`;
465
461
  },
466
462
  },
467
463
  ], { ctx: {} });
@@ -483,7 +479,14 @@ function loadContext(folderPath) {
483
479
  export const PrebuiltInput = z.tuple([
484
480
  z.string().describe('Path to the prebuilt publishable folder'),
485
481
  z.object({
486
- otp: z.string().describe('OTP for publishing. If not provided, you will be prompted for it.').optional(),
482
+ otp: z
483
+ .string()
484
+ .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.')
485
+ .optional(),
486
+ tag: z
487
+ .string()
488
+ .describe('tag to publish to. Leave unset to use the last tag from the registry.')
489
+ .optional(),
487
490
  }),
488
491
  ]);
489
492
  export async function publishPrebuilt([folder, options]) {
@@ -492,29 +495,7 @@ export async function publishPrebuilt([folder, options]) {
492
495
  throw new Error(`Failed to get npm username: ${me.stderr}`);
493
496
  console.log(me.stdout, '<<<<<<< npm whoami');
494
497
  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 });
498
+ const tasks = new Listr(createPublishTasks(ctx, options), { ctx });
518
499
  await tasks.run();
519
500
  }
520
501
  function createPublishTasks(ctx, options) {
@@ -531,7 +512,8 @@ function createPublishTasks(ctx, options) {
531
512
  publishArgs.push('--otp', options.otp);
532
513
  if (rhsPackageJson && semver.prerelease(rhsPackageJson.version)) {
533
514
  const first = semver.prerelease(rhsPackageJson.version)?.[0];
534
- const tag = typeof first === 'string' ? first : 'next';
515
+ let tag = options.tag;
516
+ tag ||= typeof first === 'string' ? first : 'next';
535
517
  publishArgs.push('--tag', tag);
536
518
  }
537
519
  await pipeExeca(subtask, 'pnpm', ['publish', ...publishArgs], {
@@ -548,9 +530,13 @@ function createPublishTasks(ctx, options) {
548
530
  title: 'Publish complete',
549
531
  rendererOptions: { persistentOutput: true },
550
532
  task: async (_ctx, task) => {
533
+ const firstPkg = ctx.packages[0];
534
+ const left = loadLHSPackageJson(firstPkg)?.version || firstPkg?.shas?.left;
535
+ const right = firstPkg?.targetVersion || firstPkg?.shas?.right;
536
+ const comparison = left && right ? ` --comparison ${left}...${right}` : '';
551
537
  task.output = `To open a release draft, run the following command:`;
552
538
  task.output += `\n\n`;
553
- task.output += `pnpm npmono release-notes`;
539
+ task.output += `npx mopub release-notes${comparison}`;
554
540
  },
555
541
  },
556
542
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mopub",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Publish packages in a pnpm monorepo",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "typescript": "^6.0.3"
33
33
  },
34
34
  "scripts": {
35
- "dogfood": "tsx src/cli",
35
+ "clean": "rm -rf dist",
36
36
  "build": "tsc --noEmit false --outDir dist",
37
37
  "lint": "eslint .",
38
38
  "test": "echo maybe later"