pubm 0.2.6 → 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 +226 -83
- package/dist/index.cjs +342 -199
- package/dist/index.js +342 -199
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4488,6 +4488,125 @@ var import_semver3 = __toESM(require("semver"), 1);
|
|
|
4488
4488
|
var import_std_env = require("std-env");
|
|
4489
4489
|
var import_tinyexec8 = require("tinyexec");
|
|
4490
4490
|
|
|
4491
|
+
// src/ecosystem/rust.ts
|
|
4492
|
+
var import_promises2 = require("fs/promises");
|
|
4493
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
4494
|
+
var import_smol_toml = require("smol-toml");
|
|
4495
|
+
var import_tinyexec = require("tinyexec");
|
|
4496
|
+
|
|
4497
|
+
// src/ecosystem/ecosystem.ts
|
|
4498
|
+
var Ecosystem = class {
|
|
4499
|
+
constructor(packagePath) {
|
|
4500
|
+
this.packagePath = packagePath;
|
|
4501
|
+
}
|
|
4502
|
+
};
|
|
4503
|
+
|
|
4504
|
+
// src/ecosystem/rust.ts
|
|
4505
|
+
var RustEcosystem = class extends Ecosystem {
|
|
4506
|
+
static async detect(packagePath) {
|
|
4507
|
+
try {
|
|
4508
|
+
return (await (0, import_promises2.stat)(import_node_path2.default.join(packagePath, "Cargo.toml"))).isFile();
|
|
4509
|
+
} catch {
|
|
4510
|
+
return false;
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
async readCargoToml() {
|
|
4514
|
+
const raw = await (0, import_promises2.readFile)(
|
|
4515
|
+
import_node_path2.default.join(this.packagePath, "Cargo.toml"),
|
|
4516
|
+
"utf-8"
|
|
4517
|
+
);
|
|
4518
|
+
return (0, import_smol_toml.parse)(raw);
|
|
4519
|
+
}
|
|
4520
|
+
async packageName() {
|
|
4521
|
+
const cargo = await this.readCargoToml();
|
|
4522
|
+
const pkg = cargo.package;
|
|
4523
|
+
return pkg.name;
|
|
4524
|
+
}
|
|
4525
|
+
async readVersion() {
|
|
4526
|
+
const cargo = await this.readCargoToml();
|
|
4527
|
+
const pkg = cargo.package;
|
|
4528
|
+
return pkg.version;
|
|
4529
|
+
}
|
|
4530
|
+
async writeVersion(newVersion) {
|
|
4531
|
+
const filePath = import_node_path2.default.join(this.packagePath, "Cargo.toml");
|
|
4532
|
+
const raw = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
4533
|
+
const cargo = (0, import_smol_toml.parse)(raw);
|
|
4534
|
+
const pkg = cargo.package;
|
|
4535
|
+
pkg.version = newVersion;
|
|
4536
|
+
await (0, import_promises2.writeFile)(filePath, (0, import_smol_toml.stringify)(cargo));
|
|
4537
|
+
}
|
|
4538
|
+
/**
|
|
4539
|
+
* Update the `version` field of dependencies that match sibling crate names.
|
|
4540
|
+
* This ensures `cargo publish` works when crates depend on each other via path.
|
|
4541
|
+
*/
|
|
4542
|
+
async updateSiblingDependencyVersions(siblingVersions) {
|
|
4543
|
+
const filePath = import_node_path2.default.join(this.packagePath, "Cargo.toml");
|
|
4544
|
+
const raw = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
4545
|
+
const cargo = (0, import_smol_toml.parse)(raw);
|
|
4546
|
+
let modified = false;
|
|
4547
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4548
|
+
const sectionData = cargo[section];
|
|
4549
|
+
if (!sectionData) continue;
|
|
4550
|
+
for (const [depName, depValue] of Object.entries(sectionData)) {
|
|
4551
|
+
if (typeof depValue === "object" && depValue !== null && "path" in depValue && siblingVersions.has(depName)) {
|
|
4552
|
+
const dep = depValue;
|
|
4553
|
+
dep.version = siblingVersions.get(depName);
|
|
4554
|
+
modified = true;
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4558
|
+
if (modified) {
|
|
4559
|
+
await (0, import_promises2.writeFile)(filePath, (0, import_smol_toml.stringify)(cargo));
|
|
4560
|
+
}
|
|
4561
|
+
return modified;
|
|
4562
|
+
}
|
|
4563
|
+
async syncLockfile() {
|
|
4564
|
+
const lockfilePath = await this.findLockfile();
|
|
4565
|
+
if (!lockfilePath) return void 0;
|
|
4566
|
+
const name = await this.packageName();
|
|
4567
|
+
await (0, import_tinyexec.exec)("cargo", ["update", "--package", name], {
|
|
4568
|
+
nodeOptions: { cwd: import_node_path2.default.dirname(lockfilePath) }
|
|
4569
|
+
});
|
|
4570
|
+
return lockfilePath;
|
|
4571
|
+
}
|
|
4572
|
+
async findLockfile() {
|
|
4573
|
+
let dir = this.packagePath;
|
|
4574
|
+
const { root } = import_node_path2.default.parse(dir);
|
|
4575
|
+
while (dir !== root) {
|
|
4576
|
+
const candidate = import_node_path2.default.join(dir, "Cargo.lock");
|
|
4577
|
+
try {
|
|
4578
|
+
if ((await (0, import_promises2.stat)(candidate)).isFile()) return candidate;
|
|
4579
|
+
} catch {
|
|
4580
|
+
}
|
|
4581
|
+
dir = import_node_path2.default.dirname(dir);
|
|
4582
|
+
}
|
|
4583
|
+
return void 0;
|
|
4584
|
+
}
|
|
4585
|
+
async dependencies() {
|
|
4586
|
+
const cargo = await this.readCargoToml();
|
|
4587
|
+
const deps = [];
|
|
4588
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4589
|
+
const sectionData = cargo[section];
|
|
4590
|
+
if (sectionData) {
|
|
4591
|
+
deps.push(...Object.keys(sectionData));
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
return deps;
|
|
4595
|
+
}
|
|
4596
|
+
manifestFiles() {
|
|
4597
|
+
return ["Cargo.toml"];
|
|
4598
|
+
}
|
|
4599
|
+
defaultTestCommand() {
|
|
4600
|
+
return "cargo test";
|
|
4601
|
+
}
|
|
4602
|
+
defaultBuildCommand() {
|
|
4603
|
+
return "cargo build --release";
|
|
4604
|
+
}
|
|
4605
|
+
supportedRegistries() {
|
|
4606
|
+
return ["crates"];
|
|
4607
|
+
}
|
|
4608
|
+
};
|
|
4609
|
+
|
|
4491
4610
|
// src/error.ts
|
|
4492
4611
|
var AbstractError = class extends Error {
|
|
4493
4612
|
constructor(message, { cause } = {}) {
|
|
@@ -4529,7 +4648,7 @@ function consoleError(error) {
|
|
|
4529
4648
|
|
|
4530
4649
|
// src/git.ts
|
|
4531
4650
|
var import_semver = __toESM(require("semver"), 1);
|
|
4532
|
-
var
|
|
4651
|
+
var import_tinyexec2 = require("tinyexec");
|
|
4533
4652
|
var GitError = class extends AbstractError {
|
|
4534
4653
|
constructor() {
|
|
4535
4654
|
super(...arguments);
|
|
@@ -4538,7 +4657,7 @@ var GitError = class extends AbstractError {
|
|
|
4538
4657
|
};
|
|
4539
4658
|
var Git = class {
|
|
4540
4659
|
async git(args) {
|
|
4541
|
-
const { stdout } = await (0,
|
|
4660
|
+
const { stdout } = await (0, import_tinyexec2.exec)("git", args, { throwOnError: true });
|
|
4542
4661
|
return stdout;
|
|
4543
4662
|
}
|
|
4544
4663
|
async userName() {
|
|
@@ -4792,7 +4911,7 @@ var Git = class {
|
|
|
4792
4911
|
async push(options) {
|
|
4793
4912
|
const args = ["push", options].filter((v) => v);
|
|
4794
4913
|
try {
|
|
4795
|
-
const { stderr } = await (0,
|
|
4914
|
+
const { stderr } = await (0, import_tinyexec2.exec)("git", args, { throwOnError: true });
|
|
4796
4915
|
if (`${stderr}`.includes("GH006")) {
|
|
4797
4916
|
return false;
|
|
4798
4917
|
}
|
|
@@ -4814,125 +4933,6 @@ function link2(text, url) {
|
|
|
4814
4933
|
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
4815
4934
|
}
|
|
4816
4935
|
|
|
4817
|
-
// src/ecosystem/rust.ts
|
|
4818
|
-
var import_promises2 = require("fs/promises");
|
|
4819
|
-
var import_node_path2 = __toESM(require("path"), 1);
|
|
4820
|
-
var import_smol_toml = require("smol-toml");
|
|
4821
|
-
var import_tinyexec2 = require("tinyexec");
|
|
4822
|
-
|
|
4823
|
-
// src/ecosystem/ecosystem.ts
|
|
4824
|
-
var Ecosystem = class {
|
|
4825
|
-
constructor(packagePath) {
|
|
4826
|
-
this.packagePath = packagePath;
|
|
4827
|
-
}
|
|
4828
|
-
};
|
|
4829
|
-
|
|
4830
|
-
// src/ecosystem/rust.ts
|
|
4831
|
-
var RustEcosystem = class extends Ecosystem {
|
|
4832
|
-
static async detect(packagePath) {
|
|
4833
|
-
try {
|
|
4834
|
-
return (await (0, import_promises2.stat)(import_node_path2.default.join(packagePath, "Cargo.toml"))).isFile();
|
|
4835
|
-
} catch {
|
|
4836
|
-
return false;
|
|
4837
|
-
}
|
|
4838
|
-
}
|
|
4839
|
-
async readCargoToml() {
|
|
4840
|
-
const raw = await (0, import_promises2.readFile)(
|
|
4841
|
-
import_node_path2.default.join(this.packagePath, "Cargo.toml"),
|
|
4842
|
-
"utf-8"
|
|
4843
|
-
);
|
|
4844
|
-
return (0, import_smol_toml.parse)(raw);
|
|
4845
|
-
}
|
|
4846
|
-
async packageName() {
|
|
4847
|
-
const cargo = await this.readCargoToml();
|
|
4848
|
-
const pkg = cargo.package;
|
|
4849
|
-
return pkg.name;
|
|
4850
|
-
}
|
|
4851
|
-
async readVersion() {
|
|
4852
|
-
const cargo = await this.readCargoToml();
|
|
4853
|
-
const pkg = cargo.package;
|
|
4854
|
-
return pkg.version;
|
|
4855
|
-
}
|
|
4856
|
-
async writeVersion(newVersion) {
|
|
4857
|
-
const filePath = import_node_path2.default.join(this.packagePath, "Cargo.toml");
|
|
4858
|
-
const raw = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
4859
|
-
const cargo = (0, import_smol_toml.parse)(raw);
|
|
4860
|
-
const pkg = cargo.package;
|
|
4861
|
-
pkg.version = newVersion;
|
|
4862
|
-
await (0, import_promises2.writeFile)(filePath, (0, import_smol_toml.stringify)(cargo));
|
|
4863
|
-
}
|
|
4864
|
-
/**
|
|
4865
|
-
* Update the `version` field of dependencies that match sibling crate names.
|
|
4866
|
-
* This ensures `cargo publish` works when crates depend on each other via path.
|
|
4867
|
-
*/
|
|
4868
|
-
async updateSiblingDependencyVersions(siblingVersions) {
|
|
4869
|
-
const filePath = import_node_path2.default.join(this.packagePath, "Cargo.toml");
|
|
4870
|
-
const raw = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
4871
|
-
const cargo = (0, import_smol_toml.parse)(raw);
|
|
4872
|
-
let modified = false;
|
|
4873
|
-
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4874
|
-
const sectionData = cargo[section];
|
|
4875
|
-
if (!sectionData) continue;
|
|
4876
|
-
for (const [depName, depValue] of Object.entries(sectionData)) {
|
|
4877
|
-
if (typeof depValue === "object" && depValue !== null && "path" in depValue && siblingVersions.has(depName)) {
|
|
4878
|
-
const dep = depValue;
|
|
4879
|
-
dep.version = siblingVersions.get(depName);
|
|
4880
|
-
modified = true;
|
|
4881
|
-
}
|
|
4882
|
-
}
|
|
4883
|
-
}
|
|
4884
|
-
if (modified) {
|
|
4885
|
-
await (0, import_promises2.writeFile)(filePath, (0, import_smol_toml.stringify)(cargo));
|
|
4886
|
-
}
|
|
4887
|
-
return modified;
|
|
4888
|
-
}
|
|
4889
|
-
async syncLockfile() {
|
|
4890
|
-
const lockfilePath = await this.findLockfile();
|
|
4891
|
-
if (!lockfilePath) return void 0;
|
|
4892
|
-
const name = await this.packageName();
|
|
4893
|
-
await (0, import_tinyexec2.exec)("cargo", ["update", "--package", name], {
|
|
4894
|
-
nodeOptions: { cwd: import_node_path2.default.dirname(lockfilePath) }
|
|
4895
|
-
});
|
|
4896
|
-
return lockfilePath;
|
|
4897
|
-
}
|
|
4898
|
-
async findLockfile() {
|
|
4899
|
-
let dir = this.packagePath;
|
|
4900
|
-
const { root } = import_node_path2.default.parse(dir);
|
|
4901
|
-
while (dir !== root) {
|
|
4902
|
-
const candidate = import_node_path2.default.join(dir, "Cargo.lock");
|
|
4903
|
-
try {
|
|
4904
|
-
if ((await (0, import_promises2.stat)(candidate)).isFile()) return candidate;
|
|
4905
|
-
} catch {
|
|
4906
|
-
}
|
|
4907
|
-
dir = import_node_path2.default.dirname(dir);
|
|
4908
|
-
}
|
|
4909
|
-
return void 0;
|
|
4910
|
-
}
|
|
4911
|
-
async dependencies() {
|
|
4912
|
-
const cargo = await this.readCargoToml();
|
|
4913
|
-
const deps = [];
|
|
4914
|
-
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4915
|
-
const sectionData = cargo[section];
|
|
4916
|
-
if (sectionData) {
|
|
4917
|
-
deps.push(...Object.keys(sectionData));
|
|
4918
|
-
}
|
|
4919
|
-
}
|
|
4920
|
-
return deps;
|
|
4921
|
-
}
|
|
4922
|
-
manifestFiles() {
|
|
4923
|
-
return ["Cargo.toml"];
|
|
4924
|
-
}
|
|
4925
|
-
defaultTestCommand() {
|
|
4926
|
-
return "cargo test";
|
|
4927
|
-
}
|
|
4928
|
-
defaultBuildCommand() {
|
|
4929
|
-
return "cargo build --release";
|
|
4930
|
-
}
|
|
4931
|
-
supportedRegistries() {
|
|
4932
|
-
return ["crates"];
|
|
4933
|
-
}
|
|
4934
|
-
};
|
|
4935
|
-
|
|
4936
4936
|
// src/utils/crate-graph.ts
|
|
4937
4937
|
async function sortCratesByDependencyOrder(cratePaths) {
|
|
4938
4938
|
if (cratePaths.length <= 1) return cratePaths;
|
|
@@ -5519,6 +5519,20 @@ ${stderr}` : "Failed to run `cargo publish --dry-run`";
|
|
|
5519
5519
|
throw new CratesError(message, { cause: error });
|
|
5520
5520
|
}
|
|
5521
5521
|
}
|
|
5522
|
+
async isVersionPublished(version2) {
|
|
5523
|
+
try {
|
|
5524
|
+
const response = await fetch(
|
|
5525
|
+
`${this.registry}/api/v1/crates/${this.packageName}/${version2}`,
|
|
5526
|
+
{ headers: this.headers }
|
|
5527
|
+
);
|
|
5528
|
+
return response.ok;
|
|
5529
|
+
} catch (error) {
|
|
5530
|
+
throw new CratesError(
|
|
5531
|
+
`Failed to check version ${version2} for '${this.packageName}' on crates.io`,
|
|
5532
|
+
{ cause: error }
|
|
5533
|
+
);
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5522
5536
|
async isPublished() {
|
|
5523
5537
|
try {
|
|
5524
5538
|
const response = await fetch(
|
|
@@ -5595,10 +5609,24 @@ function createCratesPublishTask(packagePath) {
|
|
|
5595
5609
|
const label = packagePath ? ` (${packagePath})` : "";
|
|
5596
5610
|
return {
|
|
5597
5611
|
title: `Publishing to crates.io${label}`,
|
|
5598
|
-
task: async () => {
|
|
5612
|
+
task: async (ctx, task) => {
|
|
5599
5613
|
const packageName = await getCrateName(packagePath);
|
|
5600
5614
|
const registry = new CratesRegistry(packageName);
|
|
5601
|
-
await registry.
|
|
5615
|
+
if (await registry.isVersionPublished(ctx.version)) {
|
|
5616
|
+
task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
|
|
5617
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
5618
|
+
return task.skip();
|
|
5619
|
+
}
|
|
5620
|
+
try {
|
|
5621
|
+
await registry.publish(packagePath);
|
|
5622
|
+
} catch (error) {
|
|
5623
|
+
if (error instanceof Error && error.message.includes("is already uploaded")) {
|
|
5624
|
+
task.title = `[SKIPPED] crates.io${label}: v${ctx.version} already published`;
|
|
5625
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
5626
|
+
return task.skip();
|
|
5627
|
+
}
|
|
5628
|
+
throw error;
|
|
5629
|
+
}
|
|
5602
5630
|
}
|
|
5603
5631
|
};
|
|
5604
5632
|
}
|
|
@@ -5770,6 +5798,20 @@ ${stderr}` : ""}`,
|
|
|
5770
5798
|
);
|
|
5771
5799
|
}
|
|
5772
5800
|
}
|
|
5801
|
+
async isVersionPublished(version2) {
|
|
5802
|
+
try {
|
|
5803
|
+
const [scope, name] = getScopeAndName(this.packageName);
|
|
5804
|
+
const response = await fetch(
|
|
5805
|
+
`${this.registry}/@${scope}/${name}/${version2}`
|
|
5806
|
+
);
|
|
5807
|
+
return response.status === 200;
|
|
5808
|
+
} catch (error) {
|
|
5809
|
+
throw new JsrError(
|
|
5810
|
+
`Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
|
|
5811
|
+
{ cause: error }
|
|
5812
|
+
);
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5773
5815
|
async hasPermission() {
|
|
5774
5816
|
return this.client.scopePermission(`${getScope(this.packageName)}`) !== null;
|
|
5775
5817
|
}
|
|
@@ -6044,6 +6086,19 @@ var NpmRegistry = class extends Registry {
|
|
|
6044
6086
|
);
|
|
6045
6087
|
}
|
|
6046
6088
|
}
|
|
6089
|
+
async isVersionPublished(version2) {
|
|
6090
|
+
try {
|
|
6091
|
+
const response = await fetch(
|
|
6092
|
+
`${this.registry}/${this.packageName}/${version2}`
|
|
6093
|
+
);
|
|
6094
|
+
return response.status === 200;
|
|
6095
|
+
} catch (error) {
|
|
6096
|
+
throw new NpmError(
|
|
6097
|
+
`Failed to fetch \`${this.registry}/${this.packageName}/${version2}\``,
|
|
6098
|
+
{ cause: error }
|
|
6099
|
+
);
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6047
6102
|
async userName() {
|
|
6048
6103
|
try {
|
|
6049
6104
|
return (await this.npm(["whoami"])).trim();
|
|
@@ -6249,20 +6304,30 @@ async function withTokenRetry(registryKey, task, action) {
|
|
|
6249
6304
|
}
|
|
6250
6305
|
var npmDryRunPublishTask = {
|
|
6251
6306
|
title: "Dry-run npm publish",
|
|
6252
|
-
task: async (
|
|
6307
|
+
task: async (ctx, task) => {
|
|
6308
|
+
const npm = await npmRegistry();
|
|
6309
|
+
if (await npm.isVersionPublished(ctx.version)) {
|
|
6310
|
+
task.title = `[SKIPPED] Dry-run npm publish: v${ctx.version} already published`;
|
|
6311
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6312
|
+
return task.skip();
|
|
6313
|
+
}
|
|
6253
6314
|
task.output = "Running npm publish --dry-run...";
|
|
6254
6315
|
await withTokenRetry("npm", task, async () => {
|
|
6255
|
-
const npm = await npmRegistry();
|
|
6256
6316
|
await npm.dryRunPublish();
|
|
6257
6317
|
});
|
|
6258
6318
|
}
|
|
6259
6319
|
};
|
|
6260
6320
|
var jsrDryRunPublishTask = {
|
|
6261
6321
|
title: "Dry-run jsr publish",
|
|
6262
|
-
task: async (
|
|
6322
|
+
task: async (ctx, task) => {
|
|
6323
|
+
const jsr = await jsrRegistry();
|
|
6324
|
+
if (await jsr.isVersionPublished(ctx.version)) {
|
|
6325
|
+
task.title = `[SKIPPED] Dry-run jsr publish: v${ctx.version} already published`;
|
|
6326
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6327
|
+
return task.skip();
|
|
6328
|
+
}
|
|
6263
6329
|
task.output = "Running jsr publish --dry-run...";
|
|
6264
6330
|
await withTokenRetry("jsr", task, async () => {
|
|
6265
|
-
const jsr = await jsrRegistry();
|
|
6266
6331
|
await jsr.dryRunPublish();
|
|
6267
6332
|
});
|
|
6268
6333
|
}
|
|
@@ -6271,17 +6336,58 @@ async function getCrateName2(packagePath) {
|
|
|
6271
6336
|
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6272
6337
|
return await eco.packageName();
|
|
6273
6338
|
}
|
|
6274
|
-
|
|
6339
|
+
var MISSING_CRATE_PATTERN = /no matching package named `([^`]+)` found/;
|
|
6340
|
+
async function findUnpublishedSiblingDeps(packagePath, siblingCrateNames) {
|
|
6341
|
+
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6342
|
+
const deps = await eco.dependencies();
|
|
6343
|
+
const siblingDeps = deps.filter((d2) => siblingCrateNames.includes(d2));
|
|
6344
|
+
const results = await Promise.all(
|
|
6345
|
+
siblingDeps.map(async (name) => {
|
|
6346
|
+
const registry = new CratesRegistry(name);
|
|
6347
|
+
const published = await registry.isPublished();
|
|
6348
|
+
return published ? null : name;
|
|
6349
|
+
})
|
|
6350
|
+
);
|
|
6351
|
+
return results.filter((name) => name !== null);
|
|
6352
|
+
}
|
|
6353
|
+
function createCratesDryRunPublishTask(packagePath, siblingCrateNames) {
|
|
6275
6354
|
const label = packagePath ? ` (${packagePath})` : "";
|
|
6276
6355
|
return {
|
|
6277
6356
|
title: `Dry-run crates.io publish${label}`,
|
|
6278
|
-
task: async (
|
|
6357
|
+
task: async (ctx, task) => {
|
|
6358
|
+
const packageName = await getCrateName2(packagePath);
|
|
6359
|
+
const registry = new CratesRegistry(packageName);
|
|
6360
|
+
if (await registry.isVersionPublished(ctx.version)) {
|
|
6361
|
+
task.title = `[SKIPPED] Dry-run crates.io publish${label}: v${ctx.version} already published`;
|
|
6362
|
+
task.output = `\u26A0 ${packageName}@${ctx.version} is already published on crates.io`;
|
|
6363
|
+
return task.skip();
|
|
6364
|
+
}
|
|
6365
|
+
if (siblingCrateNames?.length) {
|
|
6366
|
+
const unpublished = await findUnpublishedSiblingDeps(
|
|
6367
|
+
packagePath,
|
|
6368
|
+
siblingCrateNames
|
|
6369
|
+
);
|
|
6370
|
+
if (unpublished.length > 0) {
|
|
6371
|
+
task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${unpublished.join("`, `")}\` not yet published]`;
|
|
6372
|
+
return;
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6279
6375
|
task.output = "Running cargo publish --dry-run...";
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6376
|
+
try {
|
|
6377
|
+
await withTokenRetry("crates", task, async () => {
|
|
6378
|
+
const packageName2 = await getCrateName2(packagePath);
|
|
6379
|
+
const registry2 = new CratesRegistry(packageName2);
|
|
6380
|
+
await registry2.dryRunPublish(packagePath);
|
|
6381
|
+
});
|
|
6382
|
+
} catch (error) {
|
|
6383
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6384
|
+
const match = message.match(MISSING_CRATE_PATTERN);
|
|
6385
|
+
if (match && siblingCrateNames?.includes(match[1])) {
|
|
6386
|
+
task.title = `Dry-run crates.io publish${label} [skipped: sibling crate \`${match[1]}\` not yet published]`;
|
|
6387
|
+
return;
|
|
6388
|
+
}
|
|
6389
|
+
throw error;
|
|
6390
|
+
}
|
|
6285
6391
|
}
|
|
6286
6392
|
};
|
|
6287
6393
|
}
|
|
@@ -6462,48 +6568,62 @@ var jsrPublishTasks = {
|
|
|
6462
6568
|
title: "Running jsr publish",
|
|
6463
6569
|
task: async (ctx, task) => {
|
|
6464
6570
|
const jsr = await jsrRegistry();
|
|
6571
|
+
if (await jsr.isVersionPublished(ctx.version)) {
|
|
6572
|
+
task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
|
|
6573
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6574
|
+
return task.skip();
|
|
6575
|
+
}
|
|
6465
6576
|
task.output = "Publishing on jsr...";
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6577
|
+
try {
|
|
6578
|
+
if (!JsrClient.token && !ctx.promptEnabled) {
|
|
6579
|
+
const jsrTokenEnv = import_node_process6.default.env.JSR_TOKEN;
|
|
6580
|
+
if (!jsrTokenEnv) {
|
|
6581
|
+
throw new JsrAvailableError(
|
|
6582
|
+
"JSR_TOKEN not found in the environment variables. Please set the token and try again."
|
|
6583
|
+
);
|
|
6584
|
+
}
|
|
6585
|
+
JsrClient.token = jsrTokenEnv;
|
|
6472
6586
|
}
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
const maxAttempts = 3;
|
|
6481
|
-
task.output = `Package doesn't exist on jsr. Create it at:
|
|
6587
|
+
let result = await jsr.publish();
|
|
6588
|
+
if (!result && jsr.packageCreationUrls) {
|
|
6589
|
+
if (ctx.promptEnabled) {
|
|
6590
|
+
task.title = "Running jsr publish (package creation needed)";
|
|
6591
|
+
const urls = jsr.packageCreationUrls;
|
|
6592
|
+
const maxAttempts = 3;
|
|
6593
|
+
task.output = `Package doesn't exist on jsr. Create it at:
|
|
6482
6594
|
${urls.map((url) => ` ${color.cyan(url)}`).join("\n")}`;
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6595
|
+
open(urls[0]);
|
|
6596
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6597
|
+
await task.prompt(import_prompt_adapter_enquirer2.ListrEnquirerPromptAdapter).run({
|
|
6598
|
+
type: "input",
|
|
6599
|
+
message: `Press ${color.bold("enter")} after creating the package on jsr.io${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6600
|
+
});
|
|
6601
|
+
result = await jsr.publish();
|
|
6602
|
+
if (result) break;
|
|
6603
|
+
if (attempt < maxAttempts) {
|
|
6604
|
+
task.output = "Package still doesn't exist. Please create it and try again.";
|
|
6605
|
+
}
|
|
6493
6606
|
}
|
|
6494
|
-
|
|
6495
|
-
|
|
6607
|
+
if (!result) {
|
|
6608
|
+
throw new JsrAvailableError(
|
|
6609
|
+
"Package creation not completed after 3 attempts."
|
|
6610
|
+
);
|
|
6611
|
+
}
|
|
6612
|
+
task.title = "Running jsr publish (package created)";
|
|
6613
|
+
} else {
|
|
6496
6614
|
throw new JsrAvailableError(
|
|
6497
|
-
|
|
6615
|
+
`Package doesn't exist on jsr. Create it at:
|
|
6616
|
+
${jsr.packageCreationUrls.join("\n")}`
|
|
6498
6617
|
);
|
|
6499
6618
|
}
|
|
6500
|
-
task.title = "Running jsr publish (package created)";
|
|
6501
|
-
} else {
|
|
6502
|
-
throw new JsrAvailableError(
|
|
6503
|
-
`Package doesn't exist on jsr. Create it at:
|
|
6504
|
-
${jsr.packageCreationUrls.join("\n")}`
|
|
6505
|
-
);
|
|
6506
6619
|
}
|
|
6620
|
+
} catch (error) {
|
|
6621
|
+
if (error instanceof Error && error.message.includes("already published")) {
|
|
6622
|
+
task.title = `[SKIPPED] jsr: v${ctx.version} already published`;
|
|
6623
|
+
task.output = `\u26A0 ${jsr.packageName}@${ctx.version} is already published on jsr`;
|
|
6624
|
+
return task.skip();
|
|
6625
|
+
}
|
|
6626
|
+
throw error;
|
|
6507
6627
|
}
|
|
6508
6628
|
}
|
|
6509
6629
|
};
|
|
@@ -6600,44 +6720,62 @@ var npmPublishTasks = {
|
|
|
6600
6720
|
skip: (ctx) => !!ctx.preview,
|
|
6601
6721
|
task: async (ctx, task) => {
|
|
6602
6722
|
const npm = await npmRegistry();
|
|
6723
|
+
if (await npm.isVersionPublished(ctx.version)) {
|
|
6724
|
+
task.title = `[SKIPPED] npm: v${ctx.version} already published`;
|
|
6725
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6726
|
+
return task.skip();
|
|
6727
|
+
}
|
|
6603
6728
|
task.output = "Publishing on npm...";
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
await
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6729
|
+
try {
|
|
6730
|
+
if (ctx.promptEnabled) {
|
|
6731
|
+
let result = await npm.publish();
|
|
6732
|
+
if (!result) {
|
|
6733
|
+
task.title = "Running npm publish (OTP code needed)";
|
|
6734
|
+
const maxAttempts = 3;
|
|
6735
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6736
|
+
result = await npm.publish(
|
|
6737
|
+
await task.prompt(import_prompt_adapter_enquirer3.ListrEnquirerPromptAdapter).run({
|
|
6738
|
+
type: "password",
|
|
6739
|
+
message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6740
|
+
})
|
|
6741
|
+
);
|
|
6742
|
+
if (result) break;
|
|
6743
|
+
if (attempt < maxAttempts) {
|
|
6744
|
+
task.output = "2FA failed. Please try again.";
|
|
6745
|
+
}
|
|
6746
|
+
}
|
|
6747
|
+
if (!result) {
|
|
6748
|
+
throw new NpmAvailableError(
|
|
6749
|
+
"OTP verification failed after 3 attempts."
|
|
6750
|
+
);
|
|
6619
6751
|
}
|
|
6752
|
+
task.title = "Running npm publish (2FA passed)";
|
|
6753
|
+
}
|
|
6754
|
+
} else {
|
|
6755
|
+
const npmTokenEnv = import_node_process7.default.env.NODE_AUTH_TOKEN;
|
|
6756
|
+
if (!npmTokenEnv) {
|
|
6757
|
+
throw new NpmAvailableError(
|
|
6758
|
+
"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"
|
|
6759
|
+
);
|
|
6620
6760
|
}
|
|
6761
|
+
const result = await npm.publishProvenance();
|
|
6621
6762
|
if (!result) {
|
|
6622
6763
|
throw new NpmAvailableError(
|
|
6623
|
-
|
|
6764
|
+
`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 `
|
|
6624
6765
|
);
|
|
6625
6766
|
}
|
|
6626
|
-
task.title = "Running npm publish (2FA passed)";
|
|
6627
|
-
}
|
|
6628
|
-
} else {
|
|
6629
|
-
const npmTokenEnv = import_node_process7.default.env.NODE_AUTH_TOKEN;
|
|
6630
|
-
if (!npmTokenEnv) {
|
|
6631
|
-
throw new NpmAvailableError(
|
|
6632
|
-
"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"
|
|
6633
|
-
);
|
|
6634
6767
|
}
|
|
6635
|
-
|
|
6636
|
-
if (
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6768
|
+
} catch (error) {
|
|
6769
|
+
if (error instanceof Error && (error.message.includes(
|
|
6770
|
+
"cannot publish over the previously published"
|
|
6771
|
+
) || error.message.includes(
|
|
6772
|
+
"You cannot publish over the previously published"
|
|
6773
|
+
))) {
|
|
6774
|
+
task.title = `[SKIPPED] npm: v${ctx.version} already published`;
|
|
6775
|
+
task.output = `\u26A0 ${npm.packageName}@${ctx.version} is already published on npm`;
|
|
6776
|
+
return task.skip();
|
|
6640
6777
|
}
|
|
6778
|
+
throw error;
|
|
6641
6779
|
}
|
|
6642
6780
|
}
|
|
6643
6781
|
};
|
|
@@ -7128,10 +7266,15 @@ async function collectDryRunPublishTasks(ctx) {
|
|
|
7128
7266
|
return nonCratesTasks;
|
|
7129
7267
|
}
|
|
7130
7268
|
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
7269
|
+
const siblingCrateNames = await Promise.all(
|
|
7270
|
+
cratesPaths.map((p) => new RustEcosystem(p).packageName())
|
|
7271
|
+
);
|
|
7131
7272
|
const sequentialCratesTask = {
|
|
7132
7273
|
title: "Dry-run crates.io publish (sequential)",
|
|
7133
7274
|
task: (_ctx, task) => task.newListr(
|
|
7134
|
-
sortedPaths.map(
|
|
7275
|
+
sortedPaths.map(
|
|
7276
|
+
(p) => createCratesDryRunPublishTask(p, siblingCrateNames)
|
|
7277
|
+
),
|
|
7135
7278
|
{ concurrent: false }
|
|
7136
7279
|
)
|
|
7137
7280
|
};
|