pubz 0.6.0 → 0.7.1
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 +69 -113
- package/dist/cli.js +322 -272
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -179,118 +179,74 @@ jobs:
|
|
|
179
179
|
bunx pubz
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
+
<!-- demo-output-start -->
|
|
182
183
|
```
|
|
183
|
-
pubz
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
Publishing to
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
npm notice name: pubz
|
|
251
|
-
npm notice version: 0.4.0
|
|
252
|
-
npm notice filename: pubz-0.4.0.tgz
|
|
253
|
-
npm notice package size: 12.0 kB
|
|
254
|
-
npm notice unpacked size: 49.1 kB
|
|
255
|
-
npm notice shasum: 3026a7936458dcaa84030a0ce2e206b9f74aa65d
|
|
256
|
-
npm notice integrity: sha512-6vKMOsC7sZa87[...]w8KNx1fD45u/A==
|
|
257
|
-
npm notice total files: 3
|
|
258
|
-
npm notice
|
|
259
|
-
npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
|
|
260
|
-
Authenticate your account at:
|
|
261
|
-
https://www.npmjs.com/auth/cli/c47d9bee-2a1e-4adf-9aab-63d15acfade2
|
|
262
|
-
Press ENTER to open in the browser...
|
|
263
|
-
|
|
264
|
-
+ pubz@0.4.0
|
|
265
|
-
pubz published successfully
|
|
266
|
-
|
|
267
|
-
══════════════════════════════
|
|
268
|
-
Publishing complete!
|
|
269
|
-
|
|
270
|
-
Published version: 0.4.0
|
|
271
|
-
|
|
272
|
-
Changes since v0.2.12:
|
|
273
|
-
5553c95 Fix ENTER to open browser not working.
|
|
274
|
-
9aaddff Fix tag/push/release branch when using --yes.
|
|
275
|
-
0ce3ab8 Generate changlog and attach it to release page / print it out during publish.
|
|
276
|
-
5a29ca4 Merge branch 'main' of github.com:mm-zacharydavison/pubz
|
|
277
|
-
b4c47fc Clean up README.md formatting
|
|
278
|
-
2da403c Update README.md
|
|
279
|
-
88a4211 Update README with image and usage instructions
|
|
280
|
-
8a8148a Update README.md
|
|
281
|
-
2b45d21 Transform 'workspace:' definitions on publish, and restore them before any commit.
|
|
282
|
-
|
|
283
|
-
? Create a git tag for v0.4.0? [Y/n]
|
|
284
|
-
|
|
285
|
-
Tag v0.4.0 created
|
|
286
|
-
? Push tag to origin? [Y/n]
|
|
287
|
-
remote: This repository moved. Please use the new location:
|
|
288
|
-
remote: git@github.com:zdavison/pubz.git
|
|
289
|
-
To github.com:mm-zacharydavison/pubz.git
|
|
290
|
-
* [new tag] v0.4.0 -> v0.4.0
|
|
291
|
-
Tag v0.4.0 pushed to origin
|
|
292
|
-
? Create a GitHub release? [Y/n]
|
|
293
|
-
Release created: https://github.com/zdavison/pubz/releases/tag/v0.4.0
|
|
294
|
-
|
|
295
|
-
Done!
|
|
184
|
+
📦 pubz npm package publisher
|
|
185
|
+
|
|
186
|
+
┌─ Packages ─────────────────────────────────────────
|
|
187
|
+
• my-app@1.2.0
|
|
188
|
+
└────────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
┌─ 🔖 Version ───────────────────────────────────────
|
|
191
|
+
Bumping (minor): 1.2.0 → 1.3.0
|
|
192
|
+
Updating all packages...
|
|
193
|
+
chore: release v1.3.0
|
|
194
|
+
└────────────────────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
┌─ 🏗️ Build ───────────────────────────────────────
|
|
197
|
+
Running bun run build...
|
|
198
|
+
|
|
199
|
+
$ bun build.js
|
|
200
|
+
Bundled 3 modules in 2ms
|
|
201
|
+
|
|
202
|
+
index.js 4.12 KB (entry point)
|
|
203
|
+
|
|
204
|
+
└────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
Publishing to https://registry.npmjs.org:
|
|
207
|
+
|
|
208
|
+
• my-app@1.3.0
|
|
209
|
+
|
|
210
|
+
┌─ 🚀 Publish ───────────────────────────────────────
|
|
211
|
+
Preparing packages...
|
|
212
|
+
npm notice
|
|
213
|
+
npm notice Publishing to https://registry.npmjs.org
|
|
214
|
+
npm notice
|
|
215
|
+
└────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
✅ Published v1.3.0!
|
|
218
|
+
|
|
219
|
+
┌─ 📋 Changelog ─────────────────────────────────────
|
|
220
|
+
Since v1.2.0
|
|
221
|
+
4e215fd docs: update README
|
|
222
|
+
5cbdd88 fix: fix edge case in parser
|
|
223
|
+
6142990 feat: add feature A
|
|
224
|
+
└────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
┌─ ✨ AI Release Notes ───────────────────────────────
|
|
228
|
+
Generating...
|
|
229
|
+
|
|
230
|
+
### Features
|
|
231
|
+
|
|
232
|
+
- Added feature A.
|
|
233
|
+
|
|
234
|
+
### Bug Fixes
|
|
235
|
+
|
|
236
|
+
- Fixed an edge case in the parser.
|
|
237
|
+
|
|
238
|
+
### Documentation
|
|
239
|
+
|
|
240
|
+
- Updated README.
|
|
241
|
+
└────────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
┌─ 🏷️ Release ─────────────────────────────────────
|
|
244
|
+
Creating tag v1.3.0...
|
|
245
|
+
Pushing tag to origin...
|
|
246
|
+
* [new tag] v1.3.0 -> v1.3.0
|
|
247
|
+
Creating GitHub release...
|
|
248
|
+
└────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
🎉 Done!
|
|
296
251
|
```
|
|
252
|
+
<!-- demo-output-end -->
|
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/cli.ts
|
|
6
|
-
import { readFileSync } from "node:fs";
|
|
7
|
-
import { dirname, join as
|
|
6
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
7
|
+
import { dirname, join as join6 } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
|
|
10
10
|
// src/colors.ts
|
|
@@ -32,6 +32,18 @@ var bgGreen = fmt("42", "49");
|
|
|
32
32
|
var bgYellow = fmt("43", "49");
|
|
33
33
|
var bgBlue = fmt("44", "49");
|
|
34
34
|
var muted = gray;
|
|
35
|
+
var FRAME_WIDTH = 52;
|
|
36
|
+
function frameHeader(title) {
|
|
37
|
+
const inner = `─ ${title} `;
|
|
38
|
+
const padding = "─".repeat(Math.max(2, FRAME_WIDTH - inner.length));
|
|
39
|
+
console.log(dim(`┌${inner}${padding}`));
|
|
40
|
+
}
|
|
41
|
+
function frameFooter() {
|
|
42
|
+
console.log(dim(`└${"─".repeat(FRAME_WIDTH)}`));
|
|
43
|
+
}
|
|
44
|
+
function frameLine(text = "") {
|
|
45
|
+
console.log(" " + text);
|
|
46
|
+
}
|
|
35
47
|
|
|
36
48
|
// src/discovery.ts
|
|
37
49
|
import { readFile, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
@@ -386,6 +398,8 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
386
398
|
import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
|
|
387
399
|
import { homedir as homedir2 } from "node:os";
|
|
388
400
|
import { join as join3 } from "node:path";
|
|
401
|
+
var DIM_ON = "\x1B[90m";
|
|
402
|
+
var DIM_OFF = "\x1B[39m";
|
|
389
403
|
function run(command, args, cwd) {
|
|
390
404
|
return new Promise((resolve2) => {
|
|
391
405
|
const proc = spawn2(command, args, {
|
|
@@ -395,11 +409,11 @@ function run(command, args, cwd) {
|
|
|
395
409
|
let output = "";
|
|
396
410
|
proc.stdout?.on("data", (data) => {
|
|
397
411
|
output += data.toString();
|
|
398
|
-
process.stdout.write(data);
|
|
412
|
+
process.stdout.write(DIM_ON + data.toString() + DIM_OFF);
|
|
399
413
|
});
|
|
400
414
|
proc.stderr?.on("data", (data) => {
|
|
401
415
|
output += data.toString();
|
|
402
|
-
process.stderr.write(data);
|
|
416
|
+
process.stderr.write(DIM_ON + data.toString() + DIM_OFF);
|
|
403
417
|
});
|
|
404
418
|
proc.on("close", (code) => {
|
|
405
419
|
resolve2({ code: code ?? 1, output });
|
|
@@ -419,17 +433,12 @@ function runInteractive(command, args, cwd) {
|
|
|
419
433
|
}
|
|
420
434
|
async function runBuild(cwd, dryRun) {
|
|
421
435
|
if (dryRun) {
|
|
422
|
-
console.log("[DRY RUN] Would run: bun run build");
|
|
423
436
|
return { success: true };
|
|
424
437
|
}
|
|
425
|
-
console.log("Running build...");
|
|
426
|
-
console.log("");
|
|
427
438
|
const result = await run("bun", ["run", "build"], cwd);
|
|
428
439
|
if (result.code !== 0) {
|
|
429
440
|
return { success: false, error: "Build failed" };
|
|
430
441
|
}
|
|
431
|
-
console.log("");
|
|
432
|
-
console.log("Build completed successfully");
|
|
433
442
|
return { success: true };
|
|
434
443
|
}
|
|
435
444
|
async function verifyBuild(pkg) {
|
|
@@ -472,10 +481,8 @@ function isOtpError(output) {
|
|
|
472
481
|
var NPM_COMMAND = process.env.PUBZ_NPM_COMMAND ?? "npm";
|
|
473
482
|
async function publishPackage(pkg, registry, context, dryRun) {
|
|
474
483
|
if (dryRun) {
|
|
475
|
-
console.log(` [DRY RUN] Would publish ${pkg.name}@${pkg.version} to ${registry}`);
|
|
476
484
|
return { success: true };
|
|
477
485
|
}
|
|
478
|
-
console.log(`Publishing ${pkg.name}@${pkg.version}...`);
|
|
479
486
|
const args = ["publish", "--registry", registry, "--access", "public"];
|
|
480
487
|
if (context.otp) {
|
|
481
488
|
args.push("--otp", context.otp);
|
|
@@ -500,7 +507,6 @@ async function publishPackage(pkg, registry, context, dryRun) {
|
|
|
500
507
|
}
|
|
501
508
|
return { success: false, error: `Failed to publish ${pkg.name}` };
|
|
502
509
|
}
|
|
503
|
-
console.log(` ${pkg.name} published successfully`);
|
|
504
510
|
return { success: true };
|
|
505
511
|
}
|
|
506
512
|
async function hasUncommittedChanges(cwd) {
|
|
@@ -516,29 +522,25 @@ async function hasUncommittedChanges(cwd) {
|
|
|
516
522
|
async function commitVersionBump(version, cwd, dryRun) {
|
|
517
523
|
const tagName = `v${version}`;
|
|
518
524
|
if (dryRun) {
|
|
519
|
-
console.log(`[DRY RUN] Would commit version bump for ${tagName}`);
|
|
520
525
|
return { success: true };
|
|
521
526
|
}
|
|
522
527
|
const statusResult = await run("git", ["status", "--porcelain"], cwd);
|
|
523
528
|
if (!statusResult.output.trim()) {
|
|
524
529
|
return { success: true };
|
|
525
530
|
}
|
|
526
|
-
console.log("Committing version bump...");
|
|
527
531
|
const addResult = await run("git", ["add", "-A"], cwd);
|
|
528
532
|
if (addResult.code !== 0) {
|
|
529
533
|
return { success: false, error: "Failed to stage changes" };
|
|
530
534
|
}
|
|
531
|
-
const commitResult = await run("git", ["commit", "-m", `chore: release ${tagName}`], cwd);
|
|
535
|
+
const commitResult = await run("git", ["commit", "-m", `chore: release ${tagName}`], cwd, { silent: true });
|
|
532
536
|
if (commitResult.code !== 0) {
|
|
533
537
|
return { success: false, error: "Failed to commit changes" };
|
|
534
538
|
}
|
|
535
|
-
console.log(" Changes committed");
|
|
536
539
|
return { success: true };
|
|
537
540
|
}
|
|
538
541
|
async function createGitTag(version, cwd, dryRun) {
|
|
539
542
|
const tagName = `v${version}`;
|
|
540
543
|
if (dryRun) {
|
|
541
|
-
console.log(`[DRY RUN] Would create git tag: ${tagName}`);
|
|
542
544
|
return { success: true };
|
|
543
545
|
}
|
|
544
546
|
const tagResult = await run("git", ["tag", tagName], cwd);
|
|
@@ -548,13 +550,11 @@ async function createGitTag(version, cwd, dryRun) {
|
|
|
548
550
|
error: `Failed to create tag ${tagName} (may already exist)`
|
|
549
551
|
};
|
|
550
552
|
}
|
|
551
|
-
console.log(` Tag ${tagName} created`);
|
|
552
553
|
return { success: true };
|
|
553
554
|
}
|
|
554
555
|
async function pushGitTag(version, cwd, dryRun) {
|
|
555
556
|
const tagName = `v${version}`;
|
|
556
557
|
if (dryRun) {
|
|
557
|
-
console.log(`[DRY RUN] Would push git tag: ${tagName}`);
|
|
558
558
|
return { success: true };
|
|
559
559
|
}
|
|
560
560
|
const branchResult = await run("git", ["push"], cwd);
|
|
@@ -565,7 +565,6 @@ async function pushGitTag(version, cwd, dryRun) {
|
|
|
565
565
|
if (result.code !== 0) {
|
|
566
566
|
return { success: false, error: `Failed to push tag ${tagName}` };
|
|
567
567
|
}
|
|
568
|
-
console.log(` Tag ${tagName} pushed to origin`);
|
|
569
568
|
return { success: true };
|
|
570
569
|
}
|
|
571
570
|
|
|
@@ -678,6 +677,7 @@ async function runClaudePrompt(prompt2) {
|
|
|
678
677
|
}
|
|
679
678
|
|
|
680
679
|
// src/changelog.ts
|
|
680
|
+
var GH_COMMAND = process.env.PUBZ_GH_COMMAND ?? "gh";
|
|
681
681
|
function parseGitRemoteUrl(remoteUrl) {
|
|
682
682
|
const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
|
|
683
683
|
if (sshMatch) {
|
|
@@ -794,7 +794,7 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
|
|
|
794
794
|
console.log(`[DRY RUN] Would create GitHub release for ${tagName}`);
|
|
795
795
|
return { success: true };
|
|
796
796
|
}
|
|
797
|
-
const result = await runSilent(
|
|
797
|
+
const result = await runSilent(GH_COMMAND, ["release", "create", tagName, "--title", tagName, "--notes", body], cwd);
|
|
798
798
|
if (result.code !== 0) {
|
|
799
799
|
return {
|
|
800
800
|
success: false,
|
|
@@ -805,6 +805,54 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
|
|
|
805
805
|
return { success: true, url };
|
|
806
806
|
}
|
|
807
807
|
|
|
808
|
+
// src/config.ts
|
|
809
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
810
|
+
import { join as join5 } from "node:path";
|
|
811
|
+
var CONFIG_FILENAME = ".pubz";
|
|
812
|
+
var VALID_KEYS = new Set(["skip-build", "skip-publish", "registry"]);
|
|
813
|
+
function loadConfig(cwd) {
|
|
814
|
+
const configPath = join5(cwd, CONFIG_FILENAME);
|
|
815
|
+
if (!existsSync(configPath)) {
|
|
816
|
+
debug(`No ${CONFIG_FILENAME} found at ${configPath}`);
|
|
817
|
+
return {};
|
|
818
|
+
}
|
|
819
|
+
const content = readFileSync(configPath, "utf-8");
|
|
820
|
+
const config = {};
|
|
821
|
+
for (const rawLine of content.split(`
|
|
822
|
+
`)) {
|
|
823
|
+
const line = rawLine.trim();
|
|
824
|
+
if (!line || line.startsWith("#"))
|
|
825
|
+
continue;
|
|
826
|
+
const eqIndex = line.indexOf("=");
|
|
827
|
+
let key;
|
|
828
|
+
let value;
|
|
829
|
+
if (eqIndex === -1) {
|
|
830
|
+
key = line;
|
|
831
|
+
} else {
|
|
832
|
+
key = line.slice(0, eqIndex).trim();
|
|
833
|
+
value = line.slice(eqIndex + 1).trim();
|
|
834
|
+
}
|
|
835
|
+
if (!VALID_KEYS.has(key)) {
|
|
836
|
+
debug(`Ignoring unknown config key: ${key}`);
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
if (key === "registry") {
|
|
840
|
+
config.registry = value ?? "";
|
|
841
|
+
} else {
|
|
842
|
+
const boolKey = key;
|
|
843
|
+
if (value === undefined || value === "true") {
|
|
844
|
+
config[boolKey] = true;
|
|
845
|
+
} else if (value === "false") {
|
|
846
|
+
config[boolKey] = false;
|
|
847
|
+
} else {
|
|
848
|
+
debug(`Invalid boolean value for ${key}: ${value}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
debug(`Loaded ${CONFIG_FILENAME}: ${JSON.stringify(config)}`);
|
|
853
|
+
return config;
|
|
854
|
+
}
|
|
855
|
+
|
|
808
856
|
// src/version.ts
|
|
809
857
|
import { readFile as readFile4, writeFile } from "node:fs/promises";
|
|
810
858
|
async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
|
|
@@ -828,9 +876,7 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
|
|
|
828
876
|
if (oldVersion.startsWith("workspace:")) {
|
|
829
877
|
const modifier = oldVersion.replace("workspace:", "");
|
|
830
878
|
const newVersionSpec = modifier === "*" || modifier === "" ? newVersion : `${modifier}${newVersion}`;
|
|
831
|
-
if (dryRun) {
|
|
832
|
-
console.log(` [DRY RUN] Would temporarily transform ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
|
|
833
|
-
} else {
|
|
879
|
+
if (!dryRun) {
|
|
834
880
|
transforms.push({
|
|
835
881
|
packageJsonPath: pkg.packageJsonPath,
|
|
836
882
|
depType,
|
|
@@ -847,7 +893,6 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
|
|
|
847
893
|
if (modified && !dryRun) {
|
|
848
894
|
await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
849
895
|
`);
|
|
850
|
-
console.log(` Transformed workspace references in ${pkg.name}`);
|
|
851
896
|
}
|
|
852
897
|
}
|
|
853
898
|
return transforms;
|
|
@@ -871,9 +916,6 @@ async function restoreWorkspaceProtocol(transforms) {
|
|
|
871
916
|
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
872
917
|
`);
|
|
873
918
|
}
|
|
874
|
-
if (transforms.length > 0) {
|
|
875
|
-
console.log(` Restored workspace references in ${byPath.size} package(s)`);
|
|
876
|
-
}
|
|
877
919
|
}
|
|
878
920
|
function isValidVersion(version) {
|
|
879
921
|
return /^\d+\.\d+\.\d+(-.+)?$/.test(version);
|
|
@@ -900,12 +942,10 @@ async function updatePackageVersion(pkg, newVersion, dryRun) {
|
|
|
900
942
|
const packageJson = JSON.parse(content);
|
|
901
943
|
packageJson.version = newVersion;
|
|
902
944
|
if (dryRun) {
|
|
903
|
-
console.log(` [DRY RUN] Would update ${pkg.name}: ${pkg.version} -> ${newVersion}`);
|
|
904
945
|
return;
|
|
905
946
|
}
|
|
906
947
|
await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
907
948
|
`);
|
|
908
|
-
console.log(` Updated ${pkg.name}: ${pkg.version} -> ${newVersion}`);
|
|
909
949
|
}
|
|
910
950
|
async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
|
|
911
951
|
const packageNames = new Set(packages.map((p) => p.name));
|
|
@@ -928,13 +968,9 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
|
|
|
928
968
|
continue;
|
|
929
969
|
}
|
|
930
970
|
const newVersionSpec = oldVersion.startsWith("^") ? `^${newVersion}` : oldVersion.startsWith("~") ? `~${newVersion}` : newVersion;
|
|
931
|
-
if (deps[depName] !== newVersionSpec) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
} else {
|
|
935
|
-
deps[depName] = newVersionSpec;
|
|
936
|
-
modified = true;
|
|
937
|
-
}
|
|
971
|
+
if (deps[depName] !== newVersionSpec && !dryRun) {
|
|
972
|
+
deps[depName] = newVersionSpec;
|
|
973
|
+
modified = true;
|
|
938
974
|
}
|
|
939
975
|
}
|
|
940
976
|
}
|
|
@@ -942,7 +978,6 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
|
|
|
942
978
|
if (modified && !dryRun) {
|
|
943
979
|
await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
944
980
|
`);
|
|
945
|
-
console.log(` Updated local dependency versions in ${pkg.name}`);
|
|
946
981
|
}
|
|
947
982
|
}
|
|
948
983
|
}
|
|
@@ -954,13 +989,12 @@ var REGISTRIES = {
|
|
|
954
989
|
};
|
|
955
990
|
function getVersion() {
|
|
956
991
|
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
957
|
-
const pkgPath =
|
|
958
|
-
const pkg = JSON.parse(
|
|
992
|
+
const pkgPath = join6(__dirname2, "..", "package.json");
|
|
993
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
959
994
|
return pkg.version;
|
|
960
995
|
}
|
|
961
996
|
function printUsage() {
|
|
962
|
-
console.log(`
|
|
963
|
-
pubz - Interactive npm package publisher
|
|
997
|
+
console.log(`pubz - Interactive npm package publisher
|
|
964
998
|
|
|
965
999
|
Usage: pubz [command] [options]
|
|
966
1000
|
|
|
@@ -972,6 +1006,7 @@ Options:
|
|
|
972
1006
|
--registry <url> Specify npm registry URL (default: public npm)
|
|
973
1007
|
--otp <code> One-time password for 2FA
|
|
974
1008
|
--skip-build Skip the build step
|
|
1009
|
+
--skip-publish Skip npm publish (still does version bump, tag, and release)
|
|
975
1010
|
--yes, -y Skip yes/no confirmation prompts (still asks for choices)
|
|
976
1011
|
--ci CI mode: skip all prompts, auto-accept everything
|
|
977
1012
|
--version <value> Version bump type (patch|minor|major) or explicit version (required with --ci)
|
|
@@ -982,8 +1017,18 @@ Examples:
|
|
|
982
1017
|
pubz # Interactive publish
|
|
983
1018
|
pubz --dry-run # Preview what would happen
|
|
984
1019
|
pubz --registry https://npm.pkg.github.com # Publish to GitHub Packages
|
|
1020
|
+
pubz --skip-publish # Version bump, tag, release — no npm publish
|
|
985
1021
|
pubz --ci --version patch # CI mode with patch bump
|
|
986
1022
|
pubz --ci --version 1.2.3 # CI mode with explicit version
|
|
1023
|
+
pubz --ci --version patch --skip-publish # CI: bump, tag, release without npm publish
|
|
1024
|
+
|
|
1025
|
+
Config file:
|
|
1026
|
+
Place a .pubz file in your project root to set default options.
|
|
1027
|
+
CLI flags always override config values.
|
|
1028
|
+
|
|
1029
|
+
# .pubz
|
|
1030
|
+
skip-publish
|
|
1031
|
+
registry=https://npm.pkg.github.com
|
|
987
1032
|
`);
|
|
988
1033
|
}
|
|
989
1034
|
function parseArgs(args) {
|
|
@@ -992,39 +1037,53 @@ function parseArgs(args) {
|
|
|
992
1037
|
registry: "",
|
|
993
1038
|
otp: "",
|
|
994
1039
|
skipBuild: false,
|
|
1040
|
+
skipPublish: false,
|
|
995
1041
|
skipConfirms: false,
|
|
996
1042
|
ci: false,
|
|
997
1043
|
version: "",
|
|
998
1044
|
verbose: false,
|
|
999
1045
|
help: false
|
|
1000
1046
|
};
|
|
1047
|
+
const cliExplicit = new Set;
|
|
1001
1048
|
for (let i = 0;i < args.length; i++) {
|
|
1002
1049
|
const arg = args[i];
|
|
1003
1050
|
switch (arg) {
|
|
1004
1051
|
case "--dry-run":
|
|
1005
1052
|
options.dryRun = true;
|
|
1053
|
+
cliExplicit.add("dryRun");
|
|
1006
1054
|
break;
|
|
1007
1055
|
case "--registry":
|
|
1008
1056
|
options.registry = args[++i] || "";
|
|
1057
|
+
cliExplicit.add("registry");
|
|
1009
1058
|
break;
|
|
1010
1059
|
case "--otp":
|
|
1011
1060
|
options.otp = args[++i] || "";
|
|
1061
|
+
cliExplicit.add("otp");
|
|
1012
1062
|
break;
|
|
1013
1063
|
case "--skip-build":
|
|
1014
1064
|
options.skipBuild = true;
|
|
1065
|
+
cliExplicit.add("skipBuild");
|
|
1066
|
+
break;
|
|
1067
|
+
case "--skip-publish":
|
|
1068
|
+
options.skipPublish = true;
|
|
1069
|
+
cliExplicit.add("skipPublish");
|
|
1015
1070
|
break;
|
|
1016
1071
|
case "--yes":
|
|
1017
1072
|
case "-y":
|
|
1018
1073
|
options.skipConfirms = true;
|
|
1074
|
+
cliExplicit.add("skipConfirms");
|
|
1019
1075
|
break;
|
|
1020
1076
|
case "--ci":
|
|
1021
1077
|
options.ci = true;
|
|
1078
|
+
cliExplicit.add("ci");
|
|
1022
1079
|
break;
|
|
1023
1080
|
case "--version":
|
|
1024
1081
|
options.version = args[++i] || "";
|
|
1082
|
+
cliExplicit.add("version");
|
|
1025
1083
|
break;
|
|
1026
1084
|
case "--verbose":
|
|
1027
1085
|
options.verbose = true;
|
|
1086
|
+
cliExplicit.add("verbose");
|
|
1028
1087
|
break;
|
|
1029
1088
|
case "-h":
|
|
1030
1089
|
case "--help":
|
|
@@ -1032,19 +1091,30 @@ function parseArgs(args) {
|
|
|
1032
1091
|
break;
|
|
1033
1092
|
}
|
|
1034
1093
|
}
|
|
1035
|
-
return options;
|
|
1094
|
+
return { options, cliExplicit };
|
|
1036
1095
|
}
|
|
1037
1096
|
async function main() {
|
|
1038
1097
|
if (process.argv[2] === "version") {
|
|
1039
1098
|
console.log(getVersion());
|
|
1040
1099
|
process.exit(0);
|
|
1041
1100
|
}
|
|
1042
|
-
const options = parseArgs(process.argv.slice(2));
|
|
1101
|
+
const { options, cliExplicit } = parseArgs(process.argv.slice(2));
|
|
1043
1102
|
setVerbose(options.verbose);
|
|
1044
1103
|
if (options.help) {
|
|
1045
1104
|
printUsage();
|
|
1046
1105
|
process.exit(0);
|
|
1047
1106
|
}
|
|
1107
|
+
const cwd = process.cwd();
|
|
1108
|
+
const config = loadConfig(cwd);
|
|
1109
|
+
if (config["skip-build"] && !cliExplicit.has("skipBuild")) {
|
|
1110
|
+
options.skipBuild = config["skip-build"];
|
|
1111
|
+
}
|
|
1112
|
+
if (config["skip-publish"] && !cliExplicit.has("skipPublish")) {
|
|
1113
|
+
options.skipPublish = config["skip-publish"];
|
|
1114
|
+
}
|
|
1115
|
+
if (config.registry && !cliExplicit.has("registry")) {
|
|
1116
|
+
options.registry = config.registry;
|
|
1117
|
+
}
|
|
1048
1118
|
if (options.ci && !options.version) {
|
|
1049
1119
|
console.error(red(bold("Error:")) + " --ci requires --version to be specified");
|
|
1050
1120
|
console.log("");
|
|
@@ -1057,17 +1127,15 @@ async function main() {
|
|
|
1057
1127
|
}
|
|
1058
1128
|
const skipConfirms = options.skipConfirms || options.ci;
|
|
1059
1129
|
const skipAllPrompts = options.ci;
|
|
1060
|
-
const cwd = process.cwd();
|
|
1061
1130
|
if (options.dryRun) {
|
|
1062
|
-
console.log(yellow(bold("DRY RUN
|
|
1131
|
+
console.log(yellow(bold("⚠️ DRY RUN")) + dim(" — no actual changes will be made"));
|
|
1063
1132
|
console.log("");
|
|
1064
1133
|
}
|
|
1065
|
-
console.log(bold("pubz") + dim("
|
|
1066
|
-
console.log(dim("═".repeat(30)));
|
|
1134
|
+
console.log("\uD83D\uDCE6 " + bold("pubz") + dim(" npm package publisher"));
|
|
1067
1135
|
console.log("");
|
|
1068
1136
|
const uncommitted = await hasUncommittedChanges(cwd);
|
|
1069
1137
|
if (uncommitted.hasChanges && !options.dryRun) {
|
|
1070
|
-
console.
|
|
1138
|
+
console.error(red(bold("Error:")) + " You have uncommitted changes:");
|
|
1071
1139
|
console.log("");
|
|
1072
1140
|
for (const file of uncommitted.files.slice(0, 10)) {
|
|
1073
1141
|
console.log(` ${yellow(file)}`);
|
|
@@ -1080,8 +1148,6 @@ async function main() {
|
|
|
1080
1148
|
closePrompt();
|
|
1081
1149
|
process.exit(1);
|
|
1082
1150
|
}
|
|
1083
|
-
console.log(cyan("Discovering packages..."));
|
|
1084
|
-
console.log("");
|
|
1085
1151
|
let packages = await discoverPackages(cwd);
|
|
1086
1152
|
const publishablePackages = packages.filter((p) => !p.isPrivate);
|
|
1087
1153
|
if (publishablePackages.length === 0) {
|
|
@@ -1094,12 +1160,12 @@ async function main() {
|
|
|
1094
1160
|
process.exit(1);
|
|
1095
1161
|
}
|
|
1096
1162
|
packages = sortByDependencyOrder(publishablePackages);
|
|
1097
|
-
|
|
1098
|
-
console.log("");
|
|
1163
|
+
frameHeader("Packages");
|
|
1099
1164
|
for (const pkg of packages) {
|
|
1100
1165
|
const deps = pkg.localDependencies.length > 0 ? dim(` (depends on: ${pkg.localDependencies.join(", ")})`) : "";
|
|
1101
|
-
|
|
1166
|
+
frameLine(`${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
|
|
1102
1167
|
}
|
|
1168
|
+
frameFooter();
|
|
1103
1169
|
console.log("");
|
|
1104
1170
|
if (packages.length > 1 && !skipAllPrompts) {
|
|
1105
1171
|
const selectedPackages = await multiSelect("Select packages to publish:", packages.map((pkg) => ({
|
|
@@ -1115,18 +1181,14 @@ async function main() {
|
|
|
1115
1181
|
console.log("");
|
|
1116
1182
|
}
|
|
1117
1183
|
const currentVersion = packages[0].version;
|
|
1118
|
-
console.log(bold(cyan("Step 1:")) + " Version Management");
|
|
1119
|
-
console.log(dim("─".repeat(30)));
|
|
1120
|
-
console.log("");
|
|
1121
|
-
console.log(`Current version: ${yellow(currentVersion)}`);
|
|
1122
|
-
console.log("");
|
|
1123
1184
|
let newVersion = currentVersion;
|
|
1185
|
+
let didBump = false;
|
|
1124
1186
|
if (options.version) {
|
|
1125
1187
|
const bumpTypes = ["patch", "minor", "major"];
|
|
1126
1188
|
const isBumpType = bumpTypes.includes(options.version);
|
|
1127
1189
|
if (isBumpType) {
|
|
1128
1190
|
newVersion = bumpVersion(currentVersion, options.version);
|
|
1129
|
-
|
|
1191
|
+
didBump = true;
|
|
1130
1192
|
} else {
|
|
1131
1193
|
const cleaned = options.version.startsWith("v") ? options.version.slice(1) : options.version;
|
|
1132
1194
|
if (!isValidVersion(cleaned)) {
|
|
@@ -1135,45 +1197,18 @@ async function main() {
|
|
|
1135
1197
|
process.exit(1);
|
|
1136
1198
|
}
|
|
1137
1199
|
newVersion = cleaned;
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
console.log("");
|
|
1141
|
-
console.log(`Updating version to ${green(newVersion)} in all packages...`);
|
|
1142
|
-
console.log("");
|
|
1143
|
-
for (const pkg of packages) {
|
|
1144
|
-
await updatePackageVersion(pkg, newVersion, options.dryRun);
|
|
1145
|
-
}
|
|
1146
|
-
await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
|
|
1147
|
-
for (const pkg of packages) {
|
|
1148
|
-
pkg.version = newVersion;
|
|
1149
|
-
}
|
|
1150
|
-
const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
|
|
1151
|
-
if (!commitResult.success) {
|
|
1152
|
-
console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
|
|
1153
|
-
closePrompt();
|
|
1154
|
-
process.exit(1);
|
|
1200
|
+
didBump = true;
|
|
1155
1201
|
}
|
|
1156
|
-
console.log("");
|
|
1157
1202
|
} else if (!skipAllPrompts) {
|
|
1203
|
+
console.log(`Current version: ${yellow(currentVersion)}`);
|
|
1204
|
+
console.log("");
|
|
1158
1205
|
const shouldBump = skipConfirms || await confirm("Bump version before publishing?");
|
|
1159
1206
|
if (shouldBump) {
|
|
1160
1207
|
const bumpChoice = await select("Select version bump type:", [
|
|
1161
|
-
{
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
}
|
|
1165
|
-
{
|
|
1166
|
-
label: `minor (${previewBump(currentVersion, "minor")})`,
|
|
1167
|
-
value: "minor"
|
|
1168
|
-
},
|
|
1169
|
-
{
|
|
1170
|
-
label: `major (${previewBump(currentVersion, "major")})`,
|
|
1171
|
-
value: "major"
|
|
1172
|
-
},
|
|
1173
|
-
{
|
|
1174
|
-
label: "custom version",
|
|
1175
|
-
value: "custom"
|
|
1176
|
-
}
|
|
1208
|
+
{ label: `patch (${previewBump(currentVersion, "patch")})`, value: "patch" },
|
|
1209
|
+
{ label: `minor (${previewBump(currentVersion, "minor")})`, value: "minor" },
|
|
1210
|
+
{ label: `major (${previewBump(currentVersion, "major")})`, value: "major" },
|
|
1211
|
+
{ label: "custom version", value: "custom" }
|
|
1177
1212
|
]);
|
|
1178
1213
|
if (bumpChoice === "custom") {
|
|
1179
1214
|
let customVersion = "";
|
|
@@ -1190,93 +1225,57 @@ async function main() {
|
|
|
1190
1225
|
} else {
|
|
1191
1226
|
newVersion = bumpVersion(currentVersion, bumpChoice);
|
|
1192
1227
|
}
|
|
1193
|
-
|
|
1194
|
-
console.log(`Updating version to ${green(newVersion)} in all packages...`);
|
|
1195
|
-
console.log("");
|
|
1196
|
-
for (const pkg of packages) {
|
|
1197
|
-
await updatePackageVersion(pkg, newVersion, options.dryRun);
|
|
1198
|
-
}
|
|
1199
|
-
await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
|
|
1200
|
-
for (const pkg of packages) {
|
|
1201
|
-
pkg.version = newVersion;
|
|
1202
|
-
}
|
|
1203
|
-
const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
|
|
1204
|
-
if (!commitResult.success) {
|
|
1205
|
-
console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
|
|
1206
|
-
closePrompt();
|
|
1207
|
-
process.exit(1);
|
|
1208
|
-
}
|
|
1209
|
-
console.log("");
|
|
1228
|
+
didBump = true;
|
|
1210
1229
|
}
|
|
1230
|
+
console.log("");
|
|
1211
1231
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
{
|
|
1216
|
-
label: "Public npm registry (https://registry.npmjs.org)",
|
|
1217
|
-
value: REGISTRIES.npm
|
|
1218
|
-
},
|
|
1219
|
-
{
|
|
1220
|
-
label: "GitHub Packages (https://npm.pkg.github.com)",
|
|
1221
|
-
value: REGISTRIES.github
|
|
1222
|
-
}
|
|
1223
|
-
]);
|
|
1224
|
-
}
|
|
1225
|
-
registry = registry || REGISTRIES.npm;
|
|
1226
|
-
console.log("");
|
|
1227
|
-
console.log(`Publishing to: ${cyan(registry)}`);
|
|
1228
|
-
console.log("");
|
|
1229
|
-
if (!options.dryRun && !options.ci) {
|
|
1230
|
-
console.log(cyan("Verifying npm authentication..."));
|
|
1231
|
-
const authResult = await checkNpmAuth(registry);
|
|
1232
|
-
if (!authResult.authenticated) {
|
|
1233
|
-
console.log("");
|
|
1234
|
-
console.log(yellow("Not logged in to npm.") + " Starting login...");
|
|
1235
|
-
console.log("");
|
|
1236
|
-
pausePrompt();
|
|
1237
|
-
const loginResult = await npmLogin(registry);
|
|
1238
|
-
resetPrompt();
|
|
1239
|
-
if (!loginResult.success) {
|
|
1240
|
-
console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
|
|
1241
|
-
closePrompt();
|
|
1242
|
-
process.exit(1);
|
|
1243
|
-
}
|
|
1244
|
-
const verifyAuth = await checkNpmAuth(registry);
|
|
1245
|
-
if (!verifyAuth.authenticated) {
|
|
1246
|
-
console.error(red(bold("Error:")) + " Login did not complete successfully.");
|
|
1247
|
-
closePrompt();
|
|
1248
|
-
process.exit(1);
|
|
1249
|
-
}
|
|
1250
|
-
console.log("");
|
|
1251
|
-
console.log(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
|
|
1232
|
+
if (didBump) {
|
|
1233
|
+
frameHeader("\uD83D\uDD16 Version");
|
|
1234
|
+
if (options.version && ["patch", "minor", "major"].includes(options.version)) {
|
|
1235
|
+
frameLine(`Bumping (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
|
|
1252
1236
|
} else {
|
|
1253
|
-
|
|
1237
|
+
frameLine(`${yellow(currentVersion)} → ${green(newVersion)}`);
|
|
1238
|
+
}
|
|
1239
|
+
frameLine(dim("Updating all packages..."));
|
|
1240
|
+
for (const pkg of packages) {
|
|
1241
|
+
await updatePackageVersion(pkg, newVersion, options.dryRun);
|
|
1254
1242
|
}
|
|
1243
|
+
await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
|
|
1244
|
+
for (const pkg of packages) {
|
|
1245
|
+
pkg.version = newVersion;
|
|
1246
|
+
}
|
|
1247
|
+
const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
|
|
1248
|
+
if (!commitResult.success) {
|
|
1249
|
+
frameFooter();
|
|
1250
|
+
console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
|
|
1251
|
+
closePrompt();
|
|
1252
|
+
process.exit(1);
|
|
1253
|
+
}
|
|
1254
|
+
frameFooter();
|
|
1255
1255
|
console.log("");
|
|
1256
1256
|
}
|
|
1257
1257
|
if (!options.skipBuild) {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1258
|
+
frameHeader("\uD83C\uDFD7️ Build");
|
|
1259
|
+
frameLine(dim("Running bun run build..."));
|
|
1260
|
+
frameLine();
|
|
1261
1261
|
const buildResult = await runBuild(cwd, options.dryRun);
|
|
1262
1262
|
if (!buildResult.success) {
|
|
1263
|
+
frameFooter();
|
|
1263
1264
|
console.error(red(bold("Build failed:")) + ` ${buildResult.error}`);
|
|
1264
1265
|
closePrompt();
|
|
1265
1266
|
process.exit(1);
|
|
1266
1267
|
}
|
|
1267
|
-
console.log("");
|
|
1268
|
-
console.log(cyan("Verifying builds..."));
|
|
1269
|
-
console.log("");
|
|
1270
1268
|
let allBuildsVerified = true;
|
|
1271
1269
|
for (const pkg of packages) {
|
|
1272
1270
|
const result = await verifyBuild(pkg);
|
|
1273
1271
|
if (result.success) {
|
|
1274
|
-
|
|
1272
|
+
frameLine(` ${green("✓")} ${pkg.name}`);
|
|
1275
1273
|
} else {
|
|
1276
|
-
|
|
1274
|
+
frameLine(` ${red("✗")} ${pkg.name}: ${result.error}`);
|
|
1277
1275
|
allBuildsVerified = false;
|
|
1278
1276
|
}
|
|
1279
1277
|
}
|
|
1278
|
+
frameFooter();
|
|
1280
1279
|
console.log("");
|
|
1281
1280
|
if (!allBuildsVerified) {
|
|
1282
1281
|
console.error(red("Build verification failed.") + muted(" Please fix the issues and try again."));
|
|
@@ -1284,157 +1283,208 @@ async function main() {
|
|
|
1284
1283
|
process.exit(1);
|
|
1285
1284
|
}
|
|
1286
1285
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (options.dryRun) {
|
|
1291
|
-
console.log(yellow("[DRY RUN]") + ` Would publish the following packages to ${cyan(registry)}:`);
|
|
1286
|
+
if (options.skipPublish) {
|
|
1287
|
+
console.log(yellow(bold("⏭️ Skipping npm publish")) + dim(" — use without --skip-publish to publish to npm"));
|
|
1288
|
+
console.log("");
|
|
1292
1289
|
} else {
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
console.log(
|
|
1306
|
-
|
|
1307
|
-
|
|
1290
|
+
let registry = options.registry;
|
|
1291
|
+
if (!registry && !skipAllPrompts) {
|
|
1292
|
+
registry = await select("Select publish target:", [
|
|
1293
|
+
{
|
|
1294
|
+
label: "Public npm registry (https://registry.npmjs.org)",
|
|
1295
|
+
value: REGISTRIES.npm
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
label: "GitHub Packages (https://npm.pkg.github.com)",
|
|
1299
|
+
value: REGISTRIES.github
|
|
1300
|
+
}
|
|
1301
|
+
]);
|
|
1302
|
+
console.log("");
|
|
1303
|
+
}
|
|
1304
|
+
registry = registry || REGISTRIES.npm;
|
|
1305
|
+
if (options.dryRun) {
|
|
1306
|
+
console.log(yellow("[DRY RUN]") + ` Would publish to ${cyan(registry)}:`);
|
|
1307
|
+
} else {
|
|
1308
|
+
console.log(`Publishing to ${cyan(registry)}:`);
|
|
1308
1309
|
}
|
|
1309
1310
|
console.log("");
|
|
1310
|
-
}
|
|
1311
|
-
console.log(cyan("Preparing packages for publish..."));
|
|
1312
|
-
console.log("");
|
|
1313
|
-
const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
|
|
1314
|
-
if (workspaceTransforms.length > 0 || options.dryRun) {
|
|
1315
|
-
console.log("");
|
|
1316
|
-
}
|
|
1317
|
-
console.log(cyan("Publishing packages..."));
|
|
1318
|
-
console.log("");
|
|
1319
|
-
const publishContext = {
|
|
1320
|
-
otp: options.otp,
|
|
1321
|
-
useBrowserAuth: !options.ci,
|
|
1322
|
-
onInteractiveStart: pausePrompt,
|
|
1323
|
-
onInteractiveComplete: resetPrompt
|
|
1324
|
-
};
|
|
1325
|
-
let publishFailed = false;
|
|
1326
|
-
let failedPackageName = "";
|
|
1327
|
-
let failedError = "";
|
|
1328
|
-
try {
|
|
1329
1311
|
for (const pkg of packages) {
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1312
|
+
console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1313
|
+
}
|
|
1314
|
+
console.log("");
|
|
1315
|
+
if (!options.dryRun && !skipConfirms) {
|
|
1316
|
+
const shouldContinue = await confirm("Continue?");
|
|
1317
|
+
if (!shouldContinue) {
|
|
1318
|
+
console.log(yellow("Publish cancelled."));
|
|
1319
|
+
closePrompt();
|
|
1320
|
+
process.exit(0);
|
|
1336
1321
|
}
|
|
1322
|
+
console.log("");
|
|
1337
1323
|
}
|
|
1338
|
-
|
|
1339
|
-
if (
|
|
1324
|
+
frameHeader("\uD83D\uDE80 Publish");
|
|
1325
|
+
if (!options.dryRun && !options.ci) {
|
|
1326
|
+
frameLine(dim("Verifying authentication..."));
|
|
1327
|
+
const authResult = await checkNpmAuth(registry);
|
|
1328
|
+
if (!authResult.authenticated) {
|
|
1329
|
+
frameLine(yellow("Not authenticated.") + dim(" Starting login..."));
|
|
1330
|
+
frameLine();
|
|
1331
|
+
pausePrompt();
|
|
1332
|
+
const loginResult = await npmLogin(registry);
|
|
1333
|
+
resetPrompt();
|
|
1334
|
+
if (!loginResult.success) {
|
|
1335
|
+
frameFooter();
|
|
1336
|
+
console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
|
|
1337
|
+
closePrompt();
|
|
1338
|
+
process.exit(1);
|
|
1339
|
+
}
|
|
1340
|
+
const verifyAuth = await checkNpmAuth(registry);
|
|
1341
|
+
if (!verifyAuth.authenticated) {
|
|
1342
|
+
frameFooter();
|
|
1343
|
+
console.error(red(bold("Error:")) + " Login did not complete successfully.");
|
|
1344
|
+
closePrompt();
|
|
1345
|
+
process.exit(1);
|
|
1346
|
+
}
|
|
1347
|
+
frameLine(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
|
|
1348
|
+
frameLine();
|
|
1349
|
+
} else {
|
|
1350
|
+
frameLine(dim(`Authenticated as ${cyan(authResult.username ?? "unknown")}`));
|
|
1351
|
+
frameLine();
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
frameLine(dim("Preparing packages..."));
|
|
1355
|
+
const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
|
|
1356
|
+
const publishContext = {
|
|
1357
|
+
otp: options.otp,
|
|
1358
|
+
useBrowserAuth: !options.ci,
|
|
1359
|
+
onInteractiveStart: pausePrompt,
|
|
1360
|
+
onInteractiveComplete: resetPrompt
|
|
1361
|
+
};
|
|
1362
|
+
let publishFailed = false;
|
|
1363
|
+
let failedPackageName = "";
|
|
1364
|
+
let failedError = "";
|
|
1365
|
+
try {
|
|
1366
|
+
for (const pkg of packages) {
|
|
1367
|
+
if (options.dryRun) {
|
|
1368
|
+
frameLine(` ${dim("[dry run]")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1369
|
+
} else {
|
|
1370
|
+
frameLine(dim(` Publishing ${pkg.name}...`));
|
|
1371
|
+
}
|
|
1372
|
+
const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
|
|
1373
|
+
if (!result.success) {
|
|
1374
|
+
publishFailed = true;
|
|
1375
|
+
failedPackageName = pkg.name;
|
|
1376
|
+
failedError = result.error ?? "Unknown error";
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
if (!options.dryRun) {
|
|
1380
|
+
frameLine(` ${green("✓")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
} finally {
|
|
1384
|
+
if (workspaceTransforms.length > 0) {
|
|
1385
|
+
await restoreWorkspaceProtocol(workspaceTransforms);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (publishFailed) {
|
|
1389
|
+
frameFooter();
|
|
1390
|
+
console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
|
|
1340
1391
|
console.log("");
|
|
1341
|
-
|
|
1392
|
+
console.error(red("Stopping publish process."));
|
|
1393
|
+
closePrompt();
|
|
1394
|
+
process.exit(1);
|
|
1342
1395
|
}
|
|
1343
|
-
|
|
1344
|
-
if (publishFailed) {
|
|
1345
|
-
console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
|
|
1396
|
+
frameFooter();
|
|
1346
1397
|
console.log("");
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
if (options.dryRun) {
|
|
1352
|
-
console.log("");
|
|
1353
|
-
console.log(muted("Run without --dry-run to actually publish."));
|
|
1398
|
+
if (options.dryRun) {
|
|
1399
|
+
console.log(muted("Run without --dry-run to actually publish."));
|
|
1400
|
+
console.log("");
|
|
1401
|
+
}
|
|
1354
1402
|
}
|
|
1355
|
-
console.log("");
|
|
1356
|
-
console.log(dim("═".repeat(30)));
|
|
1357
|
-
console.log(green(bold("Publishing complete!")));
|
|
1358
|
-
console.log("");
|
|
1359
|
-
console.log(`Published version: ${green(bold(newVersion))}`);
|
|
1403
|
+
console.log("✅ " + green(bold(`Released v${newVersion}!`)));
|
|
1360
1404
|
console.log("");
|
|
1361
1405
|
const changelog = await generateChangelog(cwd);
|
|
1362
1406
|
if (changelog.terminal) {
|
|
1363
|
-
|
|
1364
|
-
|
|
1407
|
+
frameHeader("\uD83D\uDCCB Changelog");
|
|
1408
|
+
frameLine(dim(`Since ${changelog.previousTag ?? "initial"}`));
|
|
1409
|
+
for (const line of changelog.terminal.split(`
|
|
1410
|
+
`)) {
|
|
1411
|
+
frameLine(line.trimStart());
|
|
1412
|
+
}
|
|
1413
|
+
frameFooter();
|
|
1365
1414
|
console.log("");
|
|
1366
1415
|
}
|
|
1367
1416
|
let releaseNotes = changelog.markdown;
|
|
1368
|
-
if (
|
|
1417
|
+
if (changelog.commits.length > 0) {
|
|
1369
1418
|
const claudeAvailable = await isClaudeAvailable();
|
|
1370
1419
|
if (claudeAvailable) {
|
|
1371
|
-
const useAI = await confirm("Generate release notes with AI (claude)?");
|
|
1420
|
+
const useAI = skipConfirms || await confirm("Generate release notes with AI (claude)?");
|
|
1372
1421
|
if (useAI) {
|
|
1373
|
-
console.log(
|
|
1422
|
+
console.log("");
|
|
1423
|
+
frameHeader("✨ AI Release Notes");
|
|
1424
|
+
frameLine(dim("Generating..."));
|
|
1374
1425
|
const aiNotes = await generateAIReleaseNotes(changelog.commits, newVersion);
|
|
1375
1426
|
if (aiNotes) {
|
|
1376
1427
|
releaseNotes = aiNotes;
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1428
|
+
frameLine();
|
|
1429
|
+
for (const line of aiNotes.split(`
|
|
1430
|
+
`)) {
|
|
1431
|
+
frameLine(line);
|
|
1432
|
+
}
|
|
1381
1433
|
} else {
|
|
1382
|
-
|
|
1434
|
+
frameLine(yellow("Generation failed, falling back to commit list.") + dim(" (run with --verbose for details)"));
|
|
1383
1435
|
}
|
|
1436
|
+
frameFooter();
|
|
1437
|
+
console.log("");
|
|
1384
1438
|
}
|
|
1385
1439
|
}
|
|
1386
1440
|
}
|
|
1387
1441
|
if (!options.dryRun) {
|
|
1442
|
+
let shouldTag;
|
|
1443
|
+
let shouldPush = false;
|
|
1444
|
+
let shouldRelease = false;
|
|
1388
1445
|
if (options.ci) {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
console.log(cyan("Pushing tag to origin..."));
|
|
1393
|
-
await pushGitTag(newVersion, cwd, options.dryRun);
|
|
1394
|
-
if (releaseNotes) {
|
|
1395
|
-
console.log(cyan("Creating GitHub release..."));
|
|
1396
|
-
const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
|
|
1397
|
-
if (releaseResult.success && releaseResult.url) {
|
|
1398
|
-
console.log(` Release created: ${cyan(releaseResult.url)}`);
|
|
1399
|
-
} else if (!releaseResult.success) {
|
|
1400
|
-
console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
} else {
|
|
1404
|
-
console.error(red(tagResult.error ?? "Failed to create git tag"));
|
|
1405
|
-
}
|
|
1406
|
-
console.log("");
|
|
1446
|
+
shouldTag = true;
|
|
1447
|
+
shouldPush = true;
|
|
1448
|
+
shouldRelease = !!releaseNotes;
|
|
1407
1449
|
} else {
|
|
1408
|
-
|
|
1450
|
+
shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
|
|
1409
1451
|
if (shouldTag) {
|
|
1452
|
+
shouldPush = skipConfirms || await confirm("Push tag to origin?");
|
|
1453
|
+
if (shouldPush && releaseNotes) {
|
|
1454
|
+
shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
if (shouldTag)
|
|
1410
1458
|
console.log("");
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1459
|
+
}
|
|
1460
|
+
if (shouldTag) {
|
|
1461
|
+
frameHeader("\uD83C\uDFF7️ Release");
|
|
1462
|
+
frameLine(dim(`Creating tag v${newVersion}...`));
|
|
1463
|
+
const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
|
|
1464
|
+
if (tagResult.success) {
|
|
1465
|
+
if (shouldPush) {
|
|
1466
|
+
frameLine(dim("Pushing tag to origin..."));
|
|
1467
|
+
await pushGitTag(newVersion, cwd, options.dryRun);
|
|
1468
|
+
if (releaseNotes && shouldRelease) {
|
|
1469
|
+
frameLine(dim("Creating GitHub release..."));
|
|
1470
|
+
const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
|
|
1471
|
+
if (releaseResult.success && releaseResult.url) {
|
|
1472
|
+
frameLine(` Release: ${cyan(releaseResult.url)}`);
|
|
1473
|
+
} else if (!releaseResult.success) {
|
|
1474
|
+
frameLine(yellow(releaseResult.error ?? "Failed to create GitHub release"));
|
|
1426
1475
|
}
|
|
1427
|
-
} else {
|
|
1428
|
-
console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
|
|
1429
1476
|
}
|
|
1430
1477
|
} else {
|
|
1431
|
-
|
|
1478
|
+
frameLine(`Push manually: ${dim(`git push origin v${newVersion}`)}`);
|
|
1432
1479
|
}
|
|
1433
|
-
|
|
1480
|
+
} else {
|
|
1481
|
+
frameLine(red(tagResult.error ?? "Failed to create git tag"));
|
|
1434
1482
|
}
|
|
1483
|
+
frameFooter();
|
|
1484
|
+
console.log("");
|
|
1435
1485
|
}
|
|
1436
1486
|
}
|
|
1437
|
-
console.log(green(bold("Done!")));
|
|
1487
|
+
console.log("\uD83C\uDF89 " + green(bold("Done!")));
|
|
1438
1488
|
closePrompt();
|
|
1439
1489
|
}
|
|
1440
1490
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pubz",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Interactive CLI for publishing npm packages (single or monorepo)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "bun build src/cli.ts --outdir dist --target node",
|
|
14
14
|
"dev": "bun run src/cli.ts",
|
|
15
|
+
"demo": "bun .kadai/actions/gen-demo.ts",
|
|
15
16
|
"typecheck": "tsc --noEmit",
|
|
16
17
|
"lint": "bunx biome check src/",
|
|
17
18
|
"lint:fix": "bunx biome check --write src/"
|