@varlock/bumpy 1.2.0 → 1.2.2

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.
Files changed (34) hide show
  1. package/README.md +49 -34
  2. package/dist/{add-yP81c9_q.mjs → add-DEqGa5gI.mjs} +8 -8
  3. package/dist/apply-release-plan-Bi9OSWks.mjs +57 -0
  4. package/dist/{bump-file-Br2bTaWp.mjs → bump-file-BTsntOO-.mjs} +63 -24
  5. package/dist/{changelog-github-DkACMj0j.mjs → changelog-github-CEaDCtTk.mjs} +49 -18
  6. package/dist/changelog-xKuL0IKx.mjs +109 -0
  7. package/dist/{check-D_0exKi6.mjs → check-D3eXRyKJ.mjs} +12 -7
  8. package/dist/{ci-CvaikKX1.mjs → ci-BVTwTUUK.mjs} +131 -40
  9. package/dist/{ci-setup-CARJFhcE.mjs → ci-setup-D1NCzbNH.mjs} +3 -3
  10. package/dist/cli.mjs +14 -14
  11. package/dist/{config-D7Umr-fT.mjs → config-CJIj8xG3.mjs} +2 -80
  12. package/dist/{generate-BOLrTYWR.mjs → generate-wHN6Ll6p.mjs} +6 -6
  13. package/dist/{git-YDedMddc.mjs → git-D0__HP86.mjs} +11 -2
  14. package/dist/index.d.mts +14 -4
  15. package/dist/index.mjs +10 -8
  16. package/dist/{init-DJhMaceS.mjs → init-DND7zRGD.mjs} +3 -3
  17. package/dist/{publish-CPZwqyWh.mjs → publish-BwidFqbo.mjs} +9 -9
  18. package/dist/{publish-pipeline-BFt96o_h.mjs → publish-pipeline-BvLIu7WF.mjs} +4 -4
  19. package/dist/{release-plan-CNOuSI-d.mjs → release-plan-21H89Cx1.mjs} +3 -2
  20. package/dist/{status-skGX8uU7.mjs → status-CDGxgXWd.mjs} +39 -18
  21. package/dist/types-CSM0c2-m.mjs +80 -0
  22. package/dist/{version-CnXcbqi1.mjs → version-ClkaCNTE.mjs} +14 -10
  23. package/dist/{workspace-BHsAPUmC.mjs → workspace-c9-TqXed.mjs} +2 -2
  24. package/package.json +1 -1
  25. package/dist/apply-release-plan-CPzu6JcF.mjs +0 -146
  26. /package/dist/{ai-STKnq09z.mjs → ai-C66IfTzs.mjs} +0 -0
  27. /package/dist/{clack-C6bVkGxf.mjs → clack-CJT1JFFa.mjs} +0 -0
  28. /package/dist/{commit-message-BwsowSds.mjs → commit-message-DOIfDxfj.mjs} +0 -0
  29. /package/dist/{dep-graph-DiLeAhl9.mjs → dep-graph-E-9-eQ2J.mjs} +0 -0
  30. /package/dist/{names-C-TuOPbd.mjs → names-CBy7d8K_.mjs} +0 -0
  31. /package/dist/{package-manager-ByJ0wKYh.mjs → package-manager-CClZtIHP.mjs} +0 -0
  32. /package/dist/{picomatch-DMmqYjgq.mjs → picomatch-TGJi--_I.mjs} +0 -0
  33. /package/dist/{semver-BJzWIuRz.mjs → semver-DfQyVLM_.mjs} +0 -0
  34. /package/dist/{shell-CY7OD48z.mjs → shell-u3bYGxNy.mjs} +0 -0
@@ -1,9 +1,9 @@
1
1
  import { n as log, o as __toESM, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
3
- import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
4
- import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-Br2bTaWp.mjs";
5
- import { r as getChangedFiles } from "./git-YDedMddc.mjs";
6
- import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
2
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-CJIj8xG3.mjs";
3
+ import { n as discoverWorkspace } from "./workspace-c9-TqXed.mjs";
4
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-BTsntOO-.mjs";
5
+ import { r as getChangedFiles } from "./git-D0__HP86.mjs";
6
+ import { t as require_picomatch } from "./picomatch-TGJi--_I.mjs";
7
7
  import { relative } from "node:path";
8
8
  //#region src/commands/check.ts
9
9
  var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
@@ -25,8 +25,13 @@ async function checkCommand(rootDir, opts = {}) {
25
25
  log.info("No changed files detected.");
26
26
  return;
27
27
  }
28
- const { branchBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(await readBumpFiles(rootDir), changedFiles, rootDir);
29
- if (hasEmptyBumpFile) {
28
+ const { bumpFiles: allBumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
29
+ if (parseErrors.length > 0) {
30
+ for (const err of parseErrors) log.error(err);
31
+ process.exit(1);
32
+ }
33
+ const { branchBumpFiles, emptyBumpFileIds } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
34
+ if (emptyBumpFileIds.length > 0) {
30
35
  log.success("Empty bump file found — no releases needed.");
31
36
  return;
32
37
  }
@@ -1,15 +1,15 @@
1
1
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig } from "./config-D7Umr-fT.mjs";
3
- import { t as detectPackageManager } from "./package-manager-ByJ0wKYh.mjs";
4
- import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
5
- import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
6
- import { n as runArgs, r as runArgsAsync, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
7
- import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-Br2bTaWp.mjs";
8
- import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
9
- import { r as getChangedFiles } from "./git-YDedMddc.mjs";
10
- import { t as randomName } from "./names-C-TuOPbd.mjs";
11
- import { findChangedPackages } from "./check-D_0exKi6.mjs";
12
- import { t as resolveCommitMessage } from "./commit-message-BwsowSds.mjs";
2
+ import { a as loadConfig } from "./config-CJIj8xG3.mjs";
3
+ import { t as detectPackageManager } from "./package-manager-CClZtIHP.mjs";
4
+ import { n as discoverWorkspace } from "./workspace-c9-TqXed.mjs";
5
+ import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
6
+ import { n as runArgs, r as runArgsAsync, s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
7
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-BTsntOO-.mjs";
8
+ import { t as assembleReleasePlan } from "./release-plan-21H89Cx1.mjs";
9
+ import { r as getChangedFiles } from "./git-D0__HP86.mjs";
10
+ import { t as randomName } from "./names-CBy7d8K_.mjs";
11
+ import { findChangedPackages } from "./check-D3eXRyKJ.mjs";
12
+ import { t as resolveCommitMessage } from "./commit-message-DOIfDxfj.mjs";
13
13
  import { createHash } from "node:crypto";
14
14
  //#region src/commands/ci.ts
15
15
  /**
@@ -79,7 +79,7 @@ async function ciCheckCommand(rootDir, opts) {
79
79
  const config = await loadConfig(rootDir);
80
80
  const { packages } = await discoverWorkspace(rootDir, config);
81
81
  const depGraph = new DependencyGraph(packages);
82
- const allBumpFiles = await readBumpFiles(rootDir);
82
+ const { bumpFiles: allBumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
83
83
  if (detectPrBranch(rootDir) === config.versionPr.branch) {
84
84
  log.dim(" Skipping — this is the version PR branch.");
85
85
  return;
@@ -89,18 +89,22 @@ async function ciCheckCommand(rootDir, opts) {
89
89
  const prNumber = detectPrNumber();
90
90
  const pm = await detectPackageManager(rootDir);
91
91
  const changedFiles = getChangedFiles(rootDir, config.baseBranch);
92
- const { branchBumpFiles: prBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
93
- if (hasEmptyBumpFile) {
94
- log.success("Empty bump file found — no releases needed.");
95
- if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatNoBumpFilesComment(detectPrBranch(rootDir), pm), rootDir, opts.patComments);
96
- return;
97
- }
92
+ const { branchBumpFiles: prBumpFiles, emptyBumpFileIds } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors);
93
+ if (parseErrors.length > 0) for (const err of parseErrors) log.error(err);
98
94
  if (prBumpFiles.length === 0) {
99
- const willFail = !opts.noFail;
100
- const msg = "No bump files found in this PR.";
95
+ if (emptyBumpFileIds.length > 0 && parseErrors.length === 0) {
96
+ log.success("Empty bump file found no releases needed.");
97
+ if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatEmptyBumpFileComment(emptyBumpFileIds, prNumber, detectPrBranch(rootDir)), rootDir, opts.patComments);
98
+ return;
99
+ }
100
+ const willFail = !opts.noFail || parseErrors.length > 0;
101
+ const msg = parseErrors.length > 0 ? "Bump file(s) found but failed to parse — see errors above." : "No bump files found in this PR.";
101
102
  if (willFail) log.error(msg);
102
103
  else log.warn(msg);
103
- if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatNoBumpFilesComment(detectPrBranch(rootDir), pm), rootDir, opts.patComments);
104
+ if (shouldComment && prNumber) {
105
+ const prBranch = detectPrBranch(rootDir);
106
+ await postOrUpdatePrComment(prNumber, parseErrors.length > 0 ? formatBumpFileErrorsComment(parseErrors, prBranch, pm) : formatNoBumpFilesComment(prBranch, pm), rootDir, opts.patComments);
107
+ }
104
108
  if (willFail) process.exit(1);
105
109
  return;
106
110
  }
@@ -111,7 +115,8 @@ async function ciCheckCommand(rootDir, opts) {
111
115
  console.log(` ${r.name}: ${r.oldVersion} → ${colorize(r.newVersion, "cyan")}${tag}`);
112
116
  }
113
117
  if (plan.warnings.length > 0) for (const w of plan.warnings) log.warn(w);
114
- if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings), rootDir, opts.patComments);
118
+ if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings, parseErrors, emptyBumpFileIds), rootDir, opts.patComments);
119
+ if (parseErrors.length > 0 && !opts.noFail) process.exit(1);
115
120
  const coveredPackages = new Set(plan.releases.map((r) => r.name));
116
121
  const missing = (await findChangedPackages(changedFiles, packages, rootDir, config)).filter((name) => !coveredPackages.has(name));
117
122
  if (missing.length > 0) {
@@ -129,10 +134,14 @@ async function ciReleaseCommand(rootDir, opts) {
129
134
  ensureGitIdentity(rootDir, config);
130
135
  const { packages } = await discoverWorkspace(rootDir, config);
131
136
  const depGraph = new DependencyGraph(packages);
132
- const bumpFiles = await readBumpFiles(rootDir);
137
+ const { bumpFiles, errors: releaseParseErrors } = await readBumpFiles(rootDir);
138
+ if (releaseParseErrors.length > 0) {
139
+ for (const err of releaseParseErrors) log.error(err);
140
+ throw new Error("Bump file parse errors must be fixed before releasing.");
141
+ }
133
142
  if (bumpFiles.length === 0) {
134
143
  log.info("No pending bump files — checking for unpublished packages...");
135
- const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
144
+ const { publishCommand } = await import("./publish-BwidFqbo.mjs");
136
145
  await publishCommand(rootDir, { tag: opts.tag });
137
146
  return;
138
147
  }
@@ -146,7 +155,7 @@ async function ciReleaseCommand(rootDir, opts) {
146
155
  }
147
156
  async function autoPublish(rootDir, config, plan, tag) {
148
157
  log.step("Running bumpy version...");
149
- const { versionCommand } = await import("./version-CnXcbqi1.mjs");
158
+ const { versionCommand } = await import("./version-ClkaCNTE.mjs");
150
159
  await versionCommand(rootDir);
151
160
  log.step("Committing version changes...");
152
161
  runArgs([
@@ -175,7 +184,7 @@ async function autoPublish(rootDir, config, plan, tag) {
175
184
  ], { cwd: rootDir });
176
185
  }
177
186
  log.step("Running bumpy publish...");
178
- const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
187
+ const { publishCommand } = await import("./publish-BwidFqbo.mjs");
179
188
  await publishCommand(rootDir, { tag });
180
189
  }
181
190
  /**
@@ -341,7 +350,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
341
350
  branch
342
351
  ], { cwd: rootDir });
343
352
  log.step("Running bumpy version...");
344
- const { versionCommand } = await import("./version-CnXcbqi1.mjs");
353
+ const { versionCommand } = await import("./version-ClkaCNTE.mjs");
345
354
  await versionCommand(rootDir);
346
355
  runArgs([
347
356
  "git",
@@ -371,9 +380,10 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
371
380
  input: await resolveCommitMessage(config.versionCommitMessage, plan, rootDir)
372
381
  });
373
382
  pushWithToken(rootDir, branch, config);
374
- const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs);
383
+ const repo = process.env.GITHUB_REPOSITORY;
375
384
  if (existingPr) {
376
385
  const validPr = validatePrNumber(existingPr);
386
+ const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, validPr);
377
387
  log.step(`Updating existing PR #${validPr}...`);
378
388
  await withPatToken(!!patPr, () => runArgsAsync([
379
389
  "gh",
@@ -392,6 +402,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
392
402
  } else {
393
403
  log.step("Creating version PR...");
394
404
  const prTitle = config.versionPr.title;
405
+ const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, null);
395
406
  const result = await withPatToken(!!patPr, () => runArgsAsync([
396
407
  "gh",
397
408
  "pr",
@@ -409,6 +420,23 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
409
420
  input: prBody
410
421
  }));
411
422
  log.success(`🐸 Created PR: ${result}`);
423
+ if (repo) {
424
+ const newPrNumber = result?.match(/\/pull\/(\d+)/)?.[1];
425
+ if (newPrNumber) {
426
+ const updatedBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, newPrNumber);
427
+ await withPatToken(!!patPr, () => runArgsAsync([
428
+ "gh",
429
+ "pr",
430
+ "edit",
431
+ newPrNumber,
432
+ "--body-file",
433
+ "-"
434
+ ], {
435
+ cwd: rootDir,
436
+ input: updatedBody
437
+ }));
438
+ }
439
+ }
412
440
  if (!patPr) pushWithToken(rootDir, branch, config);
413
441
  }
414
442
  runArgs([
@@ -439,11 +467,11 @@ function pmRunCommand(pm) {
439
467
  if (pm === "yarn") return "yarn bumpy";
440
468
  return "npx bumpy";
441
469
  }
442
- function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warnings = []) {
470
+ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warnings = [], parseErrors = [], emptyBumpFileIds = []) {
443
471
  const repo = process.env.GITHUB_REPOSITORY;
444
472
  const lines = [];
445
473
  const preamble = [
446
- `<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-talking.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
474
+ `<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-clipboard.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
447
475
  "",
448
476
  "**The changes in this PR will be included in the next version bump.**",
449
477
  "<br clear=\"left\" />"
@@ -477,12 +505,27 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
477
505
  const filename = `${bf.id}.md`;
478
506
  const parts = [`\`${filename}\``];
479
507
  if (repo) {
480
- parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/files#diff-.bumpy/${filename}))`);
508
+ parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/changes#diff-${sha256Hex(`.bumpy/${filename}`)}))`);
509
+ if (prBranch) parts.push(`([edit](https://github.com/${repo}/edit/${prBranch}/.bumpy/${filename}))`);
510
+ }
511
+ lines.push(`- ${parts.join(" ")}`);
512
+ }
513
+ for (const id of emptyBumpFileIds) {
514
+ const filename = `${id}.md`;
515
+ const parts = [`\`${filename}\` _(empty — no release)_`];
516
+ if (repo) {
517
+ parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/changes#diff-${sha256Hex(`.bumpy/${filename}`)}))`);
481
518
  if (prBranch) parts.push(`([edit](https://github.com/${repo}/edit/${prBranch}/.bumpy/${filename}))`);
482
519
  }
483
520
  lines.push(`- ${parts.join(" ")}`);
484
521
  }
485
522
  lines.push("");
523
+ if (parseErrors.length > 0) {
524
+ lines.push("#### Errors");
525
+ lines.push("");
526
+ for (const e of parseErrors) lines.push(`> :x: ${e}`);
527
+ lines.push("");
528
+ }
486
529
  if (warnings.length > 0) {
487
530
  lines.push("#### Warnings");
488
531
  lines.push("");
@@ -496,11 +539,58 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
496
539
  lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
497
540
  return lines.join("\n");
498
541
  }
499
- function formatNoBumpFilesComment(prBranch, pm) {
542
+ function formatBumpFileErrorsComment(errors, prBranch, pm) {
500
543
  const runCmd = pmRunCommand(pm);
544
+ const lines = [
545
+ `<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-error.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
546
+ "",
547
+ "**This PR has bump file(s) with errors that need to be fixed.**",
548
+ "<br clear=\"left\" />\n",
549
+ "#### Errors",
550
+ "",
551
+ ...errors.map((e) => `> :x: ${e}`),
552
+ "",
553
+ "Please fix the errors above or recreate the bump file:\n",
554
+ "```bash",
555
+ `${runCmd} add`,
556
+ "```"
557
+ ];
558
+ const addLink = buildAddBumpFileLink(prBranch);
559
+ if (addLink) {
560
+ lines.push("");
561
+ lines.push(`Or [click here to add a bump file](${addLink}) directly on GitHub.`);
562
+ }
563
+ lines.push("\n---");
564
+ lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
565
+ return lines.join("\n");
566
+ }
567
+ function formatEmptyBumpFileComment(emptyBumpFileIds, prNumber, prBranch) {
568
+ const repo = process.env.GITHUB_REPOSITORY;
501
569
  const lines = [
502
570
  `<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-neutral.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
503
571
  "",
572
+ "**This PR includes an empty bump file — no version bump is needed.** :white_check_mark:",
573
+ "<br clear=\"left\" />",
574
+ ""
575
+ ];
576
+ for (const id of emptyBumpFileIds) {
577
+ const filename = `${id}.md`;
578
+ const parts = [`\`${filename}\``];
579
+ if (repo) {
580
+ parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/changes#diff-${sha256Hex(`.bumpy/${filename}`)}))`);
581
+ if (prBranch) parts.push(`([edit](https://github.com/${repo}/edit/${prBranch}/.bumpy/${filename}))`);
582
+ }
583
+ lines.push(`- ${parts.join(" ")}`);
584
+ }
585
+ lines.push("\n---");
586
+ lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
587
+ return lines.join("\n");
588
+ }
589
+ function formatNoBumpFilesComment(prBranch, pm) {
590
+ const runCmd = pmRunCommand(pm);
591
+ const lines = [
592
+ `<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-warning.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
593
+ "",
504
594
  "Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a bump file.**",
505
595
  "<br clear=\"left\" />\n",
506
596
  "You can add a bump file by running:\n",
@@ -518,18 +608,19 @@ function formatNoBumpFilesComment(prBranch, pm) {
518
608
  return lines.join("\n");
519
609
  }
520
610
  function bumpSectionHeader(type) {
521
- return `### ${`<img src="${FROG_IMG_BASE}/frog-${type}.png" alt="${type}" width="52" style="image-rendering: pixelated;" align="right" />`} ${type.charAt(0).toUpperCase() + type.slice(1)} releases`;
611
+ const label = `${type.charAt(0).toUpperCase() + type.slice(1)} releases`;
612
+ return `### ${`<a href="https://bumpy.varlock.dev" title="${label}"><img src="${FROG_IMG_BASE}/frog-${type}.png" alt="${type}" width="52" style="image-rendering: pixelated;" align="right" /></a>`} ${label}`;
522
613
  }
523
614
  /** Build inline diff links for a package's changed files in the PR */
524
- function buildDiffLinks(pkgDir) {
525
- const pkgJsonPath = `${pkgDir}/package.json`;
526
- const changelogPath = `${pkgDir}/CHANGELOG.md`;
527
- return ` <sub>${[`[package.json](#diff-${sha256Hex(pkgJsonPath)})`, `[CHANGELOG.md](#diff-${sha256Hex(changelogPath)})`].join(" · ")}</sub>`;
615
+ function buildDiffLinks(pkgDir, changesBaseUrl) {
616
+ if (!changesBaseUrl) return "";
617
+ return ` <sub>[CHANGELOG.md](${changesBaseUrl}#diff-${sha256Hex(`${pkgDir}/CHANGELOG.md`)})</sub>`;
528
618
  }
529
619
  function sha256Hex(input) {
530
620
  return createHash("sha256").update(input).digest("hex");
531
621
  }
532
- function formatVersionPrBody(plan, preamble, packageDirs) {
622
+ function formatVersionPrBody(plan, preamble, packageDirs, repo, prNumber) {
623
+ const changesBaseUrl = repo && prNumber ? `https://github.com/${repo}/pull/${prNumber}/changes` : null;
533
624
  const lines = [];
534
625
  lines.push(preamble);
535
626
  lines.push("");
@@ -551,13 +642,13 @@ function formatVersionPrBody(plan, preamble, packageDirs) {
551
642
  for (const r of releases) {
552
643
  const suffix = r.isDependencyBump ? " _(dep)_" : r.isCascadeBump ? " _(cascade)_" : "";
553
644
  const pkgDir = packageDirs.get(r.name);
554
- const diffLinks = pkgDir ? buildDiffLinks(pkgDir) : "";
645
+ const diffLinks = pkgDir ? buildDiffLinks(pkgDir, changesBaseUrl) : "";
555
646
  lines.push(`#### \`${r.name}\` ${r.oldVersion} → **${r.newVersion}**${suffix}${diffLinks}`);
556
647
  lines.push("");
557
648
  const relevantBumpFiles = plan.bumpFiles.filter((bf) => r.bumpFiles.includes(bf.id));
558
649
  if (relevantBumpFiles.length > 0) {
559
650
  for (const bf of relevantBumpFiles) if (bf.summary) {
560
- const bfLink = ` ([bump file](#diff-${sha256Hex(`.bumpy/${bf.id}.md`)}))`;
651
+ const bfLink = changesBaseUrl ? ` ([bump file](${changesBaseUrl}#diff-${sha256Hex(`.bumpy/${bf.id}.md`)}))` : "";
561
652
  const summaryLines = bf.summary.split("\n");
562
653
  lines.push(`- ${summaryLines[0]}${bfLink}`);
563
654
  for (let i = 1; i < summaryLines.length; i++) if (summaryLines[i].trim()) lines.push(` ${summaryLines[i]}`);
@@ -1,7 +1,7 @@
1
1
  import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
2
- import { t as detectPackageManager } from "./package-manager-ByJ0wKYh.mjs";
3
- import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
4
- import { a as fe, c as ot, i as _t, n as O, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-C6bVkGxf.mjs";
2
+ import { t as detectPackageManager } from "./package-manager-CClZtIHP.mjs";
3
+ import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
4
+ import { a as fe, c as ot, i as _t, n as O, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-CJT1JFFa.mjs";
5
5
  //#region src/commands/ci-setup.ts
6
6
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
7
7
  const PAT_PERMISSIONS = [
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
3
- import { n as findRoot } from "./config-D7Umr-fT.mjs";
3
+ import { n as findRoot } from "./config-CJIj8xG3.mjs";
4
4
  //#region src/cli.ts
5
5
  const args = process.argv.slice(2);
6
6
  const command = args[0];
@@ -25,13 +25,13 @@ async function main() {
25
25
  switch (command) {
26
26
  case "init": {
27
27
  const rootDir = await findRoot();
28
- const { initCommand } = await import("./init-DJhMaceS.mjs");
28
+ const { initCommand } = await import("./init-DND7zRGD.mjs");
29
29
  await initCommand(rootDir, { force: flags.force === true });
30
30
  break;
31
31
  }
32
32
  case "add": {
33
33
  const rootDir = await findRoot();
34
- const { addCommand } = await import("./add-yP81c9_q.mjs");
34
+ const { addCommand } = await import("./add-DEqGa5gI.mjs");
35
35
  await addCommand(rootDir, {
36
36
  packages: flags.packages,
37
37
  message: flags.message,
@@ -42,7 +42,7 @@ async function main() {
42
42
  }
43
43
  case "status": {
44
44
  const rootDir = await findRoot();
45
- const { statusCommand } = await import("./status-skGX8uU7.mjs");
45
+ const { statusCommand } = await import("./status-CDGxgXWd.mjs");
46
46
  await statusCommand(rootDir, {
47
47
  json: flags.json === true,
48
48
  packagesOnly: flags.packages === true,
@@ -54,13 +54,13 @@ async function main() {
54
54
  }
55
55
  case "version": {
56
56
  const rootDir = await findRoot();
57
- const { versionCommand } = await import("./version-CnXcbqi1.mjs");
57
+ const { versionCommand } = await import("./version-ClkaCNTE.mjs");
58
58
  await versionCommand(rootDir, { commit: flags.commit === true });
59
59
  break;
60
60
  }
61
61
  case "generate": {
62
62
  const rootDir = await findRoot();
63
- const { generateCommand } = await import("./generate-BOLrTYWR.mjs");
63
+ const { generateCommand } = await import("./generate-wHN6Ll6p.mjs");
64
64
  await generateCommand(rootDir, {
65
65
  from: flags.from,
66
66
  dryRun: flags["dry-run"] === true,
@@ -70,7 +70,7 @@ async function main() {
70
70
  }
71
71
  case "check": {
72
72
  const rootDir = await findRoot();
73
- const { checkCommand } = await import("./check-D_0exKi6.mjs");
73
+ const { checkCommand } = await import("./check-D3eXRyKJ.mjs");
74
74
  await checkCommand(rootDir, {
75
75
  strict: flags.strict === true,
76
76
  noFail: flags["no-fail"] === true
@@ -82,7 +82,7 @@ async function main() {
82
82
  const subcommand = args[1];
83
83
  const ciFlags = parseFlags(args.slice(2));
84
84
  if (subcommand === "check") {
85
- const { ciCheckCommand } = await import("./ci-CvaikKX1.mjs");
85
+ const { ciCheckCommand } = await import("./ci-BVTwTUUK.mjs");
86
86
  await ciCheckCommand(rootDir, {
87
87
  comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
88
88
  strict: ciFlags.strict === true,
@@ -90,7 +90,7 @@ async function main() {
90
90
  patComments: ciFlags["pat-comments"] === true
91
91
  });
92
92
  } else if (subcommand === "release") {
93
- const { ciReleaseCommand } = await import("./ci-CvaikKX1.mjs");
93
+ const { ciReleaseCommand } = await import("./ci-BVTwTUUK.mjs");
94
94
  await ciReleaseCommand(rootDir, {
95
95
  mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
96
96
  tag: ciFlags.tag,
@@ -98,7 +98,7 @@ async function main() {
98
98
  patPr: ciFlags["pat-pr"] === true
99
99
  });
100
100
  } else if (subcommand === "setup") {
101
- const { ciSetupCommand } = await import("./ci-setup-CARJFhcE.mjs");
101
+ const { ciSetupCommand } = await import("./ci-setup-D1NCzbNH.mjs");
102
102
  await ciSetupCommand(rootDir);
103
103
  } else {
104
104
  log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci release", or "ci setup".`);
@@ -108,7 +108,7 @@ async function main() {
108
108
  }
109
109
  case "publish": {
110
110
  const rootDir = await findRoot();
111
- const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
111
+ const { publishCommand } = await import("./publish-BwidFqbo.mjs");
112
112
  await publishCommand(rootDir, {
113
113
  dryRun: flags["dry-run"] === true,
114
114
  tag: flags.tag,
@@ -122,7 +122,7 @@ async function main() {
122
122
  const subcommand = args[1];
123
123
  const aiFlags = parseFlags(args.slice(2));
124
124
  if (subcommand === "setup") {
125
- const { aiSetupCommand } = await import("./ai-STKnq09z.mjs");
125
+ const { aiSetupCommand } = await import("./ai-C66IfTzs.mjs");
126
126
  await aiSetupCommand(rootDir, { target: aiFlags.target });
127
127
  } else {
128
128
  log.error(`Unknown ai subcommand: ${subcommand}. Use "ai setup".`);
@@ -132,7 +132,7 @@ async function main() {
132
132
  }
133
133
  case "--version":
134
134
  case "-v":
135
- console.log(`bumpy 1.2.0`);
135
+ console.log(`bumpy 1.2.2`);
136
136
  break;
137
137
  case "help":
138
138
  case "--help":
@@ -152,7 +152,7 @@ async function main() {
152
152
  }
153
153
  function printHelp() {
154
154
  console.log(`
155
- ${colorize(`🐸 bumpy v1.2.0`, "bold")} - Modern monorepo versioning
155
+ ${colorize(`🐸 bumpy v1.2.2`, "bold")} - Modern monorepo versioning
156
156
 
157
157
  Usage: bumpy <command> [options]
158
158
 
@@ -1,85 +1,7 @@
1
1
  import { a as __exportAll } from "./logger-C2dEe5Su.mjs";
2
2
  import { a as readJson, n as exists, o as readJsonc } from "./fs-DnDogVn-.mjs";
3
+ import { r as DEFAULT_CONFIG } from "./types-CSM0c2-m.mjs";
3
4
  import { resolve } from "node:path";
4
- //#region src/types.ts
5
- const BUMP_LEVELS = {
6
- patch: 0,
7
- minor: 1,
8
- major: 2
9
- };
10
- function bumpLevel(type) {
11
- return BUMP_LEVELS[type];
12
- }
13
- function maxBump(a, b) {
14
- if (!a) return b;
15
- return bumpLevel(a) >= bumpLevel(b) ? a : b;
16
- }
17
- const DEFAULT_BUMP_RULES = {
18
- dependencies: {
19
- trigger: "patch",
20
- bumpAs: "patch"
21
- },
22
- peerDependencies: {
23
- trigger: "major",
24
- bumpAs: "match"
25
- },
26
- devDependencies: false,
27
- optionalDependencies: {
28
- trigger: "minor",
29
- bumpAs: "patch"
30
- }
31
- };
32
- const DEP_TYPES = [
33
- "dependencies",
34
- "devDependencies",
35
- "peerDependencies",
36
- "optionalDependencies"
37
- ];
38
- const DEFAULT_PUBLISH_CONFIG = {
39
- packManager: "auto",
40
- publishManager: "npm",
41
- publishArgs: [],
42
- protocolResolution: "pack"
43
- };
44
- const DEFAULT_CONFIG = {
45
- baseBranch: "main",
46
- access: "public",
47
- versionCommitMessage: void 0,
48
- changedFilePatterns: ["**"],
49
- changelog: "default",
50
- fixed: [],
51
- linked: [],
52
- ignore: [],
53
- include: [],
54
- updateInternalDependencies: "out-of-range",
55
- dependencyBumpRules: {},
56
- privatePackages: {
57
- version: false,
58
- tag: false
59
- },
60
- allowCustomCommands: false,
61
- packages: {},
62
- publish: { ...DEFAULT_PUBLISH_CONFIG },
63
- aggregateRelease: false,
64
- gitUser: {
65
- name: "bumpy-bot",
66
- email: "276066384+bumpy-bot@users.noreply.github.com"
67
- },
68
- versionPr: {
69
- title: "🐸 Versioned release",
70
- branch: "bumpy/version-packages",
71
- preamble: [
72
- `<a href="https://bumpy.varlock.dev"><img src="https://raw.githubusercontent.com/dmno-dev/bumpy/main/images/frog-talking.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
73
- "",
74
- `This PR was created and will be kept in sync by [bumpy](https://bumpy.varlock.dev) based on your bump files (in \`.bumpy/\`). Merge it when you are ready to release the packages listed below:`,
75
- "<br clear=\"left\" />"
76
- ].join("\n")
77
- }
78
- };
79
- function hasCascade(r) {
80
- return "cascade" in r && Object.keys(r.cascade).length > 0;
81
- }
82
- //#endregion
83
5
  //#region src/core/config.ts
84
6
  var config_exports = /* @__PURE__ */ __exportAll({
85
7
  findRoot: () => findRoot,
@@ -218,4 +140,4 @@ function isPackageManaged(pkgName, isPrivate, config, pkgBumpy) {
218
140
  return true;
219
141
  }
220
142
  //#endregion
221
- export { loadConfig as a, BUMP_LEVELS as c, DEFAULT_PUBLISH_CONFIG as d, DEP_TYPES as f, maxBump as h, isPackageManaged as i, DEFAULT_BUMP_RULES as l, hasCascade as m, findRoot as n, loadPackageConfig as o, bumpLevel as p, getBumpyDir as r, matchGlob as s, config_exports as t, DEFAULT_CONFIG as u };
143
+ export { loadConfig as a, isPackageManaged as i, findRoot as n, loadPackageConfig as o, getBumpyDir as r, matchGlob as s, config_exports as t };
@@ -1,11 +1,11 @@
1
1
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
2
  import { t as ensureDir } from "./fs-DnDogVn-.mjs";
3
- import { a as loadConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
4
- import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
5
- import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
6
- import { i as writeBumpFile } from "./bump-file-Br2bTaWp.mjs";
7
- import { i as getFilesChangedInCommit, n as getBranchCommits } from "./git-YDedMddc.mjs";
8
- import { n as slugify, t as randomName } from "./names-C-TuOPbd.mjs";
3
+ import { a as loadConfig, r as getBumpyDir } from "./config-CJIj8xG3.mjs";
4
+ import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
5
+ import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
6
+ import { i as writeBumpFile } from "./bump-file-BTsntOO-.mjs";
7
+ import { a as getFilesChangedInCommit, n as getBranchCommits } from "./git-D0__HP86.mjs";
8
+ import { n as slugify, t as randomName } from "./names-CBy7d8K_.mjs";
9
9
  import { relative } from "node:path";
10
10
  //#region src/commands/generate.ts
11
11
  const BUMP_MAP = {
@@ -1,4 +1,4 @@
1
- import { n as runArgs, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
1
+ import { n as runArgs, s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
2
2
  //#region src/core/git.ts
3
3
  /** Create a git tag */
4
4
  function createTag(tag, opts) {
@@ -26,6 +26,15 @@ function hasUncommittedChanges(opts) {
26
26
  ], opts);
27
27
  return result !== null && result.length > 0;
28
28
  }
29
+ /** Get the current branch name */
30
+ function getCurrentBranch(opts) {
31
+ return tryRunArgs([
32
+ "git",
33
+ "rev-parse",
34
+ "--abbrev-ref",
35
+ "HEAD"
36
+ ], opts);
37
+ }
29
38
  /** Check if a tag already exists */
30
39
  function tagExists(tag, opts) {
31
40
  return tryRunArgs([
@@ -127,4 +136,4 @@ function listTags(pattern, opts) {
127
136
  return result.split("\n").filter(Boolean);
128
137
  }
129
138
  //#endregion
130
- export { hasUncommittedChanges as a, tagExists as c, getFilesChangedInCommit as i, getBranchCommits as n, listTags as o, getChangedFiles as r, pushWithTags as s, createTag as t };
139
+ export { getFilesChangedInCommit as a, pushWithTags as c, getCurrentBranch as i, tagExists as l, getBranchCommits as n, hasUncommittedChanges as o, getChangedFiles as r, listTags as s, createTag as t };
package/dist/index.d.mts CHANGED
@@ -193,10 +193,18 @@ declare class DependencyGraph {
193
193
  }
194
194
  //#endregion
195
195
  //#region src/core/bump-file.d.ts
196
+ interface ReadBumpFilesResult {
197
+ bumpFiles: BumpFile[];
198
+ errors: string[];
199
+ }
196
200
  /** Read all bump files from .bumpy/ directory, sorted by git creation order */
197
- declare function readBumpFiles(rootDir: string): Promise<BumpFile[]>;
201
+ declare function readBumpFiles(rootDir: string): Promise<ReadBumpFilesResult>;
202
+ interface BumpFileParseResult {
203
+ bumpFile: BumpFile | null;
204
+ errors: string[];
205
+ }
198
206
  /** Parse bump file content (for testing) */
199
- declare function parseBumpFile(content: string, id: string): BumpFile | null;
207
+ declare function parseBumpFile(content: string, id: string): BumpFileParseResult;
200
208
  /** Write a bump file */
201
209
  declare function writeBumpFile(rootDir: string, filename: string, releases: BumpFileRelease[], summary: string): Promise<string>;
202
210
  //#endregion
@@ -229,7 +237,7 @@ interface ChangelogContext {
229
237
  * changelog entry string for a single release.
230
238
  */
231
239
  type ChangelogFormatter = (ctx: ChangelogContext) => string | Promise<string>;
232
- /** Default formatter — version heading, date, bullet points */
240
+ /** Default formatter — version heading with date, bullet points sorted by bump type */
233
241
  declare const defaultFormatter: ChangelogFormatter;
234
242
  /**
235
243
  * Load a changelog formatter from config.
@@ -245,6 +253,8 @@ declare function prependToChangelog(existingContent: string, newEntry: string):
245
253
  interface GithubChangelogOptions {
246
254
  /** "owner/repo" — auto-detected from gh CLI if not provided */
247
255
  repo?: string;
256
+ /** Whether to include commit hash links in changelog entries (default: false) */
257
+ includeCommitLink?: boolean;
248
258
  /** Whether to include "Thanks @user" messages for contributors (default: true) */
249
259
  thankContributors?: boolean;
250
260
  /** GitHub usernames (without @) to skip "Thanks" messages for (e.g. internal team members) */
@@ -288,4 +298,4 @@ interface PublishResult {
288
298
  */
289
299
  declare function publishPackages(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig, rootDir: string, opts?: PublishOptions, catalogs?: CatalogMap, detectedPm?: PackageManager): Promise<PublishResult>;
290
300
  //#endregion
291
- export { BUMP_LEVELS, BumpFile, BumpFileRelease, BumpFileReleaseCascade, BumpFileReleaseSimple, BumpType, BumpTypeWithNone, BumpyConfig, type ChangelogContext, type ChangelogFormatter, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DepType, DependencyBumpRule, DependencyGraph, DependentInfo, type GithubChangelogOptions, PackageConfig, PackageManager, PlannedRelease, PublishConfig, ReleasePlan, WorkspacePackage, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
301
+ export { BUMP_LEVELS, BumpFile, type BumpFileParseResult, BumpFileRelease, BumpFileReleaseCascade, BumpFileReleaseSimple, BumpType, BumpTypeWithNone, BumpyConfig, type ChangelogContext, type ChangelogFormatter, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DepType, DependencyBumpRule, DependencyGraph, DependentInfo, type GithubChangelogOptions, PackageConfig, PackageManager, PlannedRelease, PublishConfig, type ReadBumpFilesResult, ReleasePlan, WorkspacePackage, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };