pubm 0.2.7 → 0.2.9

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 (4) hide show
  1. package/bin/cli.js +302 -114
  2. package/dist/index.cjs +435 -247
  3. package/dist/index.js +418 -230
  4. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -4655,6 +4655,7 @@ var Listr = (_a23 = class {
4655
4655
  }, __name(_a23, "Listr"), _a23);
4656
4656
 
4657
4657
  // src/error.ts
4658
+ import { NonZeroExitError } from "tinyexec";
4658
4659
  var AbstractError = class extends Error {
4659
4660
  constructor(message, { cause } = {}) {
4660
4661
  super(message, { cause });
@@ -4665,20 +4666,49 @@ var AbstractError = class extends Error {
4665
4666
  function replaceCode(code) {
4666
4667
  return code.replace(/`([^`].+)`/g, color.bold(color.underline("$1")));
4667
4668
  }
4669
+ function formatStderr(stderr) {
4670
+ return stderr.split("\n").map((line) => ` ${color.dim("\u2502")} ${line}`).join("\n");
4671
+ }
4672
+ function isNoisyCause(cause) {
4673
+ if (cause instanceof NonZeroExitError) return true;
4674
+ if (cause instanceof Error && /Process exited with non-zero status/i.test(cause.message))
4675
+ return true;
4676
+ return false;
4677
+ }
4668
4678
  function formatError(error) {
4669
4679
  if (!(error instanceof Error)) return `${error}`;
4670
- const message = typeof error.message === "string" ? replaceCode(error.message) : (
4680
+ const rawMessage = typeof error.message === "string" ? error.message : (
4671
4681
  /* v8 ignore next */
4672
- formatError(error)
4682
+ String(error)
4673
4683
  );
4674
- let stringifyError = `${color.bgRed(` ${error.name} `)}${color.reset("")} ${message}
4684
+ const newlineIndex = rawMessage.indexOf("\n");
4685
+ let summary;
4686
+ let detail;
4687
+ if (newlineIndex !== -1) {
4688
+ summary = rawMessage.slice(0, newlineIndex);
4689
+ detail = rawMessage.slice(newlineIndex + 1);
4690
+ } else {
4691
+ summary = rawMessage;
4692
+ }
4693
+ let result = `${color.bgRed(` ${error.name} `)}${color.reset("")} ${replaceCode(summary)}
4675
4694
  `;
4676
- stringifyError += error.stack?.split("\n").slice(1).join("\n").replace(/at/g, color.dim("at")).replace(/\(([^(].+)\)/g, `(${color.blue("$1")})`);
4677
- if (error.cause) {
4678
- stringifyError += "\n\nCaused: ";
4679
- stringifyError += formatError(error.cause);
4695
+ if (detail) {
4696
+ result += `
4697
+ ${formatStderr(detail)}
4698
+ `;
4699
+ }
4700
+ if (process.env.DEBUG === "pubm" && error.stack) {
4701
+ result += error.stack.split("\n").slice(1).join("\n").replace(/at/g, color.dim("at")).replace(/\(([^(].+)\)/g, `(${color.blue("$1")})`);
4680
4702
  }
4681
- return stringifyError;
4703
+ if (error.cause && !isNoisyCause(error.cause)) {
4704
+ const causeMsg = error.cause instanceof Error ? error.cause.message : String(error.cause);
4705
+ if (causeMsg !== summary) {
4706
+ result += `
4707
+ ${color.dim("Caused by:")} `;
4708
+ result += formatError(error.cause);
4709
+ }
4710
+ }
4711
+ return result;
4682
4712
  }
4683
4713
  function consoleError(error) {
4684
4714
  let errorText = "\n";
@@ -5468,12 +5498,6 @@ import SemVer from "semver";
5468
5498
  import { isCI as isCI2 } from "std-env";
5469
5499
  import { exec as exec9 } from "tinyexec";
5470
5500
 
5471
- // src/utils/cli.ts
5472
- var warningBadge = color.bgYellow(" Warning ");
5473
- function link2(text, url) {
5474
- return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
5475
- }
5476
-
5477
5501
  // src/ecosystem/rust.ts
5478
5502
  import { readFile, stat as stat2, writeFile } from "node:fs/promises";
5479
5503
  import path8 from "node:path";
@@ -5593,6 +5617,12 @@ var RustEcosystem = class extends Ecosystem {
5593
5617
  }
5594
5618
  };
5595
5619
 
5620
+ // src/utils/cli.ts
5621
+ var warningBadge = color.bgYellow(" Warning ");
5622
+ function link2(text, url) {
5623
+ return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
5624
+ }
5625
+
5596
5626
  // src/utils/crate-graph.ts
5597
5627
  async function sortCratesByDependencyOrder(cratePaths) {
5598
5628
  if (cratePaths.length <= 1) return cratePaths;
@@ -5645,12 +5675,19 @@ var rollbacks = [];
5645
5675
  function addRollback(rollback2, context) {
5646
5676
  rollbacks.push({ fn: rollback2, ctx: context });
5647
5677
  }
5678
+ function rollbackLog(message) {
5679
+ console.log(` ${color.yellow("\u21A9")} ${message}`);
5680
+ }
5681
+ function rollbackError(message) {
5682
+ console.error(` ${color.red("\u2717")} ${message}`);
5683
+ }
5648
5684
  var called = false;
5649
5685
  async function rollback() {
5650
5686
  if (called) return void 0;
5651
5687
  called = true;
5652
5688
  if (rollbacks.length <= 0) return void 0;
5653
- console.log("Rollback...");
5689
+ console.log(`
5690
+ ${color.yellow("\u27F2")} ${color.yellow("Rolling back...")}`);
5654
5691
  const results = await Promise.allSettled(
5655
5692
  rollbacks.map(({ fn, ctx }) => fn(ctx))
5656
5693
  );
@@ -5659,15 +5696,15 @@ async function rollback() {
5659
5696
  );
5660
5697
  if (failures.length > 0) {
5661
5698
  for (const failure of failures) {
5662
- console.error(
5663
- `Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
5699
+ rollbackError(
5700
+ failure.reason instanceof Error ? failure.reason.message : failure.reason
5664
5701
  );
5665
5702
  }
5666
5703
  console.log(
5667
- "Rollback completed with errors. Some operations may require manual recovery."
5704
+ `${color.red("\u2717")} ${color.red("Rollback completed with errors.")} Some operations may require manual recovery.`
5668
5705
  );
5669
5706
  } else {
5670
- console.log("Rollback completed");
5707
+ console.log(`${color.green("\u2713")} Rollback completed`);
5671
5708
  }
5672
5709
  }
5673
5710
 
@@ -5952,7 +5989,7 @@ function collectRegistries(ctx) {
5952
5989
 
5953
5990
  // src/registry/crates.ts
5954
5991
  import path10 from "node:path";
5955
- import { exec as exec5, NonZeroExitError } from "tinyexec";
5992
+ import { exec as exec5, NonZeroExitError as NonZeroExitError2 } from "tinyexec";
5956
5993
 
5957
5994
  // src/registry/registry.ts
5958
5995
  var Registry = class {
@@ -5972,6 +6009,14 @@ var CratesError = class extends AbstractError {
5972
6009
  }
5973
6010
  };
5974
6011
  var USER_AGENT = "pubm (https://github.com/syi0808/pubm)";
6012
+ function cleanCargoStderr(stderr) {
6013
+ return stderr.split("\n").filter((line) => {
6014
+ const trimmed = line.trim();
6015
+ if (trimmed === "Updating crates.io index") return false;
6016
+ if (trimmed === "") return false;
6017
+ return true;
6018
+ }).join("\n");
6019
+ }
5975
6020
  var CratesRegistry = class extends Registry {
5976
6021
  constructor() {
5977
6022
  super(...arguments);
@@ -6036,26 +6081,40 @@ var CratesRegistry = class extends Registry {
6036
6081
  await exec5("cargo", args, { throwOnError: true });
6037
6082
  return true;
6038
6083
  } catch (error) {
6039
- const stderr = error instanceof NonZeroExitError ? error.output?.stderr : void 0;
6084
+ const stderr = error instanceof NonZeroExitError2 ? error.output?.stderr : void 0;
6040
6085
  const message = stderr ? `Failed to run \`cargo publish\`:
6041
- ${stderr}` : "Failed to run `cargo publish`";
6086
+ ${cleanCargoStderr(stderr)}` : "Failed to run `cargo publish`";
6042
6087
  throw new CratesError(message, { cause: error });
6043
6088
  }
6044
6089
  }
6045
6090
  async dryRunPublish(manifestDir) {
6046
6091
  try {
6047
- const args = ["publish", "--dry-run", "--no-verify"];
6092
+ const args = ["publish", "--dry-run"];
6048
6093
  if (manifestDir) {
6049
6094
  args.push("--manifest-path", path10.join(manifestDir, "Cargo.toml"));
6050
6095
  }
6051
6096
  await exec5("cargo", args, { throwOnError: true });
6052
6097
  } catch (error) {
6053
- const stderr = error instanceof NonZeroExitError ? error.output?.stderr : void 0;
6098
+ const stderr = error instanceof NonZeroExitError2 ? error.output?.stderr : void 0;
6054
6099
  const message = stderr ? `Failed to run \`cargo publish --dry-run\`:
6055
- ${stderr}` : "Failed to run `cargo publish --dry-run`";
6100
+ ${cleanCargoStderr(stderr)}` : "Failed to run `cargo publish --dry-run`";
6056
6101
  throw new CratesError(message, { cause: error });
6057
6102
  }
6058
6103
  }
6104
+ async isVersionPublished(version2) {
6105
+ try {
6106
+ const response = await fetch(
6107
+ `${this.registry}/api/v1/crates/${this.packageName}/${version2}`,
6108
+ { headers: this.headers }
6109
+ );
6110
+ return response.ok;
6111
+ } catch (error) {
6112
+ throw new CratesError(
6113
+ `Failed to check version ${version2} for '${this.packageName}' on crates.io`,
6114
+ { cause: error }
6115
+ );
6116
+ }
6117
+ }
6059
6118
  async isPublished() {
6060
6119
  try {
6061
6120
  const response = await fetch(
@@ -6132,10 +6191,24 @@ function createCratesPublishTask(packagePath) {
6132
6191
  const label = packagePath ? ` (${packagePath})` : "";
6133
6192
  return {
6134
6193
  title: `Publishing to crates.io${label}`,
6135
- task: async () => {
6194
+ task: async (ctx, task) => {
6136
6195
  const packageName = await getCrateName(packagePath);
6137
6196
  const registry = new CratesRegistry(packageName);
6138
- await registry.publish(packagePath);
6197
+ if (await registry.isVersionPublished(ctx.version)) {
6198
+ task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
6199
+ task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
6200
+ return task.skip();
6201
+ }
6202
+ try {
6203
+ await registry.publish(packagePath);
6204
+ } catch (error) {
6205
+ if (error instanceof Error && error.message.includes("is already uploaded")) {
6206
+ task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
6207
+ task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
6208
+ return task.skip();
6209
+ }
6210
+ throw error;
6211
+ }
6139
6212
  }
6140
6213
  };
6141
6214
  }
@@ -6146,7 +6219,7 @@ var cratesPublishTasks = createCratesPublishTask();
6146
6219
  import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter2 } from "@listr2/prompt-adapter-enquirer";
6147
6220
 
6148
6221
  // src/registry/jsr.ts
6149
- import { exec as exec6, NonZeroExitError as NonZeroExitError2 } from "tinyexec";
6222
+ import { exec as exec6, NonZeroExitError as NonZeroExitError3 } from "tinyexec";
6150
6223
 
6151
6224
  // src/utils/package-name.ts
6152
6225
  import { builtinModules } from "node:module";
@@ -6254,7 +6327,7 @@ var JsrRegisry = class extends Registry {
6254
6327
  this.packageCreationUrls = void 0;
6255
6328
  return true;
6256
6329
  } catch (error) {
6257
- const stderr = error instanceof NonZeroExitError2 ? error.output?.stderr : void 0;
6330
+ const stderr = error instanceof NonZeroExitError3 ? error.output?.stderr : void 0;
6258
6331
  if (stderr?.includes("don't exist")) {
6259
6332
  const urls = [...stderr.matchAll(/https:\/\/jsr\.io\/new\S+/g)].map(
6260
6333
  (m) => m[0]
@@ -6306,6 +6379,20 @@ ${stderr}` : ""}`,
6306
6379
  );
6307
6380
  }
6308
6381
  }
6382
+ async isVersionPublished(version2) {
6383
+ try {
6384
+ const [scope, name] = getScopeAndName(this.packageName);
6385
+ const response = await fetch(
6386
+ `${this.registry}/@${scope}/${name}/${version2}`
6387
+ );
6388
+ return response.status === 200;
6389
+ } catch (error) {
6390
+ throw new JsrError(
6391
+ `Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
6392
+ { cause: error }
6393
+ );
6394
+ }
6395
+ }
6309
6396
  async hasPermission() {
6310
6397
  return this.client.scopePermission(`${getScope(this.packageName)}`) !== null;
6311
6398
  }
@@ -6535,7 +6622,7 @@ async function jsrRegistry() {
6535
6622
  // src/registry/npm.ts
6536
6623
  import { tmpdir } from "node:os";
6537
6624
  import { join } from "node:path";
6538
- import { exec as exec7, NonZeroExitError as NonZeroExitError3 } from "tinyexec";
6625
+ import { exec as exec7, NonZeroExitError as NonZeroExitError4 } from "tinyexec";
6539
6626
  var NpmError = class extends AbstractError {
6540
6627
  constructor() {
6541
6628
  super(...arguments);
@@ -6580,6 +6667,19 @@ var NpmRegistry = class extends Registry {
6580
6667
  );
6581
6668
  }
6582
6669
  }
6670
+ async isVersionPublished(version2) {
6671
+ try {
6672
+ const response = await fetch(
6673
+ `${this.registry}/${this.packageName}/${version2}`
6674
+ );
6675
+ return response.status === 200;
6676
+ } catch (error) {
6677
+ throw new NpmError(
6678
+ `Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
6679
+ { cause: error }
6680
+ );
6681
+ }
6682
+ }
6583
6683
  async userName() {
6584
6684
  try {
6585
6685
  return (await this.npm(["whoami"])).trim();
@@ -6592,7 +6692,7 @@ var NpmRegistry = class extends Registry {
6592
6692
  await this.npm(["whoami"]);
6593
6693
  return true;
6594
6694
  } catch (error) {
6595
- if (error instanceof NonZeroExitError3) {
6695
+ if (error instanceof NonZeroExitError4) {
6596
6696
  return false;
6597
6697
  }
6598
6698
  throw new NpmError("Failed to run `npm whoami`", { cause: error });
@@ -6670,7 +6770,7 @@ var NpmRegistry = class extends Registry {
6670
6770
  await this.npm(["publish", "--provenance", "--access", "public"]);
6671
6771
  return true;
6672
6772
  } catch (error) {
6673
- if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
6773
+ if (error instanceof NonZeroExitError4 && error.output?.stderr.includes("EOTP")) {
6674
6774
  return false;
6675
6775
  }
6676
6776
  throw this.classifyPublishError(error);
@@ -6682,7 +6782,7 @@ var NpmRegistry = class extends Registry {
6682
6782
  await this.npm(args);
6683
6783
  return true;
6684
6784
  } catch (error) {
6685
- if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
6785
+ if (error instanceof NonZeroExitError4 && error.output?.stderr.includes("EOTP")) {
6686
6786
  return false;
6687
6787
  }
6688
6788
  throw this.classifyPublishError(error);
@@ -6700,7 +6800,7 @@ var NpmRegistry = class extends Registry {
6700
6800
  }
6701
6801
  });
6702
6802
  } catch (error) {
6703
- const stderr = error instanceof NonZeroExitError3 ? error.output?.stderr : void 0;
6803
+ const stderr = error instanceof NonZeroExitError4 ? error.output?.stderr : void 0;
6704
6804
  throw new NpmError(
6705
6805
  `Failed to run \`npm publish --dry-run\`${stderr ? `
6706
6806
  ${stderr}` : ""}`,
@@ -6727,7 +6827,7 @@ ${stderr}` : ""}`,
6727
6827
  };
6728
6828
  }
6729
6829
  classifyPublishError(error) {
6730
- if (error instanceof NonZeroExitError3) {
6830
+ if (error instanceof NonZeroExitError4) {
6731
6831
  const stderr = error.output?.stderr ?? "";
6732
6832
  if (stderr.includes("EOTP")) {
6733
6833
  return new NpmError("OTP required for publishing", { cause: error });
@@ -6785,20 +6885,30 @@ async function withTokenRetry(registryKey, task, action) {
6785
6885
  }
6786
6886
  var npmDryRunPublishTask = {
6787
6887
  title: "Dry-run npm publish",
6788
- task: async (_, task) => {
6888
+ task: async (ctx, task) => {
6889
+ const npm = await npmRegistry();
6890
+ if (await npm.isVersionPublished(ctx.version)) {
6891
+ task.title = `[SKIPPED] Dry-run npm publish: v${ctx.version} already published`;
6892
+ task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
6893
+ return task.skip();
6894
+ }
6789
6895
  task.output = "Running npm publish --dry-run...";
6790
6896
  await withTokenRetry("npm", task, async () => {
6791
- const npm = await npmRegistry();
6792
6897
  await npm.dryRunPublish();
6793
6898
  });
6794
6899
  }
6795
6900
  };
6796
6901
  var jsrDryRunPublishTask = {
6797
6902
  title: "Dry-run jsr publish",
6798
- task: async (_, task) => {
6903
+ task: async (ctx, task) => {
6904
+ const jsr = await jsrRegistry();
6905
+ if (await jsr.isVersionPublished(ctx.version)) {
6906
+ task.title = `[SKIPPED] Dry-run jsr publish: v${ctx.version} already published`;
6907
+ task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
6908
+ return task.skip();
6909
+ }
6799
6910
  task.output = "Running jsr publish --dry-run...";
6800
6911
  await withTokenRetry("jsr", task, async () => {
6801
- const jsr = await jsrRegistry();
6802
6912
  await jsr.dryRunPublish();
6803
6913
  });
6804
6914
  }
@@ -6807,17 +6917,58 @@ async function getCrateName2(packagePath) {
6807
6917
  const eco = new RustEcosystem(packagePath ?? process.cwd());
6808
6918
  return await eco.packageName();
6809
6919
  }
6810
- function createCratesDryRunPublishTask(packagePath) {
6920
+ var MISSING_CRATE_PATTERN = /no matching package named `([^`]+)` found/;
6921
+ async function findUnpublishedSiblingDeps(packagePath, siblingCrateNames) {
6922
+ const eco = new RustEcosystem(packagePath ?? process.cwd());
6923
+ const deps = await eco.dependencies();
6924
+ const siblingDeps = deps.filter((d2) => siblingCrateNames.includes(d2));
6925
+ const results = await Promise.all(
6926
+ siblingDeps.map(async (name) => {
6927
+ const registry = new CratesRegistry(name);
6928
+ const published = await registry.isPublished();
6929
+ return published ? null : name;
6930
+ })
6931
+ );
6932
+ return results.filter((name) => name !== null);
6933
+ }
6934
+ function createCratesDryRunPublishTask(packagePath, siblingCrateNames) {
6811
6935
  const label = packagePath ? ` (${packagePath})` : "";
6812
6936
  return {
6813
6937
  title: `Dry-run crates.io publish${label}`,
6814
- task: async (_, task) => {
6938
+ task: async (ctx, task) => {
6939
+ const packageName = await getCrateName2(packagePath);
6940
+ const registry = new CratesRegistry(packageName);
6941
+ if (await registry.isVersionPublished(ctx.version)) {
6942
+ task.title = `[SKIPPED] Dry-run crates.io publish${label}: v${ctx.version} already published`;
6943
+ task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
6944
+ return task.skip();
6945
+ }
6946
+ if (siblingCrateNames?.length) {
6947
+ const unpublished = await findUnpublishedSiblingDeps(
6948
+ packagePath,
6949
+ siblingCrateNames
6950
+ );
6951
+ if (unpublished.length > 0) {
6952
+ task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${unpublished.join("`, `")}\` not yet published]`;
6953
+ return;
6954
+ }
6955
+ }
6815
6956
  task.output = "Running cargo publish --dry-run...";
6816
- await withTokenRetry("crates", task, async () => {
6817
- const packageName = await getCrateName2(packagePath);
6818
- const registry = new CratesRegistry(packageName);
6819
- await registry.dryRunPublish(packagePath);
6820
- });
6957
+ try {
6958
+ await withTokenRetry("crates", task, async () => {
6959
+ const packageName2 = await getCrateName2(packagePath);
6960
+ const registry2 = new CratesRegistry(packageName2);
6961
+ await registry2.dryRunPublish(packagePath);
6962
+ });
6963
+ } catch (error) {
6964
+ const message = error instanceof Error ? error.message : String(error);
6965
+ const match = message.match(MISSING_CRATE_PATTERN);
6966
+ if (match && siblingCrateNames?.includes(match[1])) {
6967
+ task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${match[1]}\` not yet published]`;
6968
+ return;
6969
+ }
6970
+ throw error;
6971
+ }
6821
6972
  }
6822
6973
  };
6823
6974
  }
@@ -6998,48 +7149,62 @@ var jsrPublishTasks = {
6998
7149
  title: "Running jsr publish",
6999
7150
  task: async (ctx, task) => {
7000
7151
  const jsr = await jsrRegistry();
7152
+ if (await jsr.isVersionPublished(ctx.version)) {
7153
+ task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
7154
+ task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
7155
+ return task.skip();
7156
+ }
7001
7157
  task.output = "Publishing on jsr...";
7002
- if (!JsrClient.token && !ctx.promptEnabled) {
7003
- const jsrTokenEnv = process12.env.JSR_TOKEN;
7004
- if (!jsrTokenEnv) {
7005
- throw new JsrAvailableError(
7006
- "JSR_TOKEN not found in the environment variables. Please set the token and try again."
7007
- );
7158
+ try {
7159
+ if (!JsrClient.token && !ctx.promptEnabled) {
7160
+ const jsrTokenEnv = process12.env.JSR_TOKEN;
7161
+ if (!jsrTokenEnv) {
7162
+ throw new JsrAvailableError(
7163
+ "JSR_TOKEN not found in the environment variables. Please set the token and try again."
7164
+ );
7165
+ }
7166
+ JsrClient.token = jsrTokenEnv;
7008
7167
  }
7009
- JsrClient.token = jsrTokenEnv;
7010
- }
7011
- let result = await jsr.publish();
7012
- if (!result && jsr.packageCreationUrls) {
7013
- if (ctx.promptEnabled) {
7014
- task.title = "Running jsr publish (package creation needed)";
7015
- const urls = jsr.packageCreationUrls;
7016
- const maxAttempts = 3;
7017
- task.output = `Package doesn't exist on jsr. Create it at:
7168
+ let result = await jsr.publish();
7169
+ if (!result && jsr.packageCreationUrls) {
7170
+ if (ctx.promptEnabled) {
7171
+ task.title = "Running jsr publish (package creation needed)";
7172
+ const urls = jsr.packageCreationUrls;
7173
+ const maxAttempts = 3;
7174
+ task.output = `Package doesn't exist on jsr. Create it at:
7018
7175
  ${urls.map((url) => ` ${color.cyan(url)}`).join("\n")}`;
7019
- open(urls[0]);
7020
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7021
- await task.prompt(ListrEnquirerPromptAdapter3).run({
7022
- type: "input",
7023
- message: `Press ${color.bold("enter")} after creating the package on jsr.io${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
7024
- });
7025
- result = await jsr.publish();
7026
- if (result) break;
7027
- if (attempt < maxAttempts) {
7028
- task.output = "Package still doesn't exist. Please create it and try again.";
7176
+ open(urls[0]);
7177
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7178
+ await task.prompt(ListrEnquirerPromptAdapter3).run({
7179
+ type: "input",
7180
+ message: `Press ${color.bold("enter")} after creating the package on jsr.io${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
7181
+ });
7182
+ result = await jsr.publish();
7183
+ if (result) break;
7184
+ if (attempt < maxAttempts) {
7185
+ task.output = "Package still doesn't exist. Please create it and try again.";
7186
+ }
7029
7187
  }
7030
- }
7031
- if (!result) {
7188
+ if (!result) {
7189
+ throw new JsrAvailableError(
7190
+ "Package creation not completed after 3 attempts."
7191
+ );
7192
+ }
7193
+ task.title = "Running jsr publish (package created)";
7194
+ } else {
7032
7195
  throw new JsrAvailableError(
7033
- "Package creation not completed after 3 attempts."
7196
+ `Package doesn't exist on jsr. Create it at:
7197
+ ${jsr.packageCreationUrls.join("\n")}`
7034
7198
  );
7035
7199
  }
7036
- task.title = "Running jsr publish (package created)";
7037
- } else {
7038
- throw new JsrAvailableError(
7039
- `Package doesn't exist on jsr. Create it at:
7040
- ${jsr.packageCreationUrls.join("\n")}`
7041
- );
7042
7200
  }
7201
+ } catch (error) {
7202
+ if (error instanceof Error && error.message.includes("already published")) {
7203
+ task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
7204
+ task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
7205
+ return task.skip();
7206
+ }
7207
+ throw error;
7043
7208
  }
7044
7209
  }
7045
7210
  };
@@ -7136,44 +7301,62 @@ var npmPublishTasks = {
7136
7301
  skip: (ctx) => !!ctx.preview,
7137
7302
  task: async (ctx, task) => {
7138
7303
  const npm = await npmRegistry();
7304
+ if (await npm.isVersionPublished(ctx.version)) {
7305
+ task.title = `[SKIPPED] npm: v${ctx.version} already published`;
7306
+ task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
7307
+ return task.skip();
7308
+ }
7139
7309
  task.output = "Publishing on npm...";
7140
- if (ctx.promptEnabled) {
7141
- let result = await npm.publish();
7142
- if (!result) {
7143
- task.title = "Running npm publish (OTP code needed)";
7144
- const maxAttempts = 3;
7145
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7146
- result = await npm.publish(
7147
- await task.prompt(ListrEnquirerPromptAdapter4).run({
7148
- type: "password",
7149
- message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
7150
- })
7151
- );
7152
- if (result) break;
7153
- if (attempt < maxAttempts) {
7154
- task.output = "2FA failed. Please try again.";
7310
+ try {
7311
+ if (ctx.promptEnabled) {
7312
+ let result = await npm.publish();
7313
+ if (!result) {
7314
+ task.title = "Running npm publish (OTP code needed)";
7315
+ const maxAttempts = 3;
7316
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7317
+ result = await npm.publish(
7318
+ await task.prompt(ListrEnquirerPromptAdapter4).run({
7319
+ type: "password",
7320
+ message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
7321
+ })
7322
+ );
7323
+ if (result) break;
7324
+ if (attempt < maxAttempts) {
7325
+ task.output = "2FA failed. Please try again.";
7326
+ }
7327
+ }
7328
+ if (!result) {
7329
+ throw new NpmAvailableError(
7330
+ "OTP verification failed after 3 attempts."
7331
+ );
7155
7332
  }
7333
+ task.title = "Running npm publish (2FA passed)";
7334
+ }
7335
+ } else {
7336
+ const npmTokenEnv = process13.env.NODE_AUTH_TOKEN;
7337
+ if (!npmTokenEnv) {
7338
+ throw new NpmAvailableError(
7339
+ "NODE_AUTH_TOKEN not found in environment variables. Set it in your CI configuration:\n GitHub Actions: Add NODE_AUTH_TOKEN as a repository secret\n Other CI: Export NODE_AUTH_TOKEN with your npm access token"
7340
+ );
7156
7341
  }
7342
+ const result = await npm.publishProvenance();
7157
7343
  if (!result) {
7158
7344
  throw new NpmAvailableError(
7159
- "OTP verification failed after 3 attempts."
7345
+ `In CI environment, publishing with 2FA is not allowed. Please disable 2FA when accessing with a token from https://www.npmjs.com/package/${npm.packageName}/access `
7160
7346
  );
7161
7347
  }
7162
- task.title = "Running npm publish (2FA passed)";
7163
7348
  }
7164
- } else {
7165
- const npmTokenEnv = process13.env.NODE_AUTH_TOKEN;
7166
- if (!npmTokenEnv) {
7167
- throw new NpmAvailableError(
7168
- "NODE_AUTH_TOKEN not found in environment variables. Set it in your CI configuration:\n GitHub Actions: Add NODE_AUTH_TOKEN as a repository secret\n Other CI: Export NODE_AUTH_TOKEN with your npm access token"
7169
- );
7170
- }
7171
- const result = await npm.publishProvenance();
7172
- if (!result) {
7173
- throw new NpmAvailableError(
7174
- `In CI environment, publishing with 2FA is not allowed. Please disable 2FA when accessing with a token from https://www.npmjs.com/package/${npm.packageName}/access `
7175
- );
7349
+ } catch (error) {
7350
+ if (error instanceof Error && (error.message.includes(
7351
+ "cannot publish over the previously published"
7352
+ ) || error.message.includes(
7353
+ "You cannot publish over the previously published"
7354
+ ))) {
7355
+ task.title = `[SKIPPED] npm: v${ctx.version} already published`;
7356
+ task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
7357
+ return task.skip();
7176
7358
  }
7359
+ throw error;
7177
7360
  }
7178
7361
  }
7179
7362
  };
@@ -7589,10 +7772,15 @@ async function collectDryRunPublishTasks(ctx) {
7589
7772
  return nonCratesTasks;
7590
7773
  }
7591
7774
  const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
7775
+ const siblingCrateNames = await Promise.all(
7776
+ cratesPaths.map((p) => new RustEcosystem(p).packageName())
7777
+ );
7592
7778
  const sequentialCratesTask = {
7593
7779
  title: "Dry-run crates.io publish (sequential)",
7594
7780
  task: (_ctx, task) => task.newListr(
7595
- sortedPaths.map((p) => createCratesDryRunPublishTask(p)),
7781
+ sortedPaths.map(
7782
+ (p) => createCratesDryRunPublishTask(p, siblingCrateNames)
7783
+ ),
7596
7784
  { concurrent: false }
7597
7785
  )
7598
7786
  };
@@ -7685,23 +7873,23 @@ async function run(options) {
7685
7873
  addRollback(async () => {
7686
7874
  if (tagCreated) {
7687
7875
  try {
7688
- console.log("Deleting tag...");
7876
+ rollbackLog("Deleting tag");
7689
7877
  await git.deleteTag(`${await git.latestTag()}`);
7690
7878
  } catch (error) {
7691
- console.error(
7879
+ rollbackError(
7692
7880
  `Failed to delete tag: ${error instanceof Error ? error.message : error}`
7693
7881
  );
7694
7882
  }
7695
7883
  }
7696
7884
  if (commited) {
7697
7885
  try {
7698
- console.log("Reset commits...");
7886
+ rollbackLog("Resetting commits");
7699
7887
  await git.reset();
7700
7888
  await git.stash();
7701
7889
  await git.reset("HEAD^", "--hard");
7702
7890
  await git.popStash();
7703
7891
  } catch (error) {
7704
- console.error(
7892
+ rollbackError(
7705
7893
  `Failed to reset commits: ${error instanceof Error ? error.message : error}`
7706
7894
  );
7707
7895
  }