mopub 0.0.4 → 0.1.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.
Files changed (2) hide show
  1. package/dist/publish.js +81 -14
  2. package/package.json +6 -3
package/dist/publish.js CHANGED
@@ -634,10 +634,18 @@ export const ReleaseNotesInput = z.object({
634
634
  });
635
635
  async function pullRegistryPackage(subtask, pkg, { version, folder }) {
636
636
  // note: `npm pack foobar` will actually pull foobar.1-2-3.tgz from the registry. It's not actually doing a "pack" at all. `pnpm pack` does not do the same thing - it packs the local directory
637
- await pipeExeca(subtask, 'npm', ['pack', `${pkg.name}@${version}`], { cwd: folder });
638
- const tgzFileName = fs.readdirSync(folder).at(0);
639
- if (!tgzFileName) {
640
- throw new Error(`No tgz file found in ${folder}, tried to pull ${pkg.name}@${version}`);
637
+ const packResult = await pipeExeca(subtask, 'npm', ['pack', `${pkg.name}@${version}`], { cwd: folder });
638
+ const packStdout = typeof packResult.stdout === 'string' ? packResult.stdout : '';
639
+ const tgzFileName = packStdout
640
+ .split('\n')
641
+ .map(line => line.trim())
642
+ .find(line => line.endsWith('.tgz'));
643
+ const folderEntries = fs.readdirSync(folder);
644
+ if (!tgzFileName || !folderEntries.includes(tgzFileName)) {
645
+ throw new Error([
646
+ `Expected npm pack ${pkg.name}@${version} to write ${tgzFileName || 'a .tgz file'} in ${folder}.`,
647
+ `Found: ${folderEntries.length ? folderEntries.join(', ') : '(nothing)'}`,
648
+ ].join('\n'));
641
649
  }
642
650
  await pipeExeca(subtask, 'tar', ['-xvzf', tgzFileName], { cwd: folder });
643
651
  const filepath = path.join(folder, 'package', 'package.json');
@@ -710,7 +718,7 @@ function getBumpedVersionValidation(lowerBoundVersion, v) {
710
718
  function getWorkspaceRoot() {
711
719
  return path.dirname(findUpSync('pnpm-workspace.yaml') || findUpSync('pnpm-lock.yaml') || findUpOrThrow('.git', { type: 'directory' }));
712
720
  }
713
- /** "Pessimistic" comparison ref. Tries to use the registry package.json's `git.sha` property, falls back to a matching version tag, and if neither exists prompts the user (with the first commit to the package folder as the default). */
721
+ /** "Pessimistic" comparison ref. Tries to use the registry package.json's `git.sha` property, falls back to a matching version tag, and if neither exists prompts the user to choose between the last publish with a findable sha, the last commit before the previous publish, the first commit to the package folder, or a manually-entered sha. */
714
722
  async function getPackageLastPublishRef(pkg, task) {
715
723
  const packageJson = loadLHSPackageJson(pkg);
716
724
  return first7(await getPackageJsonGitSha(pkg, packageJson, task));
@@ -736,18 +744,74 @@ async function getPackageJsonGitSha(pkg, packageJson, task) {
736
744
  const repoUrl = getPackageJsonRepository(loadRHSPackageJson(pkg) || loadLHSPackageJson(pkg) || loadPackageJson(path.join(getWorkspaceRoot(), 'package.json')));
737
745
  const olderUrl = repoUrl && oldestShownSha ? `\nOlder commits: ${repoUrl}/commits/${oldestShownSha}` : '';
738
746
  const recentList = commitLines.length ? `\nRecent commits in ${pkg.path}:\n${commitLines.join('\n')}${olderUrl}\n` : '';
747
+ const choices = [];
748
+ const lastPublishWithSha = await findLastPublishWithFindableSha(pkg, commitLines);
749
+ if (lastPublishWithSha) {
750
+ choices.push({
751
+ message: `${first7(lastPublishWithSha.sha)} - last publish with a findable sha (${lastPublishWithSha.version})`,
752
+ value: lastPublishWithSha.sha,
753
+ });
754
+ }
755
+ const commitBeforePreviousPublish = await getLastCommitBeforePreviousPublish(pkg, packageJson);
756
+ if (commitBeforePreviousPublish) {
757
+ choices.push({
758
+ message: `${first7(commitBeforePreviousPublish.sha)} - last commit before previous publish (${commitBeforePreviousPublish.version} @ ${commitBeforePreviousPublish.time})`,
759
+ value: commitBeforePreviousPublish.sha,
760
+ });
761
+ }
762
+ choices.push({ message: `${first7(firstRef)} - first commit in ${pkg.path}`, value: firstRef }, { message: 'Other (enter a sha manually)', value: 'other' });
763
+ const selected = await task.prompt(ListrEnquirerPromptAdapter).run({
764
+ type: 'Select',
765
+ message: `Couldn't find a git sha for the last published version of ${pkg.name}.${recentList}\nSelect the sha to diff from:`,
766
+ choices,
767
+ });
768
+ if (selected !== 'other')
769
+ return selected;
739
770
  const promptAnswer = await task.prompt(ListrEnquirerPromptAdapter).run({
740
771
  type: 'Input',
741
- message: `Couldn't find a git sha for the last published version of ${pkg.name}.${recentList}\nEnter the sha to diff from (leave empty to use ${firstRef.slice(0, 7)}, the first commit in ${pkg.path}):`,
772
+ message: `Enter the sha to diff from:`,
742
773
  validate: (v) => {
743
- if (typeof v !== 'string')
744
- return 'Enter a sha, or leave empty to use the first commit.';
745
- if (!v.trim())
746
- return true;
747
- return /^[0-9a-f]{4,40}$/i.test(v.trim()) ? true : 'Enter a valid git sha (4-40 hex chars) or leave empty.';
774
+ if (typeof v !== 'string' || !/^[0-9a-f]{4,40}$/i.test(v.trim()))
775
+ return 'Enter a valid git sha (4-40 hex chars).';
776
+ return true;
748
777
  },
749
778
  });
750
- return promptAnswer.trim() || firstRef;
779
+ return promptAnswer.trim();
780
+ }
781
+ /**
782
+ * Walks the registry's published versions newest-first looking for one whose git sha can be determined - via the
783
+ * registry package.json's `git.sha`, a version tag, or a `version x.y.z` commit message - even if its
784
+ * prerelease-ness doesn't match the version being compared against. Capped at the 20 newest versions to bound
785
+ * `npm view` calls.
786
+ */
787
+ async function findLastPublishWithFindableSha(pkg, recentCommitLines) {
788
+ const newestFirst = pkg.publishedVersions.slice().reverse().slice(0, 20);
789
+ for (const version of newestFirst) {
790
+ const { stdout: registrySha } = await execa('npm', ['view', `${pkg.name}@${version}`, 'git.sha'], { reject: false });
791
+ if (registrySha.trim())
792
+ return { version, sha: registrySha.trim() };
793
+ const tagSha = await getShaFromVersionTag(pkg, version);
794
+ if (tagSha)
795
+ return { version, sha: tagSha };
796
+ const versionCommitMessage = `version ${version}`;
797
+ const match = recentCommitLines.find(line => line.slice(line.indexOf(' ') + 1) === versionCommitMessage);
798
+ if (match)
799
+ return { version, sha: match.split(' ', 1)[0] };
800
+ }
801
+ return null;
802
+ }
803
+ /** The last commit in the package folder made before the previous version was published, based on the registry's publish timestamp. */
804
+ async function getLastCommitBeforePreviousPublish(pkg, packageJson) {
805
+ const previousVersion = packageJson?.version || pkg.publishedVersions.at(-1);
806
+ if (!previousVersion)
807
+ return null;
808
+ const timesResult = await execa('npm', ['view', pkg.name, 'time', '--json'], { reject: false });
809
+ const times = z.record(z.string(), z.string()).safeParse(JSON.parse(timesResult.stdout || '{}'));
810
+ const publishTime = times.success ? times.data[previousVersion] : undefined;
811
+ if (!publishTime)
812
+ return null;
813
+ const { stdout: sha } = await execa('git', ['log', '-n', '1', `--before=${publishTime}`, '--pretty=format:%h', '--', '.'], { cwd: pkg.path, reject: false });
814
+ return sha ? { version: previousVersion, time: publishTime, sha } : null;
751
815
  }
752
816
  async function getPackageJsonShaFromVersionTag(pkg, packageJson) {
753
817
  // throw new Error(
@@ -755,13 +819,16 @@ async function getPackageJsonShaFromVersionTag(pkg, packageJson) {
755
819
  // )
756
820
  if (!packageJson?.version)
757
821
  return null;
758
- const { stdout: vTagSha } = await execa('git', ['rev-list', '-n', '1', `v${packageJson.version}`], {
822
+ return getShaFromVersionTag(pkg, packageJson.version);
823
+ }
824
+ async function getShaFromVersionTag(pkg, version) {
825
+ const { stdout: vTagSha } = await execa('git', ['rev-list', '-n', '1', `v${version}`], {
759
826
  cwd: pkg.path,
760
827
  reject: false,
761
828
  });
762
829
  if (vTagSha)
763
830
  return vTagSha;
764
- const { stdout: tagSha } = await execa('git', ['rev-list', '-n', '1', packageJson.version], {
831
+ const { stdout: tagSha } = await execa('git', ['rev-list', '-n', '1', version], {
765
832
  cwd: pkg.path,
766
833
  reject: false,
767
834
  });
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "mopub",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Publish packages in a pnpm monorepo",
5
+ "license": "ISC",
5
6
  "type": "module",
6
7
  "bin": {
7
8
  "mopub": "dist/cli.js"
@@ -9,7 +10,6 @@
9
10
  "files": [
10
11
  "dist"
11
12
  ],
12
- "license": "ISC",
13
13
  "dependencies": {
14
14
  "@listr2/prompt-adapter-enquirer": "^4.2.1",
15
15
  "@trpc/server": "^11.16.0",
@@ -31,9 +31,12 @@
31
31
  "tsx": "^4.21.0",
32
32
  "typescript": "^6.0.3"
33
33
  },
34
+ "git": {
35
+ "sha": "43d2162"
36
+ },
34
37
  "scripts": {
35
- "clean": "rm -rf dist",
36
38
  "build": "tsc --noEmit false --outDir dist",
39
+ "clean": "rm -rf dist",
37
40
  "lint": "eslint .",
38
41
  "test": "echo maybe later"
39
42
  }