@varlock/bumpy 1.2.2 → 1.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.
Files changed (27) hide show
  1. package/README.md +4 -5
  2. package/dist/{add-DEqGa5gI.mjs → add-D1uiW7VA.mjs} +24 -5
  3. package/dist/{apply-release-plan-Bi9OSWks.mjs → apply-release-plan-60VfCLF8.mjs} +2 -2
  4. package/dist/{bump-file-BTsntOO-.mjs → bump-file-CoaSxqne.mjs} +1 -1
  5. package/dist/{changelog-xKuL0IKx.mjs → changelog-DP3OrTqQ.mjs} +7 -6
  6. package/dist/{changelog-github-CEaDCtTk.mjs → changelog-github-Da5KekQd.mjs} +1 -1
  7. package/dist/{picomatch-TGJi--_I.mjs → check-CS8WIGZA.mjs} +131 -2
  8. package/dist/{ci-BVTwTUUK.mjs → ci-CnIkaf7Q.mjs} +40 -41
  9. package/dist/cli.mjs +29 -21
  10. package/dist/{config-CJIj8xG3.mjs → config-D13G4-R8.mjs} +1 -1
  11. package/dist/{generate-wHN6Ll6p.mjs → generate-D0KJsvpD.mjs} +4 -4
  12. package/dist/{git-D0__HP86.mjs → git-ukq7VTuZ.mjs} +21 -1
  13. package/dist/index.d.mts +3 -1
  14. package/dist/index.mjs +8 -8
  15. package/dist/{publish-BwidFqbo.mjs → publish-DWdN3o9u.mjs} +45 -9
  16. package/dist/{publish-pipeline-BvLIu7WF.mjs → publish-pipeline-C1slMaJV.mjs} +1 -1
  17. package/dist/{release-plan-21H89Cx1.mjs → release-plan-pyxf71dx.mjs} +6 -56
  18. package/dist/{status-CDGxgXWd.mjs → status-DyzcQ6CD.mjs} +6 -6
  19. package/dist/{types-CSM0c2-m.mjs → types-BX4pfmKh.mjs} +1 -1
  20. package/dist/{version-ClkaCNTE.mjs → version-BxDhayli.mjs} +6 -6
  21. package/dist/{workspace-c9-TqXed.mjs → workspace-BKOAMeki.mjs} +1 -1
  22. package/package.json +1 -1
  23. package/skills/add-change/SKILL.md +1 -1
  24. package/dist/check-D3eXRyKJ.mjs +0 -92
  25. /package/dist/{ci-setup-D1NCzbNH.mjs → ci-setup-DWxrdSK6.mjs} +0 -0
  26. /package/dist/{commit-message-DOIfDxfj.mjs → commit-message-3e4KhzFV.mjs} +0 -0
  27. /package/dist/{init-DND7zRGD.mjs → init-CUIw0jg8.mjs} +0 -0
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-CJIj8xG3.mjs";
3
+ import { n as findRoot } from "./config-D13G4-R8.mjs";
4
4
  //#region src/cli.ts
5
5
  const args = process.argv.slice(2);
6
6
  const command = args[0];
@@ -25,24 +25,25 @@ async function main() {
25
25
  switch (command) {
26
26
  case "init": {
27
27
  const rootDir = await findRoot();
28
- const { initCommand } = await import("./init-DND7zRGD.mjs");
28
+ const { initCommand } = await import("./init-CUIw0jg8.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-DEqGa5gI.mjs");
34
+ const { addCommand } = await import("./add-D1uiW7VA.mjs");
35
35
  await addCommand(rootDir, {
36
36
  packages: flags.packages,
37
37
  message: flags.message,
38
38
  name: flags.name,
39
- empty: flags.empty === true
39
+ empty: flags.empty === true,
40
+ none: flags.none === true
40
41
  });
41
42
  break;
42
43
  }
43
44
  case "status": {
44
45
  const rootDir = await findRoot();
45
- const { statusCommand } = await import("./status-CDGxgXWd.mjs");
46
+ const { statusCommand } = await import("./status-DyzcQ6CD.mjs");
46
47
  await statusCommand(rootDir, {
47
48
  json: flags.json === true,
48
49
  packagesOnly: flags.packages === true,
@@ -54,13 +55,13 @@ async function main() {
54
55
  }
55
56
  case "version": {
56
57
  const rootDir = await findRoot();
57
- const { versionCommand } = await import("./version-ClkaCNTE.mjs");
58
+ const { versionCommand } = await import("./version-BxDhayli.mjs");
58
59
  await versionCommand(rootDir, { commit: flags.commit === true });
59
60
  break;
60
61
  }
61
62
  case "generate": {
62
63
  const rootDir = await findRoot();
63
- const { generateCommand } = await import("./generate-wHN6Ll6p.mjs");
64
+ const { generateCommand } = await import("./generate-D0KJsvpD.mjs");
64
65
  await generateCommand(rootDir, {
65
66
  from: flags.from,
66
67
  dryRun: flags["dry-run"] === true,
@@ -70,10 +71,16 @@ async function main() {
70
71
  }
71
72
  case "check": {
72
73
  const rootDir = await findRoot();
73
- const { checkCommand } = await import("./check-D3eXRyKJ.mjs");
74
+ const { checkCommand } = await import("./check-CS8WIGZA.mjs");
75
+ const hookValue = flags.hook;
76
+ if (hookValue && hookValue !== "pre-commit" && hookValue !== "pre-push") {
77
+ log.error(`Invalid --hook value "${hookValue}". Expected "pre-commit" or "pre-push".`);
78
+ process.exit(1);
79
+ }
74
80
  await checkCommand(rootDir, {
75
81
  strict: flags.strict === true,
76
- noFail: flags["no-fail"] === true
82
+ noFail: flags["no-fail"] === true,
83
+ hook: hookValue
77
84
  });
78
85
  break;
79
86
  }
@@ -82,23 +89,21 @@ async function main() {
82
89
  const subcommand = args[1];
83
90
  const ciFlags = parseFlags(args.slice(2));
84
91
  if (subcommand === "check") {
85
- const { ciCheckCommand } = await import("./ci-BVTwTUUK.mjs");
92
+ const { ciCheckCommand } = await import("./ci-CnIkaf7Q.mjs");
86
93
  await ciCheckCommand(rootDir, {
87
94
  comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
88
95
  strict: ciFlags.strict === true,
89
- noFail: ciFlags["no-fail"] === true,
90
- patComments: ciFlags["pat-comments"] === true
96
+ noFail: ciFlags["no-fail"] === true
91
97
  });
92
98
  } else if (subcommand === "release") {
93
- const { ciReleaseCommand } = await import("./ci-BVTwTUUK.mjs");
99
+ const { ciReleaseCommand } = await import("./ci-CnIkaf7Q.mjs");
94
100
  await ciReleaseCommand(rootDir, {
95
101
  mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
96
102
  tag: ciFlags.tag,
97
- branch: ciFlags.branch,
98
- patPr: ciFlags["pat-pr"] === true
103
+ branch: ciFlags.branch
99
104
  });
100
105
  } else if (subcommand === "setup") {
101
- const { ciSetupCommand } = await import("./ci-setup-D1NCzbNH.mjs");
106
+ const { ciSetupCommand } = await import("./ci-setup-DWxrdSK6.mjs");
102
107
  await ciSetupCommand(rootDir);
103
108
  } else {
104
109
  log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci release", or "ci setup".`);
@@ -108,7 +113,7 @@ async function main() {
108
113
  }
109
114
  case "publish": {
110
115
  const rootDir = await findRoot();
111
- const { publishCommand } = await import("./publish-BwidFqbo.mjs");
116
+ const { publishCommand } = await import("./publish-DWdN3o9u.mjs");
112
117
  await publishCommand(rootDir, {
113
118
  dryRun: flags["dry-run"] === true,
114
119
  tag: flags.tag,
@@ -132,7 +137,7 @@ async function main() {
132
137
  }
133
138
  case "--version":
134
139
  case "-v":
135
- console.log(`bumpy 1.2.2`);
140
+ console.log(`bumpy 1.4.0`);
136
141
  break;
137
142
  case "help":
138
143
  case "--help":
@@ -152,18 +157,21 @@ async function main() {
152
157
  }
153
158
  function printHelp() {
154
159
  console.log(`
155
- ${colorize(`🐸 bumpy v1.2.2`, "bold")} - Modern monorepo versioning
160
+ ${colorize(`🐸 bumpy v1.4.0`, "bold")} - Modern monorepo versioning
156
161
 
157
162
  Usage: bumpy <command> [options]
158
163
 
159
164
  Commands:
160
165
  init [--force] Initialize .bumpy/ (migrates from .changeset/ if found)
161
166
  add Create a new bump file
167
+ --none Set all changed packages to "none" (acknowledge without bumping)
168
+ --empty Create an empty bump file (no releases needed)
162
169
  generate Generate bump file from branch commits
163
170
  status Show pending releases
164
- check Verify changed packages have bump files (for pre-push hooks)
171
+ check Verify changed packages have bump files (for git hooks)
165
172
  --strict Fail if any changed package is uncovered (default: only fail if no bump files at all)
166
173
  --no-fail Warn only, never exit 1
174
+ --hook <context> Hook context: "pre-commit" or "pre-push" (controls which bump files count)
167
175
  version [--commit] Apply bump files and bump versions
168
176
  publish Publish versioned packages
169
177
  ci check PR check — report pending releases, comment on PR
@@ -206,7 +214,7 @@ function printHelp() {
206
214
  --branch <name> Branch name for version PR (default: bumpy/version-packages)
207
215
 
208
216
  AI setup options:
209
- --target <tool> Target AI tool: opencode, cursor, codex
217
+ --target <tool> Target AI tool: claude, opencode, cursor, codex
210
218
 
211
219
  ${colorize("https://bumpy.varlock.dev", "dim")}
212
220
  `);
@@ -1,6 +1,6 @@
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
+ import { r as DEFAULT_CONFIG } from "./types-BX4pfmKh.mjs";
4
4
  import { resolve } from "node:path";
5
5
  //#region src/core/config.ts
6
6
  var config_exports = /* @__PURE__ */ __exportAll({
@@ -1,10 +1,10 @@
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-CJIj8xG3.mjs";
4
- import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
3
+ import { a as loadConfig, r as getBumpyDir } from "./config-D13G4-R8.mjs";
4
+ import { t as discoverPackages } from "./workspace-BKOAMeki.mjs";
5
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";
6
+ import { i as writeBumpFile } from "./bump-file-CoaSxqne.mjs";
7
+ import { n as getBranchCommits, o as getFilesChangedInCommit } from "./git-ukq7VTuZ.mjs";
8
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
@@ -124,6 +124,26 @@ function getFilesChangedInCommit(hash, opts) {
124
124
  if (!result) return [];
125
125
  return result.split("\n").filter(Boolean);
126
126
  }
127
+ /** Get the git status of files in a directory (staged, unstaged, untracked) */
128
+ function getFileStatuses(dir, opts) {
129
+ const statuses = /* @__PURE__ */ new Map();
130
+ const result = tryRunArgs([
131
+ "git",
132
+ "status",
133
+ "--porcelain",
134
+ "--",
135
+ dir
136
+ ], opts);
137
+ if (!result) return statuses;
138
+ for (const line of result.split("\n")) {
139
+ if (!line.trim()) continue;
140
+ const indexStatus = line[0];
141
+ const file = line.slice(3);
142
+ if (indexStatus === "?") statuses.set(file, "untracked");
143
+ else statuses.set(file, "staged");
144
+ }
145
+ return statuses;
146
+ }
127
147
  /** Get all tags matching a pattern */
128
148
  function listTags(pattern, opts) {
129
149
  const result = tryRunArgs([
@@ -136,4 +156,4 @@ function listTags(pattern, opts) {
136
156
  return result.split("\n").filter(Boolean);
137
157
  }
138
158
  //#endregion
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 };
159
+ export { getFileStatuses as a, listTags as c, getCurrentBranch as i, pushWithTags as l, getBranchCommits as n, getFilesChangedInCommit as o, getChangedFiles as r, hasUncommittedChanges as s, createTag as t, tagExists as u };
package/dist/index.d.mts CHANGED
@@ -231,6 +231,8 @@ interface ChangelogContext {
231
231
  bumpFiles: BumpFile[];
232
232
  /** ISO date string (YYYY-MM-DD) */
233
233
  date: string;
234
+ /** Where this entry will be used — formatters can customize output per target (default: 'changelog') */
235
+ target?: 'changelog' | 'github-release';
234
236
  }
235
237
  /**
236
238
  * A changelog formatter receives full context and returns the complete
@@ -245,7 +247,7 @@ declare const defaultFormatter: ChangelogFormatter;
245
247
  */
246
248
  declare function loadFormatter(changelog: BumpyConfig['changelog'], rootDir: string): Promise<ChangelogFormatter>;
247
249
  /** Generate a changelog entry using the configured formatter */
248
- declare function generateChangelogEntry(release: PlannedRelease, bumpFiles: BumpFile[], formatter?: ChangelogFormatter, date?: string): Promise<string>;
250
+ declare function generateChangelogEntry(release: PlannedRelease, bumpFiles: BumpFile[], formatter?: ChangelogFormatter, date?: string, target?: ChangelogContext['target']): Promise<string>;
249
251
  /** Prepend a new entry to an existing CHANGELOG.md content */
250
252
  declare function prependToChangelog(existingContent: string, newEntry: string): string;
251
253
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { a as DEP_TYPES, c as maxBump, i as DEFAULT_PUBLISH_CONFIG, n as DEFAULT_BUMP_RULES, o as bumpLevel, r as DEFAULT_CONFIG, s as hasCascade, t as BUMP_LEVELS } from "./types-CSM0c2-m.mjs";
2
- import { a as loadConfig, n as findRoot, r as getBumpyDir, s as matchGlob } from "./config-CJIj8xG3.mjs";
3
- import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
1
+ import { a as DEP_TYPES, c as maxBump, i as DEFAULT_PUBLISH_CONFIG, n as DEFAULT_BUMP_RULES, o as bumpLevel, r as DEFAULT_CONFIG, s as hasCascade, t as BUMP_LEVELS } from "./types-BX4pfmKh.mjs";
2
+ import { a as loadConfig, n as findRoot, r as getBumpyDir, s as matchGlob } from "./config-D13G4-R8.mjs";
3
+ import { t as discoverPackages } from "./workspace-BKOAMeki.mjs";
4
4
  import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
5
- import { i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-BTsntOO-.mjs";
5
+ import { i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-CoaSxqne.mjs";
6
6
  import { n as satisfies, r as stripProtocol, t as bumpVersion } from "./semver-DfQyVLM_.mjs";
7
- import { t as assembleReleasePlan } from "./release-plan-21H89Cx1.mjs";
8
- import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry, t as defaultFormatter } from "./changelog-xKuL0IKx.mjs";
9
- import { t as applyReleasePlan } from "./apply-release-plan-Bi9OSWks.mjs";
10
- import { t as publishPackages } from "./publish-pipeline-BvLIu7WF.mjs";
7
+ import { t as assembleReleasePlan } from "./release-plan-pyxf71dx.mjs";
8
+ import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry, t as defaultFormatter } from "./changelog-DP3OrTqQ.mjs";
9
+ import { t as applyReleasePlan } from "./apply-release-plan-60VfCLF8.mjs";
10
+ import { t as publishPackages } from "./publish-pipeline-C1slMaJV.mjs";
11
11
  export { BUMP_LEVELS, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DependencyGraph, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
@@ -1,11 +1,12 @@
1
1
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig } from "./config-CJIj8xG3.mjs";
2
+ import { a as loadConfig } from "./config-D13G4-R8.mjs";
3
3
  import { n as detectWorkspaces } from "./package-manager-CClZtIHP.mjs";
4
- import { n as discoverWorkspace } from "./workspace-c9-TqXed.mjs";
4
+ import { n as discoverWorkspace } from "./workspace-BKOAMeki.mjs";
5
5
  import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
6
6
  import { r as runArgsAsync, s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
7
- import { c as pushWithTags, o as hasUncommittedChanges, s as listTags } from "./git-D0__HP86.mjs";
8
- import { t as publishPackages } from "./publish-pipeline-BvLIu7WF.mjs";
7
+ import { i as loadFormatter, n as generateChangelogEntry } from "./changelog-DP3OrTqQ.mjs";
8
+ import { c as listTags, l as pushWithTags, s as hasUncommittedChanges } from "./git-ukq7VTuZ.mjs";
9
+ import { t as publishPackages } from "./publish-pipeline-C1slMaJV.mjs";
9
10
  //#region src/core/github-release.ts
10
11
  /** Get the current HEAD commit SHA */
11
12
  function getHeadSha(rootDir) {
@@ -24,7 +25,7 @@ async function createIndividualReleases(releases, bumpFiles, rootDir, opts = {})
24
25
  const headSha = getHeadSha(rootDir);
25
26
  for (const release of releases) {
26
27
  const tag = `${release.name}@${release.newVersion}`;
27
- const body = buildReleaseBody(release, bumpFiles);
28
+ const body = opts.formatter ? await generateReleaseBody(release, bumpFiles, opts.formatter) : buildReleaseBody(release, bumpFiles);
28
29
  const title = `${release.name} v${release.newVersion}`;
29
30
  if (opts.dryRun) {
30
31
  log.dim(` Would create GitHub release: ${title}`);
@@ -58,7 +59,7 @@ async function createAggregateRelease(releases, bumpFiles, rootDir, opts = {}) {
58
59
  if (releases.length === 0) return;
59
60
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
60
61
  const { tag, title } = resolveAggregateTagAndTitle(date, listTags(`release-${date}*`, { cwd: rootDir }), opts.title);
61
- const body = buildAggregateBody(releases, bumpFiles);
62
+ const body = opts.formatter ? await generateAggregateBody(releases, bumpFiles, opts.formatter) : buildAggregateBody(releases, bumpFiles);
62
63
  if (opts.dryRun) {
63
64
  log.dim(` Would create aggregate GitHub release: ${title}`);
64
65
  log.dim(` Tag: ${tag}`);
@@ -88,6 +89,36 @@ async function createAggregateRelease(releases, bumpFiles, rootDir, opts = {}) {
88
89
  log.warn(`Failed to create aggregate GitHub release: ${err instanceof Error ? err.message : err}`);
89
90
  }
90
91
  }
92
+ /** Generate a release body for a single package using the changelog formatter */
93
+ async function generateReleaseBody(release, bumpFiles, formatter) {
94
+ return stripVersionHeading(await generateChangelogEntry(release, bumpFiles, formatter, void 0, "github-release")).trim() || "No changelog entries.";
95
+ }
96
+ /** Generate an aggregate release body using the changelog formatter */
97
+ async function generateAggregateBody(releases, bumpFiles, formatter) {
98
+ const lines = [];
99
+ const groups = [
100
+ ["Major Changes", releases.filter((r) => r.type === "major")],
101
+ ["Minor Changes", releases.filter((r) => r.type === "minor")],
102
+ ["Patch Changes", releases.filter((r) => r.type === "patch")]
103
+ ];
104
+ for (const [heading, group] of groups) {
105
+ if (group.length === 0) continue;
106
+ lines.push(`## ${heading}\n`);
107
+ for (const release of group) {
108
+ lines.push(`### ${release.name} v${release.newVersion}\n`);
109
+ const body = stripVersionHeading(await generateChangelogEntry(release, bumpFiles, formatter, void 0, "github-release")).trim();
110
+ if (body) lines.push(body);
111
+ else if (release.isDependencyBump) lines.push("- Updated dependencies");
112
+ else if (release.isCascadeBump) lines.push("- Version bump via cascade rule");
113
+ lines.push("");
114
+ }
115
+ }
116
+ return lines.join("\n").trim() || "No changelog entries.";
117
+ }
118
+ /** Strip the leading ## version heading and date sub-heading from a changelog entry */
119
+ function stripVersionHeading(entry) {
120
+ return entry.replace(/^## .+\n/, "").replace(/^<sub>.+<\/sub>\n/, "").replace(/^_.+_\n/, "");
121
+ }
91
122
  function buildReleaseBody(release, bumpFiles) {
92
123
  const lines = [];
93
124
  const relevant = bumpFiles.filter((bf) => release.bumpFiles.includes(bf.id));
@@ -148,7 +179,7 @@ async function publishCommand(rootDir, opts) {
148
179
  }
149
180
  let toPublish = await findUnpublishedPackages(packages, config);
150
181
  if (opts.filter) {
151
- const { matchGlob } = await import("./config-CJIj8xG3.mjs").then((n) => n.t);
182
+ const { matchGlob } = await import("./config-D13G4-R8.mjs").then((n) => n.t);
152
183
  const patterns = opts.filter.split(",").map((p) => p.trim());
153
184
  toPublish = toPublish.filter((r) => patterns.some((p) => matchGlob(r.name, p)));
154
185
  }
@@ -187,11 +218,16 @@ async function publishCommand(rootDir, opts) {
187
218
  const aggConfig = config.aggregateRelease;
188
219
  const isAggregate = aggConfig === true || typeof aggConfig === "object" && aggConfig.enabled;
189
220
  const aggTitle = typeof aggConfig === "object" ? aggConfig.title : void 0;
221
+ const formatter = config.changelog !== false ? await loadFormatter(config.changelog, rootDir) : void 0;
190
222
  if (isAggregate) await createAggregateRelease(publishedReleases, releasePlan.bumpFiles, rootDir, {
191
223
  dryRun: opts.dryRun,
192
- title: aggTitle
224
+ title: aggTitle,
225
+ formatter
226
+ });
227
+ else await createIndividualReleases(publishedReleases, releasePlan.bumpFiles, rootDir, {
228
+ dryRun: opts.dryRun,
229
+ formatter
193
230
  });
194
- else await createIndividualReleases(publishedReleases, releasePlan.bumpFiles, rootDir, { dryRun: opts.dryRun });
195
231
  }
196
232
  }
197
233
  /**
@@ -3,7 +3,7 @@ import { a as readJson, u as updateJsonNestedField } from "./fs-DnDogVn-.mjs";
3
3
  import { r as resolveCatalogDep } from "./package-manager-CClZtIHP.mjs";
4
4
  import { i as runAsync, o as sq, r as runArgsAsync, s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
5
5
  import { r as stripProtocol } from "./semver-DfQyVLM_.mjs";
6
- import { l as tagExists, t as createTag } from "./git-D0__HP86.mjs";
6
+ import { t as createTag, u as tagExists } from "./git-ukq7VTuZ.mjs";
7
7
  import { resolve } from "node:path";
8
8
  import { unlink } from "node:fs/promises";
9
9
  import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
@@ -1,5 +1,5 @@
1
- import { c as maxBump, n as DEFAULT_BUMP_RULES, o as bumpLevel, s as hasCascade } from "./types-CSM0c2-m.mjs";
2
- import { s as matchGlob } from "./config-CJIj8xG3.mjs";
1
+ import { c as maxBump, n as DEFAULT_BUMP_RULES, o as bumpLevel, s as hasCascade } from "./types-BX4pfmKh.mjs";
2
+ import { s as matchGlob } from "./config-D13G4-R8.mjs";
3
3
  import { n as satisfies, t as bumpVersion } from "./semver-DfQyVLM_.mjs";
4
4
  //#region src/core/release-plan.ts
5
5
  /**
@@ -20,21 +20,16 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
20
20
  const planned = /* @__PURE__ */ new Map();
21
21
  const warnings = [];
22
22
  const cascadeOverrides = /* @__PURE__ */ new Map();
23
- const suppressedPackages = /* @__PURE__ */ new Set();
24
23
  for (const bf of bumpFiles) for (const release of bf.releases) {
25
24
  if (!packages.has(release.name)) continue;
26
25
  const bump = release.type;
27
- if (bump === "none") {
28
- suppressedPackages.add(release.name);
29
- continue;
30
- }
26
+ if (bump === "none") continue;
31
27
  const existing = planned.get(release.name);
32
28
  if (existing) {
33
29
  existing.type = maxBump(existing.type, bump);
34
30
  existing.bumpFiles.add(bf.id);
35
31
  } else planned.set(release.name, {
36
32
  type: bump,
37
- suppressed: false,
38
33
  isDependencyBump: false,
39
34
  isCascadeBump: false,
40
35
  bumpFiles: new Set([bf.id])
@@ -48,13 +43,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
48
43
  }
49
44
  }
50
45
  }
51
- for (const name of suppressedPackages) if (!planned.has(name)) planned.set(name, {
52
- type: "patch",
53
- suppressed: true,
54
- isDependencyBump: false,
55
- isCascadeBump: false,
56
- bumpFiles: /* @__PURE__ */ new Set()
57
- });
58
46
  let changed = true;
59
47
  let iterations = 0;
60
48
  const MAX_ITERATIONS = 100;
@@ -62,7 +50,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
62
50
  changed = false;
63
51
  iterations++;
64
52
  for (const [pkgName, bump] of planned) {
65
- if (bump.suppressed) continue;
66
53
  const pkg = packages.get(pkgName);
67
54
  const newVersion = bumpVersion(pkg.version, bump.type);
68
55
  const dependents = depGraph.getDependents(pkgName);
@@ -73,7 +60,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
73
60
  let depBump;
74
61
  if (dep.depType === "peerDependencies") depBump = bump.type;
75
62
  else depBump = "patch";
76
- if (planned.get(dep.name)?.suppressed) throw new Error(`Cannot suppress bump for '${dep.name}' (via 'none' in bump file) — '${pkgName}' is bumping to ${newVersion} which breaks the declared range '${dep.versionRange}'. Either widen the range or remove the 'none' entry.`);
77
63
  if (dep.depType === "peerDependencies" && depBump !== "patch") {
78
64
  let resolvedRange = dep.versionRange.replace(/^workspace:/, "");
79
65
  if (resolvedRange === "^" || resolvedRange === "~") resolvedRange = `${resolvedRange}${pkg.version}`;
@@ -84,15 +70,11 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
84
70
  }
85
71
  for (const group of config.fixed) {
86
72
  let groupBump;
87
- for (const nameOrGlob of group) for (const [name, bump] of planned) {
88
- if (bump.suppressed) continue;
89
- if (matchGlob(name, nameOrGlob)) groupBump = maxBump(groupBump, bump.type);
90
- }
73
+ for (const nameOrGlob of group) for (const [name, bump] of planned) if (matchGlob(name, nameOrGlob)) groupBump = maxBump(groupBump, bump.type);
91
74
  if (!groupBump) continue;
92
75
  for (const nameOrGlob of group) for (const [name] of packages) {
93
76
  if (!matchGlob(name, nameOrGlob)) continue;
94
77
  const existing = planned.get(name);
95
- if (existing && existing.suppressed) continue;
96
78
  if (existing) {
97
79
  const newType = maxBump(existing.type, groupBump);
98
80
  if (newType !== existing.type) {
@@ -102,7 +84,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
102
84
  } else {
103
85
  planned.set(name, {
104
86
  type: groupBump,
105
- suppressed: false,
106
87
  isDependencyBump: false,
107
88
  isCascadeBump: false,
108
89
  bumpFiles: /* @__PURE__ */ new Set()
@@ -113,15 +94,12 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
113
94
  }
114
95
  for (const group of config.linked) {
115
96
  let groupBump;
116
- for (const nameOrGlob of group) for (const [name, bump] of planned) {
117
- if (bump.suppressed) continue;
118
- if (matchGlob(name, nameOrGlob)) groupBump = maxBump(groupBump, bump.type);
119
- }
97
+ for (const nameOrGlob of group) for (const [name, bump] of planned) if (matchGlob(name, nameOrGlob)) groupBump = maxBump(groupBump, bump.type);
120
98
  if (!groupBump) continue;
121
99
  for (const nameOrGlob of group) for (const [name] of packages) {
122
100
  if (!matchGlob(name, nameOrGlob)) continue;
123
101
  const existing = planned.get(name);
124
- if (!existing || existing.suppressed) continue;
102
+ if (!existing) continue;
125
103
  const newType = maxBump(existing.type, groupBump);
126
104
  if (newType !== existing.type) {
127
105
  existing.type = newType;
@@ -130,12 +108,10 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
130
108
  }
131
109
  }
132
110
  if (config.updateInternalDependencies !== "out-of-range") for (const [pkgName, bump] of planned) {
133
- if (bump.suppressed) continue;
134
111
  if (config.updateInternalDependencies === "minor" && bumpLevel(bump.type) < bumpLevel("minor")) continue;
135
112
  const bfOverrides = cascadeOverrides.get(pkgName);
136
113
  if (bfOverrides) for (const [pattern, cascadeBumpType] of bfOverrides) for (const [targetName] of packages) {
137
114
  if (!matchGlob(targetName, pattern)) continue;
138
- if (planned.get(targetName)?.suppressed) continue;
139
115
  if (applyBump(planned, targetName, cascadeBumpType, false, true, bump.bumpFiles)) changed = true;
140
116
  }
141
117
  const cascadeTo = packages.get(pkgName)?.bumpy?.cascadeTo;
@@ -144,7 +120,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
144
120
  const cascadeBump = rule.bumpAs === "match" ? bump.type : rule.bumpAs;
145
121
  for (const [targetName] of packages) {
146
122
  if (!matchGlob(targetName, pattern)) continue;
147
- if (planned.get(targetName)?.suppressed) continue;
148
123
  if (applyBump(planned, targetName, cascadeBump, false, true, bump.bumpFiles)) changed = true;
149
124
  }
150
125
  }
@@ -153,17 +128,14 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
153
128
  const rule = resolveRule(dep.name, dep.depType, packages, config);
154
129
  if (!rule) continue;
155
130
  if (!shouldTrigger(bump.type, rule.trigger)) continue;
156
- if (planned.get(dep.name)?.suppressed) continue;
157
131
  const depBump = rule.bumpAs === "match" ? bump.type : rule.bumpAs;
158
132
  if (applyBump(planned, dep.name, depBump, true, false, bump.bumpFiles)) changed = true;
159
133
  }
160
134
  }
161
135
  else for (const [pkgName, bump] of planned) {
162
- if (bump.suppressed) continue;
163
136
  const bfOverrides = cascadeOverrides.get(pkgName);
164
137
  if (bfOverrides) for (const [pattern, cascadeBumpType] of bfOverrides) for (const [targetName] of packages) {
165
138
  if (!matchGlob(targetName, pattern)) continue;
166
- if (planned.get(targetName)?.suppressed) continue;
167
139
  if (applyBump(planned, targetName, cascadeBumpType, false, true, bump.bumpFiles)) changed = true;
168
140
  }
169
141
  const cascadeTo = packages.get(pkgName)?.bumpy?.cascadeTo;
@@ -172,33 +144,13 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
172
144
  const cascadeBump = rule.bumpAs === "match" ? bump.type : rule.bumpAs;
173
145
  for (const [targetName] of packages) {
174
146
  if (!matchGlob(targetName, pattern)) continue;
175
- if (planned.get(targetName)?.suppressed) continue;
176
147
  if (applyBump(planned, targetName, cascadeBump, false, true, bump.bumpFiles)) changed = true;
177
148
  }
178
149
  }
179
150
  }
180
151
  }
181
- for (const [name, bump] of planned) {
182
- if (!bump.suppressed) continue;
183
- const pkg = packages.get(name);
184
- for (const [depName, depBump] of planned) {
185
- if (depBump.suppressed) continue;
186
- const depPkg = packages.get(depName);
187
- const newDepVersion = bumpVersion(depPkg.version, depBump.type);
188
- for (const depType of [
189
- "dependencies",
190
- "peerDependencies",
191
- "optionalDependencies"
192
- ]) {
193
- const range = pkg[depType]?.[depName];
194
- if (!range) continue;
195
- if (!satisfies(newDepVersion, range, depPkg.version)) throw new Error(`Cannot suppress bump for '${name}' (via 'none' in bump file) — '${depName}' is bumping to ${newDepVersion} which breaks the declared range '${range}'. Either widen the range or remove the 'none' entry.`);
196
- }
197
- }
198
- }
199
152
  const releases = [];
200
153
  for (const [name, bump] of planned) {
201
- if (bump.suppressed) continue;
202
154
  const pkg = packages.get(name);
203
155
  if (!pkg) continue;
204
156
  const newVersion = bumpVersion(pkg.version, bump.type);
@@ -224,7 +176,6 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
224
176
  function applyBump(planned, name, type, isDependencyBump, isCascadeBump, sourceBumpFiles) {
225
177
  const existing = planned.get(name);
226
178
  if (existing) {
227
- if (existing.suppressed) return false;
228
179
  const newType = maxBump(existing.type, type);
229
180
  if (newType === existing.type) return false;
230
181
  existing.type = newType;
@@ -235,7 +186,6 @@ function applyBump(planned, name, type, isDependencyBump, isCascadeBump, sourceB
235
186
  }
236
187
  planned.set(name, {
237
188
  type,
238
- suppressed: false,
239
189
  isDependencyBump,
240
190
  isCascadeBump,
241
191
  bumpFiles: new Set(sourceBumpFiles)
@@ -1,10 +1,10 @@
1
1
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig } from "./config-CJIj8xG3.mjs";
3
- import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
2
+ import { a as loadConfig } from "./config-D13G4-R8.mjs";
3
+ import { t as discoverPackages } from "./workspace-BKOAMeki.mjs";
4
4
  import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
5
- import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-BTsntOO-.mjs";
6
- import { t as assembleReleasePlan } from "./release-plan-21H89Cx1.mjs";
7
- import { i as getCurrentBranch, r as getChangedFiles } from "./git-D0__HP86.mjs";
5
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-CoaSxqne.mjs";
6
+ import { t as assembleReleasePlan } from "./release-plan-pyxf71dx.mjs";
7
+ import { i as getCurrentBranch, r as getChangedFiles } from "./git-ukq7VTuZ.mjs";
8
8
  //#region src/commands/status.ts
9
9
  async function statusCommand(rootDir, opts) {
10
10
  const config = await loadConfig(rootDir);
@@ -31,7 +31,7 @@ async function statusCommand(rootDir, opts) {
31
31
  releases = releases.filter((r) => types.includes(r.type));
32
32
  }
33
33
  if (opts.filter) {
34
- const { matchGlob } = await import("./config-CJIj8xG3.mjs").then((n) => n.t);
34
+ const { matchGlob } = await import("./config-D13G4-R8.mjs").then((n) => n.t);
35
35
  const patterns = opts.filter.split(",").map((p) => p.trim());
36
36
  releases = releases.filter((r) => patterns.some((p) => matchGlob(r.name, p)));
37
37
  }
@@ -66,7 +66,7 @@ const DEFAULT_CONFIG = {
66
66
  title: "🐸 Versioned release",
67
67
  branch: "bumpy/version-packages",
68
68
  preamble: [
69
- `<a href="https://bumpy.varlock.dev"><img src="https://raw.githubusercontent.com/dmno-dev/bumpy/main/images/frog-party.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
69
+ `<a href="https://bumpy.varlock.dev"><img src="https://raw.githubusercontent.com/dmno-dev/bumpy/main/images/frog-clipboard.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
70
70
  "",
71
71
  `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:`,
72
72
  "<br clear=\"left\" />"
@@ -1,13 +1,13 @@
1
1
  import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig } from "./config-CJIj8xG3.mjs";
2
+ import { a as loadConfig } from "./config-D13G4-R8.mjs";
3
3
  import { n as detectWorkspaces } from "./package-manager-CClZtIHP.mjs";
4
- import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
4
+ import { t as discoverPackages } from "./workspace-BKOAMeki.mjs";
5
5
  import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
6
6
  import { n as runArgs, s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
7
- import { r as readBumpFiles } from "./bump-file-BTsntOO-.mjs";
8
- import { t as assembleReleasePlan } from "./release-plan-21H89Cx1.mjs";
9
- import { t as applyReleasePlan } from "./apply-release-plan-Bi9OSWks.mjs";
10
- import { t as resolveCommitMessage } from "./commit-message-DOIfDxfj.mjs";
7
+ import { r as readBumpFiles } from "./bump-file-CoaSxqne.mjs";
8
+ import { t as assembleReleasePlan } from "./release-plan-pyxf71dx.mjs";
9
+ import { t as applyReleasePlan } from "./apply-release-plan-60VfCLF8.mjs";
10
+ import { t as resolveCommitMessage } from "./commit-message-3e4KhzFV.mjs";
11
11
  //#region src/commands/version.ts
12
12
  async function versionCommand(rootDir, opts = {}) {
13
13
  const config = await loadConfig(rootDir);
@@ -1,5 +1,5 @@
1
1
  import { a as readJson, n as exists } from "./fs-DnDogVn-.mjs";
2
- import { i as isPackageManaged, o as loadPackageConfig } from "./config-CJIj8xG3.mjs";
2
+ import { i as isPackageManaged, o as loadPackageConfig } from "./config-D13G4-R8.mjs";
3
3
  import { n as detectWorkspaces } from "./package-manager-CClZtIHP.mjs";
4
4
  import { relative, resolve } from "node:path";
5
5
  import { readdir, stat } from "node:fs/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varlock/bumpy",
3
- "version": "1.2.2",
3
+ "version": "1.4.0",
4
4
  "description": "Modern monorepo versioning and changelog tool",
5
5
  "keywords": [
6
6
  "bump",
@@ -43,7 +43,7 @@ For each affected package, choose the appropriate bump level:
43
43
  | **minor** | New features: added exports, new options, new functionality |
44
44
  | **patch** | Bug fixes, internal refactors, documentation, dependency updates |
45
45
 
46
- Use `none` in a bump file to suppress a bump on a package that would otherwise be included via propagation. If skipping would leave a broken range, bumpy throws an error.
46
+ Use `none` in a bump file to acknowledge a change without triggering a direct bump. Cascading bumps from other packages can still apply normally.
47
47
 
48
48
  ### 4. Write a clear summary
49
49