@varlock/bumpy 1.7.1 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -222,6 +222,33 @@
222
222
  "type": "string",
223
223
  "enum": ["major", "minor", "patch"]
224
224
  },
225
+ "cascadeConfig": {
226
+ "oneOf": [
227
+ {
228
+ "type": "array",
229
+ "description": "List of package names/glob patterns (defaults: trigger \"patch\", bumpAs \"match\")",
230
+ "items": { "type": "string" }
231
+ },
232
+ {
233
+ "type": "object",
234
+ "description": "Package name/glob patterns mapped to cascade rules",
235
+ "additionalProperties": {
236
+ "type": "object",
237
+ "properties": {
238
+ "trigger": {
239
+ "$ref": "#/$defs/bumpType",
240
+ "description": "Minimum bump level that triggers the cascade (default: \"patch\")"
241
+ },
242
+ "bumpAs": {
243
+ "description": "What level to bump the target (default: \"match\")",
244
+ "oneOf": [{ "$ref": "#/$defs/bumpType" }, { "type": "string", "const": "match" }]
245
+ }
246
+ },
247
+ "additionalProperties": false
248
+ }
249
+ }
250
+ ]
251
+ },
225
252
  "dependencyBumpRule": {
226
253
  "oneOf": [
227
254
  {
@@ -302,23 +329,12 @@
302
329
  "additionalProperties": false
303
330
  },
304
331
  "cascadeTo": {
305
- "type": "object",
306
- "description": "Explicit cascade targets — glob pattern mapped to { trigger, bumpAs }",
307
- "additionalProperties": {
308
- "type": "object",
309
- "properties": {
310
- "trigger": {
311
- "$ref": "#/$defs/bumpType",
312
- "description": "Minimum bump level that triggers the cascade"
313
- },
314
- "bumpAs": {
315
- "description": "What level to bump the target",
316
- "oneOf": [{ "$ref": "#/$defs/bumpType" }, { "type": "string", "const": "match" }]
317
- }
318
- },
319
- "required": ["trigger", "bumpAs"],
320
- "additionalProperties": false
321
- }
332
+ "description": "Explicit cascade targets — when this package is bumped, cascade to matching packages.",
333
+ "$ref": "#/$defs/cascadeConfig"
334
+ },
335
+ "cascadeFrom": {
336
+ "description": "Explicit cascade sources — when a matching package is bumped, cascade the bump to this package.",
337
+ "$ref": "#/$defs/cascadeConfig"
322
338
  }
323
339
  },
324
340
  "additionalProperties": false
@@ -1,11 +1,11 @@
1
1
  import { n as log, r as require_picocolors, s as __toESM } from "./logger-BgksGFuf.mjs";
2
2
  import { n as exists, t as ensureDir } from "./fs-CBXKZhoU.mjs";
3
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-BcmlSJJd.mjs";
4
- import { a as discoverPackages, i as writeBumpFile, o as discoverWorkspace, r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-4cnuDyfW.mjs";
5
- import { r as getChangedFiles } from "./git-nTR-JccX.mjs";
3
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-gMu1z0bz.mjs";
4
+ import { a as writeBumpFile, o as discoverPackages, r as readBumpFiles, s as discoverWorkspace, t as filterBranchBumpFiles } from "./bump-file-BbiqKKZg.mjs";
5
+ import { r as getChangedFiles } from "./git-CpJqzpp-.mjs";
6
6
  import { l as pt, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-W95rXis0.mjs";
7
7
  import { n as slugify, t as randomName } from "./names-COooXAFg.mjs";
8
- import { n as findChangedPackages, r as require_picomatch } from "./check-w-edwiNw.mjs";
8
+ import { n as findChangedPackages, r as require_picomatch } from "./check-CcRjFgSY.mjs";
9
9
  import { relative, resolve } from "node:path";
10
10
  import * as readline from "node:readline";
11
11
  //#region src/prompts/bump-select.ts
@@ -1,6 +1,6 @@
1
1
  import { a as readJson, c as removeFile, f as writeText, i as listFiles, l as updateJsonFields, n as exists, s as readText, u as updateJsonNestedField } from "./fs-CBXKZhoU.mjs";
2
- import { r as getBumpyDir } from "./config-BcmlSJJd.mjs";
3
- import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-BubwrZfr.mjs";
2
+ import { r as getBumpyDir } from "./config-gMu1z0bz.mjs";
3
+ import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-CFWf9s2q.mjs";
4
4
  import { resolve } from "node:path";
5
5
  //#region src/core/apply-release-plan.ts
6
6
  /** Apply the release plan: bump versions, update changelogs, delete bump files */
@@ -1,5 +1,5 @@
1
1
  import { a as readJson, f as writeText, i as listFiles, n as exists, s as readText } from "./fs-CBXKZhoU.mjs";
2
- import { i as isPackageManaged, o as loadPackageConfig, r as getBumpyDir } from "./config-BcmlSJJd.mjs";
2
+ import { i as isPackageManaged, o as loadPackageConfig, r as getBumpyDir } from "./config-gMu1z0bz.mjs";
3
3
  import { i as jsYaml, n as detectWorkspaces } from "./package-manager-BQPwXwu5.mjs";
4
4
  import { s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
5
5
  import { relative, resolve } from "node:path";
@@ -272,6 +272,37 @@ async function writeBumpFile(rootDir, filename, releases, summary) {
272
272
  }).trim()}\n---\n\n${summary}\n`);
273
273
  return filePath;
274
274
  }
275
+ /**
276
+ * Recover bump files that were deleted in the HEAD commit (version commit).
277
+ * Used during the publish-only flow (after version PR merge) to provide
278
+ * bump file context for GitHub release body generation.
279
+ */
280
+ function recoverDeletedBumpFiles(rootDir) {
281
+ const deleted = tryRunArgs([
282
+ "git",
283
+ "diff",
284
+ "--diff-filter=D",
285
+ "--name-only",
286
+ "HEAD~1",
287
+ "HEAD",
288
+ "--",
289
+ ".bumpy/*.md"
290
+ ], { cwd: rootDir });
291
+ if (!deleted) return [];
292
+ const bumpFiles = [];
293
+ for (const filePath of deleted.split("\n").filter(Boolean)) {
294
+ if (filePath.endsWith("README.md")) continue;
295
+ const content = tryRunArgs([
296
+ "git",
297
+ "show",
298
+ `HEAD~1:${filePath}`
299
+ ], { cwd: rootDir });
300
+ if (!content) continue;
301
+ const { bumpFile } = parseBumpFile(content, filePath.replace(/^\.bumpy\//, "").replace(/\.md$/, ""));
302
+ if (bumpFile) bumpFiles.push(bumpFile);
303
+ }
304
+ return bumpFiles;
305
+ }
275
306
  function fileToId(filePath) {
276
307
  return filePath.split("/").pop().replace(/\.md$/, "");
277
308
  }
@@ -309,4 +340,4 @@ function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors
309
340
  };
310
341
  }
311
342
  //#endregion
312
- export { discoverPackages as a, writeBumpFile as i, parseBumpFile as n, discoverWorkspace as o, readBumpFiles as r, filterBranchBumpFiles as t };
343
+ export { writeBumpFile as a, recoverDeletedBumpFiles as i, parseBumpFile as n, discoverPackages as o, readBumpFiles as r, discoverWorkspace as s, filterBranchBumpFiles as t };
@@ -1,5 +1,5 @@
1
1
  import { n as log } from "./logger-BgksGFuf.mjs";
2
- import { c as maxBump, t as BUMP_LEVELS } from "./types-BX4pfmKh.mjs";
2
+ import { c as maxBump, t as BUMP_LEVELS } from "./types-CAwBhUsn.mjs";
3
3
  import { relative, resolve } from "node:path";
4
4
  import { realpathSync } from "node:fs";
5
5
  //#region src/core/changelog.ts
@@ -45,7 +45,7 @@ const defaultFormatter = (ctx) => {
45
45
  const BUILTIN_FORMATTERS = {
46
46
  default: defaultFormatter,
47
47
  github: async () => {
48
- const { createGithubFormatter } = await import("./changelog-github-BAUnp3ic.mjs");
48
+ const { createGithubFormatter } = await import("./changelog-github-T5LqaTwV.mjs");
49
49
  return createGithubFormatter();
50
50
  }
51
51
  };
@@ -56,7 +56,7 @@ const BUILTIN_FORMATTERS = {
56
56
  async function loadFormatter(changelog, rootDir) {
57
57
  const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
58
58
  if (name === "github") {
59
- const { createGithubFormatter } = await import("./changelog-github-BAUnp3ic.mjs");
59
+ const { createGithubFormatter } = await import("./changelog-github-T5LqaTwV.mjs");
60
60
  return createGithubFormatter(options);
61
61
  }
62
62
  if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
@@ -1,6 +1,6 @@
1
- import { c as maxBump } from "./types-BX4pfmKh.mjs";
1
+ import { c as maxBump } from "./types-CAwBhUsn.mjs";
2
2
  import { s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
3
- import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-BubwrZfr.mjs";
3
+ import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-CFWf9s2q.mjs";
4
4
  //#region src/core/changelog-github.ts
5
5
  /** Authors filtered from "Thanks" attribution by default (e.g. bots) */
6
6
  /** Authors filtered from "Thanks" attribution by default (e.g. AI/automation bots) */
@@ -1,7 +1,7 @@
1
1
  import { a as __exportAll, i as __commonJSMin, n as log, s as __toESM, t as colorize } from "./logger-BgksGFuf.mjs";
2
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-BcmlSJJd.mjs";
3
- import { o as discoverWorkspace, r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-4cnuDyfW.mjs";
4
- import { a as getFileStatuses, r as getChangedFiles } from "./git-nTR-JccX.mjs";
2
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-gMu1z0bz.mjs";
3
+ import { r as readBumpFiles, s as discoverWorkspace, t as filterBranchBumpFiles } from "./bump-file-BbiqKKZg.mjs";
4
+ import { a as getFileStatuses, r as getChangedFiles } from "./git-CpJqzpp-.mjs";
5
5
  import { relative } from "node:path";
6
6
  //#region ../../node_modules/.bun/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
7
7
  var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -1,12 +1,12 @@
1
1
  import { n as log, t as colorize } from "./logger-BgksGFuf.mjs";
2
- import { a as loadConfig } from "./config-BcmlSJJd.mjs";
2
+ import { a as loadConfig } from "./config-gMu1z0bz.mjs";
3
3
  import { t as detectPackageManager } from "./package-manager-BQPwXwu5.mjs";
4
- import { o as discoverWorkspace, r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-4cnuDyfW.mjs";
5
- import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-iZvGo-SB.mjs";
4
+ import { i as recoverDeletedBumpFiles, r as readBumpFiles, s as discoverWorkspace, t as filterBranchBumpFiles } from "./bump-file-BbiqKKZg.mjs";
5
+ import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-7ApKPR6T.mjs";
6
6
  import { n as runArgs, r as runArgsAsync, s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
7
- import { r as getChangedFiles } from "./git-nTR-JccX.mjs";
7
+ import { d as withGitToken, r as getChangedFiles } from "./git-CpJqzpp-.mjs";
8
8
  import { t as randomName } from "./names-COooXAFg.mjs";
9
- import { n as findChangedPackages } from "./check-w-edwiNw.mjs";
9
+ import { n as findChangedPackages } from "./check-CcRjFgSY.mjs";
10
10
  import { t as resolveCommitMessage } from "./commit-message-CSWVKPJ-.mjs";
11
11
  import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
12
12
  import { createHash } from "node:crypto";
@@ -155,7 +155,7 @@ async function ciPlanCommand(rootDir) {
155
155
  packageNames: plan.releases.map((r) => r.name)
156
156
  };
157
157
  } else {
158
- const { findUnpublishedPackages } = await import("./publish-BJ-Cs0TR.mjs");
158
+ const { findUnpublishedPackages } = await import("./publish-CbvWNkjU.mjs");
159
159
  const unpublished = await findUnpublishedPackages(packages, config);
160
160
  if (unpublished.length > 0) output = {
161
161
  mode: "publish",
@@ -225,8 +225,12 @@ async function ciReleaseCommand(rootDir, opts) {
225
225
  }
226
226
  if (bumpFiles.length === 0) {
227
227
  log.info("No pending bump files — checking for unpublished packages...");
228
- const { publishCommand } = await import("./publish-BJ-Cs0TR.mjs");
229
- await publishCommand(rootDir, { tag: opts.tag });
228
+ const recoveredBumpFiles = recoverDeletedBumpFiles(rootDir);
229
+ const { publishCommand } = await import("./publish-CbvWNkjU.mjs");
230
+ await publishCommand(rootDir, {
231
+ tag: opts.tag,
232
+ recoveredBumpFiles
233
+ });
230
234
  return;
231
235
  }
232
236
  const plan = assembleReleasePlan(bumpFiles, packages, depGraph, config);
@@ -239,7 +243,7 @@ async function ciReleaseCommand(rootDir, opts) {
239
243
  }
240
244
  async function autoPublish(rootDir, config, plan, tag) {
241
245
  log.step("Running bumpy version...");
242
- const { versionCommand } = await import("./version-nJ0vhPWw.mjs");
246
+ const { versionCommand } = await import("./version-DFCrc_fz.mjs");
243
247
  await versionCommand(rootDir);
244
248
  log.step("Committing version changes...");
245
249
  runArgs([
@@ -268,7 +272,7 @@ async function autoPublish(rootDir, config, plan, tag) {
268
272
  ], { cwd: rootDir });
269
273
  }
270
274
  log.step("Running bumpy publish...");
271
- const { publishCommand } = await import("./publish-BJ-Cs0TR.mjs");
275
+ const { publishCommand } = await import("./publish-CbvWNkjU.mjs");
272
276
  await publishCommand(rootDir, { tag });
273
277
  }
274
278
  /**
@@ -284,100 +288,7 @@ async function autoPublish(rootDir, config, plan, tag) {
284
288
  */
285
289
  function pushWithToken(rootDir, branch, config) {
286
290
  if (branch === config.baseBranch || branch === "main" || branch === "master") throw new Error(`Refusing to force-push to "${branch}" — this looks like a base branch, not a version PR branch`);
287
- const token = process.env.BUMPY_GH_TOKEN;
288
- const repo = process.env.GITHUB_REPOSITORY;
289
- const server = process.env.GITHUB_SERVER_URL || "https://github.com";
290
- if (token && repo) {
291
- const authedUrl = `${server.replace("://", `://x-access-token:${token}@`)}/${repo}.git`;
292
- const originalUrl = tryRunArgs([
293
- "git",
294
- "remote",
295
- "get-url",
296
- "origin"
297
- ], { cwd: rootDir });
298
- const extraHeaderKey = `http.${server}/.extraheader`;
299
- const savedHeader = tryRunArgs([
300
- "git",
301
- "config",
302
- "--local",
303
- extraHeaderKey
304
- ], { cwd: rootDir });
305
- const includeIfRaw = tryRunArgs([
306
- "git",
307
- "config",
308
- "--local",
309
- "--get-regexp",
310
- "^includeif\\.gitdir:"
311
- ], { cwd: rootDir });
312
- const savedIncludeIfs = [];
313
- if (includeIfRaw) for (const line of includeIfRaw.split("\n").filter(Boolean)) {
314
- const spaceIdx = line.indexOf(" ");
315
- if (spaceIdx > 0) savedIncludeIfs.push({
316
- key: line.slice(0, spaceIdx),
317
- value: line.slice(spaceIdx + 1)
318
- });
319
- }
320
- try {
321
- if (savedHeader) runArgs([
322
- "git",
323
- "config",
324
- "--local",
325
- "--unset-all",
326
- extraHeaderKey
327
- ], { cwd: rootDir });
328
- for (const entry of savedIncludeIfs) tryRunArgs([
329
- "git",
330
- "config",
331
- "--local",
332
- "--unset",
333
- entry.key
334
- ], { cwd: rootDir });
335
- runArgs([
336
- "git",
337
- "remote",
338
- "set-url",
339
- "origin",
340
- authedUrl
341
- ], { cwd: rootDir });
342
- try {
343
- runArgs([
344
- "git",
345
- "push",
346
- "-u",
347
- "origin",
348
- branch,
349
- "--force",
350
- "--no-verify"
351
- ], { cwd: rootDir });
352
- } catch (err) {
353
- const msg = err instanceof Error ? err.message : String(err);
354
- throw new Error(msg.replaceAll(token, "***"));
355
- }
356
- } finally {
357
- if (originalUrl) runArgs([
358
- "git",
359
- "remote",
360
- "set-url",
361
- "origin",
362
- originalUrl
363
- ], { cwd: rootDir });
364
- if (savedHeader) runArgs([
365
- "git",
366
- "config",
367
- "--local",
368
- extraHeaderKey,
369
- savedHeader
370
- ], { cwd: rootDir });
371
- for (const entry of savedIncludeIfs) tryRunArgs([
372
- "git",
373
- "config",
374
- "--local",
375
- entry.key,
376
- entry.value
377
- ], { cwd: rootDir });
378
- }
379
- log.dim(" Pushed with custom token — PR workflows will be triggered");
380
- } else {
291
+ withGitToken(rootDir, () => {
381
292
  runArgs([
382
293
  "git",
383
294
  "push",
@@ -387,8 +298,9 @@ function pushWithToken(rootDir, branch, config) {
387
298
  "--force",
388
299
  "--no-verify"
389
300
  ], { cwd: rootDir });
390
- if (!token && repo) log.warn("BUMPY_GH_TOKEN is not set — PR checks will not trigger automatically.\n Run `bumpy ci setup` for help.");
391
- }
301
+ });
302
+ if (process.env.BUMPY_GH_TOKEN && process.env.GITHUB_REPOSITORY) log.dim(" Pushed with custom token — PR workflows will be triggered");
303
+ else if (!process.env.BUMPY_GH_TOKEN && process.env.GITHUB_REPOSITORY) log.warn("BUMPY_GH_TOKEN is not set — PR checks will not trigger automatically.\n Run `bumpy ci setup` for help.");
392
304
  }
393
305
  async function createVersionPr(rootDir, plan, config, packageDirs, branchName) {
394
306
  const branch = validateBranchName(branchName || config.versionPr.branch);
@@ -434,7 +346,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName) {
434
346
  branch
435
347
  ], { cwd: rootDir });
436
348
  log.step("Running bumpy version...");
437
- const { versionCommand } = await import("./version-nJ0vhPWw.mjs");
349
+ const { versionCommand } = await import("./version-DFCrc_fz.mjs");
438
350
  await versionCommand(rootDir);
439
351
  runArgs([
440
352
  "git",
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-BgksGFuf.mjs";
3
- import { n as findRoot } from "./config-BcmlSJJd.mjs";
3
+ import { n as findRoot } from "./config-gMu1z0bz.mjs";
4
4
  //#region src/cli.ts
5
5
  const args = process.argv.slice(2);
6
6
  const command = args[0];
@@ -31,7 +31,7 @@ async function main() {
31
31
  }
32
32
  case "add": {
33
33
  const rootDir = await findRoot();
34
- const { addCommand } = await import("./add-CEOjsSPY.mjs");
34
+ const { addCommand } = await import("./add-BL_7iHAo.mjs");
35
35
  await addCommand(rootDir, {
36
36
  packages: flags.packages,
37
37
  message: flags.message,
@@ -43,7 +43,7 @@ async function main() {
43
43
  }
44
44
  case "status": {
45
45
  const rootDir = await findRoot();
46
- const { statusCommand } = await import("./status-CpGvpJBm.mjs");
46
+ const { statusCommand } = await import("./status-C02g_WIx.mjs");
47
47
  await statusCommand(rootDir, {
48
48
  json: flags.json === true,
49
49
  packagesOnly: flags.packages === true,
@@ -55,13 +55,13 @@ async function main() {
55
55
  }
56
56
  case "version": {
57
57
  const rootDir = await findRoot();
58
- const { versionCommand } = await import("./version-nJ0vhPWw.mjs");
58
+ const { versionCommand } = await import("./version-DFCrc_fz.mjs");
59
59
  await versionCommand(rootDir, { commit: flags.commit === true });
60
60
  break;
61
61
  }
62
62
  case "generate": {
63
63
  const rootDir = await findRoot();
64
- const { generateCommand } = await import("./generate-DU27B8co.mjs");
64
+ const { generateCommand } = await import("./generate-BfLL5AfI.mjs");
65
65
  await generateCommand(rootDir, {
66
66
  from: flags.from,
67
67
  dryRun: flags["dry-run"] === true,
@@ -71,7 +71,7 @@ async function main() {
71
71
  }
72
72
  case "check": {
73
73
  const rootDir = await findRoot();
74
- const { checkCommand } = await import("./check-w-edwiNw.mjs").then((n) => n.t);
74
+ const { checkCommand } = await import("./check-CcRjFgSY.mjs").then((n) => n.t);
75
75
  const hookValue = flags.hook;
76
76
  if (hookValue && hookValue !== "pre-commit" && hookValue !== "pre-push") {
77
77
  log.error(`Invalid --hook value "${hookValue}". Expected "pre-commit" or "pre-push".`);
@@ -89,17 +89,17 @@ async function main() {
89
89
  const subcommand = args[1];
90
90
  const ciFlags = parseFlags(args.slice(2));
91
91
  if (subcommand === "check") {
92
- const { ciCheckCommand } = await import("./ci-Di_Tur0k.mjs");
92
+ const { ciCheckCommand } = await import("./ci-BWxlSnSN.mjs");
93
93
  await ciCheckCommand(rootDir, {
94
94
  comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
95
95
  strict: ciFlags.strict === true,
96
96
  noFail: ciFlags["no-fail"] === true
97
97
  });
98
98
  } else if (subcommand === "plan") {
99
- const { ciPlanCommand } = await import("./ci-Di_Tur0k.mjs");
99
+ const { ciPlanCommand } = await import("./ci-BWxlSnSN.mjs");
100
100
  await ciPlanCommand(rootDir);
101
101
  } else if (subcommand === "release") {
102
- const { ciReleaseCommand } = await import("./ci-Di_Tur0k.mjs");
102
+ const { ciReleaseCommand } = await import("./ci-BWxlSnSN.mjs");
103
103
  await ciReleaseCommand(rootDir, {
104
104
  mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
105
105
  tag: ciFlags.tag,
@@ -116,7 +116,7 @@ async function main() {
116
116
  }
117
117
  case "publish": {
118
118
  const rootDir = await findRoot();
119
- const { publishCommand } = await import("./publish-BJ-Cs0TR.mjs");
119
+ const { publishCommand } = await import("./publish-CbvWNkjU.mjs");
120
120
  await publishCommand(rootDir, {
121
121
  dryRun: flags["dry-run"] === true,
122
122
  tag: flags.tag,
@@ -140,7 +140,7 @@ async function main() {
140
140
  }
141
141
  case "--version":
142
142
  case "-v":
143
- console.log(`bumpy 1.7.1`);
143
+ console.log(`bumpy 1.8.1`);
144
144
  break;
145
145
  case "help":
146
146
  case "--help":
@@ -160,7 +160,7 @@ async function main() {
160
160
  }
161
161
  function printHelp() {
162
162
  console.log(`
163
- ${colorize(`🐸 bumpy v1.7.1`, "bold")} - Modern monorepo versioning
163
+ ${colorize(`🐸 bumpy v1.8.1`, "bold")} - Modern monorepo versioning
164
164
 
165
165
  Usage: bumpy <command> [options]
166
166
 
@@ -1,6 +1,6 @@
1
1
  import { a as __exportAll } from "./logger-BgksGFuf.mjs";
2
2
  import { a as readJson, n as exists, o as readJsonc } from "./fs-CBXKZhoU.mjs";
3
- import { r as DEFAULT_CONFIG } from "./types-BX4pfmKh.mjs";
3
+ import { l as normalizeCascadeConfig, r as DEFAULT_CONFIG } from "./types-CAwBhUsn.mjs";
4
4
  import { resolve } from "node:path";
5
5
  //#region src/core/config.ts
6
6
  var config_exports = /* @__PURE__ */ __exportAll({
@@ -101,8 +101,12 @@ function mergePackageConfig(...configs) {
101
101
  ...cfg.dependencyBumpRules
102
102
  };
103
103
  if (cfg.cascadeTo) result.cascadeTo = {
104
- ...result.cascadeTo,
105
- ...cfg.cascadeTo
104
+ ...result.cascadeTo ? normalizeCascadeConfig(result.cascadeTo) : {},
105
+ ...normalizeCascadeConfig(cfg.cascadeTo)
106
+ };
107
+ if (cfg.cascadeFrom) result.cascadeFrom = {
108
+ ...result.cascadeFrom ? normalizeCascadeConfig(result.cascadeFrom) : {},
109
+ ...normalizeCascadeConfig(cfg.cascadeFrom)
106
110
  };
107
111
  }
108
112
  return result;
@@ -1,9 +1,9 @@
1
1
  import { n as log, t as colorize } from "./logger-BgksGFuf.mjs";
2
2
  import { t as ensureDir } from "./fs-CBXKZhoU.mjs";
3
- import { a as loadConfig, r as getBumpyDir } from "./config-BcmlSJJd.mjs";
4
- import { a as discoverPackages, i as writeBumpFile } from "./bump-file-4cnuDyfW.mjs";
3
+ import { a as loadConfig, r as getBumpyDir } from "./config-gMu1z0bz.mjs";
4
+ import { a as writeBumpFile, o as discoverPackages } from "./bump-file-BbiqKKZg.mjs";
5
5
  import { s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
6
- import { n as getBranchCommits, o as getFilesChangedInCommit } from "./git-nTR-JccX.mjs";
6
+ import { n as getBranchCommits, o as getFilesChangedInCommit } from "./git-CpJqzpp-.mjs";
7
7
  import { n as slugify, t as randomName } from "./names-COooXAFg.mjs";
8
8
  import { relative } from "node:path";
9
9
  //#region src/commands/generate.ts
@@ -8,14 +8,111 @@ function createTag(tag, opts) {
8
8
  tag
9
9
  ], opts);
10
10
  }
11
- /** Push commits and tags to remote */
11
+ /** Push tags to remote, using BUMPY_GH_TOKEN if available */
12
12
  function pushWithTags(opts) {
13
- runArgs(["git", "push"], opts);
14
- runArgs([
13
+ withGitToken(opts?.cwd, () => {
14
+ runArgs([
15
+ "git",
16
+ "push",
17
+ "--tags"
18
+ ], opts);
19
+ });
20
+ }
21
+ /**
22
+ * Temporarily configure git credentials using BUMPY_GH_TOKEN (or GH_TOKEN),
23
+ * execute a callback, then restore the original config.
24
+ *
25
+ * Embeds the token in the remote URL and clears any existing credential config
26
+ * set by actions/checkout (extraheader or includeIf entries) so our token is
27
+ * used instead of the default GITHUB_TOKEN.
28
+ */
29
+ function withGitToken(cwd, fn) {
30
+ const token = process.env.BUMPY_GH_TOKEN || process.env.GH_TOKEN;
31
+ const server = process.env.GITHUB_SERVER_URL || "https://github.com";
32
+ if (!token) {
33
+ fn();
34
+ return;
35
+ }
36
+ const extraHeaderKey = `http.${server}/.extraheader`;
37
+ const savedHeader = tryRunArgs([
15
38
  "git",
16
- "push",
17
- "--tags"
18
- ], opts);
39
+ "config",
40
+ "--local",
41
+ extraHeaderKey
42
+ ], { cwd });
43
+ const includeIfRaw = tryRunArgs([
44
+ "git",
45
+ "config",
46
+ "--local",
47
+ "--get-regexp",
48
+ "^includeif\\.gitdir:"
49
+ ], { cwd });
50
+ const savedIncludeIfs = [];
51
+ if (includeIfRaw) for (const line of includeIfRaw.split("\n").filter(Boolean)) {
52
+ const spaceIdx = line.indexOf(" ");
53
+ if (spaceIdx > 0) savedIncludeIfs.push({
54
+ key: line.slice(0, spaceIdx),
55
+ value: line.slice(spaceIdx + 1)
56
+ });
57
+ }
58
+ const originalUrl = tryRunArgs([
59
+ "git",
60
+ "remote",
61
+ "get-url",
62
+ "origin"
63
+ ], { cwd });
64
+ const authedUrl = originalUrl ? originalUrl.replace(/^https:\/\//, `https://x-access-token:${token}@`) : null;
65
+ try {
66
+ if (savedHeader) runArgs([
67
+ "git",
68
+ "config",
69
+ "--local",
70
+ "--unset-all",
71
+ extraHeaderKey
72
+ ], { cwd });
73
+ for (const entry of savedIncludeIfs) tryRunArgs([
74
+ "git",
75
+ "config",
76
+ "--local",
77
+ "--unset",
78
+ entry.key
79
+ ], { cwd });
80
+ if (authedUrl) runArgs([
81
+ "git",
82
+ "remote",
83
+ "set-url",
84
+ "origin",
85
+ authedUrl
86
+ ], { cwd });
87
+ try {
88
+ fn();
89
+ } catch (err) {
90
+ const msg = err instanceof Error ? err.message : String(err);
91
+ throw new Error(msg.replaceAll(token, "***"));
92
+ }
93
+ } finally {
94
+ if (originalUrl) runArgs([
95
+ "git",
96
+ "remote",
97
+ "set-url",
98
+ "origin",
99
+ originalUrl
100
+ ], { cwd });
101
+ if (savedHeader) runArgs([
102
+ "git",
103
+ "config",
104
+ "--local",
105
+ extraHeaderKey,
106
+ savedHeader
107
+ ], { cwd });
108
+ for (const entry of savedIncludeIfs) tryRunArgs([
109
+ "git",
110
+ "config",
111
+ "--local",
112
+ entry.key,
113
+ entry.value
114
+ ], { cwd });
115
+ }
19
116
  }
20
117
  /** Check if there are uncommitted changes */
21
118
  function hasUncommittedChanges(opts) {
@@ -156,4 +253,4 @@ function listTags(pattern, opts) {
156
253
  return result.split("\n").filter(Boolean);
157
254
  }
158
255
  //#endregion
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 };
256
+ export { getFileStatuses as a, listTags as c, withGitToken as d, 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
@@ -10,6 +10,16 @@ interface DependencyBumpRule {
10
10
  /** What bump to apply to the dependent */
11
11
  bumpAs: BumpType | 'match';
12
12
  }
13
+ interface CascadeRule {
14
+ /** What bump level in the source triggers the cascade. Default: "patch" (any bump) */
15
+ trigger?: BumpType;
16
+ /** What bump to apply to the target. Default: "match" (same as the source bump level) */
17
+ bumpAs?: BumpType | 'match';
18
+ }
19
+ /** Input type for cascadeTo/cascadeFrom — array of names/globs, or object with per-entry rules */
20
+ type CascadeConfig = string[] | Record<string, CascadeRule>;
21
+ /** Normalize CascadeConfig into a consistent Record form with defaults applied */
22
+ declare function normalizeCascadeConfig(config: CascadeConfig): Record<string, Required<CascadeRule>>;
13
23
  declare const DEFAULT_BUMP_RULES: Record<string, DependencyBumpRule | false>;
14
24
  type DepType = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies';
15
25
  declare const DEP_TYPES: DepType[];
@@ -102,7 +112,8 @@ interface PackageConfig {
102
112
  /** Glob patterns to filter which changed files count toward marking this package as changed */
103
113
  changedFilePatterns?: string[];
104
114
  dependencyBumpRules?: Partial<Record<DepType, DependencyBumpRule | false>>;
105
- cascadeTo?: Record<string, DependencyBumpRule>;
115
+ cascadeTo?: CascadeConfig;
116
+ cascadeFrom?: CascadeConfig;
106
117
  }
107
118
  declare const DEFAULT_PUBLISH_CONFIG: PublishConfig;
108
119
  declare const DEFAULT_CONFIG: BumpyConfig;
@@ -307,4 +318,4 @@ interface PublishResult {
307
318
  */
308
319
  declare function publishPackages(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig, rootDir: string, opts?: PublishOptions, catalogs?: CatalogMap, detectedPm?: PackageManager): Promise<PublishResult>;
309
320
  //#endregion
310
- 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 };
321
+ export { BUMP_LEVELS, BumpFile, type BumpFileParseResult, BumpFileRelease, BumpFileReleaseCascade, BumpFileReleaseSimple, BumpType, BumpTypeWithNone, BumpyConfig, CascadeConfig, CascadeRule, 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, normalizeCascadeConfig, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
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-BcmlSJJd.mjs";
3
- import { a as discoverPackages, i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-4cnuDyfW.mjs";
4
- import { a as DependencyGraph, i as stripProtocol, n as bumpVersion, r as satisfies, t as assembleReleasePlan } from "./release-plan-iZvGo-SB.mjs";
5
- import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry, t as defaultFormatter } from "./changelog-BubwrZfr.mjs";
6
- import { t as applyReleasePlan } from "./apply-release-plan-CAx8E9MJ.mjs";
7
- import { t as publishPackages } from "./publish-pipeline-BsxtJ3-A.mjs";
8
- 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
+ import { a as DEP_TYPES, c as maxBump, i as DEFAULT_PUBLISH_CONFIG, l as normalizeCascadeConfig, n as DEFAULT_BUMP_RULES, o as bumpLevel, r as DEFAULT_CONFIG, s as hasCascade, t as BUMP_LEVELS } from "./types-CAwBhUsn.mjs";
2
+ import { a as loadConfig, n as findRoot, r as getBumpyDir, s as matchGlob } from "./config-gMu1z0bz.mjs";
3
+ import { a as writeBumpFile, n as parseBumpFile, o as discoverPackages, r as readBumpFiles } from "./bump-file-BbiqKKZg.mjs";
4
+ import { a as DependencyGraph, i as stripProtocol, n as bumpVersion, r as satisfies, t as assembleReleasePlan } from "./release-plan-7ApKPR6T.mjs";
5
+ import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry, t as defaultFormatter } from "./changelog-CFWf9s2q.mjs";
6
+ import { t as applyReleasePlan } from "./apply-release-plan-DncfboRW.mjs";
7
+ import { t as publishPackages } from "./publish-pipeline-D99nLAtI.mjs";
8
+ 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, normalizeCascadeConfig, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
@@ -1,13 +1,13 @@
1
1
  import { n as log, o as __require, t as colorize } from "./logger-BgksGFuf.mjs";
2
- import { a as loadConfig } from "./config-BcmlSJJd.mjs";
2
+ import { a as loadConfig } from "./config-gMu1z0bz.mjs";
3
3
  import { n as detectWorkspaces } from "./package-manager-BQPwXwu5.mjs";
4
- import { o as discoverWorkspace } from "./bump-file-4cnuDyfW.mjs";
5
- import { a as DependencyGraph } from "./release-plan-iZvGo-SB.mjs";
4
+ import { s as discoverWorkspace } from "./bump-file-BbiqKKZg.mjs";
5
+ import { a as DependencyGraph } from "./release-plan-7ApKPR6T.mjs";
6
6
  import { r as runArgsAsync, s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
7
- import { i as loadFormatter, n as generateChangelogEntry } from "./changelog-BubwrZfr.mjs";
8
- import { c as listTags, l as pushWithTags, s as hasUncommittedChanges } from "./git-nTR-JccX.mjs";
9
- import { t as publishPackages } from "./publish-pipeline-BsxtJ3-A.mjs";
10
- import { CI_PLAN_CACHE_PATH } from "./ci-Di_Tur0k.mjs";
7
+ import { i as loadFormatter, n as generateChangelogEntry } from "./changelog-CFWf9s2q.mjs";
8
+ import { c as listTags, l as pushWithTags, s as hasUncommittedChanges } from "./git-CpJqzpp-.mjs";
9
+ import { t as publishPackages } from "./publish-pipeline-D99nLAtI.mjs";
10
+ import { CI_PLAN_CACHE_PATH } from "./ci-BWxlSnSN.mjs";
11
11
  //#region src/core/github-release.ts
12
12
  /** Get the current HEAD commit SHA */
13
13
  function getHeadSha(rootDir) {
@@ -197,7 +197,7 @@ async function publishCommand(rootDir, opts) {
197
197
  }
198
198
  let toPublish = await findUnpublishedWithCache(rootDir, packages, config);
199
199
  if (opts.filter) {
200
- const { matchGlob } = await import("./config-BcmlSJJd.mjs").then((n) => n.t);
200
+ const { matchGlob } = await import("./config-gMu1z0bz.mjs").then((n) => n.t);
201
201
  const patterns = opts.filter.split(",").map((p) => p.trim());
202
202
  toPublish = toPublish.filter((r) => patterns.some((p) => matchGlob(r.name, p)));
203
203
  }
@@ -205,8 +205,10 @@ async function publishCommand(rootDir, opts) {
205
205
  log.info("No unpublished packages found.");
206
206
  return;
207
207
  }
208
+ const recoveredBumpFiles = opts.recoveredBumpFiles || [];
209
+ if (recoveredBumpFiles.length > 0) for (const release of toPublish) release.bumpFiles = recoveredBumpFiles.filter((bf) => bf.releases.some((r) => r.name === release.name)).map((bf) => bf.id);
208
210
  const releasePlan = {
209
- bumpFiles: [],
211
+ bumpFiles: recoveredBumpFiles,
210
212
  releases: toPublish,
211
213
  warnings: []
212
214
  };
@@ -1,9 +1,9 @@
1
1
  import { n as log, t as colorize } from "./logger-BgksGFuf.mjs";
2
2
  import { a as readJson, u as updateJsonNestedField } from "./fs-CBXKZhoU.mjs";
3
3
  import { r as resolveCatalogDep } from "./package-manager-BQPwXwu5.mjs";
4
- import { i as stripProtocol } from "./release-plan-iZvGo-SB.mjs";
4
+ import { i as stripProtocol } from "./release-plan-7ApKPR6T.mjs";
5
5
  import { i as runAsync, o as sq, r as runArgsAsync, s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
6
- import { t as createTag, u as tagExists } from "./git-nTR-JccX.mjs";
6
+ import { t as createTag, u as tagExists } from "./git-CpJqzpp-.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,6 +1,6 @@
1
1
  import { i as __commonJSMin, s as __toESM } from "./logger-BgksGFuf.mjs";
2
- import { c as maxBump, n as DEFAULT_BUMP_RULES, o as bumpLevel, s as hasCascade } from "./types-BX4pfmKh.mjs";
3
- import { s as matchGlob } from "./config-BcmlSJJd.mjs";
2
+ import { c as maxBump, l as normalizeCascadeConfig, n as DEFAULT_BUMP_RULES, o as bumpLevel, s as hasCascade } from "./types-CAwBhUsn.mjs";
3
+ import { s as matchGlob } from "./config-gMu1z0bz.mjs";
4
4
  //#region src/core/dep-graph.ts
5
5
  var DependencyGraph = class {
6
6
  /** Map from package name → packages that depend on it */
@@ -1567,15 +1567,11 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
1567
1567
  if (!matchGlob(targetName, pattern)) continue;
1568
1568
  if (applyBump(planned, targetName, cascadeBumpType, false, true, pkgName)) changed = true;
1569
1569
  }
1570
- const cascadeTo = packages.get(pkgName)?.bumpy?.cascadeTo;
1571
- if (cascadeTo) for (const [pattern, rule] of Object.entries(cascadeTo)) {
1572
- if (!shouldTrigger(bump.type, rule.trigger)) continue;
1573
- const cascadeBump = rule.bumpAs === "match" ? bump.type : rule.bumpAs;
1574
- for (const [targetName] of packages) {
1575
- if (!matchGlob(targetName, pattern)) continue;
1576
- if (applyBump(planned, targetName, cascadeBump, false, true, pkgName)) changed = true;
1577
- }
1570
+ const pkg = packages.get(pkgName);
1571
+ if (pkg?.bumpy?.cascadeTo) {
1572
+ if (applyCascadeRules(normalizeCascadeConfig(pkg.bumpy.cascadeTo), pkgName, bump.type, packages, planned)) changed = true;
1578
1573
  }
1574
+ if (applyCascadeFrom(pkgName, bump.type, packages, planned)) changed = true;
1579
1575
  const dependents = depGraph.getDependents(pkgName);
1580
1576
  for (const dep of dependents) {
1581
1577
  const rule = resolveRule(dep.name, dep.depType, packages, config);
@@ -1591,15 +1587,11 @@ function assembleReleasePlan(bumpFiles, packages, depGraph, config) {
1591
1587
  if (!matchGlob(targetName, pattern)) continue;
1592
1588
  if (applyBump(planned, targetName, cascadeBumpType, false, true, pkgName)) changed = true;
1593
1589
  }
1594
- const cascadeTo = packages.get(pkgName)?.bumpy?.cascadeTo;
1595
- if (cascadeTo) for (const [pattern, rule] of Object.entries(cascadeTo)) {
1596
- if (!shouldTrigger(bump.type, rule.trigger)) continue;
1597
- const cascadeBump = rule.bumpAs === "match" ? bump.type : rule.bumpAs;
1598
- for (const [targetName] of packages) {
1599
- if (!matchGlob(targetName, pattern)) continue;
1600
- if (applyBump(planned, targetName, cascadeBump, false, true, pkgName)) changed = true;
1601
- }
1590
+ const pkg = packages.get(pkgName);
1591
+ if (pkg?.bumpy?.cascadeTo) {
1592
+ if (applyCascadeRules(normalizeCascadeConfig(pkg.bumpy.cascadeTo), pkgName, bump.type, packages, planned)) changed = true;
1602
1593
  }
1594
+ if (applyCascadeFrom(pkgName, bump.type, packages, planned)) changed = true;
1603
1595
  }
1604
1596
  }
1605
1597
  const releases = [];
@@ -1657,6 +1649,41 @@ function applyBump(planned, name, type, isDependencyBump, isCascadeBump, sourceP
1657
1649
  });
1658
1650
  return true;
1659
1651
  }
1652
+ /**
1653
+ * Apply normalized cascade rules (used for both cascadeTo and cascadeFrom).
1654
+ * Keys in `rules` are target package name/glob patterns.
1655
+ * Returns true if any bump was applied.
1656
+ */
1657
+ function applyCascadeRules(rules, sourceName, sourceType, packages, planned) {
1658
+ let changed = false;
1659
+ for (const [pattern, rule] of Object.entries(rules)) {
1660
+ if (!shouldTrigger(sourceType, rule.trigger)) continue;
1661
+ const cascadeBump = rule.bumpAs === "match" ? sourceType : rule.bumpAs;
1662
+ for (const [targetName] of packages) {
1663
+ if (!matchGlob(targetName, pattern)) continue;
1664
+ if (applyBump(planned, targetName, cascadeBump, false, true, sourceName)) changed = true;
1665
+ }
1666
+ }
1667
+ return changed;
1668
+ }
1669
+ /**
1670
+ * Apply consumer-side cascadeFrom rules.
1671
+ * Scans all packages for cascadeFrom entries where the pattern matches the bumped source.
1672
+ * Returns true if any bump was applied.
1673
+ */
1674
+ function applyCascadeFrom(sourceName, sourceType, packages, planned) {
1675
+ let changed = false;
1676
+ for (const [targetName, targetPkg] of packages) {
1677
+ if (!targetPkg.bumpy?.cascadeFrom) continue;
1678
+ const rules = normalizeCascadeConfig(targetPkg.bumpy.cascadeFrom);
1679
+ for (const [pattern, rule] of Object.entries(rules)) {
1680
+ if (!matchGlob(sourceName, pattern)) continue;
1681
+ if (!shouldTrigger(sourceType, rule.trigger)) continue;
1682
+ if (applyBump(planned, targetName, rule.bumpAs === "match" ? sourceType : rule.bumpAs, false, true, sourceName)) changed = true;
1683
+ }
1684
+ }
1685
+ return changed;
1686
+ }
1660
1687
  /** Check if a bump level meets the trigger threshold */
1661
1688
  function shouldTrigger(bumpType, trigger) {
1662
1689
  return bumpLevel(bumpType) >= bumpLevel(trigger);
@@ -1,8 +1,8 @@
1
1
  import { n as log, t as colorize } from "./logger-BgksGFuf.mjs";
2
- import { a as loadConfig } from "./config-BcmlSJJd.mjs";
3
- import { a as discoverPackages, r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-4cnuDyfW.mjs";
4
- import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-iZvGo-SB.mjs";
5
- import { i as getCurrentBranch, r as getChangedFiles } from "./git-nTR-JccX.mjs";
2
+ import { a as loadConfig } from "./config-gMu1z0bz.mjs";
3
+ import { o as discoverPackages, r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-BbiqKKZg.mjs";
4
+ import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-7ApKPR6T.mjs";
5
+ import { i as getCurrentBranch, r as getChangedFiles } from "./git-CpJqzpp-.mjs";
6
6
  //#region src/commands/status.ts
7
7
  async function statusCommand(rootDir, opts) {
8
8
  const config = await loadConfig(rootDir);
@@ -29,7 +29,7 @@ async function statusCommand(rootDir, opts) {
29
29
  releases = releases.filter((r) => types.includes(r.type));
30
30
  }
31
31
  if (opts.filter) {
32
- const { matchGlob } = await import("./config-BcmlSJJd.mjs").then((n) => n.t);
32
+ const { matchGlob } = await import("./config-gMu1z0bz.mjs").then((n) => n.t);
33
33
  const patterns = opts.filter.split(",").map((p) => p.trim());
34
34
  releases = releases.filter((r) => patterns.some((p) => matchGlob(r.name, p)));
35
35
  }
@@ -11,6 +11,19 @@ function maxBump(a, b) {
11
11
  if (!a) return b;
12
12
  return bumpLevel(a) >= bumpLevel(b) ? a : b;
13
13
  }
14
+ /** Normalize CascadeConfig into a consistent Record form with defaults applied */
15
+ function normalizeCascadeConfig(config) {
16
+ const result = {};
17
+ if (Array.isArray(config)) for (const name of config) result[name] = {
18
+ trigger: "patch",
19
+ bumpAs: "match"
20
+ };
21
+ else for (const [name, rule] of Object.entries(config)) result[name] = {
22
+ trigger: rule.trigger ?? "patch",
23
+ bumpAs: rule.bumpAs ?? "match"
24
+ };
25
+ return result;
26
+ }
14
27
  const DEFAULT_BUMP_RULES = {
15
28
  dependencies: {
16
29
  trigger: "patch",
@@ -77,4 +90,4 @@ function hasCascade(r) {
77
90
  return "cascade" in r && Object.keys(r.cascade).length > 0;
78
91
  }
79
92
  //#endregion
80
- export { DEP_TYPES as a, maxBump as c, DEFAULT_PUBLISH_CONFIG as i, DEFAULT_BUMP_RULES as n, bumpLevel as o, DEFAULT_CONFIG as r, hasCascade as s, BUMP_LEVELS as t };
93
+ export { DEP_TYPES as a, maxBump as c, DEFAULT_PUBLISH_CONFIG as i, normalizeCascadeConfig as l, DEFAULT_BUMP_RULES as n, bumpLevel as o, DEFAULT_CONFIG as r, hasCascade as s, BUMP_LEVELS as t };
@@ -1,10 +1,10 @@
1
1
  import { n as log, t as colorize } from "./logger-BgksGFuf.mjs";
2
- import { a as loadConfig } from "./config-BcmlSJJd.mjs";
2
+ import { a as loadConfig } from "./config-gMu1z0bz.mjs";
3
3
  import { n as detectWorkspaces } from "./package-manager-BQPwXwu5.mjs";
4
- import { a as discoverPackages, r as readBumpFiles } from "./bump-file-4cnuDyfW.mjs";
5
- import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-iZvGo-SB.mjs";
4
+ import { o as discoverPackages, r as readBumpFiles } from "./bump-file-BbiqKKZg.mjs";
5
+ import { a as DependencyGraph, t as assembleReleasePlan } from "./release-plan-7ApKPR6T.mjs";
6
6
  import { n as runArgs, s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
7
- import { t as applyReleasePlan } from "./apply-release-plan-CAx8E9MJ.mjs";
7
+ import { t as applyReleasePlan } from "./apply-release-plan-DncfboRW.mjs";
8
8
  import { t as resolveCommitMessage } from "./commit-message-CSWVKPJ-.mjs";
9
9
  //#region src/commands/version.ts
10
10
  async function versionCommand(rootDir, opts = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varlock/bumpy",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "Modern monorepo versioning and changelog tool",
5
5
  "keywords": [
6
6
  "bump",