pubm 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/bin/cli.js +660 -404
- package/dist/index.cjs +369 -151
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +368 -150
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4453,7 +4453,7 @@ var Listr = (_a23 = class {
|
|
|
4453
4453
|
// src/tasks/runner.ts
|
|
4454
4454
|
import SemVer from "semver";
|
|
4455
4455
|
import { isCI as isCI2 } from "std-env";
|
|
4456
|
-
import { exec as
|
|
4456
|
+
import { exec as exec8 } from "tinyexec";
|
|
4457
4457
|
|
|
4458
4458
|
// src/error.ts
|
|
4459
4459
|
var AbstractError = class extends Error {
|
|
@@ -5174,8 +5174,130 @@ function collectRegistries(ctx) {
|
|
|
5174
5174
|
return ctx.registries;
|
|
5175
5175
|
}
|
|
5176
5176
|
|
|
5177
|
-
// src/
|
|
5177
|
+
// src/utils/db.ts
|
|
5178
|
+
import { createCipheriv, createDecipheriv, createHash } from "node:crypto";
|
|
5179
|
+
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
5178
5180
|
import path4 from "node:path";
|
|
5181
|
+
var a = "aes-256-cbc";
|
|
5182
|
+
var n = statSync(import.meta.dirname);
|
|
5183
|
+
var k = `${n.rdev}${n.birthtimeMs}${n.nlink}${n.gid}`;
|
|
5184
|
+
var l = createHash("md5").update(k).digest();
|
|
5185
|
+
function e(e2, f) {
|
|
5186
|
+
const c = createCipheriv(a, createHash("sha-256").update(f).digest(), l);
|
|
5187
|
+
return c.update(e2, "utf8", "hex") + c.final("hex");
|
|
5188
|
+
}
|
|
5189
|
+
function d(g, h) {
|
|
5190
|
+
const d2 = createDecipheriv(a, createHash("sha-256").update(h).digest(), l);
|
|
5191
|
+
return d2.update(g, "hex", "utf8") + d2.final("utf8");
|
|
5192
|
+
}
|
|
5193
|
+
var Db = class {
|
|
5194
|
+
constructor() {
|
|
5195
|
+
__publicField(this, "path", path4.resolve(import.meta.dirname, ".pubm"));
|
|
5196
|
+
try {
|
|
5197
|
+
if (!statSync(this.path).isDirectory()) {
|
|
5198
|
+
mkdirSync(this.path);
|
|
5199
|
+
}
|
|
5200
|
+
} catch {
|
|
5201
|
+
try {
|
|
5202
|
+
mkdirSync(this.path);
|
|
5203
|
+
} catch (error) {
|
|
5204
|
+
throw new Error(
|
|
5205
|
+
`Failed to create token storage directory at '${this.path}': ${error instanceof Error ? error.message : error}`
|
|
5206
|
+
);
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
set(field, value) {
|
|
5211
|
+
try {
|
|
5212
|
+
writeFileSync(
|
|
5213
|
+
path4.resolve(
|
|
5214
|
+
this.path,
|
|
5215
|
+
Buffer.from(e(field, field)).toString("base64")
|
|
5216
|
+
),
|
|
5217
|
+
Buffer.from(e(`${value}`, field)),
|
|
5218
|
+
{ encoding: "binary" }
|
|
5219
|
+
);
|
|
5220
|
+
} catch (error) {
|
|
5221
|
+
throw new Error(
|
|
5222
|
+
`Failed to save token for '${field}': ${error instanceof Error ? error.message : error}`
|
|
5223
|
+
);
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
get(field) {
|
|
5227
|
+
const filePath = path4.resolve(
|
|
5228
|
+
this.path,
|
|
5229
|
+
Buffer.from(e(field, field)).toString("base64")
|
|
5230
|
+
);
|
|
5231
|
+
let raw;
|
|
5232
|
+
try {
|
|
5233
|
+
raw = readFileSync(filePath);
|
|
5234
|
+
} catch {
|
|
5235
|
+
return null;
|
|
5236
|
+
}
|
|
5237
|
+
try {
|
|
5238
|
+
return d(Buffer.from(raw).toString(), field);
|
|
5239
|
+
} catch {
|
|
5240
|
+
console.warn(
|
|
5241
|
+
`Stored token for '${field}' appears corrupted. It will be re-requested.`
|
|
5242
|
+
);
|
|
5243
|
+
return null;
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
};
|
|
5247
|
+
|
|
5248
|
+
// src/utils/token.ts
|
|
5249
|
+
var TOKEN_CONFIG = {
|
|
5250
|
+
npm: {
|
|
5251
|
+
envVar: "NODE_AUTH_TOKEN",
|
|
5252
|
+
dbKey: "npm-token",
|
|
5253
|
+
ghSecretName: "NODE_AUTH_TOKEN",
|
|
5254
|
+
promptLabel: "npm access token"
|
|
5255
|
+
},
|
|
5256
|
+
jsr: {
|
|
5257
|
+
envVar: "JSR_TOKEN",
|
|
5258
|
+
dbKey: "jsr-token",
|
|
5259
|
+
ghSecretName: "JSR_TOKEN",
|
|
5260
|
+
promptLabel: "jsr API token"
|
|
5261
|
+
},
|
|
5262
|
+
crates: {
|
|
5263
|
+
envVar: "CARGO_REGISTRY_TOKEN",
|
|
5264
|
+
dbKey: "cargo-token",
|
|
5265
|
+
ghSecretName: "CARGO_REGISTRY_TOKEN",
|
|
5266
|
+
promptLabel: "crates.io API token"
|
|
5267
|
+
}
|
|
5268
|
+
};
|
|
5269
|
+
function loadTokensFromDb(registries) {
|
|
5270
|
+
const db = new Db();
|
|
5271
|
+
const tokens = {};
|
|
5272
|
+
for (const registry of registries) {
|
|
5273
|
+
const config = TOKEN_CONFIG[registry];
|
|
5274
|
+
if (!config) continue;
|
|
5275
|
+
const token = db.get(config.dbKey);
|
|
5276
|
+
if (token) tokens[registry] = token;
|
|
5277
|
+
}
|
|
5278
|
+
return tokens;
|
|
5279
|
+
}
|
|
5280
|
+
function injectTokensToEnv(tokens) {
|
|
5281
|
+
const originals = {};
|
|
5282
|
+
for (const [registry, token] of Object.entries(tokens)) {
|
|
5283
|
+
const config = TOKEN_CONFIG[registry];
|
|
5284
|
+
if (!config) continue;
|
|
5285
|
+
originals[config.envVar] = process.env[config.envVar];
|
|
5286
|
+
process.env[config.envVar] = token;
|
|
5287
|
+
}
|
|
5288
|
+
return () => {
|
|
5289
|
+
for (const [envVar, original] of Object.entries(originals)) {
|
|
5290
|
+
if (original === void 0) {
|
|
5291
|
+
delete process.env[envVar];
|
|
5292
|
+
} else {
|
|
5293
|
+
process.env[envVar] = original;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
};
|
|
5297
|
+
}
|
|
5298
|
+
|
|
5299
|
+
// src/registry/crates.ts
|
|
5300
|
+
import path5 from "node:path";
|
|
5179
5301
|
import { exec as exec3, NonZeroExitError } from "tinyexec";
|
|
5180
5302
|
|
|
5181
5303
|
// src/registry/registry.ts
|
|
@@ -5255,7 +5377,7 @@ var CratesRegistry = class extends Registry {
|
|
|
5255
5377
|
try {
|
|
5256
5378
|
const args = ["publish"];
|
|
5257
5379
|
if (manifestDir) {
|
|
5258
|
-
args.push("--manifest-path",
|
|
5380
|
+
args.push("--manifest-path", path5.join(manifestDir, "Cargo.toml"));
|
|
5259
5381
|
}
|
|
5260
5382
|
await exec3("cargo", args, { throwOnError: true });
|
|
5261
5383
|
return true;
|
|
@@ -5270,13 +5392,13 @@ ${stderr}` : "Failed to run `cargo publish`";
|
|
|
5270
5392
|
try {
|
|
5271
5393
|
const args = ["publish", "--dry-run"];
|
|
5272
5394
|
if (manifestDir) {
|
|
5273
|
-
args.push("--manifest-path",
|
|
5395
|
+
args.push("--manifest-path", path5.join(manifestDir, "Cargo.toml"));
|
|
5274
5396
|
}
|
|
5275
5397
|
await exec3("cargo", args, { throwOnError: true });
|
|
5276
5398
|
} catch (error) {
|
|
5277
5399
|
const stderr = error instanceof NonZeroExitError ? error.output?.stderr : void 0;
|
|
5278
|
-
const message = stderr ? `
|
|
5279
|
-
${stderr}` : "
|
|
5400
|
+
const message = stderr ? `Failed to run \`cargo publish --dry-run\`:
|
|
5401
|
+
${stderr}` : "Failed to run `cargo publish --dry-run`";
|
|
5280
5402
|
throw new CratesError(message, { cause: error });
|
|
5281
5403
|
}
|
|
5282
5404
|
}
|
|
@@ -5366,80 +5488,12 @@ function createCratesPublishTask(packagePath) {
|
|
|
5366
5488
|
var cratesAvailableCheckTasks = createCratesAvailableCheckTask();
|
|
5367
5489
|
var cratesPublishTasks = createCratesPublishTask();
|
|
5368
5490
|
|
|
5491
|
+
// src/tasks/dry-run-publish.ts
|
|
5492
|
+
import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
|
|
5493
|
+
|
|
5369
5494
|
// src/registry/jsr.ts
|
|
5370
5495
|
import { exec as exec4, NonZeroExitError as NonZeroExitError2 } from "tinyexec";
|
|
5371
5496
|
|
|
5372
|
-
// src/utils/db.ts
|
|
5373
|
-
import { createCipheriv, createDecipheriv, createHash } from "node:crypto";
|
|
5374
|
-
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
5375
|
-
import path5 from "node:path";
|
|
5376
|
-
var a = "aes-256-cbc";
|
|
5377
|
-
var n = statSync(import.meta.dirname);
|
|
5378
|
-
var k = `${n.rdev}${n.birthtimeMs}${n.nlink}${n.gid}`;
|
|
5379
|
-
var l = createHash("md5").update(k).digest();
|
|
5380
|
-
function e(e2, f) {
|
|
5381
|
-
const c = createCipheriv(a, createHash("sha-256").update(f).digest(), l);
|
|
5382
|
-
return c.update(e2, "utf8", "hex") + c.final("hex");
|
|
5383
|
-
}
|
|
5384
|
-
function d(g, h) {
|
|
5385
|
-
const d2 = createDecipheriv(a, createHash("sha-256").update(h).digest(), l);
|
|
5386
|
-
return d2.update(g, "hex", "utf8") + d2.final("utf8");
|
|
5387
|
-
}
|
|
5388
|
-
var Db = class {
|
|
5389
|
-
constructor() {
|
|
5390
|
-
__publicField(this, "path", path5.resolve(import.meta.dirname, ".pubm"));
|
|
5391
|
-
try {
|
|
5392
|
-
if (!statSync(this.path).isDirectory()) {
|
|
5393
|
-
mkdirSync(this.path);
|
|
5394
|
-
}
|
|
5395
|
-
} catch {
|
|
5396
|
-
try {
|
|
5397
|
-
mkdirSync(this.path);
|
|
5398
|
-
} catch (error) {
|
|
5399
|
-
throw new Error(
|
|
5400
|
-
`Failed to create token storage directory at '${this.path}': ${error instanceof Error ? error.message : error}`
|
|
5401
|
-
);
|
|
5402
|
-
}
|
|
5403
|
-
}
|
|
5404
|
-
}
|
|
5405
|
-
set(field, value) {
|
|
5406
|
-
try {
|
|
5407
|
-
writeFileSync(
|
|
5408
|
-
path5.resolve(
|
|
5409
|
-
this.path,
|
|
5410
|
-
Buffer.from(e(field, field)).toString("base64")
|
|
5411
|
-
),
|
|
5412
|
-
Buffer.from(e(`${value}`, field)),
|
|
5413
|
-
{ encoding: "binary" }
|
|
5414
|
-
);
|
|
5415
|
-
} catch (error) {
|
|
5416
|
-
throw new Error(
|
|
5417
|
-
`Failed to save token for '${field}': ${error instanceof Error ? error.message : error}`
|
|
5418
|
-
);
|
|
5419
|
-
}
|
|
5420
|
-
}
|
|
5421
|
-
get(field) {
|
|
5422
|
-
const filePath = path5.resolve(
|
|
5423
|
-
this.path,
|
|
5424
|
-
Buffer.from(e(field, field)).toString("base64")
|
|
5425
|
-
);
|
|
5426
|
-
let raw;
|
|
5427
|
-
try {
|
|
5428
|
-
raw = readFileSync(filePath);
|
|
5429
|
-
} catch {
|
|
5430
|
-
return null;
|
|
5431
|
-
}
|
|
5432
|
-
try {
|
|
5433
|
-
return d(Buffer.from(raw).toString(), field);
|
|
5434
|
-
} catch {
|
|
5435
|
-
console.warn(
|
|
5436
|
-
`Stored token for '${field}' appears corrupted. It will be re-requested.`
|
|
5437
|
-
);
|
|
5438
|
-
return null;
|
|
5439
|
-
}
|
|
5440
|
-
}
|
|
5441
|
-
};
|
|
5442
|
-
|
|
5443
5497
|
// src/utils/package-name.ts
|
|
5444
5498
|
import { builtinModules } from "node:module";
|
|
5445
5499
|
function isScopedPackage(packageName) {
|
|
@@ -5579,12 +5633,9 @@ ${stderr}` : ""}`,
|
|
|
5579
5633
|
{ throwOnError: true }
|
|
5580
5634
|
);
|
|
5581
5635
|
} catch (error) {
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
${stderr}` : ""}`,
|
|
5586
|
-
{ cause: error }
|
|
5587
|
-
);
|
|
5636
|
+
throw new JsrError("Failed to run `jsr publish --dry-run`", {
|
|
5637
|
+
cause: error
|
|
5638
|
+
});
|
|
5588
5639
|
}
|
|
5589
5640
|
}
|
|
5590
5641
|
async version() {
|
|
@@ -5985,7 +6036,9 @@ var NpmRegistry = class extends Registry {
|
|
|
5985
6036
|
try {
|
|
5986
6037
|
await this.npm(["publish", "--dry-run"]);
|
|
5987
6038
|
} catch (error) {
|
|
5988
|
-
throw
|
|
6039
|
+
throw new NpmError("Failed to run `npm publish --dry-run`", {
|
|
6040
|
+
cause: error
|
|
6041
|
+
});
|
|
5989
6042
|
}
|
|
5990
6043
|
}
|
|
5991
6044
|
async twoFactorAuthMode() {
|
|
@@ -6034,69 +6087,78 @@ async function npmRegistry() {
|
|
|
6034
6087
|
}
|
|
6035
6088
|
|
|
6036
6089
|
// src/tasks/dry-run-publish.ts
|
|
6090
|
+
var AUTH_ERROR_PATTERNS = [
|
|
6091
|
+
/401/i,
|
|
6092
|
+
/403/i,
|
|
6093
|
+
/unauthorized/i,
|
|
6094
|
+
/forbidden/i,
|
|
6095
|
+
/invalid.token/i,
|
|
6096
|
+
/eotp/i
|
|
6097
|
+
];
|
|
6098
|
+
function isAuthError(error) {
|
|
6099
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6100
|
+
return AUTH_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
6101
|
+
}
|
|
6102
|
+
async function withTokenRetry(registryKey, task, action) {
|
|
6103
|
+
try {
|
|
6104
|
+
await action();
|
|
6105
|
+
} catch (error) {
|
|
6106
|
+
if (!isAuthError(error)) throw error;
|
|
6107
|
+
const config = TOKEN_CONFIG[registryKey];
|
|
6108
|
+
if (!config) throw error;
|
|
6109
|
+
task.output = `Auth failed. Re-enter ${config.promptLabel}`;
|
|
6110
|
+
const newToken = await task.prompt(ListrEnquirerPromptAdapter).run({
|
|
6111
|
+
type: "password",
|
|
6112
|
+
message: `Re-enter ${config.promptLabel}`
|
|
6113
|
+
});
|
|
6114
|
+
new Db().set(config.dbKey, newToken);
|
|
6115
|
+
process.env[config.envVar] = newToken;
|
|
6116
|
+
await action();
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6037
6119
|
var npmDryRunPublishTask = {
|
|
6038
6120
|
title: "Dry-run npm publish",
|
|
6039
6121
|
task: async (_, task) => {
|
|
6040
|
-
const npm = await npmRegistry();
|
|
6041
6122
|
task.output = "Running npm publish --dry-run...";
|
|
6042
|
-
await npm
|
|
6123
|
+
await withTokenRetry("npm", task, async () => {
|
|
6124
|
+
const npm = await npmRegistry();
|
|
6125
|
+
await npm.dryRunPublish();
|
|
6126
|
+
});
|
|
6043
6127
|
}
|
|
6044
6128
|
};
|
|
6045
6129
|
var jsrDryRunPublishTask = {
|
|
6046
6130
|
title: "Dry-run jsr publish",
|
|
6047
|
-
skip: () => !JsrClient.token,
|
|
6048
6131
|
task: async (_, task) => {
|
|
6049
|
-
const jsr = await jsrRegistry();
|
|
6050
6132
|
task.output = "Running jsr publish --dry-run...";
|
|
6051
|
-
await jsr
|
|
6133
|
+
await withTokenRetry("jsr", task, async () => {
|
|
6134
|
+
const jsr = await jsrRegistry();
|
|
6135
|
+
await jsr.dryRunPublish();
|
|
6136
|
+
});
|
|
6052
6137
|
}
|
|
6053
6138
|
};
|
|
6139
|
+
async function getCrateName2(packagePath) {
|
|
6140
|
+
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6141
|
+
return await eco.packageName();
|
|
6142
|
+
}
|
|
6054
6143
|
function createCratesDryRunPublishTask(packagePath) {
|
|
6055
6144
|
const label = packagePath ? ` (${packagePath})` : "";
|
|
6056
6145
|
return {
|
|
6057
|
-
title: `Dry-run
|
|
6146
|
+
title: `Dry-run crates.io publish${label}`,
|
|
6058
6147
|
task: async (_, task) => {
|
|
6059
|
-
const eco = new RustEcosystem(packagePath ?? process.cwd());
|
|
6060
|
-
const packageName = await eco.packageName();
|
|
6061
|
-
const registry = new CratesRegistry(packageName);
|
|
6062
6148
|
task.output = "Running cargo publish --dry-run...";
|
|
6063
|
-
await
|
|
6149
|
+
await withTokenRetry("crates", task, async () => {
|
|
6150
|
+
const packageName = await getCrateName2(packagePath);
|
|
6151
|
+
const registry = new CratesRegistry(packageName);
|
|
6152
|
+
await registry.dryRunPublish(packagePath);
|
|
6153
|
+
});
|
|
6064
6154
|
}
|
|
6065
6155
|
};
|
|
6066
6156
|
}
|
|
6067
6157
|
var cratesDryRunPublishTask = createCratesDryRunPublishTask();
|
|
6068
|
-
function registryDryRunTask(registryKey) {
|
|
6069
|
-
switch (registryKey) {
|
|
6070
|
-
case "npm":
|
|
6071
|
-
return npmDryRunPublishTask;
|
|
6072
|
-
case "jsr":
|
|
6073
|
-
return jsrDryRunPublishTask;
|
|
6074
|
-
case "crates":
|
|
6075
|
-
return cratesDryRunPublishTask;
|
|
6076
|
-
default:
|
|
6077
|
-
return npmDryRunPublishTask;
|
|
6078
|
-
}
|
|
6079
|
-
}
|
|
6080
|
-
var dryRunPublishTask = {
|
|
6081
|
-
title: "Validating publish (dry-run)",
|
|
6082
|
-
task: (ctx, parentTask) => {
|
|
6083
|
-
if (ctx.packages?.length) {
|
|
6084
|
-
const tasks = ctx.packages.flatMap(
|
|
6085
|
-
(pkg) => pkg.registries.map(
|
|
6086
|
-
(registryKey) => registryKey === "crates" ? createCratesDryRunPublishTask(pkg.path) : registryDryRunTask(registryKey)
|
|
6087
|
-
)
|
|
6088
|
-
);
|
|
6089
|
-
return parentTask.newListr(tasks, { concurrent: true });
|
|
6090
|
-
}
|
|
6091
|
-
return parentTask.newListr(collectRegistries(ctx).map(registryDryRunTask), {
|
|
6092
|
-
concurrent: true
|
|
6093
|
-
});
|
|
6094
|
-
}
|
|
6095
|
-
};
|
|
6096
6158
|
|
|
6097
6159
|
// src/tasks/jsr.ts
|
|
6098
6160
|
import process8 from "node:process";
|
|
6099
|
-
import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
|
|
6161
|
+
import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter2 } from "@listr2/prompt-adapter-enquirer";
|
|
6100
6162
|
import npmCli from "@npmcli/promise-spawn";
|
|
6101
6163
|
var { open } = npmCli;
|
|
6102
6164
|
var JsrAvailableError = class extends AbstractError {
|
|
@@ -6125,7 +6187,7 @@ var jsrAvailableCheckTasks = {
|
|
|
6125
6187
|
if (ctx.promptEnabled) {
|
|
6126
6188
|
const maxAttempts = 3;
|
|
6127
6189
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6128
|
-
JsrClient.token = await task.prompt(
|
|
6190
|
+
JsrClient.token = await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6129
6191
|
type: "password",
|
|
6130
6192
|
message: `Please enter the jsr ${color.bold("API token")}${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`,
|
|
6131
6193
|
footer: `
|
|
@@ -6175,7 +6237,7 @@ Generate a token from ${color.bold(link2("jsr.io", "https://jsr.io/account/token
|
|
|
6175
6237
|
)
|
|
6176
6238
|
)).filter((v) => v !== null);
|
|
6177
6239
|
if (searchResults.length > 0) {
|
|
6178
|
-
jsrName = await task.prompt(
|
|
6240
|
+
jsrName = await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6179
6241
|
type: "select",
|
|
6180
6242
|
message: "Is there a scoped package you want to publish in the already published list?",
|
|
6181
6243
|
choices: [
|
|
@@ -6193,7 +6255,7 @@ Generate a token from ${color.bold(link2("jsr.io", "https://jsr.io/account/token
|
|
|
6193
6255
|
}
|
|
6194
6256
|
const userName = await new Git().userName();
|
|
6195
6257
|
task.output = "Select the scope of the package to publish";
|
|
6196
|
-
jsrName = await task.prompt(
|
|
6258
|
+
jsrName = await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6197
6259
|
type: "select",
|
|
6198
6260
|
message: "jsr.json does not exist, and the package name is not scoped. Please select a scope for the 'jsr' package",
|
|
6199
6261
|
choices: [
|
|
@@ -6221,7 +6283,7 @@ Generate a token from ${color.bold(link2("jsr.io", "https://jsr.io/account/token
|
|
|
6221
6283
|
});
|
|
6222
6284
|
if (jsrName === "specify") {
|
|
6223
6285
|
while (!isScopedPackage(jsrName)) {
|
|
6224
|
-
jsrName = await task.prompt(
|
|
6286
|
+
jsrName = await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6225
6287
|
type: "input",
|
|
6226
6288
|
message: "Package name"
|
|
6227
6289
|
});
|
|
@@ -6289,7 +6351,7 @@ var jsrPublishTasks = {
|
|
|
6289
6351
|
${urls.map((url) => ` ${color.cyan(url)}`).join("\n")}`;
|
|
6290
6352
|
open(urls[0]);
|
|
6291
6353
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6292
|
-
await task.prompt(
|
|
6354
|
+
await task.prompt(ListrEnquirerPromptAdapter2).run({
|
|
6293
6355
|
type: "input",
|
|
6294
6356
|
message: `Press ${color.bold("enter")} after creating the package on jsr.io${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6295
6357
|
});
|
|
@@ -6318,7 +6380,7 @@ ${jsr.packageCreationUrls.join("\n")}`
|
|
|
6318
6380
|
// src/tasks/npm.ts
|
|
6319
6381
|
import { spawn } from "node:child_process";
|
|
6320
6382
|
import process9 from "node:process";
|
|
6321
|
-
import { ListrEnquirerPromptAdapter as
|
|
6383
|
+
import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter3 } from "@listr2/prompt-adapter-enquirer";
|
|
6322
6384
|
import npmCli2 from "@npmcli/promise-spawn";
|
|
6323
6385
|
var { open: open2 } = npmCli2;
|
|
6324
6386
|
var NpmAvailableError = class extends AbstractError {
|
|
@@ -6415,7 +6477,7 @@ var npmPublishTasks = {
|
|
|
6415
6477
|
const maxAttempts = 3;
|
|
6416
6478
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
6417
6479
|
result = await npm.publish(
|
|
6418
|
-
await task.prompt(
|
|
6480
|
+
await task.prompt(ListrEnquirerPromptAdapter3).run({
|
|
6419
6481
|
type: "password",
|
|
6420
6482
|
message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
|
|
6421
6483
|
})
|
|
@@ -6449,8 +6511,64 @@ var npmPublishTasks = {
|
|
|
6449
6511
|
}
|
|
6450
6512
|
};
|
|
6451
6513
|
|
|
6514
|
+
// src/tasks/preflight.ts
|
|
6515
|
+
import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter4 } from "@listr2/prompt-adapter-enquirer";
|
|
6516
|
+
import { exec as exec6 } from "tinyexec";
|
|
6517
|
+
var PreflightError = class extends AbstractError {
|
|
6518
|
+
constructor() {
|
|
6519
|
+
super(...arguments);
|
|
6520
|
+
__publicField(this, "name", "Preflight Error");
|
|
6521
|
+
}
|
|
6522
|
+
};
|
|
6523
|
+
async function collectTokens(registries, task) {
|
|
6524
|
+
const existing = loadTokensFromDb(registries);
|
|
6525
|
+
const tokens = { ...existing };
|
|
6526
|
+
for (const registry of registries) {
|
|
6527
|
+
const config = TOKEN_CONFIG[registry];
|
|
6528
|
+
if (!config || tokens[registry]) continue;
|
|
6529
|
+
task.output = `Enter ${config.promptLabel}`;
|
|
6530
|
+
const token = await task.prompt(ListrEnquirerPromptAdapter4).run({
|
|
6531
|
+
type: "password",
|
|
6532
|
+
message: `Enter ${config.promptLabel}`
|
|
6533
|
+
});
|
|
6534
|
+
tokens[registry] = token;
|
|
6535
|
+
new Db().set(config.dbKey, token);
|
|
6536
|
+
}
|
|
6537
|
+
return tokens;
|
|
6538
|
+
}
|
|
6539
|
+
async function syncGhSecrets(tokens) {
|
|
6540
|
+
for (const [registry, token] of Object.entries(tokens)) {
|
|
6541
|
+
const config = TOKEN_CONFIG[registry];
|
|
6542
|
+
if (!config) continue;
|
|
6543
|
+
await exec6("gh", ["secret", "set", config.ghSecretName], {
|
|
6544
|
+
throwOnError: true,
|
|
6545
|
+
nodeOptions: { input: token }
|
|
6546
|
+
});
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
async function promptGhSecretsSync(tokens, task) {
|
|
6550
|
+
const shouldSync = await task.prompt(ListrEnquirerPromptAdapter4).run({
|
|
6551
|
+
type: "toggle",
|
|
6552
|
+
message: "Sync tokens to GitHub Secrets?",
|
|
6553
|
+
enabled: "Yes",
|
|
6554
|
+
disabled: "No"
|
|
6555
|
+
});
|
|
6556
|
+
if (shouldSync) {
|
|
6557
|
+
task.output = "Syncing tokens to GitHub Secrets...";
|
|
6558
|
+
try {
|
|
6559
|
+
await syncGhSecrets(tokens);
|
|
6560
|
+
task.output = "Tokens synced to GitHub Secrets.";
|
|
6561
|
+
} catch (error) {
|
|
6562
|
+
throw new PreflightError(
|
|
6563
|
+
"Failed to sync tokens to GitHub Secrets. Ensure `gh` CLI is installed and authenticated (`gh auth login`).",
|
|
6564
|
+
{ cause: error }
|
|
6565
|
+
);
|
|
6566
|
+
}
|
|
6567
|
+
}
|
|
6568
|
+
}
|
|
6569
|
+
|
|
6452
6570
|
// src/tasks/prerequisites-check.ts
|
|
6453
|
-
import { ListrEnquirerPromptAdapter as
|
|
6571
|
+
import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter5 } from "@listr2/prompt-adapter-enquirer";
|
|
6454
6572
|
var PrerequisitesCheckError = class extends AbstractError {
|
|
6455
6573
|
constructor(message, { cause } = {}) {
|
|
6456
6574
|
super(message, { cause });
|
|
@@ -6470,7 +6588,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6470
6588
|
title: "Verifying current branch is a release branch",
|
|
6471
6589
|
task: async (ctx, task) => {
|
|
6472
6590
|
if (await git.branch() !== ctx.branch) {
|
|
6473
|
-
const swtichBranch = await task.prompt(
|
|
6591
|
+
const swtichBranch = await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6474
6592
|
type: "toggle",
|
|
6475
6593
|
message: `${warningBadge} The current HEAD branch is not the release target branch. Do you want to switch branch to ${ctx.branch}?`,
|
|
6476
6594
|
enabled: "Yes",
|
|
@@ -6492,7 +6610,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6492
6610
|
task: async (_2, task) => {
|
|
6493
6611
|
task.output = "Checking for updates with `git fetch`";
|
|
6494
6612
|
if ((await git.dryFetch()).trim()) {
|
|
6495
|
-
const fetch2 = await task.prompt(
|
|
6613
|
+
const fetch2 = await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6496
6614
|
type: "toggle",
|
|
6497
6615
|
message: `${warningBadge} Local history is outdated. Do you want to run \`git fetch\`?`,
|
|
6498
6616
|
enabled: "Yes",
|
|
@@ -6509,7 +6627,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6509
6627
|
}
|
|
6510
6628
|
task.output = "Checking for updates with `git pull`";
|
|
6511
6629
|
if (await git.revisionDiffsCount()) {
|
|
6512
|
-
const pull = await task.prompt(
|
|
6630
|
+
const pull = await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6513
6631
|
type: "toggle",
|
|
6514
6632
|
message: `${warningBadge} Local history is outdated. Do you want to run \`git pull\`?`,
|
|
6515
6633
|
enabled: "Yes",
|
|
@@ -6531,7 +6649,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6531
6649
|
task: async (ctx, task) => {
|
|
6532
6650
|
if (await git.status()) {
|
|
6533
6651
|
task.output = "Local working tree is not clean.";
|
|
6534
|
-
if (!await task.prompt(
|
|
6652
|
+
if (!await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6535
6653
|
type: "toggle",
|
|
6536
6654
|
message: `${warningBadge} Local working tree is not clean. Do you want to skip?`,
|
|
6537
6655
|
enabled: "Yes",
|
|
@@ -6556,7 +6674,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6556
6674
|
return void 0;
|
|
6557
6675
|
}
|
|
6558
6676
|
if ((await git.commits(latestTag, "HEAD")).length <= 0) {
|
|
6559
|
-
if (!await task.prompt(
|
|
6677
|
+
if (!await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6560
6678
|
type: "toggle",
|
|
6561
6679
|
message: `${warningBadge} No commits exist from the latest tag. Do you want to skip?`,
|
|
6562
6680
|
enabled: "Yes",
|
|
@@ -6574,7 +6692,7 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6574
6692
|
task: async (ctx, task) => {
|
|
6575
6693
|
const gitTag = `v${ctx.version}`;
|
|
6576
6694
|
if (await git.checkTagExist(gitTag)) {
|
|
6577
|
-
const deleteTag = await task.prompt(
|
|
6695
|
+
const deleteTag = await task.prompt(ListrEnquirerPromptAdapter5).run({
|
|
6578
6696
|
type: "toggle",
|
|
6579
6697
|
message: `${warningBadge} The Git tag '${gitTag}' already exists. Do you want to delete tag?`,
|
|
6580
6698
|
enabled: "Yes",
|
|
@@ -6596,13 +6714,13 @@ var prerequisitesCheckTask = (options) => {
|
|
|
6596
6714
|
};
|
|
6597
6715
|
|
|
6598
6716
|
// src/tasks/required-conditions-check.ts
|
|
6599
|
-
import { ListrEnquirerPromptAdapter as
|
|
6717
|
+
import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter6 } from "@listr2/prompt-adapter-enquirer";
|
|
6600
6718
|
|
|
6601
6719
|
// src/registry/custom-registry.ts
|
|
6602
|
-
import { exec as
|
|
6720
|
+
import { exec as exec7 } from "tinyexec";
|
|
6603
6721
|
var CustomRegistry = class extends NpmRegistry {
|
|
6604
6722
|
async npm(args) {
|
|
6605
|
-
const { stdout } = await
|
|
6723
|
+
const { stdout } = await exec7(
|
|
6606
6724
|
"npm",
|
|
6607
6725
|
args.concat("--registry", this.registry),
|
|
6608
6726
|
{ throwOnError: true }
|
|
@@ -6704,7 +6822,7 @@ var requiredConditionsCheckTask = (options) => createListr({
|
|
|
6704
6822
|
task: async (_3, task) => {
|
|
6705
6823
|
const jsr = await jsrRegistry();
|
|
6706
6824
|
if (!await jsr.isInstalled()) {
|
|
6707
|
-
const install = await task.prompt(
|
|
6825
|
+
const install = await task.prompt(ListrEnquirerPromptAdapter6).run({
|
|
6708
6826
|
type: "toggle",
|
|
6709
6827
|
message: `${warningBadge} jsr is not installed. Do you want to install jsr?`,
|
|
6710
6828
|
enabled: "Yes",
|
|
@@ -6838,14 +6956,66 @@ async function collectPublishTasks(ctx) {
|
|
|
6838
6956
|
}
|
|
6839
6957
|
return collectRegistries(ctx).map(registryTask);
|
|
6840
6958
|
}
|
|
6959
|
+
function dryRunRegistryTask(registry) {
|
|
6960
|
+
switch (registry) {
|
|
6961
|
+
case "npm":
|
|
6962
|
+
return npmDryRunPublishTask;
|
|
6963
|
+
case "jsr":
|
|
6964
|
+
return jsrDryRunPublishTask;
|
|
6965
|
+
case "crates":
|
|
6966
|
+
return cratesDryRunPublishTask;
|
|
6967
|
+
default:
|
|
6968
|
+
return npmDryRunPublishTask;
|
|
6969
|
+
}
|
|
6970
|
+
}
|
|
6971
|
+
async function collectDryRunPublishTasks(ctx) {
|
|
6972
|
+
if (ctx.packages?.length) {
|
|
6973
|
+
const nonCratesTasks = ctx.packages.flatMap(
|
|
6974
|
+
(pkg) => pkg.registries.filter((reg) => reg !== "crates").map((reg) => dryRunRegistryTask(reg))
|
|
6975
|
+
);
|
|
6976
|
+
const cratesPaths = ctx.packages.filter((pkg) => pkg.registries.includes("crates")).map((pkg) => pkg.path);
|
|
6977
|
+
if (cratesPaths.length === 0) {
|
|
6978
|
+
return nonCratesTasks;
|
|
6979
|
+
}
|
|
6980
|
+
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
6981
|
+
const sequentialCratesTask = {
|
|
6982
|
+
title: "Dry-run crates.io publish (sequential)",
|
|
6983
|
+
task: (_ctx, task) => task.newListr(
|
|
6984
|
+
sortedPaths.map((p) => createCratesDryRunPublishTask(p)),
|
|
6985
|
+
{ concurrent: false }
|
|
6986
|
+
)
|
|
6987
|
+
};
|
|
6988
|
+
return [...nonCratesTasks, sequentialCratesTask];
|
|
6989
|
+
}
|
|
6990
|
+
return collectRegistries(ctx).map(dryRunRegistryTask);
|
|
6991
|
+
}
|
|
6841
6992
|
async function run(options) {
|
|
6842
6993
|
const ctx = {
|
|
6843
6994
|
...options,
|
|
6844
6995
|
promptEnabled: !isCI2 && process10.stdin.isTTY
|
|
6845
6996
|
};
|
|
6997
|
+
let cleanupEnv;
|
|
6846
6998
|
try {
|
|
6847
6999
|
if (options.contents) process10.chdir(options.contents);
|
|
6848
|
-
if (
|
|
7000
|
+
if (options.preflight) {
|
|
7001
|
+
await createListr({
|
|
7002
|
+
title: "Collecting registry tokens",
|
|
7003
|
+
task: async (ctx2, task) => {
|
|
7004
|
+
const registries2 = collectRegistries(ctx2);
|
|
7005
|
+
const tokens = await collectTokens(registries2, task);
|
|
7006
|
+
await promptGhSecretsSync(tokens, task);
|
|
7007
|
+
cleanupEnv = injectTokensToEnv(tokens);
|
|
7008
|
+
ctx2.promptEnabled = false;
|
|
7009
|
+
}
|
|
7010
|
+
}).run(ctx);
|
|
7011
|
+
await prerequisitesCheckTask({
|
|
7012
|
+
skip: options.skipPrerequisitesCheck
|
|
7013
|
+
}).run(ctx);
|
|
7014
|
+
await requiredConditionsCheckTask({
|
|
7015
|
+
skip: options.skipConditionsCheck
|
|
7016
|
+
}).run(ctx);
|
|
7017
|
+
}
|
|
7018
|
+
if (!options.publishOnly && !options.preflight) {
|
|
6849
7019
|
await prerequisitesCheckTask({
|
|
6850
7020
|
skip: options.skipPrerequisitesCheck
|
|
6851
7021
|
}).run(ctx);
|
|
@@ -6859,14 +7029,14 @@ async function run(options) {
|
|
|
6859
7029
|
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
6860
7030
|
concurrent: true
|
|
6861
7031
|
})
|
|
6862
|
-
} : [
|
|
7032
|
+
} : options.preflight ? [
|
|
6863
7033
|
{
|
|
6864
7034
|
skip: options.skipTests,
|
|
6865
7035
|
title: "Running tests",
|
|
6866
7036
|
task: async (ctx2) => {
|
|
6867
7037
|
const packageManager = await getPackageManager();
|
|
6868
7038
|
try {
|
|
6869
|
-
await
|
|
7039
|
+
await exec8(packageManager, ["run", ctx2.testScript], {
|
|
6870
7040
|
throwOnError: true
|
|
6871
7041
|
});
|
|
6872
7042
|
} catch (error) {
|
|
@@ -6883,7 +7053,7 @@ async function run(options) {
|
|
|
6883
7053
|
task: async (ctx2) => {
|
|
6884
7054
|
const packageManager = await getPackageManager();
|
|
6885
7055
|
try {
|
|
6886
|
-
await
|
|
7056
|
+
await exec8(packageManager, ["run", ctx2.buildScript], {
|
|
6887
7057
|
throwOnError: true
|
|
6888
7058
|
});
|
|
6889
7059
|
} catch (error) {
|
|
@@ -6895,8 +7065,45 @@ async function run(options) {
|
|
|
6895
7065
|
}
|
|
6896
7066
|
},
|
|
6897
7067
|
{
|
|
6898
|
-
|
|
6899
|
-
|
|
7068
|
+
title: "Validating publish (dry-run)",
|
|
7069
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectDryRunPublishTasks(ctx2), {
|
|
7070
|
+
concurrent: true
|
|
7071
|
+
})
|
|
7072
|
+
}
|
|
7073
|
+
] : [
|
|
7074
|
+
{
|
|
7075
|
+
skip: options.skipTests,
|
|
7076
|
+
title: "Running tests",
|
|
7077
|
+
task: async (ctx2) => {
|
|
7078
|
+
const packageManager = await getPackageManager();
|
|
7079
|
+
try {
|
|
7080
|
+
await exec8(packageManager, ["run", ctx2.testScript], {
|
|
7081
|
+
throwOnError: true
|
|
7082
|
+
});
|
|
7083
|
+
} catch (error) {
|
|
7084
|
+
throw new AbstractError(
|
|
7085
|
+
`Test script '${ctx2.testScript}' failed. Run \`${packageManager} run ${ctx2.testScript}\` locally to see full output.`,
|
|
7086
|
+
{ cause: error }
|
|
7087
|
+
);
|
|
7088
|
+
}
|
|
7089
|
+
}
|
|
7090
|
+
},
|
|
7091
|
+
{
|
|
7092
|
+
skip: options.skipBuild,
|
|
7093
|
+
title: "Building the project",
|
|
7094
|
+
task: async (ctx2) => {
|
|
7095
|
+
const packageManager = await getPackageManager();
|
|
7096
|
+
try {
|
|
7097
|
+
await exec8(packageManager, ["run", ctx2.buildScript], {
|
|
7098
|
+
throwOnError: true
|
|
7099
|
+
});
|
|
7100
|
+
} catch (error) {
|
|
7101
|
+
throw new AbstractError(
|
|
7102
|
+
`Build script '${ctx2.buildScript}' failed. Run \`${packageManager} run ${ctx2.buildScript}\` locally to see full output.`,
|
|
7103
|
+
{ cause: error }
|
|
7104
|
+
);
|
|
7105
|
+
}
|
|
7106
|
+
}
|
|
6900
7107
|
},
|
|
6901
7108
|
{
|
|
6902
7109
|
title: "Bumping version",
|
|
@@ -7012,13 +7219,24 @@ ${repositoryUrl}/compare/${lastRev}...${latestTag}`;
|
|
|
7012
7219
|
parts.push(`${color.bold(name)} on ${color.red("crates.io")}`);
|
|
7013
7220
|
}
|
|
7014
7221
|
}
|
|
7015
|
-
|
|
7016
|
-
|
|
7222
|
+
if (options.preflight) {
|
|
7223
|
+
cleanupEnv?.();
|
|
7224
|
+
console.log(
|
|
7225
|
+
`
|
|
7226
|
+
|
|
7227
|
+
\u2705 Preflight check passed. CI publish should succeed for ${parts.join(", ")}.
|
|
7228
|
+
`
|
|
7229
|
+
);
|
|
7230
|
+
} else {
|
|
7231
|
+
console.log(
|
|
7232
|
+
`
|
|
7017
7233
|
|
|
7018
7234
|
\u{1F680} Successfully published ${parts.join(", ")} ${color.blueBright(`v${ctx.version}`)} \u{1F680}
|
|
7019
7235
|
`
|
|
7020
|
-
|
|
7236
|
+
);
|
|
7237
|
+
}
|
|
7021
7238
|
} catch (e2) {
|
|
7239
|
+
cleanupEnv?.();
|
|
7022
7240
|
consoleError(e2);
|
|
7023
7241
|
await rollback();
|
|
7024
7242
|
process10.exit(1);
|