@varlock/bumpy 1.0.0 → 1.2.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 +256 -0
- package/config-schema.json +327 -0
- package/dist/{add-CgCjs4d-.mjs → add-yP81c9_q.mjs} +23 -13
- package/dist/{ai-sMYUf3lP.mjs → ai-STKnq09z.mjs} +1 -1
- package/dist/{apply-release-plan-CczGWJTk.mjs → apply-release-plan-CPzu6JcF.mjs} +12 -7
- package/dist/{bump-file-CCLXMLA8.mjs → bump-file-Br2bTaWp.mjs} +36 -10
- package/dist/{changelog-github-Cd8uJHZI.mjs → changelog-github-DkACMj0j.mjs} +1 -1
- package/dist/check-D_0exKi6.mjs +87 -0
- package/dist/{ci-Bhx--Tj6.mjs → ci-CvaikKX1.mjs} +48 -33
- package/dist/{ci-setup-qz4Y3v7T.mjs → ci-setup-CARJFhcE.mjs} +3 -3
- package/dist/cli.mjs +31 -31
- package/dist/commit-message-BwsowSds.mjs +23 -0
- package/dist/{config-XZWUL3ma.mjs → config-D7Umr-fT.mjs} +6 -5
- package/dist/{fs-DYR2XuFE.mjs → fs-DnDogVn-.mjs} +16 -1
- package/dist/{generate-gYKTpvex.mjs → generate-BOLrTYWR.mjs} +74 -65
- package/dist/{git-CGHVXXKw.mjs → git-YDedMddc.mjs} +54 -2
- package/dist/index.d.mts +13 -2
- package/dist/index.mjs +8 -8
- package/dist/init-DJhMaceS.mjs +196 -0
- package/dist/{js-yaml-DpZfOoD4.mjs → package-manager-ByJ0wKYh.mjs} +79 -1
- package/dist/picomatch-DMmqYjgq.mjs +1870 -0
- package/dist/{publish-Cun-zQ1b.mjs → publish-CPZwqyWh.mjs} +10 -10
- package/dist/{publish-pipeline-BwBuKCIk.mjs → publish-pipeline-BFt96o_h.mjs} +5 -5
- package/dist/{release-plan-Bi5QNSEo.mjs → release-plan-CNOuSI-d.mjs} +2 -2
- package/dist/{shell-Dj7JRD_q.mjs → shell-CY7OD48z.mjs} +20 -2
- package/dist/{status-CfE63ti5.mjs → status-skGX8uU7.mjs} +6 -6
- package/dist/{version-19vVt9dv.mjs → version-CnXcbqi1.mjs} +13 -16
- package/dist/{workspace-C5ULTyUN.mjs → workspace-BHsAPUmC.mjs} +3 -3
- package/package.json +5 -1
- package/skills/add-change/SKILL.md +11 -3
- package/dist/check-BOoxpWqk.mjs +0 -51
- package/dist/init-lA9E5pEc.mjs +0 -22
- package/dist/migrate-DmOYgmfD.mjs +0 -121
- package/dist/package-manager-VCe10bjc.mjs +0 -80
- /package/dist/{clack-CDRCHrC-.mjs → clack-C6bVkGxf.mjs} +0 -0
- /package/dist/{dep-graph-E-9-eQ2J.mjs → dep-graph-DiLeAhl9.mjs} +0 -0
- /package/dist/{names-9VubBmL0.mjs → names-C-TuOPbd.mjs} +0 -0
- /package/dist/{semver-DfQyVLM_.mjs → semver-BJzWIuRz.mjs} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as log } from "./logger-C2dEe5Su.mjs";
|
|
2
|
-
import { a as readJson, c as
|
|
3
|
-
import {
|
|
2
|
+
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";
|
|
3
|
+
import { r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
4
4
|
import { relative, resolve } from "node:path";
|
|
5
5
|
import { realpathSync } from "node:fs";
|
|
6
6
|
//#region src/core/changelog.ts
|
|
@@ -28,7 +28,7 @@ const defaultFormatter = (ctx) => {
|
|
|
28
28
|
const BUILTIN_FORMATTERS = {
|
|
29
29
|
default: defaultFormatter,
|
|
30
30
|
github: async () => {
|
|
31
|
-
const { createGithubFormatter } = await import("./changelog-github-
|
|
31
|
+
const { createGithubFormatter } = await import("./changelog-github-DkACMj0j.mjs");
|
|
32
32
|
return createGithubFormatter();
|
|
33
33
|
}
|
|
34
34
|
};
|
|
@@ -39,7 +39,7 @@ const BUILTIN_FORMATTERS = {
|
|
|
39
39
|
async function loadFormatter(changelog, rootDir) {
|
|
40
40
|
const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
|
|
41
41
|
if (name === "github") {
|
|
42
|
-
const { createGithubFormatter } = await import("./changelog-github-
|
|
42
|
+
const { createGithubFormatter } = await import("./changelog-github-DkACMj0j.mjs");
|
|
43
43
|
return createGithubFormatter(options);
|
|
44
44
|
}
|
|
45
45
|
if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
|
|
@@ -95,7 +95,7 @@ function prependToChangelog(existingContent, newEntry) {
|
|
|
95
95
|
/** Apply the release plan: bump versions, update changelogs, delete bump files */
|
|
96
96
|
async function applyReleasePlan(releasePlan, packages, rootDir, config) {
|
|
97
97
|
const releaseMap = new Map(releasePlan.releases.map((r) => [r.name, r]));
|
|
98
|
-
const formatter = await loadFormatter(config.changelog, rootDir);
|
|
98
|
+
const formatter = config.changelog !== false ? await loadFormatter(config.changelog, rootDir) : null;
|
|
99
99
|
for (const release of releasePlan.releases) {
|
|
100
100
|
const pkgJsonPath = resolve(packages.get(release.name).dir, "package.json");
|
|
101
101
|
const pkgJson = await readJson(pkgJsonPath);
|
|
@@ -115,14 +115,19 @@ async function applyReleasePlan(releasePlan, packages, rootDir, config) {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
for (const release of releasePlan.releases) {
|
|
118
|
+
if (formatter) for (const release of releasePlan.releases) {
|
|
119
119
|
const changelogPath = resolve(packages.get(release.name).dir, "CHANGELOG.md");
|
|
120
120
|
const entry = await generateChangelogEntry(release, releasePlan.bumpFiles, formatter);
|
|
121
121
|
let existingContent = "";
|
|
122
122
|
if (await exists(changelogPath)) existingContent = await readText(changelogPath);
|
|
123
123
|
await writeText(changelogPath, prependToChangelog(existingContent, entry));
|
|
124
124
|
}
|
|
125
|
-
|
|
125
|
+
const bumpyDir = getBumpyDir(rootDir);
|
|
126
|
+
const allBumpFiles = await listFiles(bumpyDir, ".md");
|
|
127
|
+
for (const file of allBumpFiles) {
|
|
128
|
+
if (file === "README.md") continue;
|
|
129
|
+
await removeFile(resolve(bumpyDir, file));
|
|
130
|
+
}
|
|
126
131
|
}
|
|
127
132
|
/** Update a version range to include a new version, preserving the range prefix */
|
|
128
133
|
function updateRange(range, newVersion) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { n as log } from "./logger-C2dEe5Su.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { r as getBumpyDir } from "./config-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { f as writeText, i as listFiles, s as readText } from "./fs-DnDogVn-.mjs";
|
|
3
|
+
import { r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
4
|
+
import { i as jsYaml } from "./package-manager-ByJ0wKYh.mjs";
|
|
5
|
+
import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
7
8
|
//#region src/core/bump-file.ts
|
|
8
9
|
const VALID_BUMP_TYPES = new Set([
|
|
9
10
|
"major",
|
|
@@ -131,13 +132,38 @@ async function writeBumpFile(rootDir, filename, releases, summary) {
|
|
|
131
132
|
}).trim()}\n---\n\n${summary}\n`);
|
|
132
133
|
return filePath;
|
|
133
134
|
}
|
|
134
|
-
/** Delete consumed bump files */
|
|
135
|
-
async function deleteBumpFiles(rootDir, ids) {
|
|
136
|
-
const dir = getBumpyDir(rootDir);
|
|
137
|
-
for (const id of ids) await removeFile(resolve(dir, `${id}.md`));
|
|
138
|
-
}
|
|
139
135
|
function fileToId(filePath) {
|
|
140
136
|
return filePath.split("/").pop().replace(/\.md$/, "");
|
|
141
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Given a list of changed file paths (relative to root), extract the IDs
|
|
140
|
+
* of bump files that were added/modified. Shared by `check` and `ci check`.
|
|
141
|
+
*/
|
|
142
|
+
function extractBumpFileIdsFromChangedFiles(changedFiles) {
|
|
143
|
+
return new Set(changedFiles.filter((f) => /^\.bumpy\/.*\.md$/.test(f) && !f.endsWith("README.md")).map((f) => f.replace(/^\.bumpy\//, "").replace(/\.md$/, "")));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Filter bump files to only those added/modified on the current branch.
|
|
147
|
+
* Also detects empty bump files (no releases) that still exist on disk,
|
|
148
|
+
* which signal intentionally no releases needed.
|
|
149
|
+
*/
|
|
150
|
+
function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir) {
|
|
151
|
+
const branchBumpFileIds = extractBumpFileIdsFromChangedFiles(changedFiles);
|
|
152
|
+
const branchBumpFiles = allBumpFiles.filter((bf) => branchBumpFileIds.has(bf.id));
|
|
153
|
+
let hasEmptyBumpFile = false;
|
|
154
|
+
if (rootDir) {
|
|
155
|
+
const parsedIds = new Set(branchBumpFiles.map((bf) => bf.id));
|
|
156
|
+
const bumpyDir = getBumpyDir(rootDir);
|
|
157
|
+
for (const id of branchBumpFileIds) if (!parsedIds.has(id) && existsSync(resolve(bumpyDir, `${id}.md`))) {
|
|
158
|
+
hasEmptyBumpFile = true;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
branchBumpFiles,
|
|
164
|
+
branchBumpFileIds,
|
|
165
|
+
hasEmptyBumpFile
|
|
166
|
+
};
|
|
167
|
+
}
|
|
142
168
|
//#endregion
|
|
143
|
-
export { writeBumpFile as i, parseBumpFile as n, readBumpFiles as r,
|
|
169
|
+
export { writeBumpFile as i, parseBumpFile as n, readBumpFiles as r, filterBranchBumpFiles as t };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { n as log, o as __toESM, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
3
|
+
import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
|
|
4
|
+
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-Br2bTaWp.mjs";
|
|
5
|
+
import { r as getChangedFiles } from "./git-YDedMddc.mjs";
|
|
6
|
+
import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
|
|
7
|
+
import { relative } from "node:path";
|
|
8
|
+
//#region src/commands/check.ts
|
|
9
|
+
var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
|
|
10
|
+
/**
|
|
11
|
+
* Local check: detect which packages have changed on this branch
|
|
12
|
+
* and verify they have corresponding bump files.
|
|
13
|
+
* Designed for pre-push hooks — no GitHub API needed.
|
|
14
|
+
*
|
|
15
|
+
* Default: at least one bump file must exist, uncovered packages are warned.
|
|
16
|
+
* --strict: every changed package must be covered.
|
|
17
|
+
* --no-fail: warn only, never exit 1.
|
|
18
|
+
*/
|
|
19
|
+
async function checkCommand(rootDir, opts = {}) {
|
|
20
|
+
const config = await loadConfig(rootDir);
|
|
21
|
+
const { packages } = await discoverWorkspace(rootDir, config);
|
|
22
|
+
const baseBranch = config.baseBranch;
|
|
23
|
+
const changedFiles = getChangedFiles(rootDir, baseBranch);
|
|
24
|
+
if (changedFiles.length === 0) {
|
|
25
|
+
log.info("No changed files detected.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const { branchBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(await readBumpFiles(rootDir), changedFiles, rootDir);
|
|
29
|
+
if (hasEmptyBumpFile) {
|
|
30
|
+
log.success("Empty bump file found — no releases needed.");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const coveredPackages = /* @__PURE__ */ new Set();
|
|
34
|
+
for (const bf of branchBumpFiles) for (const release of bf.releases) coveredPackages.add(release.name);
|
|
35
|
+
const changedPackages = await findChangedPackages(changedFiles, packages, rootDir, config);
|
|
36
|
+
if (changedPackages.length === 0) {
|
|
37
|
+
log.info("No managed packages have changed.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const willFailNoBump = !opts.noFail;
|
|
41
|
+
if (branchBumpFiles.length === 0) {
|
|
42
|
+
(willFailNoBump ? log.error : log.warn)(`${changedPackages.length} changed package(s) missing bump files:\n`);
|
|
43
|
+
for (const name of changedPackages) console.log(` ${colorize(name, "yellow")}`);
|
|
44
|
+
console.log();
|
|
45
|
+
log.dim("Run `bumpy add` to create a bump file, or `bumpy add --empty` if no release is needed.");
|
|
46
|
+
log.dim("To adjust which files trigger change detection, set `changedFilePatterns` in .bumpy/_config.json.");
|
|
47
|
+
if (willFailNoBump) process.exit(1);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const missing = changedPackages.filter((name) => !coveredPackages.has(name));
|
|
51
|
+
if (missing.length === 0) {
|
|
52
|
+
log.success(`🐸 All ${changedPackages.length} changed package(s) have bump files.`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const willFailUncovered = opts.strict && !opts.noFail;
|
|
56
|
+
(willFailUncovered ? log.error : log.warn)(`${missing.length} changed package(s) missing bump files:\n`);
|
|
57
|
+
for (const name of missing) console.log(` ${colorize(name, "yellow")}`);
|
|
58
|
+
if (branchBumpFiles.length > 0) {
|
|
59
|
+
console.log();
|
|
60
|
+
log.dim(`Existing bump files on this branch:`);
|
|
61
|
+
for (const bf of branchBumpFiles) log.dim(` ${getBumpyDir(rootDir)}/${bf.id}.md`);
|
|
62
|
+
}
|
|
63
|
+
console.log();
|
|
64
|
+
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 release.");
|
|
65
|
+
else log.dim("Run `bumpy add` to create a bump file, or `bumpy add --empty` if no release is needed.");
|
|
66
|
+
log.dim("To adjust which files trigger change detection, set `changedFilePatterns` in .bumpy/_config.json.");
|
|
67
|
+
if (willFailUncovered) process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
/** Map changed files to the packages they belong to */
|
|
70
|
+
async function findChangedPackages(changedFiles, packages, rootDir, config) {
|
|
71
|
+
const changed = /* @__PURE__ */ new Set();
|
|
72
|
+
const matchers = /* @__PURE__ */ new Map();
|
|
73
|
+
for (const [name, pkg] of packages) {
|
|
74
|
+
const patterns = (await loadPackageConfig(pkg.dir, config, name)).changedFilePatterns ?? config.changedFilePatterns;
|
|
75
|
+
matchers.set(name, (0, import_picomatch.default)(patterns));
|
|
76
|
+
}
|
|
77
|
+
for (const file of changedFiles) for (const [name, pkg] of packages) {
|
|
78
|
+
const pkgRelDir = relative(rootDir, pkg.dir);
|
|
79
|
+
if (file.startsWith(pkgRelDir + "/")) {
|
|
80
|
+
const relToPackage = file.slice(pkgRelDir.length + 1);
|
|
81
|
+
if (matchers.get(name)(relToPackage)) changed.add(name);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return [...changed];
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { checkCommand, findChangedPackages };
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
2
|
-
import { a as loadConfig } from "./config-
|
|
3
|
-
import { t as detectPackageManager } from "./package-manager-
|
|
4
|
-
import { n as discoverWorkspace } from "./workspace-
|
|
5
|
-
import { t as DependencyGraph } from "./dep-graph-
|
|
6
|
-
import { n as
|
|
7
|
-
import { r as readBumpFiles } from "./bump-file-
|
|
8
|
-
import { t as assembleReleasePlan } from "./release-plan-
|
|
9
|
-
import {
|
|
10
|
-
import { t as randomName } from "./names-
|
|
2
|
+
import { a as loadConfig } from "./config-D7Umr-fT.mjs";
|
|
3
|
+
import { t as detectPackageManager } from "./package-manager-ByJ0wKYh.mjs";
|
|
4
|
+
import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
|
|
5
|
+
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
|
+
import { n as runArgs, r as runArgsAsync, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
7
|
+
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-Br2bTaWp.mjs";
|
|
8
|
+
import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
|
|
9
|
+
import { r as getChangedFiles } from "./git-YDedMddc.mjs";
|
|
10
|
+
import { t as randomName } from "./names-C-TuOPbd.mjs";
|
|
11
|
+
import { findChangedPackages } from "./check-D_0exKi6.mjs";
|
|
12
|
+
import { t as resolveCommitMessage } from "./commit-message-BwsowSds.mjs";
|
|
11
13
|
import { createHash } from "node:crypto";
|
|
12
14
|
//#region src/commands/ci.ts
|
|
13
15
|
/**
|
|
@@ -87,12 +89,19 @@ async function ciCheckCommand(rootDir, opts) {
|
|
|
87
89
|
const prNumber = detectPrNumber();
|
|
88
90
|
const pm = await detectPackageManager(rootDir);
|
|
89
91
|
const changedFiles = getChangedFiles(rootDir, config.baseBranch);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
+
const { branchBumpFiles: prBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
|
|
93
|
+
if (hasEmptyBumpFile) {
|
|
94
|
+
log.success("Empty bump file found — no releases needed.");
|
|
95
|
+
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatNoBumpFilesComment(detectPrBranch(rootDir), pm), rootDir, opts.patComments);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
92
98
|
if (prBumpFiles.length === 0) {
|
|
93
|
-
|
|
99
|
+
const willFail = !opts.noFail;
|
|
100
|
+
const msg = "No bump files found in this PR.";
|
|
101
|
+
if (willFail) log.error(msg);
|
|
102
|
+
else log.warn(msg);
|
|
94
103
|
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatNoBumpFilesComment(detectPrBranch(rootDir), pm), rootDir, opts.patComments);
|
|
95
|
-
if (
|
|
104
|
+
if (willFail) process.exit(1);
|
|
96
105
|
return;
|
|
97
106
|
}
|
|
98
107
|
const plan = assembleReleasePlan(prBumpFiles, packages, depGraph, config);
|
|
@@ -103,6 +112,13 @@ async function ciCheckCommand(rootDir, opts) {
|
|
|
103
112
|
}
|
|
104
113
|
if (plan.warnings.length > 0) for (const w of plan.warnings) log.warn(w);
|
|
105
114
|
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings), rootDir, opts.patComments);
|
|
115
|
+
const coveredPackages = new Set(plan.releases.map((r) => r.name));
|
|
116
|
+
const missing = (await findChangedPackages(changedFiles, packages, rootDir, config)).filter((name) => !coveredPackages.has(name));
|
|
117
|
+
if (missing.length > 0) {
|
|
118
|
+
const willFail = opts.strict && !opts.noFail;
|
|
119
|
+
(willFail ? log.error : log.warn)(`${missing.length} changed package(s) not covered by bump files: ${missing.join(", ")}`);
|
|
120
|
+
if (willFail) process.exit(1);
|
|
121
|
+
}
|
|
106
122
|
}
|
|
107
123
|
/**
|
|
108
124
|
* CI release: either auto-publish or create a version PR.
|
|
@@ -116,7 +132,7 @@ async function ciReleaseCommand(rootDir, opts) {
|
|
|
116
132
|
const bumpFiles = await readBumpFiles(rootDir);
|
|
117
133
|
if (bumpFiles.length === 0) {
|
|
118
134
|
log.info("No pending bump files — checking for unpublished packages...");
|
|
119
|
-
const { publishCommand } = await import("./publish-
|
|
135
|
+
const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
|
|
120
136
|
await publishCommand(rootDir, { tag: opts.tag });
|
|
121
137
|
return;
|
|
122
138
|
}
|
|
@@ -125,12 +141,12 @@ async function ciReleaseCommand(rootDir, opts) {
|
|
|
125
141
|
log.info("Bump files found but no packages would be released.");
|
|
126
142
|
return;
|
|
127
143
|
}
|
|
128
|
-
if (opts.mode === "auto-publish") await autoPublish(rootDir, config, opts.tag);
|
|
144
|
+
if (opts.mode === "auto-publish") await autoPublish(rootDir, config, plan, opts.tag);
|
|
129
145
|
else await createVersionPr(rootDir, plan, config, new Map([...packages.values()].map((p) => [p.name, p.relativeDir])), opts.branch, opts.patPr);
|
|
130
146
|
}
|
|
131
|
-
async function autoPublish(rootDir, config, tag) {
|
|
147
|
+
async function autoPublish(rootDir, config, plan, tag) {
|
|
132
148
|
log.step("Running bumpy version...");
|
|
133
|
-
const { versionCommand } = await import("./version-
|
|
149
|
+
const { versionCommand } = await import("./version-CnXcbqi1.mjs");
|
|
134
150
|
await versionCommand(rootDir);
|
|
135
151
|
log.step("Committing version changes...");
|
|
136
152
|
runArgs([
|
|
@@ -146,9 +162,12 @@ async function autoPublish(rootDir, config, tag) {
|
|
|
146
162
|
runArgs([
|
|
147
163
|
"git",
|
|
148
164
|
"commit",
|
|
149
|
-
"-
|
|
150
|
-
"
|
|
151
|
-
], {
|
|
165
|
+
"-F",
|
|
166
|
+
"-"
|
|
167
|
+
], {
|
|
168
|
+
cwd: rootDir,
|
|
169
|
+
input: await resolveCommitMessage(config.versionCommitMessage, plan, rootDir)
|
|
170
|
+
});
|
|
152
171
|
runArgs([
|
|
153
172
|
"git",
|
|
154
173
|
"push",
|
|
@@ -156,7 +175,7 @@ async function autoPublish(rootDir, config, tag) {
|
|
|
156
175
|
], { cwd: rootDir });
|
|
157
176
|
}
|
|
158
177
|
log.step("Running bumpy publish...");
|
|
159
|
-
const { publishCommand } = await import("./publish-
|
|
178
|
+
const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
|
|
160
179
|
await publishCommand(rootDir, { tag });
|
|
161
180
|
}
|
|
162
181
|
/**
|
|
@@ -322,7 +341,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
322
341
|
branch
|
|
323
342
|
], { cwd: rootDir });
|
|
324
343
|
log.step("Running bumpy version...");
|
|
325
|
-
const { versionCommand } = await import("./version-
|
|
344
|
+
const { versionCommand } = await import("./version-CnXcbqi1.mjs");
|
|
326
345
|
await versionCommand(rootDir);
|
|
327
346
|
runArgs([
|
|
328
347
|
"git",
|
|
@@ -349,11 +368,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
349
368
|
"-"
|
|
350
369
|
], {
|
|
351
370
|
cwd: rootDir,
|
|
352
|
-
input:
|
|
353
|
-
"Version packages",
|
|
354
|
-
"",
|
|
355
|
-
...plan.releases.map((r) => `${r.name}@${r.newVersion}`)
|
|
356
|
-
].join("\n")
|
|
371
|
+
input: await resolveCommitMessage(config.versionCommitMessage, plan, rootDir)
|
|
357
372
|
});
|
|
358
373
|
pushWithToken(rootDir, branch, config);
|
|
359
374
|
const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs);
|
|
@@ -373,7 +388,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
373
388
|
cwd: rootDir,
|
|
374
389
|
input: prBody
|
|
375
390
|
}));
|
|
376
|
-
log.success(
|
|
391
|
+
log.success(`🐸 Updated PR #${validPr}`);
|
|
377
392
|
} else {
|
|
378
393
|
log.step("Creating version PR...");
|
|
379
394
|
const prTitle = config.versionPr.title;
|
|
@@ -393,7 +408,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
393
408
|
cwd: rootDir,
|
|
394
409
|
input: prBody
|
|
395
410
|
}));
|
|
396
|
-
log.success(
|
|
411
|
+
log.success(`🐸 Created PR: ${result}`);
|
|
397
412
|
if (!patPr) pushWithToken(rootDir, branch, config);
|
|
398
413
|
}
|
|
399
414
|
runArgs([
|
|
@@ -428,7 +443,7 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
|
|
|
428
443
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
429
444
|
const lines = [];
|
|
430
445
|
const preamble = [
|
|
431
|
-
`<a href="https://
|
|
446
|
+
`<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-talking.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
|
|
432
447
|
"",
|
|
433
448
|
"**The changes in this PR will be included in the next version bump.**",
|
|
434
449
|
"<br clear=\"left\" />"
|
|
@@ -478,13 +493,13 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
|
|
|
478
493
|
if (addLink) lines.push(`[Click here if you want to add another bump file to this PR](${addLink})\n`);
|
|
479
494
|
else lines.push(`To add another bump file, run \`${pmRunCommand(pm)} add\`\n`);
|
|
480
495
|
lines.push("---");
|
|
481
|
-
lines.push(`_This comment is maintained by [bumpy](https://
|
|
496
|
+
lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
|
|
482
497
|
return lines.join("\n");
|
|
483
498
|
}
|
|
484
499
|
function formatNoBumpFilesComment(prBranch, pm) {
|
|
485
500
|
const runCmd = pmRunCommand(pm);
|
|
486
501
|
const lines = [
|
|
487
|
-
`<a href="https://
|
|
502
|
+
`<a href="https://bumpy.varlock.dev"><img src="${FROG_IMG_BASE}/frog-neutral.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
|
|
488
503
|
"",
|
|
489
504
|
"Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a bump file.**",
|
|
490
505
|
"<br clear=\"left\" />\n",
|
|
@@ -499,7 +514,7 @@ function formatNoBumpFilesComment(prBranch, pm) {
|
|
|
499
514
|
lines.push(`Or [click here to add a bump file](${addLink}) directly on GitHub.`);
|
|
500
515
|
}
|
|
501
516
|
lines.push("\n---");
|
|
502
|
-
lines.push(`_This comment is maintained by [bumpy](https://
|
|
517
|
+
lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
|
|
503
518
|
return lines.join("\n");
|
|
504
519
|
}
|
|
505
520
|
function bumpSectionHeader(type) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
|
|
2
|
-
import { t as detectPackageManager } from "./package-manager-
|
|
3
|
-
import {
|
|
4
|
-
import { a as fe, c as ot, i as _t, n as O, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-
|
|
2
|
+
import { t as detectPackageManager } from "./package-manager-ByJ0wKYh.mjs";
|
|
3
|
+
import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
4
|
+
import { a as fe, c as ot, i as _t, n as O, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-C6bVkGxf.mjs";
|
|
5
5
|
//#region src/commands/ci-setup.ts
|
|
6
6
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
7
7
|
const PAT_PERMISSIONS = [
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
3
|
-
import { n as findRoot } from "./config-
|
|
3
|
+
import { n as findRoot } from "./config-D7Umr-fT.mjs";
|
|
4
4
|
//#region src/cli.ts
|
|
5
5
|
const args = process.argv.slice(2);
|
|
6
6
|
const command = args[0];
|
|
@@ -25,13 +25,13 @@ async function main() {
|
|
|
25
25
|
switch (command) {
|
|
26
26
|
case "init": {
|
|
27
27
|
const rootDir = await findRoot();
|
|
28
|
-
const { initCommand } = await import("./init-
|
|
29
|
-
await initCommand(rootDir);
|
|
28
|
+
const { initCommand } = await import("./init-DJhMaceS.mjs");
|
|
29
|
+
await initCommand(rootDir, { force: flags.force === true });
|
|
30
30
|
break;
|
|
31
31
|
}
|
|
32
32
|
case "add": {
|
|
33
33
|
const rootDir = await findRoot();
|
|
34
|
-
const { addCommand } = await import("./add-
|
|
34
|
+
const { addCommand } = await import("./add-yP81c9_q.mjs");
|
|
35
35
|
await addCommand(rootDir, {
|
|
36
36
|
packages: flags.packages,
|
|
37
37
|
message: flags.message,
|
|
@@ -42,7 +42,7 @@ async function main() {
|
|
|
42
42
|
}
|
|
43
43
|
case "status": {
|
|
44
44
|
const rootDir = await findRoot();
|
|
45
|
-
const { statusCommand } = await import("./status-
|
|
45
|
+
const { statusCommand } = await import("./status-skGX8uU7.mjs");
|
|
46
46
|
await statusCommand(rootDir, {
|
|
47
47
|
json: flags.json === true,
|
|
48
48
|
packagesOnly: flags.packages === true,
|
|
@@ -54,13 +54,13 @@ async function main() {
|
|
|
54
54
|
}
|
|
55
55
|
case "version": {
|
|
56
56
|
const rootDir = await findRoot();
|
|
57
|
-
const { versionCommand } = await import("./version-
|
|
58
|
-
await versionCommand(rootDir);
|
|
57
|
+
const { versionCommand } = await import("./version-CnXcbqi1.mjs");
|
|
58
|
+
await versionCommand(rootDir, { commit: flags.commit === true });
|
|
59
59
|
break;
|
|
60
60
|
}
|
|
61
61
|
case "generate": {
|
|
62
62
|
const rootDir = await findRoot();
|
|
63
|
-
const { generateCommand } = await import("./generate-
|
|
63
|
+
const { generateCommand } = await import("./generate-BOLrTYWR.mjs");
|
|
64
64
|
await generateCommand(rootDir, {
|
|
65
65
|
from: flags.from,
|
|
66
66
|
dryRun: flags["dry-run"] === true,
|
|
@@ -68,16 +68,13 @@ async function main() {
|
|
|
68
68
|
});
|
|
69
69
|
break;
|
|
70
70
|
}
|
|
71
|
-
case "migrate": {
|
|
72
|
-
const rootDir = await findRoot();
|
|
73
|
-
const { migrateCommand } = await import("./migrate-DmOYgmfD.mjs");
|
|
74
|
-
await migrateCommand(rootDir, { force: flags.force === true });
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
71
|
case "check": {
|
|
78
72
|
const rootDir = await findRoot();
|
|
79
|
-
const { checkCommand } = await import("./check-
|
|
80
|
-
await checkCommand(rootDir
|
|
73
|
+
const { checkCommand } = await import("./check-D_0exKi6.mjs");
|
|
74
|
+
await checkCommand(rootDir, {
|
|
75
|
+
strict: flags.strict === true,
|
|
76
|
+
noFail: flags["no-fail"] === true
|
|
77
|
+
});
|
|
81
78
|
break;
|
|
82
79
|
}
|
|
83
80
|
case "ci": {
|
|
@@ -85,14 +82,15 @@ async function main() {
|
|
|
85
82
|
const subcommand = args[1];
|
|
86
83
|
const ciFlags = parseFlags(args.slice(2));
|
|
87
84
|
if (subcommand === "check") {
|
|
88
|
-
const { ciCheckCommand } = await import("./ci-
|
|
85
|
+
const { ciCheckCommand } = await import("./ci-CvaikKX1.mjs");
|
|
89
86
|
await ciCheckCommand(rootDir, {
|
|
90
87
|
comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
|
|
91
|
-
|
|
88
|
+
strict: ciFlags.strict === true,
|
|
89
|
+
noFail: ciFlags["no-fail"] === true,
|
|
92
90
|
patComments: ciFlags["pat-comments"] === true
|
|
93
91
|
});
|
|
94
92
|
} else if (subcommand === "release") {
|
|
95
|
-
const { ciReleaseCommand } = await import("./ci-
|
|
93
|
+
const { ciReleaseCommand } = await import("./ci-CvaikKX1.mjs");
|
|
96
94
|
await ciReleaseCommand(rootDir, {
|
|
97
95
|
mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
|
|
98
96
|
tag: ciFlags.tag,
|
|
@@ -100,7 +98,7 @@ async function main() {
|
|
|
100
98
|
patPr: ciFlags["pat-pr"] === true
|
|
101
99
|
});
|
|
102
100
|
} else if (subcommand === "setup") {
|
|
103
|
-
const { ciSetupCommand } = await import("./ci-setup-
|
|
101
|
+
const { ciSetupCommand } = await import("./ci-setup-CARJFhcE.mjs");
|
|
104
102
|
await ciSetupCommand(rootDir);
|
|
105
103
|
} else {
|
|
106
104
|
log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci release", or "ci setup".`);
|
|
@@ -110,7 +108,7 @@ async function main() {
|
|
|
110
108
|
}
|
|
111
109
|
case "publish": {
|
|
112
110
|
const rootDir = await findRoot();
|
|
113
|
-
const { publishCommand } = await import("./publish-
|
|
111
|
+
const { publishCommand } = await import("./publish-CPZwqyWh.mjs");
|
|
114
112
|
await publishCommand(rootDir, {
|
|
115
113
|
dryRun: flags["dry-run"] === true,
|
|
116
114
|
tag: flags.tag,
|
|
@@ -124,7 +122,7 @@ async function main() {
|
|
|
124
122
|
const subcommand = args[1];
|
|
125
123
|
const aiFlags = parseFlags(args.slice(2));
|
|
126
124
|
if (subcommand === "setup") {
|
|
127
|
-
const { aiSetupCommand } = await import("./ai-
|
|
125
|
+
const { aiSetupCommand } = await import("./ai-STKnq09z.mjs");
|
|
128
126
|
await aiSetupCommand(rootDir, { target: aiFlags.target });
|
|
129
127
|
} else {
|
|
130
128
|
log.error(`Unknown ai subcommand: ${subcommand}. Use "ai setup".`);
|
|
@@ -134,7 +132,7 @@ async function main() {
|
|
|
134
132
|
}
|
|
135
133
|
case "--version":
|
|
136
134
|
case "-v":
|
|
137
|
-
console.log(`bumpy 1.
|
|
135
|
+
console.log(`bumpy 1.2.0`);
|
|
138
136
|
break;
|
|
139
137
|
case "help":
|
|
140
138
|
case "--help":
|
|
@@ -154,22 +152,23 @@ async function main() {
|
|
|
154
152
|
}
|
|
155
153
|
function printHelp() {
|
|
156
154
|
console.log(`
|
|
157
|
-
${colorize(`🐸 bumpy v1.
|
|
155
|
+
${colorize(`🐸 bumpy v1.2.0`, "bold")} - Modern monorepo versioning
|
|
158
156
|
|
|
159
157
|
Usage: bumpy <command> [options]
|
|
160
158
|
|
|
161
159
|
Commands:
|
|
162
|
-
init
|
|
160
|
+
init [--force] Initialize .bumpy/ (migrates from .changeset/ if found)
|
|
163
161
|
add Create a new bump file
|
|
164
|
-
generate Generate bump file from
|
|
162
|
+
generate Generate bump file from branch commits
|
|
165
163
|
status Show pending releases
|
|
166
164
|
check Verify changed packages have bump files (for pre-push hooks)
|
|
167
|
-
|
|
165
|
+
--strict Fail if any changed package is uncovered (default: only fail if no bump files at all)
|
|
166
|
+
--no-fail Warn only, never exit 1
|
|
167
|
+
version [--commit] Apply bump files and bump versions
|
|
168
168
|
publish Publish versioned packages
|
|
169
169
|
ci check PR check — report pending releases, comment on PR
|
|
170
170
|
ci release Release — create version PR or auto-publish
|
|
171
171
|
ci setup Set up a token for triggering CI on version PRs
|
|
172
|
-
migrate Migrate from .changeset/ to .bumpy/
|
|
173
172
|
ai setup Install AI skill for creating bump files
|
|
174
173
|
|
|
175
174
|
Add options:
|
|
@@ -179,7 +178,7 @@ function printHelp() {
|
|
|
179
178
|
--empty Create an empty bump file
|
|
180
179
|
|
|
181
180
|
Generate options:
|
|
182
|
-
--from <ref> Git ref to scan from (default:
|
|
181
|
+
--from <ref> Git ref to scan from (default: branch point from baseBranch)
|
|
183
182
|
--dry-run Preview without creating a bump file
|
|
184
183
|
--name <name> Bump file filename
|
|
185
184
|
|
|
@@ -198,7 +197,8 @@ function printHelp() {
|
|
|
198
197
|
|
|
199
198
|
CI check options:
|
|
200
199
|
--comment Force PR comment on/off (auto-detected in CI)
|
|
201
|
-
--fail
|
|
200
|
+
--strict Fail if any changed package is uncovered (default: only fail if no bump files at all)
|
|
201
|
+
--no-fail Warn only, never exit 1
|
|
202
202
|
|
|
203
203
|
CI release options:
|
|
204
204
|
--auto-publish Version + publish directly (default: create version PR)
|
|
@@ -208,7 +208,7 @@ function printHelp() {
|
|
|
208
208
|
AI setup options:
|
|
209
209
|
--target <tool> Target AI tool: opencode, cursor, codex
|
|
210
210
|
|
|
211
|
-
${colorize("https://
|
|
211
|
+
${colorize("https://bumpy.varlock.dev", "dim")}
|
|
212
212
|
`);
|
|
213
213
|
}
|
|
214
214
|
main();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
//#region src/core/commit-message.ts
|
|
3
|
+
/** Build the default version commit message */
|
|
4
|
+
function defaultCommitMessage(plan) {
|
|
5
|
+
return [
|
|
6
|
+
"Version packages",
|
|
7
|
+
"",
|
|
8
|
+
...plan.releases.map((r) => `${r.name}@${r.newVersion}`)
|
|
9
|
+
].join("\n");
|
|
10
|
+
}
|
|
11
|
+
/** Resolve the commit message from config, falling back to the default */
|
|
12
|
+
async function resolveCommitMessage(config, plan, rootDir) {
|
|
13
|
+
if (!config) return defaultCommitMessage(plan);
|
|
14
|
+
if (config.startsWith("./") || config.startsWith("../")) {
|
|
15
|
+
const mod = await import(resolve(rootDir, config));
|
|
16
|
+
const fn = mod.default ?? mod;
|
|
17
|
+
if (typeof fn !== "function") throw new Error(`versionCommitMessage module "${config}" must export a function`);
|
|
18
|
+
return fn(plan);
|
|
19
|
+
}
|
|
20
|
+
return config;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { resolveCommitMessage as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __exportAll } from "./logger-C2dEe5Su.mjs";
|
|
2
|
-
import { a as readJson, n as exists } from "./fs-
|
|
2
|
+
import { a as readJson, n as exists, o as readJsonc } from "./fs-DnDogVn-.mjs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
//#region src/types.ts
|
|
5
5
|
const BUMP_LEVELS = {
|
|
@@ -44,7 +44,8 @@ const DEFAULT_PUBLISH_CONFIG = {
|
|
|
44
44
|
const DEFAULT_CONFIG = {
|
|
45
45
|
baseBranch: "main",
|
|
46
46
|
access: "public",
|
|
47
|
-
|
|
47
|
+
versionCommitMessage: void 0,
|
|
48
|
+
changedFilePatterns: ["**"],
|
|
48
49
|
changelog: "default",
|
|
49
50
|
fixed: [],
|
|
50
51
|
linked: [],
|
|
@@ -68,9 +69,9 @@ const DEFAULT_CONFIG = {
|
|
|
68
69
|
title: "🐸 Versioned release",
|
|
69
70
|
branch: "bumpy/version-packages",
|
|
70
71
|
preamble: [
|
|
71
|
-
`<a href="https://
|
|
72
|
+
`<a href="https://bumpy.varlock.dev"><img src="https://raw.githubusercontent.com/dmno-dev/bumpy/main/images/frog-talking.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
|
|
72
73
|
"",
|
|
73
|
-
`This PR was created and will be kept in sync by [bumpy](https://
|
|
74
|
+
`This PR was created and will be kept in sync by [bumpy](https://bumpy.varlock.dev) based on your bump files (in \`.bumpy/\`). Merge it when you are ready to release the packages listed below:`,
|
|
74
75
|
"<br clear=\"left\" />"
|
|
75
76
|
].join("\n")
|
|
76
77
|
}
|
|
@@ -108,7 +109,7 @@ async function findRoot(startDir = process.cwd()) {
|
|
|
108
109
|
async function loadConfig(rootDir) {
|
|
109
110
|
const configPath = resolve(rootDir, BUMPY_DIR, CONFIG_FILE);
|
|
110
111
|
let userConfig = {};
|
|
111
|
-
if (await exists(configPath)) userConfig = await
|
|
112
|
+
if (await exists(configPath)) userConfig = await readJsonc(configPath);
|
|
112
113
|
return mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
113
114
|
}
|
|
114
115
|
/** Load per-package bumpy config from package.json["bumpy"] or .bumpy.config.json */
|