@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.
- package/README.md +4 -5
- package/dist/{add-DEqGa5gI.mjs → add-D1uiW7VA.mjs} +24 -5
- package/dist/{apply-release-plan-Bi9OSWks.mjs → apply-release-plan-60VfCLF8.mjs} +2 -2
- package/dist/{bump-file-BTsntOO-.mjs → bump-file-CoaSxqne.mjs} +1 -1
- package/dist/{changelog-xKuL0IKx.mjs → changelog-DP3OrTqQ.mjs} +7 -6
- package/dist/{changelog-github-CEaDCtTk.mjs → changelog-github-Da5KekQd.mjs} +1 -1
- package/dist/{picomatch-TGJi--_I.mjs → check-CS8WIGZA.mjs} +131 -2
- package/dist/{ci-BVTwTUUK.mjs → ci-CnIkaf7Q.mjs} +40 -41
- package/dist/cli.mjs +29 -21
- package/dist/{config-CJIj8xG3.mjs → config-D13G4-R8.mjs} +1 -1
- package/dist/{generate-wHN6Ll6p.mjs → generate-D0KJsvpD.mjs} +4 -4
- package/dist/{git-D0__HP86.mjs → git-ukq7VTuZ.mjs} +21 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +8 -8
- package/dist/{publish-BwidFqbo.mjs → publish-DWdN3o9u.mjs} +45 -9
- package/dist/{publish-pipeline-BvLIu7WF.mjs → publish-pipeline-C1slMaJV.mjs} +1 -1
- package/dist/{release-plan-21H89Cx1.mjs → release-plan-pyxf71dx.mjs} +6 -56
- package/dist/{status-CDGxgXWd.mjs → status-DyzcQ6CD.mjs} +6 -6
- package/dist/{types-CSM0c2-m.mjs → types-BX4pfmKh.mjs} +1 -1
- package/dist/{version-ClkaCNTE.mjs → version-BxDhayli.mjs} +6 -6
- package/dist/{workspace-c9-TqXed.mjs → workspace-BKOAMeki.mjs} +1 -1
- package/package.json +1 -1
- package/skills/add-change/SKILL.md +1 -1
- package/dist/check-D3eXRyKJ.mjs +0 -92
- /package/dist/{ci-setup-D1NCzbNH.mjs → ci-setup-DWxrdSK6.mjs} +0 -0
- /package/dist/{commit-message-DOIfDxfj.mjs → commit-message-3e4KhzFV.mjs} +0 -0
- /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-
|
|
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
|
-
-
|
|
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 }} #
|
|
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
|
|
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-
|
|
4
|
-
import { t as discoverPackages } from "./workspace-
|
|
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-
|
|
7
|
-
import { r as getChangedFiles } from "./git-
|
|
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 "./
|
|
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-
|
|
3
|
-
import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
8
|
-
import { t as assembleReleasePlan } from "./release-plan-
|
|
9
|
-
import { r as getChangedFiles } from "./git-
|
|
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-
|
|
12
|
-
import { t as resolveCommitMessage } from "./commit-message-
|
|
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
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
|
23
|
+
async function withPatToken(fn) {
|
|
25
24
|
const token = process.env.BUMPY_GH_TOKEN;
|
|
26
|
-
if (!token)
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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(
|
|
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(
|
|
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(
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
|
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) {
|