pubm 0.2.7 → 0.2.8
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/bin/cli.js +227 -84
- package/dist/index.cjs +343 -200
- package/dist/index.js +343 -200
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4455,6 +4455,125 @@ import SemVer from "semver";
|
|
|
4455
4455
|
import { isCI as isCI2 } from "std-env";
|
|
4456
4456
|
import { exec as exec9 } from "tinyexec";
|
|
4457
4457
|
|
|
4458
|
+
// src/ecosystem/rust.ts
|
|
4459
|
+
import { readFile, stat as stat2, writeFile } from "node:fs/promises";
|
|
4460
|
+
import path2 from "node:path";
|
|
4461
|
+
import { parse, stringify } from "smol-toml";
|
|
4462
|
+
import { exec as exec2 } from "tinyexec";
|
|
4463
|
+
|
|
4464
|
+
// src/ecosystem/ecosystem.ts
|
|
4465
|
+
var Ecosystem = class {
|
|
4466
|
+
constructor(packagePath) {
|
|
4467
|
+
this.packagePath = packagePath;
|
|
4468
|
+
}
|
|
4469
|
+
};
|
|
4470
|
+
|
|
4471
|
+
// src/ecosystem/rust.ts
|
|
4472
|
+
var RustEcosystem = class extends Ecosystem {
|
|
4473
|
+
static async detect(packagePath) {
|
|
4474
|
+
try {
|
|
4475
|
+
return (await stat2(path2.join(packagePath, "Cargo.toml"))).isFile();
|
|
4476
|
+
} catch {
|
|
4477
|
+
return false;
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
async readCargoToml() {
|
|
4481
|
+
const raw = await readFile(
|
|
4482
|
+
path2.join(this.packagePath, "Cargo.toml"),
|
|
4483
|
+
"utf-8"
|
|
4484
|
+
);
|
|
4485
|
+
return parse(raw);
|
|
4486
|
+
}
|
|
4487
|
+
async packageName() {
|
|
4488
|
+
const cargo = await this.readCargoToml();
|
|
4489
|
+
const pkg = cargo.package;
|
|
4490
|
+
return pkg.name;
|
|
4491
|
+
}
|
|
4492
|
+
async readVersion() {
|
|
4493
|
+
const cargo = await this.readCargoToml();
|
|
4494
|
+
const pkg = cargo.package;
|
|
4495
|
+
return pkg.version;
|
|
4496
|
+
}
|
|
4497
|
+
async writeVersion(newVersion) {
|
|
4498
|
+
const filePath = path2.join(this.packagePath, "Cargo.toml");
|
|
4499
|
+
const raw = await readFile(filePath, "utf-8");
|
|
4500
|
+
const cargo = parse(raw);
|
|
4501
|
+
const pkg = cargo.package;
|
|
4502
|
+
pkg.version = newVersion;
|
|
4503
|
+
await writeFile(filePath, stringify(cargo));
|
|
4504
|
+
}
|
|
4505
|
+
/**
|
|
4506
|
+
* Update the `version` field of dependencies that match sibling crate names.
|
|
4507
|
+
* This ensures `cargo publish` works when crates depend on each other via path.
|
|
4508
|
+
*/
|
|
4509
|
+
async updateSiblingDependencyVersions(siblingVersions) {
|
|
4510
|
+
const filePath = path2.join(this.packagePath, "Cargo.toml");
|
|
4511
|
+
const raw = await readFile(filePath, "utf-8");
|
|
4512
|
+
const cargo = parse(raw);
|
|
4513
|
+
let modified = false;
|
|
4514
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4515
|
+
const sectionData = cargo[section];
|
|
4516
|
+
if (!sectionData) continue;
|
|
4517
|
+
for (const [depName, depValue] of Object.entries(sectionData)) {
|
|
4518
|
+
if (typeof depValue === "object" && depValue !== null && "path" in depValue && siblingVersions.has(depName)) {
|
|
4519
|
+
const dep = depValue;
|
|
4520
|
+
dep.version = siblingVersions.get(depName);
|
|
4521
|
+
modified = true;
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
if (modified) {
|
|
4526
|
+
await writeFile(filePath, stringify(cargo));
|
|
4527
|
+
}
|
|
4528
|
+
return modified;
|
|
4529
|
+
}
|
|
4530
|
+
async syncLockfile() {
|
|
4531
|
+
const lockfilePath = await this.findLockfile();
|
|
4532
|
+
if (!lockfilePath) return void 0;
|
|
4533
|
+
const name = await this.packageName();
|
|
4534
|
+
await exec2("cargo", ["update", "--package", name], {
|
|
4535
|
+
nodeOptions: { cwd: path2.dirname(lockfilePath) }
|
|
4536
|
+
});
|
|
4537
|
+
return lockfilePath;
|
|
4538
|
+
}
|
|
4539
|
+
async findLockfile() {
|
|
4540
|
+
let dir = this.packagePath;
|
|
4541
|
+
const { root } = path2.parse(dir);
|
|
4542
|
+
while (dir !== root) {
|
|
4543
|
+
const candidate = path2.join(dir, "Cargo.lock");
|
|
4544
|
+
try {
|
|
4545
|
+
if ((await stat2(candidate)).isFile()) return candidate;
|
|
4546
|
+
} catch {
|
|
4547
|
+
}
|
|
4548
|
+
dir = path2.dirname(dir);
|
|
4549
|
+
}
|
|
4550
|
+
return void 0;
|
|
4551
|
+
}
|
|
4552
|
+
async dependencies() {
|
|
4553
|
+
const cargo = await this.readCargoToml();
|
|
4554
|
+
const deps = [];
|
|
4555
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4556
|
+
const sectionData = cargo[section];
|
|
4557
|
+
if (sectionData) {
|
|
4558
|
+
deps.push(...Object.keys(sectionData));
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
return deps;
|
|
4562
|
+
}
|
|
4563
|
+
manifestFiles() {
|
|
4564
|
+
return ["Cargo.toml"];
|
|
4565
|
+
}
|
|
4566
|
+
defaultTestCommand() {
|
|
4567
|
+
return "cargo test";
|
|
4568
|
+
}
|
|
4569
|
+
defaultBuildCommand() {
|
|
4570
|
+
return "cargo build --release";
|
|
4571
|
+
}
|
|
4572
|
+
supportedRegistries() {
|
|
4573
|
+
return ["crates"];
|
|
4574
|
+
}
|
|
4575
|
+
};
|
|
4576
|
+
|
|
4458
4577
|
// src/error.ts
|
|
4459
4578
|
var AbstractError = class extends Error {
|
|
4460
4579
|
constructor(message, { cause } = {}) {
|
|
@@ -4496,7 +4615,7 @@ function consoleError(error) {
|
|
|
4496
4615
|
|
|
4497
4616
|
// src/git.ts
|
|
4498
4617
|
import semver from "semver";
|
|
4499
|
-
import { exec as
|
|
4618
|
+
import { exec as exec3 } from "tinyexec";
|
|
4500
4619
|
var GitError = class extends AbstractError {
|
|
4501
4620
|
constructor() {
|
|
4502
4621
|
super(...arguments);
|
|
@@ -4505,7 +4624,7 @@ var GitError = class extends AbstractError {
|
|
|
4505
4624
|
};
|
|
4506
4625
|
var Git = class {
|
|
4507
4626
|
async git(args) {
|
|
4508
|
-
const { stdout } = await
|
|
4627
|
+
const { stdout } = await exec3("git", args, { throwOnError: true });
|
|
4509
4628
|
return stdout;
|
|
4510
4629
|
}
|
|
4511
4630
|
async userName() {
|
|
@@ -4759,7 +4878,7 @@ var Git = class {
|
|
|
4759
4878
|
async push(options) {
|
|
4760
4879
|
const args = ["push", options].filter((v) => v);
|
|
4761
4880
|
try {
|
|
4762
|
-
const { stderr } = await
|
|
4881
|
+
const { stderr } = await exec3("git", args, { throwOnError: true });
|
|
4763
4882
|
if (`${stderr}`.includes("GH006")) {
|
|
4764
4883
|
return false;
|
|
4765
4884
|
}
|
|
@@ -4781,125 +4900,6 @@ function link2(text, url) {
|
|
|
4781
4900
|
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
4782
4901
|
}
|
|
4783
4902
|
|
|
4784
|
-
// src/ecosystem/rust.ts
|
|
4785
|
-
import { readFile, stat as stat2, writeFile } from "node:fs/promises";
|
|
4786
|
-
import path2 from "node:path";
|
|
4787
|
-
import { parse, stringify } from "smol-toml";
|
|
4788
|
-
import { exec as exec3 } from "tinyexec";
|
|
4789
|
-
|
|
4790
|
-
// src/ecosystem/ecosystem.ts
|
|
4791
|
-
var Ecosystem = class {
|
|
4792
|
-
constructor(packagePath) {
|
|
4793
|
-
this.packagePath = packagePath;
|
|
4794
|
-
}
|
|
4795
|
-
};
|
|
4796
|
-
|
|
4797
|
-
// src/ecosystem/rust.ts
|
|
4798
|
-
var RustEcosystem = class extends Ecosystem {
|
|
4799
|
-
static async detect(packagePath) {
|
|
4800
|
-
try {
|
|
4801
|
-
return (await stat2(path2.join(packagePath, "Cargo.toml"))).isFile();
|
|
4802
|
-
} catch {
|
|
4803
|
-
return false;
|
|
4804
|
-
}
|
|
4805
|
-
}
|
|
4806
|
-
async readCargoToml() {
|
|
4807
|
-
const raw = await readFile(
|
|
4808
|
-
path2.join(this.packagePath, "Cargo.toml"),
|
|
4809
|
-
"utf-8"
|
|
4810
|
-
);
|
|
4811
|
-
return parse(raw);
|
|
4812
|
-
}
|
|
4813
|
-
async packageName() {
|
|
4814
|
-
const cargo = await this.readCargoToml();
|
|
4815
|
-
const pkg = cargo.package;
|
|
4816
|
-
return pkg.name;
|
|
4817
|
-
}
|
|
4818
|
-
async readVersion() {
|
|
4819
|
-
const cargo = await this.readCargoToml();
|
|
4820
|
-
const pkg = cargo.package;
|
|
4821
|
-
return pkg.version;
|
|
4822
|
-
}
|
|
4823
|
-
async writeVersion(newVersion) {
|
|
4824
|
-
const filePath = path2.join(this.packagePath, "Cargo.toml");
|
|
4825
|
-
const raw = await readFile(filePath, "utf-8");
|
|
4826
|
-
const cargo = parse(raw);
|
|
4827
|
-
const pkg = cargo.package;
|
|
4828
|
-
pkg.version = newVersion;
|
|
4829
|
-
await writeFile(filePath, stringify(cargo));
|
|
4830
|
-
}
|
|
4831
|
-
/**
|
|
4832
|
-
* Update the `version` field of dependencies that match sibling crate names.
|
|
4833
|
-
* This ensures `cargo publish` works when crates depend on each other via path.
|
|
4834
|
-
*/
|
|
4835
|
-
async updateSiblingDependencyVersions(siblingVersions) {
|
|
4836
|
-
const filePath = path2.join(this.packagePath, "Cargo.toml");
|
|
4837
|
-
const raw = await readFile(filePath, "utf-8");
|
|
4838
|
-
const cargo = parse(raw);
|
|
4839
|
-
let modified = false;
|
|
4840
|
-
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4841
|
-
const sectionData = cargo[section];
|
|
4842
|
-
if (!sectionData) continue;
|
|
4843
|
-
for (const [depName, depValue] of Object.entries(sectionData)) {
|
|
4844
|
-
if (typeof depValue === "object" && depValue !== null && "path" in depValue && siblingVersions.has(depName)) {
|
|
4845
|
-
const dep = depValue;
|
|
4846
|
-
dep.version = siblingVersions.get(depName);
|
|
4847
|
-
modified = true;
|
|
4848
|
-
}
|
|
4849
|
-
}
|
|
4850
|
-
}
|
|
4851
|
-
if (modified) {
|
|
4852
|
-
await writeFile(filePath, stringify(cargo));
|
|
4853
|
-
}
|
|
4854
|
-
return modified;
|
|
4855
|
-
}
|
|
4856
|
-
async syncLockfile() {
|
|
4857
|
-
const lockfilePath = await this.findLockfile();
|
|
4858
|
-
if (!lockfilePath) return void 0;
|
|
4859
|
-
const name = await this.packageName();
|
|
4860
|
-
await exec3("cargo", ["update", "--package", name], {
|
|
4861
|
-
nodeOptions: { cwd: path2.dirname(lockfilePath) }
|
|
4862
|
-
});
|
|
4863
|
-
return lockfilePath;
|
|
4864
|
-
}
|
|
4865
|
-
async findLockfile() {
|
|
4866
|
-
let dir = this.packagePath;
|
|
4867
|
-
const { root } = path2.parse(dir);
|
|
4868
|
-
while (dir !== root) {
|
|
4869
|
-
const candidate = path2.join(dir, "Cargo.lock");
|
|
4870
|
-
try {
|
|
4871
|
-
if ((await stat2(candidate)).isFile()) return candidate;
|
|
4872
|
-
} catch {
|
|
4873
|
-
}
|
|
4874
|
-
dir = path2.dirname(dir);
|
|
4875
|
-
}
|
|
4876
|
-
return void 0;
|
|
4877
|
-
}
|
|
4878
|
-
async dependencies() {
|
|
4879
|
-
const cargo = await this.readCargoToml();
|
|
4880
|
-
const deps = [];
|
|
4881
|
-
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4882
|
-
const sectionData = cargo[section];
|
|
4883
|
-
if (sectionData) {
|
|
4884
|
-
deps.push(...Object.keys(sectionData));
|
|
4885
|
-
}
|
|
4886
|
-
}
|
|
4887
|
-
return deps;
|
|
4888
|
-
}
|
|
4889
|
-
manifestFiles() {
|
|
4890
|
-
return ["Cargo.toml"];
|
|
4891
|
-
}
|
|
4892
|
-
defaultTestCommand() {
|
|
4893
|
-
return "cargo test";
|
|
4894
|
-
}
|
|
4895
|
-
defaultBuildCommand() {
|
|
4896
|
-
return "cargo build --release";
|
|
4897
|
-
}
|
|
4898
|
-
supportedRegistries() {
|
|
4899
|
-
return ["crates"];
|
|
4900
|
-
}
|
|
4901
|
-
};
|
|
4902
|
-
|
|
4903
4903
|
// src/utils/crate-graph.ts
|
|
4904
4904
|
async function sortCratesByDependencyOrder(cratePaths) {
|
|
4905
4905
|
if (cratePaths.length <= 1) return cratePaths;
|
|
@@ -5473,7 +5473,7 @@ ${stderr}` : "Failed to run `cargo publish`";
|
|
|
5473
5473
|
}
|
|
5474
5474
|
async dryRunPublish(manifestDir) {
|
|
5475
5475
|
try {
|
|
5476
|
-
const args = ["publish", "--dry-run"
|
|
5476
|
+
const args = ["publish", "--dry-run"];
|
|
5477
5477
|
if (manifestDir) {
|
|
5478
5478
|
args.push("--manifest-path", path5.join(manifestDir, "Cargo.toml"));
|
|
5479
5479
|
}
|
|
@@ -5485,6 +5485,20 @@ ${stderr}` : "Failed to run `cargo publish --dry-run`";
|
|
|
5485
5485
|
throw new CratesError(message, { cause: error });
|
|
5486
5486
|
}
|
|
5487
5487
|
}
|
|
5488
|
+
async isVersionPublished(version2) {
|
|
5489
|
+
try {
|
|
5490
|
+
const response = await fetch(
|
|
5491
|
+
`${this.registry}/api/v1/crates/${this.packageName}/${version2}`,
|
|
5492
|
+
{ headers: this.headers }
|
|
5493
|
+
);
|
|
5494
|
+
return response.ok;
|
|
5495
|
+
} catch (error) {
|
|
5496
|
+
throw new CratesError(
|
|
5497
|
+
`Failed to check version ${version2} for '${this.packageName}' on crates.io`,
|
|
5498
|
+
{ cause: error }
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5488
5502
|
async isPublished() {
|
|
5489
5503
|
try {
|
|
5490
5504
|
const response = await fetch(
|
|
@@ -5561,10 +5575,24 @@ function createCratesPublishTask(packagePath) {
|
|
|
5561
5575
|
const label = packagePath ? ` (${packagePath})` : "";
|
|
5562
5576
|
return {
|
|
5563
5577
|
title: `Publishing to crates.io${label}`,
|
|
5564
|
-
task: async () => {
|
|
5578
|
+
task: async (ctx, task) => {
|
|
5565
5579
|
const packageName = await getCrateName(packagePath);
|
|
5566
5580
|
const registry = new CratesRegistry(packageName);
|
|
5567
|
-
await registry.
|
|
5581
|
+
if (await registry.isVersionPublished(ctx.version)) {
|
|
5582
|
+
task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
|
|
5583
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
5584
|
+
return task.skip();
|
|
5585
|
+
}
|
|
5586
|
+
try {
|
|
5587
|
+
await registry.publish(packagePath);
|
|
5588
|
+
} catch (error) {
|
|
5589
|
+
if (error instanceof Error && error.message.includes("is already uploaded")) {
|
|
5590
|
+
task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
|
|
5591
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
5592
|
+
return task.skip();
|
|
5593
|
+
}
|
|
5594
|
+
throw error;
|
|
5595
|
+
}
|
|
5568
5596
|
}
|
|
5569
5597
|
};
|
|
5570
5598
|
}
|
|
@@ -5735,6 +5763,20 @@ ${stderr}` : ""}`,
|
|
|
5735
5763
|
);
|
|
5736
5764
|
}
|
|
5737
5765
|
}
|
|
5766
|
+
async isVersionPublished(version2) {
|
|
5767
|
+
try {
|
|
5768
|
+
const [scope, name] = getScopeAndName(this.packageName);
|
|
5769
|
+
const response = await fetch(
|
|
5770
|
+
`${this.registry}/@${scope}/${name}/${version2}`
|
|
5771
|
+
);
|
|
5772
|
+
return response.status === 200;
|
|
5773
|
+
} catch (error) {
|
|
5774
|
+
throw new JsrError(
|
|
5775
|
+
`Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
|
|
5776
|
+
{ cause: error }
|
|
5777
|
+
);
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5738
5780
|
async hasPermission() {
|
|
5739
5781
|
return this.client.scopePermission(`${getScope(this.packageName)}`) !== null;
|
|
5740
5782
|
}
|
|
@@ -6009,6 +6051,19 @@ var NpmRegistry = class extends Registry {
|
|
|
6009
6051
|
);
|
|
6010
6052
|
}
|
|
6011
6053
|
}
|
|
6054
|
+
async isVersionPublished(version2) {
|
|
6055
|
+
try {
|
|
6056
|
+
const response = await fetch(
|
|
6057
|
+
`${this.registry}/${this.packageName}/${version2}`
|
|
6058
|
+
);
|
|
6059
|
+
return response.status === 200;
|
|
6060
|
+
} catch (error) {
|
|
6061
|
+
throw new NpmError(
|
|
6062
|
+
`Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
|
|
6063
|
+
{ cause: error }
|
|
6064
|
+
);
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6012
6067
|
async userName() {
|
|
6013
6068
|
try {
|
|
6014
6069
|
return (await this.npm(["whoami"])).trim();
|
|
@@ -6214,20 +6269,30 @@ async function withTokenRetry(registryKey, task, action) {
|
|
|
6214
6269
|
}
|
|
6215
6270
|
var npmDryRunPublishTask = {
|
|
6216
6271
|
title: "Dry-run npm publish",
|
|
6217
|
-
task: async (
|
|
6272
|
+
task: async (ctx, task) => {
|
|
6273
|
+
const npm = await npmRegistry();
|
|
6274
|
+
if (await npm.isVersionPublished(ctx.version)) {
|
|
6275
|
+
task.title = `[SKIPPED] Dry-run npm publish: v${ctx.version} already published`;
|
|
6276
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6277
|
+
return task.skip();
|
|
6278
|
+
}
|
|
6218
6279
|
task.output = "Running npm publish --dry-run...";
|
|
6219
6280
|
await withTokenRetry("npm", task, async () => {
|
|
6220
|
-
const npm = await npmRegistry();
|
|
6221
6281
|
await npm.dryRunPublish();
|
|
6222
6282
|
});
|
|
6223
6283
|
}
|
|
6224
6284
|
};
|
|
6225
6285
|
var jsrDryRunPublishTask = {
|
|
6226
6286
|
title: "Dry-run jsr publish",
|
|
6227
|
-
task: async (
|
|
6287
|
+
task: async (ctx, task) => {
|
|
6288
|
+
const jsr = await jsrRegistry();
|
|
6289
|
+
if (await jsr.isVersionPublished(ctx.version)) {
|
|
6290
|
+
task.title = `[SKIPPED] Dry-run jsr publish: v${ctx.version} already published`;
|
|
6291
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6292
|
+
return task.skip();
|
|
6293
|
+
}
|
|
6228
6294
|
task.output = "Running jsr publish --dry-run...";
|
|
6229
6295
|
await withTokenRetry("jsr", task, async () => {
|
|
6230
|
-
const jsr = await jsrRegistry();
|
|
6231
6296
|
await jsr.dryRunPublish();
|
|
6232
6297
|
});
|
|
6233
6298
|
}
|
|
@@ -6236,17 +6301,58 @@ async function getCrateName2(packagePath) {
|
|
|
6236
6301
|
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6237
6302
|
return await eco.packageName();
|
|
6238
6303
|
}
|
|
6239
|
-
|
|
6304
|
+
var MISSING_CRATE_PATTERN = /no matching package named `([^`]+)` found/;
|
|
6305
|
+
async function findUnpublishedSiblingDeps(packagePath, siblingCrateNames) {
|
|
6306
|
+
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6307
|
+
const deps = await eco.dependencies();
|
|
6308
|
+
const siblingDeps = deps.filter((d2) => siblingCrateNames.includes(d2));
|
|
6309
|
+
const results = await Promise.all(
|
|
6310
|
+
siblingDeps.map(async (name) => {
|
|
6311
|
+
const registry = new CratesRegistry(name);
|
|
6312
|
+
const published = await registry.isPublished();
|
|
6313
|
+
return published ? null : name;
|
|
6314
|
+
})
|
|
6315
|
+
);
|
|
6316
|
+
return results.filter((name) => name !== null);
|
|
6317
|
+
}
|
|
6318
|
+
function createCratesDryRunPublishTask(packagePath, siblingCrateNames) {
|
|
6240
6319
|
const label = packagePath ? ` (${packagePath})` : "";
|
|
6241
6320
|
return {
|
|
6242
6321
|
title: `Dry-run crates.io publish${label}`,
|
|
6243
|
-
task: async (
|
|
6322
|
+
task: async (ctx, task) => {
|
|
6323
|
+
const packageName = await getCrateName2(packagePath);
|
|
6324
|
+
const registry = new CratesRegistry(packageName);
|
|
6325
|
+
if (await registry.isVersionPublished(ctx.version)) {
|
|
6326
|
+
task.title = `[SKIPPED] Dry-run crates.io publish${label}: v${ctx.version} already published`;
|
|
6327
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
6328
|
+
return task.skip();
|
|
6329
|
+
}
|
|
6330
|
+
if (siblingCrateNames?.length) {
|
|
6331
|
+
const unpublished = await findUnpublishedSiblingDeps(
|
|
6332
|
+
packagePath,
|
|
6333
|
+
siblingCrateNames
|
|
6334
|
+
);
|
|
6335
|
+
if (unpublished.length > 0) {
|
|
6336
|
+
task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${unpublished.join("`, `")}\` not yet published]`;
|
|
6337
|
+
return;
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6244
6340
|
task.output = "Running cargo publish --dry-run...";
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6341
|
+
try {
|
|
6342
|
+
await withTokenRetry("crates", task, async () => {
|
|
6343
|
+
const packageName2 = await getCrateName2(packagePath);
|
|
6344
|
+
const registry2 = new CratesRegistry(packageName2);
|
|
6345
|
+
await registry2.dryRunPublish(packagePath);
|
|
6346
|
+
});
|
|
6347
|
+
} catch (error) {
|
|
6348
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6349
|
+
const match = message.match(MISSING_CRATE_PATTERN);
|
|
6350
|
+
if (match && siblingCrateNames?.includes(match[1])) {
|
|
6351
|
+
task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${match[1]}\` not yet published]`;
|
|
6352
|
+
return;
|
|
6353
|
+
}
|
|
6354
|
+
throw error;
|
|
6355
|
+
}
|
|
6250
6356
|
}
|
|
6251
6357
|
};
|
|
6252
6358
|
}
|
|
@@ -6427,48 +6533,62 @@ var jsrPublishTasks = {
|
|
|
6427
6533
|
title: "Running jsr publish",
|
|
6428
6534
|
task: async (ctx, task) => {
|
|
6429
6535
|
const jsr = await jsrRegistry();
|
|
6536
|
+
if (await jsr.isVersionPublished(ctx.version)) {
|
|
6537
|
+
task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
|
|
6538
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6539
|
+
return task.skip();
|
|
6540
|
+
}
|
|
6430
6541
|
task.output = "Publishing on jsr...";
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6542
|
+
try {
|
|
6543
|
+
if (!JsrClient.token && !ctx.promptEnabled) {
|
|
6544
|
+
const jsrTokenEnv = process8.env.JSR_TOKEN;
|
|
6545
|
+
if (!jsrTokenEnv) {
|
|
6546
|
+
throw new JsrAvailableError(
|
|
6547
|
+
"JSR_TOKEN not found in the environment variables. Please set the token and try again."
|
|
6548
|
+
);
|
|
6549
|
+
}
|
|
6550
|
+
JsrClient.token = jsrTokenEnv;
|
|
6437
6551
|
}
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
const maxAttempts = 3;
|
|
6446
|
-
task.output = `Package doesn't exist on jsr. Create it at:
|
|
6552
|
+
let result = await jsr.publish();
|
|
6553
|
+
if (!result && jsr.packageCreationUrls) {
|
|
6554
|
+
if (ctx.promptEnabled) {
|
|
6555
|
+
task.title = "Running jsr publish (package creation needed)";
|
|
6556
|
+
const urls = jsr.packageCreationUrls;
|
|
6557
|
+
const maxAttempts = 3;
|
|
6558
|
+
task.output = `Package doesn't exist on jsr. Create it at:
|
|
6447
6559
|
${urls.map((url) => ` ${color.cyan(url)}`).join("\n")}`;
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6560
|
+
open(urls[0]);
|
|
6561
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6562
|
+
await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6563
|
+
type: "input",
|
|
6564
|
+
message: `Press ${color.bold("enter")} after creating the package on jsr.io${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6565
|
+
});
|
|
6566
|
+
result = await jsr.publish();
|
|
6567
|
+
if (result) break;
|
|
6568
|
+
if (attempt < maxAttempts) {
|
|
6569
|
+
task.output = "Package still doesn't exist. Please create it and try again.";
|
|
6570
|
+
}
|
|
6458
6571
|
}
|
|
6459
|
-
|
|
6460
|
-
|
|
6572
|
+
if (!result) {
|
|
6573
|
+
throw new JsrAvailableError(
|
|
6574
|
+
"Package creation not completed after 3 attempts."
|
|
6575
|
+
);
|
|
6576
|
+
}
|
|
6577
|
+
task.title = "Running jsr publish (package created)";
|
|
6578
|
+
} else {
|
|
6461
6579
|
throw new JsrAvailableError(
|
|
6462
|
-
|
|
6580
|
+
`Package doesn't exist on jsr. Create it at:
|
|
6581
|
+
${jsr.packageCreationUrls.join("\n")}`
|
|
6463
6582
|
);
|
|
6464
6583
|
}
|
|
6465
|
-
task.title = "Running jsr publish (package created)";
|
|
6466
|
-
} else {
|
|
6467
|
-
throw new JsrAvailableError(
|
|
6468
|
-
`Package doesn't exist on jsr. Create it at:
|
|
6469
|
-
${jsr.packageCreationUrls.join("\n")}`
|
|
6470
|
-
);
|
|
6471
6584
|
}
|
|
6585
|
+
} catch (error) {
|
|
6586
|
+
if (error instanceof Error && error.message.includes("already published")) {
|
|
6587
|
+
task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
|
|
6588
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6589
|
+
return task.skip();
|
|
6590
|
+
}
|
|
6591
|
+
throw error;
|
|
6472
6592
|
}
|
|
6473
6593
|
}
|
|
6474
6594
|
};
|
|
@@ -6565,44 +6685,62 @@ var npmPublishTasks = {
|
|
|
6565
6685
|
skip: (ctx) => !!ctx.preview,
|
|
6566
6686
|
task: async (ctx, task) => {
|
|
6567
6687
|
const npm = await npmRegistry();
|
|
6688
|
+
if (await npm.isVersionPublished(ctx.version)) {
|
|
6689
|
+
task.title = `[SKIPPED] npm: v${ctx.version} already published`;
|
|
6690
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6691
|
+
return task.skip();
|
|
6692
|
+
}
|
|
6568
6693
|
task.output = "Publishing on npm...";
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
await
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6694
|
+
try {
|
|
6695
|
+
if (ctx.promptEnabled) {
|
|
6696
|
+
let result = await npm.publish();
|
|
6697
|
+
if (!result) {
|
|
6698
|
+
task.title = "Running npm publish (OTP code needed)";
|
|
6699
|
+
const maxAttempts = 3;
|
|
6700
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6701
|
+
result = await npm.publish(
|
|
6702
|
+
await task.prompt(ListrEnquirerPromptAdapter3).run({
|
|
6703
|
+
type: "password",
|
|
6704
|
+
message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6705
|
+
})
|
|
6706
|
+
);
|
|
6707
|
+
if (result) break;
|
|
6708
|
+
if (attempt < maxAttempts) {
|
|
6709
|
+
task.output = "2FA failed. Please try again.";
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6712
|
+
if (!result) {
|
|
6713
|
+
throw new NpmAvailableError(
|
|
6714
|
+
"OTP verification failed after 3 attempts."
|
|
6715
|
+
);
|
|
6584
6716
|
}
|
|
6717
|
+
task.title = "Running npm publish (2FA passed)";
|
|
6718
|
+
}
|
|
6719
|
+
} else {
|
|
6720
|
+
const npmTokenEnv = process9.env.NODE_AUTH_TOKEN;
|
|
6721
|
+
if (!npmTokenEnv) {
|
|
6722
|
+
throw new NpmAvailableError(
|
|
6723
|
+
"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"
|
|
6724
|
+
);
|
|
6585
6725
|
}
|
|
6726
|
+
const result = await npm.publishProvenance();
|
|
6586
6727
|
if (!result) {
|
|
6587
6728
|
throw new NpmAvailableError(
|
|
6588
|
-
|
|
6729
|
+
`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 `
|
|
6589
6730
|
);
|
|
6590
6731
|
}
|
|
6591
|
-
task.title = "Running npm publish (2FA passed)";
|
|
6592
|
-
}
|
|
6593
|
-
} else {
|
|
6594
|
-
const npmTokenEnv = process9.env.NODE_AUTH_TOKEN;
|
|
6595
|
-
if (!npmTokenEnv) {
|
|
6596
|
-
throw new NpmAvailableError(
|
|
6597
|
-
"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"
|
|
6598
|
-
);
|
|
6599
6732
|
}
|
|
6600
|
-
|
|
6601
|
-
if (
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6733
|
+
} catch (error) {
|
|
6734
|
+
if (error instanceof Error && (error.message.includes(
|
|
6735
|
+
"cannot publish over the previously published"
|
|
6736
|
+
) || error.message.includes(
|
|
6737
|
+
"You cannot publish over the previously published"
|
|
6738
|
+
))) {
|
|
6739
|
+
task.title = `[SKIPPED] npm: v${ctx.version} already published`;
|
|
6740
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6741
|
+
return task.skip();
|
|
6605
6742
|
}
|
|
6743
|
+
throw error;
|
|
6606
6744
|
}
|
|
6607
6745
|
}
|
|
6608
6746
|
};
|
|
@@ -7092,10 +7230,15 @@ async function collectDryRunPublishTasks(ctx) {
|
|
|
7092
7230
|
return nonCratesTasks;
|
|
7093
7231
|
}
|
|
7094
7232
|
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
7233
|
+
const siblingCrateNames = await Promise.all(
|
|
7234
|
+
cratesPaths.map((p) => new RustEcosystem(p).packageName())
|
|
7235
|
+
);
|
|
7095
7236
|
const sequentialCratesTask = {
|
|
7096
7237
|
title: "Dry-run crates.io publish (sequential)",
|
|
7097
7238
|
task: (_ctx, task) => task.newListr(
|
|
7098
|
-
sortedPaths.map(
|
|
7239
|
+
sortedPaths.map(
|
|
7240
|
+
(p) => createCratesDryRunPublishTask(p, siblingCrateNames)
|
|
7241
|
+
),
|
|
7099
7242
|
{ concurrent: false }
|
|
7100
7243
|
)
|
|
7101
7244
|
};
|