pubz 0.2.12 → 0.4.0
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 +7 -2
- package/dist/cli.js +295 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# `pubz`
|
|
2
2
|
|
|
3
|
+
<img width="1024" height="1024" alt="image" src="https://github.com/user-attachments/assets/11ffa33c-e895-4a7d-b2c3-dfadde8dd124" />
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
3
7
|
```bash
|
|
4
8
|
bunx pubz
|
|
5
9
|
```
|
|
@@ -14,8 +18,9 @@ bunx pubz
|
|
|
14
18
|
6. Commits version changes
|
|
15
19
|
7. Prompts you for where you want to publish (e.g. `npm` or private registry)
|
|
16
20
|
8. Builds packages
|
|
17
|
-
9.
|
|
18
|
-
10.
|
|
21
|
+
9. Transforms `workspace:` definitions to hard version numbers (so `npm` can be used for publishing with OIDC support).
|
|
22
|
+
10. Publishes to npm
|
|
23
|
+
11. Prompts you to create a `git tag` and push it
|
|
19
24
|
|
|
20
25
|
## Options
|
|
21
26
|
|
package/dist/cli.js
CHANGED
|
@@ -195,6 +195,9 @@ function prompt(question) {
|
|
|
195
195
|
function closePrompt() {
|
|
196
196
|
rl.close();
|
|
197
197
|
}
|
|
198
|
+
function pausePrompt() {
|
|
199
|
+
rl.close();
|
|
200
|
+
}
|
|
198
201
|
function resetPrompt() {
|
|
199
202
|
rl.close();
|
|
200
203
|
rl = readline.createInterface({
|
|
@@ -317,10 +320,25 @@ async function multiSelect(message, options, allSelectedByDefault = true) {
|
|
|
317
320
|
|
|
318
321
|
// src/auth.ts
|
|
319
322
|
import { spawn } from "node:child_process";
|
|
323
|
+
import { homedir } from "node:os";
|
|
324
|
+
|
|
325
|
+
// src/log.ts
|
|
326
|
+
var verboseEnabled = false;
|
|
327
|
+
function setVerbose(enabled) {
|
|
328
|
+
verboseEnabled = enabled;
|
|
329
|
+
}
|
|
330
|
+
function debug(...args) {
|
|
331
|
+
if (verboseEnabled) {
|
|
332
|
+
console.error("[debug]", ...args);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/auth.ts
|
|
320
337
|
async function checkNpmAuth(registry) {
|
|
321
338
|
return new Promise((resolve2) => {
|
|
322
339
|
const proc = spawn("npm", ["whoami", "--registry", registry], {
|
|
323
|
-
stdio: ["
|
|
340
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
341
|
+
cwd: homedir()
|
|
324
342
|
});
|
|
325
343
|
let stdout = "";
|
|
326
344
|
let stderr = "";
|
|
@@ -334,6 +352,7 @@ async function checkNpmAuth(registry) {
|
|
|
334
352
|
if (code === 0 && stdout.trim()) {
|
|
335
353
|
resolve2({ authenticated: true, username: stdout.trim() });
|
|
336
354
|
} else {
|
|
355
|
+
debug(`npm whoami failed: code=${code}, stdout=${JSON.stringify(stdout)}, stderr=${JSON.stringify(stderr)}`);
|
|
337
356
|
resolve2({ authenticated: false });
|
|
338
357
|
}
|
|
339
358
|
});
|
|
@@ -341,10 +360,13 @@ async function checkNpmAuth(registry) {
|
|
|
341
360
|
}
|
|
342
361
|
async function npmLogin(registry) {
|
|
343
362
|
return new Promise((resolve2) => {
|
|
363
|
+
debug(`spawning: npm login --registry ${registry}`);
|
|
344
364
|
const proc = spawn("npm", ["login", "--registry", registry], {
|
|
345
|
-
stdio: "inherit"
|
|
365
|
+
stdio: "inherit",
|
|
366
|
+
cwd: homedir()
|
|
346
367
|
});
|
|
347
368
|
proc.on("close", (code) => {
|
|
369
|
+
debug(`npm login exited: code=${code}`);
|
|
348
370
|
if (code === 0) {
|
|
349
371
|
resolve2({ success: true });
|
|
350
372
|
} else {
|
|
@@ -357,6 +379,7 @@ async function npmLogin(registry) {
|
|
|
357
379
|
// src/publish.ts
|
|
358
380
|
import { spawn as spawn2 } from "node:child_process";
|
|
359
381
|
import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
|
|
382
|
+
import { homedir as homedir2 } from "node:os";
|
|
360
383
|
import { join as join3 } from "node:path";
|
|
361
384
|
function run(command, args, cwd) {
|
|
362
385
|
return new Promise((resolve2) => {
|
|
@@ -441,6 +464,7 @@ async function verifyBuild(pkg) {
|
|
|
441
464
|
function isOtpError(output) {
|
|
442
465
|
return output.includes("EOTP") || output.includes("one-time password");
|
|
443
466
|
}
|
|
467
|
+
var NPM_COMMAND = process.env.PUBZ_NPM_COMMAND ?? "npm";
|
|
444
468
|
async function publishPackage(pkg, registry, context, dryRun) {
|
|
445
469
|
if (dryRun) {
|
|
446
470
|
console.log(` [DRY RUN] Would publish ${pkg.name}@${pkg.version} to ${registry}`);
|
|
@@ -454,11 +478,13 @@ async function publishPackage(pkg, registry, context, dryRun) {
|
|
|
454
478
|
let result;
|
|
455
479
|
if (context.useBrowserAuth) {
|
|
456
480
|
args.push("--auth-type", "web");
|
|
457
|
-
|
|
481
|
+
args.push(pkg.path);
|
|
482
|
+
context.onInteractiveStart?.();
|
|
483
|
+
const interactiveResult = await runInteractive(NPM_COMMAND, args, homedir2());
|
|
458
484
|
result = { code: interactiveResult.code, output: "" };
|
|
459
485
|
context.onInteractiveComplete?.();
|
|
460
486
|
} else {
|
|
461
|
-
result = await run(
|
|
487
|
+
result = await run(NPM_COMMAND, args, pkg.path);
|
|
462
488
|
}
|
|
463
489
|
if (result.code !== 0) {
|
|
464
490
|
if (isOtpError(result.output)) {
|
|
@@ -534,8 +560,184 @@ async function pushGitTag(version, cwd, dryRun) {
|
|
|
534
560
|
return { success: true };
|
|
535
561
|
}
|
|
536
562
|
|
|
563
|
+
// src/changelog.ts
|
|
564
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
565
|
+
function parseGitRemoteUrl(remoteUrl) {
|
|
566
|
+
const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
|
|
567
|
+
if (sshMatch) {
|
|
568
|
+
return `https://${sshMatch[1]}/${sshMatch[2]}`;
|
|
569
|
+
}
|
|
570
|
+
const httpsMatch = remoteUrl.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);
|
|
571
|
+
if (httpsMatch) {
|
|
572
|
+
return `https://${httpsMatch[1]}/${httpsMatch[2]}`;
|
|
573
|
+
}
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
function runSilent(command, args, cwd) {
|
|
577
|
+
return new Promise((resolve2) => {
|
|
578
|
+
const proc = spawn3(command, args, {
|
|
579
|
+
cwd,
|
|
580
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
581
|
+
});
|
|
582
|
+
let output = "";
|
|
583
|
+
proc.stdout?.on("data", (data) => {
|
|
584
|
+
output += data.toString();
|
|
585
|
+
});
|
|
586
|
+
proc.stderr?.on("data", (data) => {
|
|
587
|
+
output += data.toString();
|
|
588
|
+
});
|
|
589
|
+
proc.on("close", (code) => {
|
|
590
|
+
resolve2({ code: code ?? 1, output });
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
async function getPreviousTag(cwd) {
|
|
595
|
+
const result = await runSilent("git", ["tag", "--sort=-version:refname"], cwd);
|
|
596
|
+
if (result.code !== 0)
|
|
597
|
+
return null;
|
|
598
|
+
const tags = result.output.trim().split(`
|
|
599
|
+
`).filter((t) => t.length > 0);
|
|
600
|
+
return tags[0] ?? null;
|
|
601
|
+
}
|
|
602
|
+
async function getRepoUrl(cwd) {
|
|
603
|
+
const result = await runSilent("git", ["remote", "get-url", "origin"], cwd);
|
|
604
|
+
if (result.code !== 0)
|
|
605
|
+
return null;
|
|
606
|
+
return parseGitRemoteUrl(result.output.trim());
|
|
607
|
+
}
|
|
608
|
+
async function getCommitsSince(ref, cwd) {
|
|
609
|
+
const result = await runSilent("git", ["log", `${ref}..HEAD`, "--oneline", "--no-decorate"], cwd);
|
|
610
|
+
if (result.code !== 0)
|
|
611
|
+
return [];
|
|
612
|
+
return result.output.trim().split(`
|
|
613
|
+
`).filter((line) => line.length > 0).map((line) => {
|
|
614
|
+
const spaceIdx = line.indexOf(" ");
|
|
615
|
+
return {
|
|
616
|
+
sha: line.slice(0, spaceIdx),
|
|
617
|
+
message: line.slice(spaceIdx + 1)
|
|
618
|
+
};
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function isReleaseCommit(message) {
|
|
622
|
+
return /^chore: release v/.test(message);
|
|
623
|
+
}
|
|
624
|
+
function formatChangelogTerminal(commits) {
|
|
625
|
+
const filtered = commits.filter((c) => !isReleaseCommit(c.message));
|
|
626
|
+
if (filtered.length === 0)
|
|
627
|
+
return "";
|
|
628
|
+
return filtered.map((c) => ` ${dim(c.sha)} ${c.message}`).join(`
|
|
629
|
+
`);
|
|
630
|
+
}
|
|
631
|
+
function formatChangelogMarkdown(commits, repoUrl) {
|
|
632
|
+
const filtered = commits.filter((c) => !isReleaseCommit(c.message));
|
|
633
|
+
if (filtered.length === 0)
|
|
634
|
+
return "";
|
|
635
|
+
return filtered.map((c) => {
|
|
636
|
+
const shaRef = repoUrl ? `[\`${c.sha}\`](${repoUrl}/commit/${c.sha})` : `\`${c.sha}\``;
|
|
637
|
+
return `- ${shaRef} ${c.message}`;
|
|
638
|
+
}).join(`
|
|
639
|
+
`);
|
|
640
|
+
}
|
|
641
|
+
async function generateChangelog(cwd) {
|
|
642
|
+
const [previousTag, repoUrl] = await Promise.all([
|
|
643
|
+
getPreviousTag(cwd),
|
|
644
|
+
getRepoUrl(cwd)
|
|
645
|
+
]);
|
|
646
|
+
if (!previousTag) {
|
|
647
|
+
return { commits: [], terminal: "", markdown: "", previousTag: null, repoUrl };
|
|
648
|
+
}
|
|
649
|
+
const commits = await getCommitsSince(previousTag, cwd);
|
|
650
|
+
const terminal = formatChangelogTerminal(commits);
|
|
651
|
+
const markdown = formatChangelogMarkdown(commits, repoUrl);
|
|
652
|
+
return { commits, terminal, markdown, previousTag, repoUrl };
|
|
653
|
+
}
|
|
654
|
+
async function createGitHubRelease(version, body, cwd, dryRun) {
|
|
655
|
+
const tagName = `v${version}`;
|
|
656
|
+
if (dryRun) {
|
|
657
|
+
console.log(`[DRY RUN] Would create GitHub release for ${tagName}`);
|
|
658
|
+
return { success: true };
|
|
659
|
+
}
|
|
660
|
+
const result = await runSilent("gh", ["release", "create", tagName, "--title", tagName, "--notes", body], cwd);
|
|
661
|
+
if (result.code !== 0) {
|
|
662
|
+
return {
|
|
663
|
+
success: false,
|
|
664
|
+
error: result.output.trim() || `Failed to create GitHub release for ${tagName}`
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const url = result.output.trim();
|
|
668
|
+
return { success: true, url };
|
|
669
|
+
}
|
|
670
|
+
|
|
537
671
|
// src/version.ts
|
|
538
672
|
import { readFile as readFile3, writeFile } from "node:fs/promises";
|
|
673
|
+
async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
|
|
674
|
+
const packageNames = new Set(packages.map((p) => p.name));
|
|
675
|
+
const transforms = [];
|
|
676
|
+
for (const pkg of packages) {
|
|
677
|
+
const content = await readFile3(pkg.packageJsonPath, "utf-8");
|
|
678
|
+
const packageJson = JSON.parse(content);
|
|
679
|
+
let modified = false;
|
|
680
|
+
for (const depType of [
|
|
681
|
+
"dependencies",
|
|
682
|
+
"devDependencies",
|
|
683
|
+
"peerDependencies"
|
|
684
|
+
]) {
|
|
685
|
+
const deps = packageJson[depType];
|
|
686
|
+
if (!deps)
|
|
687
|
+
continue;
|
|
688
|
+
for (const depName of Object.keys(deps)) {
|
|
689
|
+
if (packageNames.has(depName)) {
|
|
690
|
+
const oldVersion = deps[depName];
|
|
691
|
+
if (oldVersion.startsWith("workspace:")) {
|
|
692
|
+
const modifier = oldVersion.replace("workspace:", "");
|
|
693
|
+
const newVersionSpec = modifier === "*" || modifier === "" ? newVersion : `${modifier}${newVersion}`;
|
|
694
|
+
if (dryRun) {
|
|
695
|
+
console.log(` [DRY RUN] Would temporarily transform ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
|
|
696
|
+
} else {
|
|
697
|
+
transforms.push({
|
|
698
|
+
packageJsonPath: pkg.packageJsonPath,
|
|
699
|
+
depType,
|
|
700
|
+
depName,
|
|
701
|
+
originalValue: oldVersion
|
|
702
|
+
});
|
|
703
|
+
deps[depName] = newVersionSpec;
|
|
704
|
+
modified = true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (modified && !dryRun) {
|
|
711
|
+
await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
712
|
+
`);
|
|
713
|
+
console.log(` Transformed workspace references in ${pkg.name}`);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return transforms;
|
|
717
|
+
}
|
|
718
|
+
async function restoreWorkspaceProtocol(transforms) {
|
|
719
|
+
const byPath = new Map;
|
|
720
|
+
for (const transform of transforms) {
|
|
721
|
+
const existing = byPath.get(transform.packageJsonPath) ?? [];
|
|
722
|
+
existing.push(transform);
|
|
723
|
+
byPath.set(transform.packageJsonPath, existing);
|
|
724
|
+
}
|
|
725
|
+
for (const [packageJsonPath, pathTransforms] of byPath) {
|
|
726
|
+
const content = await readFile3(packageJsonPath, "utf-8");
|
|
727
|
+
const packageJson = JSON.parse(content);
|
|
728
|
+
for (const transform of pathTransforms) {
|
|
729
|
+
const deps = packageJson[transform.depType];
|
|
730
|
+
if (deps) {
|
|
731
|
+
deps[transform.depName] = transform.originalValue;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
735
|
+
`);
|
|
736
|
+
}
|
|
737
|
+
if (transforms.length > 0) {
|
|
738
|
+
console.log(` Restored workspace references in ${byPath.size} package(s)`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
539
741
|
function bumpVersion(version, type) {
|
|
540
742
|
if (type === "none")
|
|
541
743
|
return version;
|
|
@@ -633,6 +835,7 @@ Options:
|
|
|
633
835
|
--yes, -y Skip yes/no confirmation prompts (still asks for choices)
|
|
634
836
|
--ci CI mode: skip all prompts, auto-accept everything
|
|
635
837
|
--version <value> Version bump type (patch|minor|major) or explicit version (required with --ci)
|
|
838
|
+
--verbose Show debug logging
|
|
636
839
|
-h, --help Show this help message
|
|
637
840
|
|
|
638
841
|
Examples:
|
|
@@ -652,6 +855,7 @@ function parseArgs(args) {
|
|
|
652
855
|
skipConfirms: false,
|
|
653
856
|
ci: false,
|
|
654
857
|
version: "",
|
|
858
|
+
verbose: false,
|
|
655
859
|
help: false
|
|
656
860
|
};
|
|
657
861
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -679,6 +883,9 @@ function parseArgs(args) {
|
|
|
679
883
|
case "--version":
|
|
680
884
|
options.version = args[++i] || "";
|
|
681
885
|
break;
|
|
886
|
+
case "--verbose":
|
|
887
|
+
options.verbose = true;
|
|
888
|
+
break;
|
|
682
889
|
case "-h":
|
|
683
890
|
case "--help":
|
|
684
891
|
options.help = true;
|
|
@@ -693,6 +900,7 @@ async function main() {
|
|
|
693
900
|
process.exit(0);
|
|
694
901
|
}
|
|
695
902
|
const options = parseArgs(process.argv.slice(2));
|
|
903
|
+
setVerbose(options.verbose);
|
|
696
904
|
if (options.help) {
|
|
697
905
|
printUsage();
|
|
698
906
|
process.exit(0);
|
|
@@ -861,7 +1069,9 @@ async function main() {
|
|
|
861
1069
|
console.log("");
|
|
862
1070
|
console.log(yellow("Not logged in to npm.") + " Starting login...");
|
|
863
1071
|
console.log("");
|
|
1072
|
+
pausePrompt();
|
|
864
1073
|
const loginResult = await npmLogin(registry);
|
|
1074
|
+
resetPrompt();
|
|
865
1075
|
if (!loginResult.success) {
|
|
866
1076
|
console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
|
|
867
1077
|
closePrompt();
|
|
@@ -915,47 +1125,68 @@ async function main() {
|
|
|
915
1125
|
console.log("");
|
|
916
1126
|
if (options.dryRun) {
|
|
917
1127
|
console.log(yellow("[DRY RUN]") + ` Would publish the following packages to ${cyan(registry)}:`);
|
|
918
|
-
console.log("");
|
|
919
|
-
for (const pkg of packages) {
|
|
920
|
-
console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
921
|
-
}
|
|
922
|
-
console.log("");
|
|
923
|
-
console.log(muted("Run without --dry-run to actually publish."));
|
|
924
1128
|
} else {
|
|
925
1129
|
console.log("About to publish the following packages:");
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1130
|
+
}
|
|
1131
|
+
console.log("");
|
|
1132
|
+
for (const pkg of packages) {
|
|
1133
|
+
console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
|
|
1134
|
+
}
|
|
1135
|
+
console.log("");
|
|
1136
|
+
console.log(`Registry: ${cyan(registry)}`);
|
|
1137
|
+
console.log("");
|
|
1138
|
+
if (!options.dryRun && !skipConfirms) {
|
|
1139
|
+
const shouldContinue = await confirm("Continue?");
|
|
1140
|
+
if (!shouldContinue) {
|
|
1141
|
+
console.log(yellow("Publish cancelled."));
|
|
1142
|
+
closePrompt();
|
|
1143
|
+
process.exit(0);
|
|
940
1144
|
}
|
|
941
1145
|
console.log("");
|
|
942
|
-
|
|
1146
|
+
}
|
|
1147
|
+
console.log(cyan("Preparing packages for publish..."));
|
|
1148
|
+
console.log("");
|
|
1149
|
+
const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
|
|
1150
|
+
if (workspaceTransforms.length > 0 || options.dryRun) {
|
|
943
1151
|
console.log("");
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1152
|
+
}
|
|
1153
|
+
console.log(cyan("Publishing packages..."));
|
|
1154
|
+
console.log("");
|
|
1155
|
+
const publishContext = {
|
|
1156
|
+
otp: options.otp,
|
|
1157
|
+
useBrowserAuth: !options.ci,
|
|
1158
|
+
onInteractiveStart: pausePrompt,
|
|
1159
|
+
onInteractiveComplete: resetPrompt
|
|
1160
|
+
};
|
|
1161
|
+
let publishFailed = false;
|
|
1162
|
+
let failedPackageName = "";
|
|
1163
|
+
let failedError = "";
|
|
1164
|
+
try {
|
|
949
1165
|
for (const pkg of packages) {
|
|
950
1166
|
const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
|
|
951
1167
|
if (!result.success) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
process.exit(1);
|
|
1168
|
+
publishFailed = true;
|
|
1169
|
+
failedPackageName = pkg.name;
|
|
1170
|
+
failedError = result.error ?? "Unknown error";
|
|
1171
|
+
break;
|
|
957
1172
|
}
|
|
958
1173
|
}
|
|
1174
|
+
} finally {
|
|
1175
|
+
if (workspaceTransforms.length > 0) {
|
|
1176
|
+
console.log("");
|
|
1177
|
+
await restoreWorkspaceProtocol(workspaceTransforms);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
if (publishFailed) {
|
|
1181
|
+
console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
|
|
1182
|
+
console.log("");
|
|
1183
|
+
console.log(red("Stopping publish process."));
|
|
1184
|
+
closePrompt();
|
|
1185
|
+
process.exit(1);
|
|
1186
|
+
}
|
|
1187
|
+
if (options.dryRun) {
|
|
1188
|
+
console.log("");
|
|
1189
|
+
console.log(muted("Run without --dry-run to actually publish."));
|
|
959
1190
|
}
|
|
960
1191
|
console.log("");
|
|
961
1192
|
console.log(dim("═".repeat(30)));
|
|
@@ -963,27 +1194,52 @@ async function main() {
|
|
|
963
1194
|
console.log("");
|
|
964
1195
|
console.log(`Published version: ${green(bold(newVersion))}`);
|
|
965
1196
|
console.log("");
|
|
1197
|
+
const changelog = await generateChangelog(cwd);
|
|
1198
|
+
if (changelog.terminal) {
|
|
1199
|
+
console.log(bold("Changes since ") + cyan(changelog.previousTag ?? "initial") + bold(":"));
|
|
1200
|
+
console.log(changelog.terminal);
|
|
1201
|
+
console.log("");
|
|
1202
|
+
}
|
|
966
1203
|
if (!options.dryRun) {
|
|
967
1204
|
if (options.ci) {
|
|
968
|
-
console.log("");
|
|
969
1205
|
console.log(cyan("Creating git tag..."));
|
|
970
1206
|
const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
|
|
971
1207
|
if (tagResult.success) {
|
|
972
1208
|
console.log(cyan("Pushing tag to origin..."));
|
|
973
1209
|
await pushGitTag(newVersion, cwd, options.dryRun);
|
|
1210
|
+
if (changelog.markdown) {
|
|
1211
|
+
console.log(cyan("Creating GitHub release..."));
|
|
1212
|
+
const releaseResult = await createGitHubRelease(newVersion, changelog.markdown, cwd, options.dryRun);
|
|
1213
|
+
if (releaseResult.success && releaseResult.url) {
|
|
1214
|
+
console.log(` Release created: ${cyan(releaseResult.url)}`);
|
|
1215
|
+
} else if (!releaseResult.success) {
|
|
1216
|
+
console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
974
1219
|
} else {
|
|
975
1220
|
console.error(red(tagResult.error ?? "Failed to create git tag"));
|
|
976
1221
|
}
|
|
977
1222
|
console.log("");
|
|
978
|
-
} else
|
|
979
|
-
const shouldTag = await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
|
|
1223
|
+
} else {
|
|
1224
|
+
const shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
|
|
980
1225
|
if (shouldTag) {
|
|
981
1226
|
console.log("");
|
|
982
1227
|
const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
|
|
983
1228
|
if (tagResult.success) {
|
|
984
|
-
const shouldPush = await confirm("Push tag to origin?");
|
|
1229
|
+
const shouldPush = skipConfirms || await confirm("Push tag to origin?");
|
|
985
1230
|
if (shouldPush) {
|
|
986
1231
|
await pushGitTag(newVersion, cwd, options.dryRun);
|
|
1232
|
+
if (changelog.markdown) {
|
|
1233
|
+
const shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
|
|
1234
|
+
if (shouldRelease) {
|
|
1235
|
+
const releaseResult = await createGitHubRelease(newVersion, changelog.markdown, cwd, options.dryRun);
|
|
1236
|
+
if (releaseResult.success && releaseResult.url) {
|
|
1237
|
+
console.log(` Release created: ${cyan(releaseResult.url)}`);
|
|
1238
|
+
} else if (!releaseResult.success) {
|
|
1239
|
+
console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
987
1243
|
} else {
|
|
988
1244
|
console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
|
|
989
1245
|
}
|