@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/README.md CHANGED
@@ -22,13 +22,13 @@ A modern package versioning, release, and changelog generation tool. Built for m
22
22
  Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) - small markdown files that declare an intent to release packages with a bump level (patch/minor/major), and a description that ends up in changelogs. Developers create these files as part of their PRs, and these files are then used to consolidate changes, generate changelogs, and trigger publishing. Specifically:
23
23
 
24
24
  - Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
25
- - A pre-push git hook can enforce bump files exist for changed packages
25
+ - A git hook (pre-commit or pre-push) can enforce bump files exist for changed packages
26
26
  - In CI, a workflow checks PRs for bump files, leaves a comment on the PR detailing changed packages
27
27
  - As PRs merge to the base branch, a "release PR" is kept up to date
28
28
  - Shows what packages will be released and their changelogs
29
29
  - Including packages bumped automatically due to dependency relationships
30
30
  - When release PR is merged, publishing is triggered
31
- - Oending bump files are deleted and packages are published with updated versions and changelogs
31
+ - Pending bump files are deleted and packages are published with updated versions and changelogs
32
32
 
33
33
  All of this is automated via two simple GitHub Actions workflows (see [CI setup](#ci--github-actions) below). You can also run everything locally with `bumpy status`, `bumpy version`, and `bumpy publish`.
34
34
 
@@ -104,7 +104,6 @@ jobs:
104
104
  - run: bunx @varlock/bumpy ci check
105
105
  env:
106
106
  GH_TOKEN: ${{ github.token }}
107
- BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # additional PAT (optional)
108
107
  ```
109
108
 
110
109
  ### Release workflow
@@ -135,7 +134,7 @@ jobs:
135
134
  - run: bunx @varlock/bumpy ci release
136
135
  env:
137
136
  GH_TOKEN: ${{ github.token }}
138
- BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # additonal PAT, needed to trigger CI checks on release PR
137
+ BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # PAT so that version PR triggers CI
139
138
  ```
140
139
 
141
140
  > **Trusted publishing setup:** Configure each package on [npmjs.com](https://docs.npmjs.com/trusted-publishers/) → Package Settings → Trusted Publishers → GitHub Actions. Specify your org/user, repo, and the workflow filename (`bumpy-release.yml`). No `NPM_TOKEN` secret needed. Requires npm >= 11.5.1 - bumpy will warn if your version is too old.
@@ -240,7 +239,7 @@ Bumpy is built as a successor to [@changesets/changesets](https://github.com/cha
240
239
 
241
240
  ```bash
242
241
  bun install # install deps
243
- bun test # run tests
242
+ bun run test # run tests
244
243
  bun run build # build CLI
245
244
  bunx bumpy --help # invoke built cli
246
245
  ```
@@ -1,13 +1,13 @@
1
1
  import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
2
2
  import { n as exists, t as ensureDir } from "./fs-DnDogVn-.mjs";
3
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-CJIj8xG3.mjs";
4
- import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
3
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-D13G4-R8.mjs";
4
+ import { n as discoverWorkspace, t as discoverPackages } from "./workspace-BKOAMeki.mjs";
5
5
  import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
6
- import { i as writeBumpFile } from "./bump-file-BTsntOO-.mjs";
7
- import { r as getChangedFiles } from "./git-D0__HP86.mjs";
6
+ import { i as writeBumpFile } from "./bump-file-CoaSxqne.mjs";
7
+ import { r as getChangedFiles } from "./git-ukq7VTuZ.mjs";
8
8
  import { c as ot, d as yt, i as _t, l as pt, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-CJT1JFFa.mjs";
9
9
  import { n as slugify, t as randomName } from "./names-CBy7d8K_.mjs";
10
- import { t as require_picomatch } from "./picomatch-TGJi--_I.mjs";
10
+ import { findChangedPackages, t as require_picomatch } from "./check-CS8WIGZA.mjs";
11
11
  import { relative, resolve } from "node:path";
12
12
  import * as readline from "node:readline";
13
13
  //#region src/prompts/bump-select.ts
@@ -191,6 +191,25 @@ async function addCommand(rootDir, opts) {
191
191
  log.success(`🐸 Created empty bump file: .bumpy/${filename}.md`);
192
192
  return;
193
193
  }
194
+ if (opts.none) {
195
+ const { packages } = await discoverWorkspace(rootDir, config);
196
+ const changedPackages = await findChangedPackages(getChangedFiles(rootDir, config.baseBranch), packages, rootDir, config);
197
+ if (changedPackages.length === 0) {
198
+ log.info("No changed packages detected.");
199
+ return;
200
+ }
201
+ const releases = changedPackages.map((name) => ({
202
+ name,
203
+ type: "none"
204
+ }));
205
+ const summary = opts.message || "";
206
+ const filename = opts.name ? slugify(opts.name) : randomName();
207
+ if (await exists(resolve(bumpyDir, `${filename}.md`))) await writeBumpFile(rootDir, `${filename}-${Date.now()}`, releases, summary);
208
+ else await writeBumpFile(rootDir, filename, releases, summary);
209
+ log.success(`🐸 Created bump file with ${changedPackages.length} package(s) set to none: .bumpy/${filename}.md`);
210
+ for (const name of changedPackages) log.dim(` ${name}: none`);
211
+ return;
212
+ }
194
213
  let releases;
195
214
  let summary;
196
215
  let filename;
@@ -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-DnDogVn-.mjs";
2
- import { r as getBumpyDir } from "./config-CJIj8xG3.mjs";
3
- import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-xKuL0IKx.mjs";
2
+ import { r as getBumpyDir } from "./config-D13G4-R8.mjs";
3
+ import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-DP3OrTqQ.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 { f as writeText, i as listFiles, s as readText } from "./fs-DnDogVn-.mjs";
2
- import { r as getBumpyDir } from "./config-CJIj8xG3.mjs";
2
+ import { r as getBumpyDir } from "./config-D13G4-R8.mjs";
3
3
  import { i as jsYaml } from "./package-manager-CClZtIHP.mjs";
4
4
  import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
5
5
  import { resolve } from "node:path";
@@ -1,12 +1,12 @@
1
1
  import { n as log } from "./logger-C2dEe5Su.mjs";
2
- import { t as BUMP_LEVELS } from "./types-CSM0c2-m.mjs";
2
+ import { t as BUMP_LEVELS } from "./types-BX4pfmKh.mjs";
3
3
  import { relative, resolve } from "node:path";
4
4
  import { realpathSync } from "node:fs";
5
5
  //#region src/core/changelog.ts
6
6
  /** Get the bump type a bump file applies to a specific package */
7
7
  function getBumpTypeForPackage(bf, packageName) {
8
8
  const rel = bf.releases.find((r) => r.name === packageName);
9
- return rel?.type === "none" ? "patch" : rel?.type ?? "patch";
9
+ return rel?.type === "none" || !rel?.type ? "patch" : rel.type;
10
10
  }
11
11
  /** Sort bump files by bump type for a specific package (major → minor → patch) */
12
12
  function sortBumpFilesByType(bumpFiles, packageName) {
@@ -43,7 +43,7 @@ const defaultFormatter = (ctx) => {
43
43
  const BUILTIN_FORMATTERS = {
44
44
  default: defaultFormatter,
45
45
  github: async () => {
46
- const { createGithubFormatter } = await import("./changelog-github-CEaDCtTk.mjs");
46
+ const { createGithubFormatter } = await import("./changelog-github-Da5KekQd.mjs");
47
47
  return createGithubFormatter();
48
48
  }
49
49
  };
@@ -54,7 +54,7 @@ const BUILTIN_FORMATTERS = {
54
54
  async function loadFormatter(changelog, rootDir) {
55
55
  const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
56
56
  if (name === "github") {
57
- const { createGithubFormatter } = await import("./changelog-github-CEaDCtTk.mjs");
57
+ const { createGithubFormatter } = await import("./changelog-github-Da5KekQd.mjs");
58
58
  return createGithubFormatter(options);
59
59
  }
60
60
  if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
@@ -88,11 +88,12 @@ async function loadFormatter(changelog, rootDir) {
88
88
  return defaultFormatter;
89
89
  }
90
90
  /** Generate a changelog entry using the configured formatter */
91
- async function generateChangelogEntry(release, bumpFiles, formatter = defaultFormatter, date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0]) {
91
+ async function generateChangelogEntry(release, bumpFiles, formatter = defaultFormatter, date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], target = "changelog") {
92
92
  return formatter({
93
93
  release,
94
94
  bumpFiles,
95
- date
95
+ date,
96
+ target
96
97
  });
97
98
  }
98
99
  /** Prepend a new entry to an existing CHANGELOG.md content */
@@ -1,5 +1,5 @@
1
1
  import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
2
- import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-xKuL0IKx.mjs";
2
+ import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-DP3OrTqQ.mjs";
3
3
  //#region src/core/changelog-github.ts
4
4
  /** Authors filtered from "Thanks" attribution by default (e.g. bots) */
5
5
  /** Authors filtered from "Thanks" attribution by default (e.g. AI/automation bots) */
@@ -1,4 +1,9 @@
1
- import { i as __commonJSMin } from "./logger-C2dEe5Su.mjs";
1
+ import { i as __commonJSMin, 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-D13G4-R8.mjs";
3
+ import { n as discoverWorkspace } from "./workspace-BKOAMeki.mjs";
4
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-CoaSxqne.mjs";
5
+ import { a as getFileStatuses, r as getChangedFiles } from "./git-ukq7VTuZ.mjs";
6
+ import { relative } from "node:path";
2
7
  //#region ../../node_modules/.bun/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
3
8
  var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4
9
  const WIN_SLASH = "\\\\/";
@@ -1867,4 +1872,128 @@ var require_picomatch = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1867
1872
  module.exports = picomatch;
1868
1873
  }));
1869
1874
  //#endregion
1870
- export { require_picomatch as t };
1875
+ //#region src/commands/check.ts
1876
+ var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
1877
+ /**
1878
+ * Local check: detect which packages have changed on this branch
1879
+ * and verify they have corresponding bump files.
1880
+ * Designed for pre-push hooks — no GitHub API needed.
1881
+ *
1882
+ * Default: at least one bump file must exist, uncovered packages are warned.
1883
+ * --strict: every changed package must be covered.
1884
+ * --no-fail: warn only, never exit 1.
1885
+ * --hook pre-commit: only staged + committed bump files count.
1886
+ * --hook pre-push: only committed bump files count.
1887
+ */
1888
+ async function checkCommand(rootDir, opts = {}) {
1889
+ const config = await loadConfig(rootDir);
1890
+ const { packages } = await discoverWorkspace(rootDir, config);
1891
+ const baseBranch = config.baseBranch;
1892
+ const changedFiles = getChangedFiles(rootDir, baseBranch);
1893
+ if (changedFiles.length === 0) {
1894
+ log.info("No changed files detected.");
1895
+ return;
1896
+ }
1897
+ const { bumpFiles: allBumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
1898
+ if (parseErrors.length > 0) {
1899
+ for (const err of parseErrors) log.error(err);
1900
+ process.exit(1);
1901
+ }
1902
+ const bumpyRelDir = relative(rootDir, getBumpyDir(rootDir));
1903
+ const fileStatuses = getFileStatuses(bumpyRelDir, { cwd: rootDir });
1904
+ const augmentedChangedFiles = [...changedFiles];
1905
+ for (const [file] of fileStatuses) if (file.endsWith(".md") && !file.endsWith("README.md") && !augmentedChangedFiles.includes(file)) augmentedChangedFiles.push(file);
1906
+ const { branchBumpFiles, emptyBumpFileIds } = filterBranchBumpFiles(allBumpFiles, augmentedChangedFiles, rootDir);
1907
+ const bumpFileStatuses = /* @__PURE__ */ new Map();
1908
+ for (const bf of branchBumpFiles) {
1909
+ const filePath = `${bumpyRelDir}/${bf.id}.md`;
1910
+ const status = fileStatuses.get(filePath);
1911
+ bumpFileStatuses.set(bf.id, status ?? "committed");
1912
+ }
1913
+ for (const id of emptyBumpFileIds) {
1914
+ const filePath = `${bumpyRelDir}/${id}.md`;
1915
+ const status = fileStatuses.get(filePath);
1916
+ bumpFileStatuses.set(id, status ?? "committed");
1917
+ }
1918
+ const effectiveBumpFiles = opts.hook ? branchBumpFiles.filter((bf) => {
1919
+ const status = bumpFileStatuses.get(bf.id);
1920
+ if (opts.hook === "pre-push") return status === "committed";
1921
+ if (opts.hook === "pre-commit") return status !== "untracked";
1922
+ return true;
1923
+ }) : branchBumpFiles;
1924
+ const effectiveEmptyIds = opts.hook ? emptyBumpFileIds.filter((id) => {
1925
+ const status = bumpFileStatuses.get(id);
1926
+ if (opts.hook === "pre-push") return status === "committed";
1927
+ if (opts.hook === "pre-commit") return status !== "untracked";
1928
+ return true;
1929
+ }) : emptyBumpFileIds;
1930
+ if (opts.hook) {
1931
+ const excludedBumpFiles = branchBumpFiles.filter((bf) => !effectiveBumpFiles.includes(bf));
1932
+ const excludedEmptyIds = emptyBumpFileIds.filter((id) => !effectiveEmptyIds.includes(id));
1933
+ for (const bf of excludedBumpFiles) {
1934
+ const status = bumpFileStatuses.get(bf.id);
1935
+ if (opts.hook === "pre-push" && status === "staged") log.warn(`${bumpyRelDir}/${bf.id}.md is staged but not committed — it won't be included in the push`);
1936
+ else if (status === "untracked") log.warn(`${bumpyRelDir}/${bf.id}.md is untracked — run \`git add\` to include it`);
1937
+ }
1938
+ for (const id of excludedEmptyIds) {
1939
+ const status = bumpFileStatuses.get(id);
1940
+ if (opts.hook === "pre-push" && status === "staged") log.warn(`${bumpyRelDir}/${id}.md is staged but not committed — it won't be included in the push`);
1941
+ else if (status === "untracked") log.warn(`${bumpyRelDir}/${id}.md is untracked — run \`git add\` to include it`);
1942
+ }
1943
+ }
1944
+ const hasEmptyBumpFile = effectiveEmptyIds.length > 0;
1945
+ const coveredPackages = /* @__PURE__ */ new Set();
1946
+ for (const bf of effectiveBumpFiles) for (const release of bf.releases) coveredPackages.add(release.name);
1947
+ const changedPackages = await findChangedPackages(changedFiles, packages, rootDir, config);
1948
+ if (changedPackages.length === 0) {
1949
+ log.info("No managed packages have changed.");
1950
+ return;
1951
+ }
1952
+ const missing = changedPackages.filter((name) => !coveredPackages.has(name));
1953
+ const hasAnyCoverage = effectiveBumpFiles.length > 0 || hasEmptyBumpFile;
1954
+ if (missing.length === 0 || hasEmptyBumpFile && !opts.strict) {
1955
+ if (hasEmptyBumpFile && missing.length > 0) log.success("Empty bump file found — uncovered packages acknowledged.");
1956
+ else log.success(`🐸 All ${changedPackages.length} changed package(s) have bump files.`);
1957
+ if (effectiveBumpFiles.length > 0) printBumpFileList(effectiveBumpFiles.map((bf) => bf.id), bumpyRelDir, bumpFileStatuses);
1958
+ return;
1959
+ }
1960
+ const willFail = !opts.noFail && (opts.strict || !hasAnyCoverage);
1961
+ (willFail ? log.error : log.warn)(`${missing.length} changed package(s) missing bump files:\n`);
1962
+ for (const name of missing) console.log(` ${colorize(name, "yellow")}`);
1963
+ if (effectiveBumpFiles.length > 0) {
1964
+ console.log();
1965
+ printBumpFileList(effectiveBumpFiles.map((bf) => bf.id), bumpyRelDir, bumpFileStatuses);
1966
+ }
1967
+ console.log();
1968
+ if (opts.strict) log.dim("Run `bumpy add` to create a bump file. Use bump type `none` for packages that changed but don't need a bump.");
1969
+ else log.dim("Run `bumpy add` to create a bump file, or `bumpy add --empty` if no release is needed.");
1970
+ log.dim("To adjust which files trigger change detection, set `changedFilePatterns` in .bumpy/_config.json.");
1971
+ if (willFail) process.exit(1);
1972
+ }
1973
+ function printBumpFileList(ids, bumpyRelDir, statuses) {
1974
+ log.dim("Bump files on this branch:");
1975
+ for (const id of ids) {
1976
+ const status = statuses.get(id);
1977
+ const statusLabel = status === "staged" ? colorize(" (staged)", "yellow") : status === "untracked" ? colorize(" (untracked)", "yellow") : "";
1978
+ log.dim(` ${bumpyRelDir}/${id}.md${statusLabel}`);
1979
+ }
1980
+ }
1981
+ /** Map changed files to the packages they belong to */
1982
+ async function findChangedPackages(changedFiles, packages, rootDir, config) {
1983
+ const changed = /* @__PURE__ */ new Set();
1984
+ const matchers = /* @__PURE__ */ new Map();
1985
+ for (const [name, pkg] of packages) {
1986
+ const patterns = (await loadPackageConfig(pkg.dir, config, name)).changedFilePatterns ?? config.changedFilePatterns;
1987
+ matchers.set(name, (0, import_picomatch.default)(patterns));
1988
+ }
1989
+ for (const file of changedFiles) for (const [name, pkg] of packages) {
1990
+ const pkgRelDir = relative(rootDir, pkg.dir);
1991
+ if (file.startsWith(pkgRelDir + "/")) {
1992
+ const relToPackage = file.slice(pkgRelDir.length + 1);
1993
+ if (matchers.get(name)(relToPackage)) changed.add(name);
1994
+ }
1995
+ }
1996
+ return [...changed];
1997
+ }
1998
+ //#endregion
1999
+ export { checkCommand, findChangedPackages, require_picomatch as t };
@@ -1,34 +1,28 @@
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 { t as detectPackageManager } 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 { 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";
7
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-CoaSxqne.mjs";
8
+ import { t as assembleReleasePlan } from "./release-plan-pyxf71dx.mjs";
9
+ import { r as getChangedFiles } from "./git-ukq7VTuZ.mjs";
10
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";
11
+ import { findChangedPackages } from "./check-CS8WIGZA.mjs";
12
+ import { t as resolveCommitMessage } from "./commit-message-3e4KhzFV.mjs";
13
13
  import { createHash } from "node:crypto";
14
14
  //#region src/commands/ci.ts
15
15
  /**
16
16
  * Temporarily override GH_TOKEN with BUMPY_GH_TOKEN for a gh CLI call.
17
17
  *
18
- * Use `--pat-pr` / `--pat-comments` flags to opt in. This is useful when
19
- * BUMPY_GH_TOKEN belongs to a dedicated automation/bot account. If you're
20
- * using a developer's personal PAT, it's better to leave these flags off so
21
- * that PRs and comments appear from github-actions[bot] allowing the
22
- * developer to still review and approve the PR.
18
+ * When BUMPY_GH_TOKEN is set (e.g. a dedicated bot PAT or GitHub App token),
19
+ * it is used so that PRs created by bumpy can trigger CI workflows (the
20
+ * default GITHUB_TOKEN cannot do this). If BUMPY_GH_TOKEN is not available
21
+ * (e.g. fork PRs where secrets are hidden), falls back to the default token.
23
22
  */
24
- function requirePatToken() {
23
+ async function withPatToken(fn) {
25
24
  const token = process.env.BUMPY_GH_TOKEN;
26
- if (!token) throw new Error("BUMPY_GH_TOKEN must be set when using --pat-pr or --pat-comments");
27
- return token;
28
- }
29
- async function withPatToken(usePat, fn) {
30
- if (!usePat) return fn();
31
- const token = requirePatToken();
25
+ if (!token) return fn();
32
26
  const originalGhToken = process.env.GH_TOKEN;
33
27
  process.env.GH_TOKEN = token;
34
28
  try {
@@ -94,7 +88,7 @@ async function ciCheckCommand(rootDir, opts) {
94
88
  if (prBumpFiles.length === 0) {
95
89
  if (emptyBumpFileIds.length > 0 && parseErrors.length === 0) {
96
90
  log.success("Empty bump file found — no releases needed.");
97
- if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatEmptyBumpFileComment(emptyBumpFileIds, prNumber, detectPrBranch(rootDir)), rootDir, opts.patComments);
91
+ if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatEmptyBumpFileComment(emptyBumpFileIds, prNumber, detectPrBranch(rootDir)), rootDir);
98
92
  return;
99
93
  }
100
94
  const willFail = !opts.noFail || parseErrors.length > 0;
@@ -103,7 +97,7 @@ async function ciCheckCommand(rootDir, opts) {
103
97
  else log.warn(msg);
104
98
  if (shouldComment && prNumber) {
105
99
  const prBranch = detectPrBranch(rootDir);
106
- await postOrUpdatePrComment(prNumber, parseErrors.length > 0 ? formatBumpFileErrorsComment(parseErrors, prBranch, pm) : formatNoBumpFilesComment(prBranch, pm), rootDir, opts.patComments);
100
+ await postOrUpdatePrComment(prNumber, parseErrors.length > 0 ? formatBumpFileErrorsComment(parseErrors, prBranch, pm) : formatNoBumpFilesComment(prBranch, pm), rootDir);
107
101
  }
108
102
  if (willFail) process.exit(1);
109
103
  return;
@@ -115,7 +109,7 @@ async function ciCheckCommand(rootDir, opts) {
115
109
  console.log(` ${r.name}: ${r.oldVersion} → ${colorize(r.newVersion, "cyan")}${tag}`);
116
110
  }
117
111
  if (plan.warnings.length > 0) for (const w of plan.warnings) log.warn(w);
118
- if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings, parseErrors, emptyBumpFileIds), rootDir, opts.patComments);
112
+ if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings, parseErrors, emptyBumpFileIds), rootDir);
119
113
  if (parseErrors.length > 0 && !opts.noFail) process.exit(1);
120
114
  const coveredPackages = new Set(plan.releases.map((r) => r.name));
121
115
  const missing = (await findChangedPackages(changedFiles, packages, rootDir, config)).filter((name) => !coveredPackages.has(name));
@@ -141,7 +135,7 @@ async function ciReleaseCommand(rootDir, opts) {
141
135
  }
142
136
  if (bumpFiles.length === 0) {
143
137
  log.info("No pending bump files — checking for unpublished packages...");
144
- const { publishCommand } = await import("./publish-BwidFqbo.mjs");
138
+ const { publishCommand } = await import("./publish-DWdN3o9u.mjs");
145
139
  await publishCommand(rootDir, { tag: opts.tag });
146
140
  return;
147
141
  }
@@ -151,11 +145,11 @@ async function ciReleaseCommand(rootDir, opts) {
151
145
  return;
152
146
  }
153
147
  if (opts.mode === "auto-publish") await autoPublish(rootDir, config, plan, opts.tag);
154
- else await createVersionPr(rootDir, plan, config, new Map([...packages.values()].map((p) => [p.name, p.relativeDir])), opts.branch, opts.patPr);
148
+ else await createVersionPr(rootDir, plan, config, new Map([...packages.values()].map((p) => [p.name, p.relativeDir])), opts.branch);
155
149
  }
156
150
  async function autoPublish(rootDir, config, plan, tag) {
157
151
  log.step("Running bumpy version...");
158
- const { versionCommand } = await import("./version-ClkaCNTE.mjs");
152
+ const { versionCommand } = await import("./version-BxDhayli.mjs");
159
153
  await versionCommand(rootDir);
160
154
  log.step("Committing version changes...");
161
155
  runArgs([
@@ -184,7 +178,7 @@ async function autoPublish(rootDir, config, plan, tag) {
184
178
  ], { cwd: rootDir });
185
179
  }
186
180
  log.step("Running bumpy publish...");
187
- const { publishCommand } = await import("./publish-BwidFqbo.mjs");
181
+ const { publishCommand } = await import("./publish-DWdN3o9u.mjs");
188
182
  await publishCommand(rootDir, { tag });
189
183
  }
190
184
  /**
@@ -306,7 +300,7 @@ function pushWithToken(rootDir, branch, config) {
306
300
  if (!token && repo) log.warn("BUMPY_GH_TOKEN is not set — PR checks will not trigger automatically.\n Run `bumpy ci setup` for help.");
307
301
  }
308
302
  }
309
- async function createVersionPr(rootDir, plan, config, packageDirs, branchName, patPr) {
303
+ async function createVersionPr(rootDir, plan, config, packageDirs, branchName) {
310
304
  const branch = validateBranchName(branchName || config.versionPr.branch);
311
305
  const baseBranch = validateBranchName(tryRunArgs([
312
306
  "git",
@@ -350,7 +344,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
350
344
  branch
351
345
  ], { cwd: rootDir });
352
346
  log.step("Running bumpy version...");
353
- const { versionCommand } = await import("./version-ClkaCNTE.mjs");
347
+ const { versionCommand } = await import("./version-BxDhayli.mjs");
354
348
  await versionCommand(rootDir);
355
349
  runArgs([
356
350
  "git",
@@ -381,11 +375,12 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
381
375
  });
382
376
  pushWithToken(rootDir, branch, config);
383
377
  const repo = process.env.GITHUB_REPOSITORY;
378
+ const noPatWarning = !process.env.BUMPY_GH_TOKEN && !!repo;
384
379
  if (existingPr) {
385
380
  const validPr = validatePrNumber(existingPr);
386
- const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, validPr);
381
+ const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, validPr, noPatWarning);
387
382
  log.step(`Updating existing PR #${validPr}...`);
388
- await withPatToken(!!patPr, () => runArgsAsync([
383
+ await withPatToken(() => runArgsAsync([
389
384
  "gh",
390
385
  "pr",
391
386
  "edit",
@@ -402,8 +397,8 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
402
397
  } else {
403
398
  log.step("Creating version PR...");
404
399
  const prTitle = config.versionPr.title;
405
- const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, null);
406
- const result = await withPatToken(!!patPr, () => runArgsAsync([
400
+ const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, null, noPatWarning);
401
+ const result = await withPatToken(() => runArgsAsync([
407
402
  "gh",
408
403
  "pr",
409
404
  "create",
@@ -423,8 +418,8 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
423
418
  if (repo) {
424
419
  const newPrNumber = result?.match(/\/pull\/(\d+)/)?.[1];
425
420
  if (newPrNumber) {
426
- const updatedBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, newPrNumber);
427
- await withPatToken(!!patPr, () => runArgsAsync([
421
+ const updatedBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, newPrNumber, noPatWarning);
422
+ await withPatToken(() => runArgsAsync([
428
423
  "gh",
429
424
  "pr",
430
425
  "edit",
@@ -437,7 +432,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
437
432
  }));
438
433
  }
439
434
  }
440
- if (!patPr) pushWithToken(rootDir, branch, config);
435
+ if (!process.env.BUMPY_GH_TOKEN) pushWithToken(rootDir, branch, config);
441
436
  }
442
437
  runArgs([
443
438
  "git",
@@ -619,7 +614,7 @@ function buildDiffLinks(pkgDir, changesBaseUrl) {
619
614
  function sha256Hex(input) {
620
615
  return createHash("sha256").update(input).digest("hex");
621
616
  }
622
- function formatVersionPrBody(plan, preamble, packageDirs, repo, prNumber) {
617
+ function formatVersionPrBody(plan, preamble, packageDirs, repo, prNumber, showNoPatWarning = false) {
623
618
  const changesBaseUrl = repo && prNumber ? `https://github.com/${repo}/pull/${prNumber}/changes` : null;
624
619
  const lines = [];
625
620
  lines.push(preamble);
@@ -658,10 +653,14 @@ function formatVersionPrBody(plan, preamble, packageDirs, repo, prNumber) {
658
653
  lines.push("");
659
654
  }
660
655
  }
656
+ if (showNoPatWarning) {
657
+ lines.push("> ⚠️ `BUMPY_GH_TOKEN` is not set — CI checks will not run automatically on this PR. Run `bumpy ci setup` for help.");
658
+ lines.push("");
659
+ }
661
660
  return lines.join("\n");
662
661
  }
663
662
  const COMMENT_MARKER = "<!-- bumpy-release-plan -->";
664
- async function postOrUpdatePrComment(prNumber, body, rootDir, usePat = false) {
663
+ async function postOrUpdatePrComment(prNumber, body, rootDir) {
665
664
  const validPr = validatePrNumber(prNumber);
666
665
  const markedBody = `${COMMENT_MARKER}\n${body}`;
667
666
  try {
@@ -676,7 +675,7 @@ async function postOrUpdatePrComment(prNumber, body, rootDir, usePat = false) {
676
675
  `.comments[] | select(.body | startswith("${COMMENT_MARKER}")) | .url | capture("issuecomment-(?<id>[0-9]+)$") | .id`
677
676
  ], { cwd: rootDir })?.split("\n")[0]?.trim();
678
677
  if (commentId) {
679
- await withPatToken(usePat, () => runArgsAsync([
678
+ await runArgsAsync([
680
679
  "gh",
681
680
  "api",
682
681
  `repos/{owner}/{repo}/issues/comments/${commentId}`,
@@ -687,10 +686,10 @@ async function postOrUpdatePrComment(prNumber, body, rootDir, usePat = false) {
687
686
  ], {
688
687
  cwd: rootDir,
689
688
  input: markedBody
690
- }));
689
+ });
691
690
  log.dim(" Updated PR comment");
692
691
  } else {
693
- await withPatToken(usePat, () => runArgsAsync([
692
+ await runArgsAsync([
694
693
  "gh",
695
694
  "pr",
696
695
  "comment",
@@ -700,7 +699,7 @@ async function postOrUpdatePrComment(prNumber, body, rootDir, usePat = false) {
700
699
  ], {
701
700
  cwd: rootDir,
702
701
  input: markedBody
703
- }));
702
+ });
704
703
  log.dim(" Posted PR comment");
705
704
  }
706
705
  } catch (err) {