@varlock/bumpy 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{add-yP81c9_q.mjs → add-DF6bawDT.mjs} +2 -2
- package/dist/{apply-release-plan-CPzu6JcF.mjs → apply-release-plan-B1Wwx3HG.mjs} +3 -3
- package/dist/{bump-file-Br2bTaWp.mjs → bump-file-C3S_bzSf.mjs} +61 -19
- package/dist/{changelog-github-DkACMj0j.mjs → changelog-github-DZSHX3Tb.mjs} +20 -5
- package/dist/{check-D_0exKi6.mjs → check-BJL-YDWz.mjs} +8 -3
- package/dist/{ci-CvaikKX1.mjs → ci-C88ecvIP.mjs} +100 -30
- package/dist/cli.mjs +10 -10
- package/dist/{generate-BOLrTYWR.mjs → generate-D93b3NAD.mjs} +2 -2
- package/dist/{git-YDedMddc.mjs → git-H9S9z6g-.mjs} +10 -1
- package/dist/index.d.mts +13 -3
- package/dist/index.mjs +3 -3
- package/dist/{publish-CPZwqyWh.mjs → publish-DGSV607z.mjs} +2 -2
- package/dist/{publish-pipeline-BFt96o_h.mjs → publish-pipeline-DiwZZ5AF.mjs} +1 -1
- package/dist/{status-skGX8uU7.mjs → status-S2ztf_8E.mjs} +34 -13
- package/dist/{version-CnXcbqi1.mjs → version-BXrP4TIO.mjs} +7 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ Then set up CI to automate versioning and publishing (see below).
|
|
|
77
77
|
|
|
78
78
|
## CI / GitHub Actions
|
|
79
79
|
|
|
80
|
-
No separate action to rely on — just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
|
|
80
|
+
No GitHub App to install, no separate action to rely on — just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
|
|
81
81
|
|
|
82
82
|
- **`bumpy ci check`** — runs on every PR. Computes the release plan from pending bump files and posts/updates a comment on the PR showing what versions would be released. Warns if any changed packages are missing bump files.
|
|
83
83
|
- **`bumpy ci release`** — runs on push to main. If pending bump files exist, it opens (or updates) a "Version Packages" PR that applies all version bumps and changelog updates. If the current push _is_ the Version Packages PR being merged, it publishes the new versions, creates git tags, and creates GitHub releases.
|
|
@@ -232,7 +232,7 @@ Bumpy is built as a successor to [@changesets/changesets](https://github.com/cha
|
|
|
232
232
|
- **Workspace protocol resolution** — changesets uses `npm publish` even in pnpm/yarn workspaces, so `workspace:^` and `catalog:` protocols are NOT resolved, resulting in broken published packages.
|
|
233
233
|
- **Custom publish commands** — changesets is hardcoded to `npm publish`. Bumpy supports per-package custom publish for VSCode extensions, Docker images, JSR, etc.
|
|
234
234
|
- **Flexible package management** — changesets treats all private packages the same. Bumpy lets you include/exclude any package individually.
|
|
235
|
-
- **CI without a separate action** —
|
|
235
|
+
- **CI without a separate action or bot** — changesets requires installing a [GitHub App](https://github.com/apps/changeset-bot) _and_ using a [separate GitHub Action](https://github.com/changesets/action). Bumpy replaces both with two CLI commands (`bumpy ci check` + `bumpy ci release`) that run directly in your workflows — no extra repos to trust, no app installation requiring org admin approval.
|
|
236
236
|
- **Automatic migration** — `bumpy init` detects `.changeset/`, renames it to `.bumpy/`, migrates config, keeps pending files, and offers to uninstall `@changesets/cli`.
|
|
237
237
|
|
|
238
238
|
## Development
|
|
@@ -3,8 +3,8 @@ import { n as exists, t as ensureDir } from "./fs-DnDogVn-.mjs";
|
|
|
3
3
|
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-D7Umr-fT.mjs";
|
|
4
4
|
import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
|
|
5
5
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
|
-
import { i as writeBumpFile } from "./bump-file-
|
|
7
|
-
import { r as getChangedFiles } from "./git-
|
|
6
|
+
import { i as writeBumpFile } from "./bump-file-C3S_bzSf.mjs";
|
|
7
|
+
import { r as getChangedFiles } from "./git-H9S9z6g-.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-C6bVkGxf.mjs";
|
|
9
9
|
import { n as slugify, t as randomName } from "./names-C-TuOPbd.mjs";
|
|
10
10
|
import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
|
|
@@ -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-DZSHX3Tb.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-DZSHX3Tb.mjs");
|
|
43
43
|
return createGithubFormatter(options);
|
|
44
44
|
}
|
|
45
45
|
if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
|
|
@@ -139,7 +139,7 @@ function updateRange(range, newVersion) {
|
|
|
139
139
|
cleanRange = range.slice(protocol.length);
|
|
140
140
|
}
|
|
141
141
|
const prefix = cleanRange.match(/^(\^|~|>=|>|<=|<|=)?/)?.[1] ?? "^";
|
|
142
|
-
if (cleanRange === "*" || cleanRange === "") return range;
|
|
142
|
+
if (cleanRange === "*" || cleanRange === "" || cleanRange === "^" || cleanRange === "~") return range;
|
|
143
143
|
return `${protocol}${prefix}${newVersion}`;
|
|
144
144
|
}
|
|
145
145
|
//#endregion
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { n as log } from "./logger-C2dEe5Su.mjs";
|
|
2
1
|
import { f as writeText, i as listFiles, s as readText } from "./fs-DnDogVn-.mjs";
|
|
3
2
|
import { r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
4
3
|
import { i as jsYaml } from "./package-manager-ByJ0wKYh.mjs";
|
|
@@ -30,16 +29,21 @@ async function readBumpFiles(rootDir) {
|
|
|
30
29
|
const dir = getBumpyDir(rootDir);
|
|
31
30
|
const files = await listFiles(dir, ".md");
|
|
32
31
|
const bumpFiles = [];
|
|
32
|
+
const errors = [];
|
|
33
33
|
for (const file of files) {
|
|
34
34
|
if (file === "README.md") continue;
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
35
|
+
const result = await parseBumpFileFromPath(resolve(dir, file));
|
|
36
|
+
if (result.bumpFile) bumpFiles.push(result.bumpFile);
|
|
37
|
+
errors.push(...result.errors);
|
|
37
38
|
}
|
|
38
39
|
const creationOrder = getBumpFileCreationOrder(rootDir);
|
|
39
40
|
if (creationOrder.size > 0) bumpFiles.sort((a, b) => {
|
|
40
41
|
return (creationOrder.get(a.id) ?? Infinity) - (creationOrder.get(b.id) ?? Infinity) || a.id.localeCompare(b.id);
|
|
41
42
|
});
|
|
42
|
-
return
|
|
43
|
+
return {
|
|
44
|
+
bumpFiles,
|
|
45
|
+
errors
|
|
46
|
+
};
|
|
43
47
|
}
|
|
44
48
|
/**
|
|
45
49
|
* Use `git log` to get the commit timestamp when each bump file was first added.
|
|
@@ -75,21 +79,47 @@ async function parseBumpFileFromPath(filePath) {
|
|
|
75
79
|
}
|
|
76
80
|
/** Parse bump file content (for testing) */
|
|
77
81
|
function parseBumpFile(content, id) {
|
|
78
|
-
const
|
|
79
|
-
|
|
82
|
+
const errors = [];
|
|
83
|
+
const match = content.match(/^---\n([\s\S]*?)\n?---\n?([\s\S]*)$/);
|
|
84
|
+
if (!match) {
|
|
85
|
+
errors.push(`Bump file "${id}" has no valid frontmatter (expected --- delimiters)`);
|
|
86
|
+
return {
|
|
87
|
+
bumpFile: null,
|
|
88
|
+
errors
|
|
89
|
+
};
|
|
90
|
+
}
|
|
80
91
|
const frontmatter = match[1];
|
|
81
92
|
const summary = match[2].trim();
|
|
82
|
-
|
|
83
|
-
|
|
93
|
+
if (!frontmatter.trim()) return {
|
|
94
|
+
bumpFile: null,
|
|
95
|
+
errors
|
|
96
|
+
};
|
|
97
|
+
let parsed;
|
|
98
|
+
try {
|
|
99
|
+
parsed = jsYaml.load(frontmatter);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
errors.push(`Bump file "${id}" has invalid YAML: ${e instanceof Error ? e.message : e}`);
|
|
102
|
+
return {
|
|
103
|
+
bumpFile: null,
|
|
104
|
+
errors
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (!parsed || typeof parsed !== "object") {
|
|
108
|
+
errors.push(`Bump file "${id}" has empty or invalid frontmatter`);
|
|
109
|
+
return {
|
|
110
|
+
bumpFile: null,
|
|
111
|
+
errors
|
|
112
|
+
};
|
|
113
|
+
}
|
|
84
114
|
const releases = [];
|
|
85
115
|
for (const [name, value] of Object.entries(parsed)) {
|
|
86
116
|
if (!validatePackageName(name)) {
|
|
87
|
-
|
|
117
|
+
errors.push(`Invalid package name "${name}" in bump file "${id}"`);
|
|
88
118
|
continue;
|
|
89
119
|
}
|
|
90
120
|
if (typeof value === "string") {
|
|
91
121
|
if (!VALID_BUMP_TYPES.has(value)) {
|
|
92
|
-
|
|
122
|
+
errors.push(`Unknown bump type "${value}" for "${name}" in bump file "${id}" (expected: major, minor, patch, or none)`);
|
|
93
123
|
continue;
|
|
94
124
|
}
|
|
95
125
|
releases.push({
|
|
@@ -99,7 +129,7 @@ function parseBumpFile(content, id) {
|
|
|
99
129
|
} else if (value && typeof value === "object") {
|
|
100
130
|
const obj = value;
|
|
101
131
|
if (!VALID_BUMP_TYPES.has(obj.bump)) {
|
|
102
|
-
|
|
132
|
+
errors.push(`Unknown bump type "${obj.bump}" for "${name}" in bump file "${id}" (expected: major, minor, patch, or none)`);
|
|
103
133
|
continue;
|
|
104
134
|
}
|
|
105
135
|
const release = {
|
|
@@ -108,13 +138,19 @@ function parseBumpFile(content, id) {
|
|
|
108
138
|
cascade: obj.cascade || {}
|
|
109
139
|
};
|
|
110
140
|
releases.push(release);
|
|
111
|
-
}
|
|
141
|
+
} else errors.push(`Invalid value for "${name}" in bump file "${id}" — expected a bump type string or object`);
|
|
112
142
|
}
|
|
113
|
-
if (releases.length === 0) return
|
|
143
|
+
if (releases.length === 0 && errors.length === 0) return {
|
|
144
|
+
bumpFile: null,
|
|
145
|
+
errors
|
|
146
|
+
};
|
|
114
147
|
return {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
148
|
+
bumpFile: releases.length > 0 ? {
|
|
149
|
+
id,
|
|
150
|
+
releases,
|
|
151
|
+
summary
|
|
152
|
+
} : null,
|
|
153
|
+
errors
|
|
118
154
|
};
|
|
119
155
|
}
|
|
120
156
|
/** Write a bump file */
|
|
@@ -146,8 +182,12 @@ function extractBumpFileIdsFromChangedFiles(changedFiles) {
|
|
|
146
182
|
* Filter bump files to only those added/modified on the current branch.
|
|
147
183
|
* Also detects empty bump files (no releases) that still exist on disk,
|
|
148
184
|
* which signal intentionally no releases needed.
|
|
185
|
+
*
|
|
186
|
+
* When `parseErrors` is provided, a file that exists on disk but didn't parse
|
|
187
|
+
* is only treated as an "empty bump file" if it produced no parse errors —
|
|
188
|
+
* otherwise it's a broken file, not an intentionally empty one.
|
|
149
189
|
*/
|
|
150
|
-
function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir) {
|
|
190
|
+
function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors = []) {
|
|
151
191
|
const branchBumpFileIds = extractBumpFileIdsFromChangedFiles(changedFiles);
|
|
152
192
|
const branchBumpFiles = allBumpFiles.filter((bf) => branchBumpFileIds.has(bf.id));
|
|
153
193
|
let hasEmptyBumpFile = false;
|
|
@@ -155,8 +195,10 @@ function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir) {
|
|
|
155
195
|
const parsedIds = new Set(branchBumpFiles.map((bf) => bf.id));
|
|
156
196
|
const bumpyDir = getBumpyDir(rootDir);
|
|
157
197
|
for (const id of branchBumpFileIds) if (!parsedIds.has(id) && existsSync(resolve(bumpyDir, `${id}.md`))) {
|
|
158
|
-
|
|
159
|
-
|
|
198
|
+
if (!parseErrors.some((e) => e.includes(`"${id}"`))) {
|
|
199
|
+
hasEmptyBumpFile = true;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
160
202
|
}
|
|
161
203
|
}
|
|
162
204
|
return {
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
2
2
|
//#region src/core/changelog-github.ts
|
|
3
|
+
/** Authors filtered from "Thanks" attribution by default (e.g. bots) */
|
|
4
|
+
/** Authors filtered from "Thanks" attribution by default (e.g. AI/automation bots) */
|
|
5
|
+
const DEFAULT_INTERNAL_AUTHORS = [
|
|
6
|
+
"copilot",
|
|
7
|
+
"app/copilot-swe-agent",
|
|
8
|
+
"claude",
|
|
9
|
+
"dependabot",
|
|
10
|
+
"dependabot[bot]",
|
|
11
|
+
"app/dependabot",
|
|
12
|
+
"renovate[bot]",
|
|
13
|
+
"app/renovate",
|
|
14
|
+
"github-actions[bot]",
|
|
15
|
+
"snyk-bot"
|
|
16
|
+
];
|
|
3
17
|
/**
|
|
4
18
|
* GitHub-enhanced changelog formatter.
|
|
5
|
-
* Adds PR links,
|
|
19
|
+
* Adds PR links, contributor attribution, and optionally commit links when git/gh info is available.
|
|
6
20
|
*
|
|
7
21
|
* Usage in config:
|
|
8
22
|
* "changelog": "github"
|
|
@@ -11,8 +25,9 @@ import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
|
11
25
|
* "changelog": ["github", { "internalAuthors": ["theoephraim"] }]
|
|
12
26
|
*/
|
|
13
27
|
function createGithubFormatter(options = {}) {
|
|
28
|
+
const includeCommitLink = options.includeCommitLink ?? false;
|
|
14
29
|
const thankContributors = options.thankContributors ?? true;
|
|
15
|
-
const internalAuthorsSet = new Set(
|
|
30
|
+
const internalAuthorsSet = new Set([...DEFAULT_INTERNAL_AUTHORS, ...options.internalAuthors ?? []].map((a) => a.toLowerCase()));
|
|
16
31
|
return async (ctx) => {
|
|
17
32
|
const { release, bumpFiles, date } = ctx;
|
|
18
33
|
const repoSlug = options.repo ?? detectRepo();
|
|
@@ -29,7 +44,7 @@ function createGithubFormatter(options = {}) {
|
|
|
29
44
|
const gitInfo = resolveBumpFileInfo(bf.id, repoSlug, serverUrl, overrides);
|
|
30
45
|
const summaryLines = cleanSummary.split("\n");
|
|
31
46
|
const firstLine = linkifyIssueRefs(summaryLines[0], serverUrl, repoSlug);
|
|
32
|
-
const prefix = formatPrefix(gitInfo, serverUrl, repoSlug, thankContributors, internalAuthorsSet);
|
|
47
|
+
const prefix = formatPrefix(gitInfo, serverUrl, repoSlug, includeCommitLink, thankContributors, internalAuthorsSet);
|
|
33
48
|
lines.push(`-${prefix ? ` ${prefix} -` : ""} ${firstLine}`);
|
|
34
49
|
for (let i = 1; i < summaryLines.length; i++) if (summaryLines[i].trim()) lines.push(` ${linkifyIssueRefs(summaryLines[i], serverUrl, repoSlug)}`);
|
|
35
50
|
}
|
|
@@ -157,10 +172,10 @@ function findBumpFileCommitInfo(bumpFileId, repo) {
|
|
|
157
172
|
* Build the prefix portion of a changelog line: PR link, commit link, thanks.
|
|
158
173
|
* Matches the format used by @changesets/changelog-github.
|
|
159
174
|
*/
|
|
160
|
-
function formatPrefix(info, serverUrl, repo, thankContributors, internalAuthors) {
|
|
175
|
+
function formatPrefix(info, serverUrl, repo, includeCommitLink, thankContributors, internalAuthors) {
|
|
161
176
|
const parts = [];
|
|
162
177
|
if (info.prNumber && info.prUrl) parts.push(`[#${info.prNumber}](${info.prUrl})`);
|
|
163
|
-
if (info.commitHash && repo) {
|
|
178
|
+
if (includeCommitLink && info.commitHash && repo) {
|
|
164
179
|
const short = info.commitHash.slice(0, 7);
|
|
165
180
|
parts.push(`[\`${short}\`](${serverUrl}/${repo}/commit/${info.commitHash})`);
|
|
166
181
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as log, o as __toESM, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
2
2
|
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
3
3
|
import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
|
|
4
|
-
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-
|
|
5
|
-
import { r as getChangedFiles } from "./git-
|
|
4
|
+
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-C3S_bzSf.mjs";
|
|
5
|
+
import { r as getChangedFiles } from "./git-H9S9z6g-.mjs";
|
|
6
6
|
import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
|
|
7
7
|
import { relative } from "node:path";
|
|
8
8
|
//#region src/commands/check.ts
|
|
@@ -25,7 +25,12 @@ async function checkCommand(rootDir, opts = {}) {
|
|
|
25
25
|
log.info("No changed files detected.");
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
const {
|
|
28
|
+
const { bumpFiles: allBumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
|
|
29
|
+
if (parseErrors.length > 0) {
|
|
30
|
+
for (const err of parseErrors) log.error(err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const { branchBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
|
|
29
34
|
if (hasEmptyBumpFile) {
|
|
30
35
|
log.success("Empty bump file found — no releases needed.");
|
|
31
36
|
return;
|
|
@@ -4,11 +4,11 @@ import { t as detectPackageManager } from "./package-manager-ByJ0wKYh.mjs";
|
|
|
4
4
|
import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
|
|
5
5
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
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-
|
|
7
|
+
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-C3S_bzSf.mjs";
|
|
8
8
|
import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
|
|
9
|
-
import { r as getChangedFiles } from "./git-
|
|
9
|
+
import { r as getChangedFiles } from "./git-H9S9z6g-.mjs";
|
|
10
10
|
import { t as randomName } from "./names-C-TuOPbd.mjs";
|
|
11
|
-
import { findChangedPackages } from "./check-
|
|
11
|
+
import { findChangedPackages } from "./check-BJL-YDWz.mjs";
|
|
12
12
|
import { t as resolveCommitMessage } from "./commit-message-BwsowSds.mjs";
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
14
14
|
//#region src/commands/ci.ts
|
|
@@ -79,7 +79,7 @@ async function ciCheckCommand(rootDir, opts) {
|
|
|
79
79
|
const config = await loadConfig(rootDir);
|
|
80
80
|
const { packages } = await discoverWorkspace(rootDir, config);
|
|
81
81
|
const depGraph = new DependencyGraph(packages);
|
|
82
|
-
const allBumpFiles = await readBumpFiles(rootDir);
|
|
82
|
+
const { bumpFiles: allBumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
|
|
83
83
|
if (detectPrBranch(rootDir) === config.versionPr.branch) {
|
|
84
84
|
log.dim(" Skipping — this is the version PR branch.");
|
|
85
85
|
return;
|
|
@@ -89,18 +89,22 @@ async function ciCheckCommand(rootDir, opts) {
|
|
|
89
89
|
const prNumber = detectPrNumber();
|
|
90
90
|
const pm = await detectPackageManager(rootDir);
|
|
91
91
|
const changedFiles = getChangedFiles(rootDir, config.baseBranch);
|
|
92
|
-
const { branchBumpFiles: prBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
|
|
93
|
-
if (
|
|
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
|
+
const { branchBumpFiles: prBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors);
|
|
93
|
+
if (parseErrors.length > 0) for (const err of parseErrors) log.error(err);
|
|
98
94
|
if (prBumpFiles.length === 0) {
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
if (hasEmptyBumpFile && parseErrors.length === 0) {
|
|
96
|
+
log.success("Empty bump file found — no releases needed.");
|
|
97
|
+
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatEmptyBumpFileComment(), rootDir, opts.patComments);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const willFail = !opts.noFail || parseErrors.length > 0;
|
|
101
|
+
const msg = parseErrors.length > 0 ? "Bump file(s) found but failed to parse — see errors above." : "No bump files found in this PR.";
|
|
101
102
|
if (willFail) log.error(msg);
|
|
102
103
|
else log.warn(msg);
|
|
103
|
-
if (shouldComment && prNumber)
|
|
104
|
+
if (shouldComment && prNumber) {
|
|
105
|
+
const prBranch = detectPrBranch(rootDir);
|
|
106
|
+
await postOrUpdatePrComment(prNumber, parseErrors.length > 0 ? formatBumpFileErrorsComment(parseErrors, prBranch, pm) : formatNoBumpFilesComment(prBranch, pm), rootDir, opts.patComments);
|
|
107
|
+
}
|
|
104
108
|
if (willFail) process.exit(1);
|
|
105
109
|
return;
|
|
106
110
|
}
|
|
@@ -111,7 +115,8 @@ async function ciCheckCommand(rootDir, opts) {
|
|
|
111
115
|
console.log(` ${r.name}: ${r.oldVersion} → ${colorize(r.newVersion, "cyan")}${tag}`);
|
|
112
116
|
}
|
|
113
117
|
if (plan.warnings.length > 0) for (const w of plan.warnings) log.warn(w);
|
|
114
|
-
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings), rootDir, opts.patComments);
|
|
118
|
+
if (shouldComment && prNumber) await postOrUpdatePrComment(prNumber, formatReleasePlanComment(plan, prBumpFiles, prNumber, detectPrBranch(rootDir), pm, plan.warnings, parseErrors), rootDir, opts.patComments);
|
|
119
|
+
if (parseErrors.length > 0 && !opts.noFail) process.exit(1);
|
|
115
120
|
const coveredPackages = new Set(plan.releases.map((r) => r.name));
|
|
116
121
|
const missing = (await findChangedPackages(changedFiles, packages, rootDir, config)).filter((name) => !coveredPackages.has(name));
|
|
117
122
|
if (missing.length > 0) {
|
|
@@ -129,10 +134,14 @@ async function ciReleaseCommand(rootDir, opts) {
|
|
|
129
134
|
ensureGitIdentity(rootDir, config);
|
|
130
135
|
const { packages } = await discoverWorkspace(rootDir, config);
|
|
131
136
|
const depGraph = new DependencyGraph(packages);
|
|
132
|
-
const bumpFiles = await readBumpFiles(rootDir);
|
|
137
|
+
const { bumpFiles, errors: releaseParseErrors } = await readBumpFiles(rootDir);
|
|
138
|
+
if (releaseParseErrors.length > 0) {
|
|
139
|
+
for (const err of releaseParseErrors) log.error(err);
|
|
140
|
+
throw new Error("Bump file parse errors must be fixed before releasing.");
|
|
141
|
+
}
|
|
133
142
|
if (bumpFiles.length === 0) {
|
|
134
143
|
log.info("No pending bump files — checking for unpublished packages...");
|
|
135
|
-
const { publishCommand } = await import("./publish-
|
|
144
|
+
const { publishCommand } = await import("./publish-DGSV607z.mjs");
|
|
136
145
|
await publishCommand(rootDir, { tag: opts.tag });
|
|
137
146
|
return;
|
|
138
147
|
}
|
|
@@ -146,7 +155,7 @@ async function ciReleaseCommand(rootDir, opts) {
|
|
|
146
155
|
}
|
|
147
156
|
async function autoPublish(rootDir, config, plan, tag) {
|
|
148
157
|
log.step("Running bumpy version...");
|
|
149
|
-
const { versionCommand } = await import("./version-
|
|
158
|
+
const { versionCommand } = await import("./version-BXrP4TIO.mjs");
|
|
150
159
|
await versionCommand(rootDir);
|
|
151
160
|
log.step("Committing version changes...");
|
|
152
161
|
runArgs([
|
|
@@ -175,7 +184,7 @@ async function autoPublish(rootDir, config, plan, tag) {
|
|
|
175
184
|
], { cwd: rootDir });
|
|
176
185
|
}
|
|
177
186
|
log.step("Running bumpy publish...");
|
|
178
|
-
const { publishCommand } = await import("./publish-
|
|
187
|
+
const { publishCommand } = await import("./publish-DGSV607z.mjs");
|
|
179
188
|
await publishCommand(rootDir, { tag });
|
|
180
189
|
}
|
|
181
190
|
/**
|
|
@@ -341,7 +350,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
341
350
|
branch
|
|
342
351
|
], { cwd: rootDir });
|
|
343
352
|
log.step("Running bumpy version...");
|
|
344
|
-
const { versionCommand } = await import("./version-
|
|
353
|
+
const { versionCommand } = await import("./version-BXrP4TIO.mjs");
|
|
345
354
|
await versionCommand(rootDir);
|
|
346
355
|
runArgs([
|
|
347
356
|
"git",
|
|
@@ -371,9 +380,10 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
371
380
|
input: await resolveCommitMessage(config.versionCommitMessage, plan, rootDir)
|
|
372
381
|
});
|
|
373
382
|
pushWithToken(rootDir, branch, config);
|
|
374
|
-
const
|
|
383
|
+
const repo = process.env.GITHUB_REPOSITORY;
|
|
375
384
|
if (existingPr) {
|
|
376
385
|
const validPr = validatePrNumber(existingPr);
|
|
386
|
+
const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, validPr);
|
|
377
387
|
log.step(`Updating existing PR #${validPr}...`);
|
|
378
388
|
await withPatToken(!!patPr, () => runArgsAsync([
|
|
379
389
|
"gh",
|
|
@@ -392,6 +402,7 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
392
402
|
} else {
|
|
393
403
|
log.step("Creating version PR...");
|
|
394
404
|
const prTitle = config.versionPr.title;
|
|
405
|
+
const prBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, null);
|
|
395
406
|
const result = await withPatToken(!!patPr, () => runArgsAsync([
|
|
396
407
|
"gh",
|
|
397
408
|
"pr",
|
|
@@ -409,6 +420,23 @@ async function createVersionPr(rootDir, plan, config, packageDirs, branchName, p
|
|
|
409
420
|
input: prBody
|
|
410
421
|
}));
|
|
411
422
|
log.success(`🐸 Created PR: ${result}`);
|
|
423
|
+
if (repo) {
|
|
424
|
+
const newPrNumber = result?.match(/\/pull\/(\d+)/)?.[1];
|
|
425
|
+
if (newPrNumber) {
|
|
426
|
+
const updatedBody = formatVersionPrBody(plan, config.versionPr.preamble, packageDirs, repo, newPrNumber);
|
|
427
|
+
await withPatToken(!!patPr, () => runArgsAsync([
|
|
428
|
+
"gh",
|
|
429
|
+
"pr",
|
|
430
|
+
"edit",
|
|
431
|
+
newPrNumber,
|
|
432
|
+
"--body-file",
|
|
433
|
+
"-"
|
|
434
|
+
], {
|
|
435
|
+
cwd: rootDir,
|
|
436
|
+
input: updatedBody
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
412
440
|
if (!patPr) pushWithToken(rootDir, branch, config);
|
|
413
441
|
}
|
|
414
442
|
runArgs([
|
|
@@ -439,7 +467,7 @@ function pmRunCommand(pm) {
|
|
|
439
467
|
if (pm === "yarn") return "yarn bumpy";
|
|
440
468
|
return "npx bumpy";
|
|
441
469
|
}
|
|
442
|
-
function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warnings = []) {
|
|
470
|
+
function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warnings = [], parseErrors = []) {
|
|
443
471
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
444
472
|
const lines = [];
|
|
445
473
|
const preamble = [
|
|
@@ -477,12 +505,18 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
|
|
|
477
505
|
const filename = `${bf.id}.md`;
|
|
478
506
|
const parts = [`\`${filename}\``];
|
|
479
507
|
if (repo) {
|
|
480
|
-
parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/
|
|
508
|
+
parts.push(`([view diff](https://github.com/${repo}/pull/${prNumber}/changes#diff-${sha256Hex(`.bumpy/${filename}`)}))`);
|
|
481
509
|
if (prBranch) parts.push(`([edit](https://github.com/${repo}/edit/${prBranch}/.bumpy/${filename}))`);
|
|
482
510
|
}
|
|
483
511
|
lines.push(`- ${parts.join(" ")}`);
|
|
484
512
|
}
|
|
485
513
|
lines.push("");
|
|
514
|
+
if (parseErrors.length > 0) {
|
|
515
|
+
lines.push("#### Errors");
|
|
516
|
+
lines.push("");
|
|
517
|
+
for (const e of parseErrors) lines.push(`> :x: ${e}`);
|
|
518
|
+
lines.push("");
|
|
519
|
+
}
|
|
486
520
|
if (warnings.length > 0) {
|
|
487
521
|
lines.push("#### Warnings");
|
|
488
522
|
lines.push("");
|
|
@@ -496,6 +530,41 @@ function formatReleasePlanComment(plan, bumpFiles, prNumber, prBranch, pm, warni
|
|
|
496
530
|
lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
|
|
497
531
|
return lines.join("\n");
|
|
498
532
|
}
|
|
533
|
+
function formatBumpFileErrorsComment(errors, prBranch, pm) {
|
|
534
|
+
const runCmd = pmRunCommand(pm);
|
|
535
|
+
const lines = [
|
|
536
|
+
`<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>`,
|
|
537
|
+
"",
|
|
538
|
+
"**This PR has bump file(s) with errors that need to be fixed.**",
|
|
539
|
+
"<br clear=\"left\" />\n",
|
|
540
|
+
"#### Errors",
|
|
541
|
+
"",
|
|
542
|
+
...errors.map((e) => `> :x: ${e}`),
|
|
543
|
+
"",
|
|
544
|
+
"Please fix the errors above or recreate the bump file:\n",
|
|
545
|
+
"```bash",
|
|
546
|
+
`${runCmd} add`,
|
|
547
|
+
"```"
|
|
548
|
+
];
|
|
549
|
+
const addLink = buildAddBumpFileLink(prBranch);
|
|
550
|
+
if (addLink) {
|
|
551
|
+
lines.push("");
|
|
552
|
+
lines.push(`Or [click here to add a bump file](${addLink}) directly on GitHub.`);
|
|
553
|
+
}
|
|
554
|
+
lines.push("\n---");
|
|
555
|
+
lines.push(`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`);
|
|
556
|
+
return lines.join("\n");
|
|
557
|
+
}
|
|
558
|
+
function formatEmptyBumpFileComment() {
|
|
559
|
+
return [
|
|
560
|
+
`<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>`,
|
|
561
|
+
"",
|
|
562
|
+
"**This PR includes an empty bump file — no version bump is needed.** :white_check_mark:",
|
|
563
|
+
"<br clear=\"left\" />",
|
|
564
|
+
"\n---",
|
|
565
|
+
`_This comment is maintained by [bumpy](https://bumpy.varlock.dev)._`
|
|
566
|
+
].join("\n");
|
|
567
|
+
}
|
|
499
568
|
function formatNoBumpFilesComment(prBranch, pm) {
|
|
500
569
|
const runCmd = pmRunCommand(pm);
|
|
501
570
|
const lines = [
|
|
@@ -518,18 +587,19 @@ function formatNoBumpFilesComment(prBranch, pm) {
|
|
|
518
587
|
return lines.join("\n");
|
|
519
588
|
}
|
|
520
589
|
function bumpSectionHeader(type) {
|
|
521
|
-
|
|
590
|
+
const label = `${type.charAt(0).toUpperCase() + type.slice(1)} releases`;
|
|
591
|
+
return `### ${`<a href="https://bumpy.varlock.dev" title="${label}"><img src="${FROG_IMG_BASE}/frog-${type}.png" alt="${type}" width="52" style="image-rendering: pixelated;" align="right" /></a>`} ${label}`;
|
|
522
592
|
}
|
|
523
593
|
/** Build inline diff links for a package's changed files in the PR */
|
|
524
|
-
function buildDiffLinks(pkgDir) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
return ` <sub>${[`[package.json](#diff-${sha256Hex(pkgJsonPath)})`, `[CHANGELOG.md](#diff-${sha256Hex(changelogPath)})`].join(" · ")}</sub>`;
|
|
594
|
+
function buildDiffLinks(pkgDir, changesBaseUrl) {
|
|
595
|
+
if (!changesBaseUrl) return "";
|
|
596
|
+
return ` <sub>[CHANGELOG.md](${changesBaseUrl}#diff-${sha256Hex(`${pkgDir}/CHANGELOG.md`)})</sub>`;
|
|
528
597
|
}
|
|
529
598
|
function sha256Hex(input) {
|
|
530
599
|
return createHash("sha256").update(input).digest("hex");
|
|
531
600
|
}
|
|
532
|
-
function formatVersionPrBody(plan, preamble, packageDirs) {
|
|
601
|
+
function formatVersionPrBody(plan, preamble, packageDirs, repo, prNumber) {
|
|
602
|
+
const changesBaseUrl = repo && prNumber ? `https://github.com/${repo}/pull/${prNumber}/changes` : null;
|
|
533
603
|
const lines = [];
|
|
534
604
|
lines.push(preamble);
|
|
535
605
|
lines.push("");
|
|
@@ -551,13 +621,13 @@ function formatVersionPrBody(plan, preamble, packageDirs) {
|
|
|
551
621
|
for (const r of releases) {
|
|
552
622
|
const suffix = r.isDependencyBump ? " _(dep)_" : r.isCascadeBump ? " _(cascade)_" : "";
|
|
553
623
|
const pkgDir = packageDirs.get(r.name);
|
|
554
|
-
const diffLinks = pkgDir ? buildDiffLinks(pkgDir) : "";
|
|
624
|
+
const diffLinks = pkgDir ? buildDiffLinks(pkgDir, changesBaseUrl) : "";
|
|
555
625
|
lines.push(`#### \`${r.name}\` ${r.oldVersion} → **${r.newVersion}**${suffix}${diffLinks}`);
|
|
556
626
|
lines.push("");
|
|
557
627
|
const relevantBumpFiles = plan.bumpFiles.filter((bf) => r.bumpFiles.includes(bf.id));
|
|
558
628
|
if (relevantBumpFiles.length > 0) {
|
|
559
629
|
for (const bf of relevantBumpFiles) if (bf.summary) {
|
|
560
|
-
const bfLink = ` ([bump file](#diff-${sha256Hex(`.bumpy/${bf.id}.md`)}))
|
|
630
|
+
const bfLink = changesBaseUrl ? ` ([bump file](${changesBaseUrl}#diff-${sha256Hex(`.bumpy/${bf.id}.md`)}))` : "";
|
|
561
631
|
const summaryLines = bf.summary.split("\n");
|
|
562
632
|
lines.push(`- ${summaryLines[0]}${bfLink}`);
|
|
563
633
|
for (let i = 1; i < summaryLines.length; i++) if (summaryLines[i].trim()) lines.push(` ${summaryLines[i]}`);
|
package/dist/cli.mjs
CHANGED
|
@@ -31,7 +31,7 @@ async function main() {
|
|
|
31
31
|
}
|
|
32
32
|
case "add": {
|
|
33
33
|
const rootDir = await findRoot();
|
|
34
|
-
const { addCommand } = await import("./add-
|
|
34
|
+
const { addCommand } = await import("./add-DF6bawDT.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-S2ztf_8E.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-
|
|
57
|
+
const { versionCommand } = await import("./version-BXrP4TIO.mjs");
|
|
58
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-D93b3NAD.mjs");
|
|
64
64
|
await generateCommand(rootDir, {
|
|
65
65
|
from: flags.from,
|
|
66
66
|
dryRun: flags["dry-run"] === true,
|
|
@@ -70,7 +70,7 @@ async function main() {
|
|
|
70
70
|
}
|
|
71
71
|
case "check": {
|
|
72
72
|
const rootDir = await findRoot();
|
|
73
|
-
const { checkCommand } = await import("./check-
|
|
73
|
+
const { checkCommand } = await import("./check-BJL-YDWz.mjs");
|
|
74
74
|
await checkCommand(rootDir, {
|
|
75
75
|
strict: flags.strict === true,
|
|
76
76
|
noFail: flags["no-fail"] === true
|
|
@@ -82,7 +82,7 @@ async function main() {
|
|
|
82
82
|
const subcommand = args[1];
|
|
83
83
|
const ciFlags = parseFlags(args.slice(2));
|
|
84
84
|
if (subcommand === "check") {
|
|
85
|
-
const { ciCheckCommand } = await import("./ci-
|
|
85
|
+
const { ciCheckCommand } = await import("./ci-C88ecvIP.mjs");
|
|
86
86
|
await ciCheckCommand(rootDir, {
|
|
87
87
|
comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
|
|
88
88
|
strict: ciFlags.strict === true,
|
|
@@ -90,7 +90,7 @@ async function main() {
|
|
|
90
90
|
patComments: ciFlags["pat-comments"] === true
|
|
91
91
|
});
|
|
92
92
|
} else if (subcommand === "release") {
|
|
93
|
-
const { ciReleaseCommand } = await import("./ci-
|
|
93
|
+
const { ciReleaseCommand } = await import("./ci-C88ecvIP.mjs");
|
|
94
94
|
await ciReleaseCommand(rootDir, {
|
|
95
95
|
mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
|
|
96
96
|
tag: ciFlags.tag,
|
|
@@ -108,7 +108,7 @@ async function main() {
|
|
|
108
108
|
}
|
|
109
109
|
case "publish": {
|
|
110
110
|
const rootDir = await findRoot();
|
|
111
|
-
const { publishCommand } = await import("./publish-
|
|
111
|
+
const { publishCommand } = await import("./publish-DGSV607z.mjs");
|
|
112
112
|
await publishCommand(rootDir, {
|
|
113
113
|
dryRun: flags["dry-run"] === true,
|
|
114
114
|
tag: flags.tag,
|
|
@@ -132,7 +132,7 @@ async function main() {
|
|
|
132
132
|
}
|
|
133
133
|
case "--version":
|
|
134
134
|
case "-v":
|
|
135
|
-
console.log(`bumpy 1.2.
|
|
135
|
+
console.log(`bumpy 1.2.1`);
|
|
136
136
|
break;
|
|
137
137
|
case "help":
|
|
138
138
|
case "--help":
|
|
@@ -152,7 +152,7 @@ async function main() {
|
|
|
152
152
|
}
|
|
153
153
|
function printHelp() {
|
|
154
154
|
console.log(`
|
|
155
|
-
${colorize(`🐸 bumpy v1.2.
|
|
155
|
+
${colorize(`🐸 bumpy v1.2.1`, "bold")} - Modern monorepo versioning
|
|
156
156
|
|
|
157
157
|
Usage: bumpy <command> [options]
|
|
158
158
|
|
|
@@ -3,8 +3,8 @@ import { t as ensureDir } from "./fs-DnDogVn-.mjs";
|
|
|
3
3
|
import { a as loadConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
|
|
4
4
|
import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
|
|
5
5
|
import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
6
|
-
import { i as writeBumpFile } from "./bump-file-
|
|
7
|
-
import {
|
|
6
|
+
import { i as writeBumpFile } from "./bump-file-C3S_bzSf.mjs";
|
|
7
|
+
import { a as getFilesChangedInCommit, n as getBranchCommits } from "./git-H9S9z6g-.mjs";
|
|
8
8
|
import { n as slugify, t as randomName } from "./names-C-TuOPbd.mjs";
|
|
9
9
|
import { relative } from "node:path";
|
|
10
10
|
//#region src/commands/generate.ts
|
|
@@ -26,6 +26,15 @@ function hasUncommittedChanges(opts) {
|
|
|
26
26
|
], opts);
|
|
27
27
|
return result !== null && result.length > 0;
|
|
28
28
|
}
|
|
29
|
+
/** Get the current branch name */
|
|
30
|
+
function getCurrentBranch(opts) {
|
|
31
|
+
return tryRunArgs([
|
|
32
|
+
"git",
|
|
33
|
+
"rev-parse",
|
|
34
|
+
"--abbrev-ref",
|
|
35
|
+
"HEAD"
|
|
36
|
+
], opts);
|
|
37
|
+
}
|
|
29
38
|
/** Check if a tag already exists */
|
|
30
39
|
function tagExists(tag, opts) {
|
|
31
40
|
return tryRunArgs([
|
|
@@ -127,4 +136,4 @@ function listTags(pattern, opts) {
|
|
|
127
136
|
return result.split("\n").filter(Boolean);
|
|
128
137
|
}
|
|
129
138
|
//#endregion
|
|
130
|
-
export {
|
|
139
|
+
export { getFilesChangedInCommit as a, pushWithTags as c, getCurrentBranch as i, tagExists as l, getBranchCommits as n, hasUncommittedChanges as o, getChangedFiles as r, listTags as s, createTag as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -193,10 +193,18 @@ declare class DependencyGraph {
|
|
|
193
193
|
}
|
|
194
194
|
//#endregion
|
|
195
195
|
//#region src/core/bump-file.d.ts
|
|
196
|
+
interface ReadBumpFilesResult {
|
|
197
|
+
bumpFiles: BumpFile[];
|
|
198
|
+
errors: string[];
|
|
199
|
+
}
|
|
196
200
|
/** Read all bump files from .bumpy/ directory, sorted by git creation order */
|
|
197
|
-
declare function readBumpFiles(rootDir: string): Promise<
|
|
201
|
+
declare function readBumpFiles(rootDir: string): Promise<ReadBumpFilesResult>;
|
|
202
|
+
interface BumpFileParseResult {
|
|
203
|
+
bumpFile: BumpFile | null;
|
|
204
|
+
errors: string[];
|
|
205
|
+
}
|
|
198
206
|
/** Parse bump file content (for testing) */
|
|
199
|
-
declare function parseBumpFile(content: string, id: string):
|
|
207
|
+
declare function parseBumpFile(content: string, id: string): BumpFileParseResult;
|
|
200
208
|
/** Write a bump file */
|
|
201
209
|
declare function writeBumpFile(rootDir: string, filename: string, releases: BumpFileRelease[], summary: string): Promise<string>;
|
|
202
210
|
//#endregion
|
|
@@ -245,6 +253,8 @@ declare function prependToChangelog(existingContent: string, newEntry: string):
|
|
|
245
253
|
interface GithubChangelogOptions {
|
|
246
254
|
/** "owner/repo" — auto-detected from gh CLI if not provided */
|
|
247
255
|
repo?: string;
|
|
256
|
+
/** Whether to include commit hash links in changelog entries (default: false) */
|
|
257
|
+
includeCommitLink?: boolean;
|
|
248
258
|
/** Whether to include "Thanks @user" messages for contributors (default: true) */
|
|
249
259
|
thankContributors?: boolean;
|
|
250
260
|
/** GitHub usernames (without @) to skip "Thanks" messages for (e.g. internal team members) */
|
|
@@ -288,4 +298,4 @@ interface PublishResult {
|
|
|
288
298
|
*/
|
|
289
299
|
declare function publishPackages(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig, rootDir: string, opts?: PublishOptions, catalogs?: CatalogMap, detectedPm?: PackageManager): Promise<PublishResult>;
|
|
290
300
|
//#endregion
|
|
291
|
-
export { BUMP_LEVELS, BumpFile, BumpFileRelease, BumpFileReleaseCascade, BumpFileReleaseSimple, BumpType, BumpTypeWithNone, BumpyConfig, type ChangelogContext, type ChangelogFormatter, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DepType, DependencyBumpRule, DependencyGraph, DependentInfo, type GithubChangelogOptions, PackageConfig, PackageManager, PlannedRelease, PublishConfig, ReleasePlan, WorkspacePackage, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
|
|
301
|
+
export { BUMP_LEVELS, BumpFile, type BumpFileParseResult, BumpFileRelease, BumpFileReleaseCascade, BumpFileReleaseSimple, BumpType, BumpTypeWithNone, BumpyConfig, type ChangelogContext, type ChangelogFormatter, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DepType, DependencyBumpRule, DependencyGraph, DependentInfo, type GithubChangelogOptions, PackageConfig, PackageManager, PlannedRelease, PublishConfig, type ReadBumpFilesResult, ReleasePlan, WorkspacePackage, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as loadConfig, c as BUMP_LEVELS, d as DEFAULT_PUBLISH_CONFIG, f as DEP_TYPES, h as maxBump, l as DEFAULT_BUMP_RULES, m as hasCascade, n as findRoot, p as bumpLevel, r as getBumpyDir, s as matchGlob, u as DEFAULT_CONFIG } from "./config-D7Umr-fT.mjs";
|
|
2
2
|
import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
|
|
3
3
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
4
|
-
import { i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-
|
|
4
|
+
import { i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-C3S_bzSf.mjs";
|
|
5
5
|
import { n as satisfies, r as stripProtocol, t as bumpVersion } from "./semver-BJzWIuRz.mjs";
|
|
6
6
|
import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
|
|
7
|
-
import { a as prependToChangelog, i as loadFormatter, n as defaultFormatter, r as generateChangelogEntry, t as applyReleasePlan } from "./apply-release-plan-
|
|
8
|
-
import { t as publishPackages } from "./publish-pipeline-
|
|
7
|
+
import { a as prependToChangelog, i as loadFormatter, n as defaultFormatter, r as generateChangelogEntry, t as applyReleasePlan } from "./apply-release-plan-B1Wwx3HG.mjs";
|
|
8
|
+
import { t as publishPackages } from "./publish-pipeline-DiwZZ5AF.mjs";
|
|
9
9
|
export { BUMP_LEVELS, DEFAULT_BUMP_RULES, DEFAULT_CONFIG, DEFAULT_PUBLISH_CONFIG, DEP_TYPES, DependencyGraph, applyReleasePlan, assembleReleasePlan, bumpLevel, bumpVersion, defaultFormatter, discoverPackages, findRoot, generateChangelogEntry, getBumpyDir, hasCascade, loadConfig, loadFormatter, matchGlob, maxBump, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
|
|
@@ -4,8 +4,8 @@ import { n as detectWorkspaces } from "./package-manager-ByJ0wKYh.mjs";
|
|
|
4
4
|
import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
|
|
5
5
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
6
|
import { r as runArgsAsync, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import { t as publishPackages } from "./publish-pipeline-
|
|
7
|
+
import { c as pushWithTags, o as hasUncommittedChanges, s as listTags } from "./git-H9S9z6g-.mjs";
|
|
8
|
+
import { t as publishPackages } from "./publish-pipeline-DiwZZ5AF.mjs";
|
|
9
9
|
//#region src/core/github-release.ts
|
|
10
10
|
/** Get the current HEAD commit SHA */
|
|
11
11
|
function getHeadSha(rootDir) {
|
|
@@ -3,7 +3,7 @@ import { a as readJson, u as updateJsonNestedField } from "./fs-DnDogVn-.mjs";
|
|
|
3
3
|
import { r as resolveCatalogDep } from "./package-manager-ByJ0wKYh.mjs";
|
|
4
4
|
import { i as runAsync, o as sq, r as runArgsAsync, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
5
5
|
import { r as stripProtocol } from "./semver-BJzWIuRz.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { l as tagExists, t as createTag } from "./git-H9S9z6g-.mjs";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { unlink } from "node:fs/promises";
|
|
9
9
|
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
@@ -2,14 +2,16 @@ import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
|
2
2
|
import { a as loadConfig } from "./config-D7Umr-fT.mjs";
|
|
3
3
|
import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
|
|
4
4
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
5
|
-
import { r as readBumpFiles } from "./bump-file-
|
|
5
|
+
import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-C3S_bzSf.mjs";
|
|
6
6
|
import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
|
|
7
|
+
import { i as getCurrentBranch, r as getChangedFiles } from "./git-H9S9z6g-.mjs";
|
|
7
8
|
//#region src/commands/status.ts
|
|
8
9
|
async function statusCommand(rootDir, opts) {
|
|
9
10
|
const config = await loadConfig(rootDir);
|
|
10
11
|
const packages = await discoverPackages(rootDir, config);
|
|
11
12
|
const depGraph = new DependencyGraph(packages);
|
|
12
|
-
const bumpFiles = await readBumpFiles(rootDir);
|
|
13
|
+
const { bumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
|
|
14
|
+
if (parseErrors.length > 0) for (const err of parseErrors) log.error(err);
|
|
13
15
|
if (bumpFiles.length === 0) {
|
|
14
16
|
if (opts.json) console.log(JSON.stringify({
|
|
15
17
|
bumpFiles: [],
|
|
@@ -20,6 +22,9 @@ async function statusCommand(rootDir, opts) {
|
|
|
20
22
|
process.exit(1);
|
|
21
23
|
}
|
|
22
24
|
const plan = assembleReleasePlan(bumpFiles, packages, depGraph, config);
|
|
25
|
+
let branchBumpFileIds;
|
|
26
|
+
const currentBranch = getCurrentBranch({ cwd: rootDir });
|
|
27
|
+
if (currentBranch && currentBranch !== config.baseBranch) branchBumpFileIds = filterBranchBumpFiles(bumpFiles, getChangedFiles(rootDir, config.baseBranch), rootDir).branchBumpFileIds;
|
|
23
28
|
let releases = plan.releases;
|
|
24
29
|
if (opts.bumpType) {
|
|
25
30
|
const types = opts.bumpType.split(",").map((t) => t.trim());
|
|
@@ -38,18 +43,25 @@ async function statusCommand(rootDir, opts) {
|
|
|
38
43
|
releases: bf.releases.map((r) => ({
|
|
39
44
|
name: r.name,
|
|
40
45
|
type: r.type
|
|
41
|
-
}))
|
|
42
|
-
|
|
43
|
-
releases: releases.map((r) => ({
|
|
44
|
-
name: r.name,
|
|
45
|
-
type: r.type,
|
|
46
|
-
oldVersion: r.oldVersion,
|
|
47
|
-
newVersion: r.newVersion,
|
|
48
|
-
dir: packages.get(r.name)?.relativeDir,
|
|
49
|
-
bumpFiles: r.bumpFiles,
|
|
50
|
-
isDependencyBump: r.isDependencyBump,
|
|
51
|
-
isCascadeBump: r.isCascadeBump
|
|
46
|
+
})),
|
|
47
|
+
...branchBumpFileIds ? { inCurrentBranch: branchBumpFileIds.has(bf.id) } : {}
|
|
52
48
|
})),
|
|
49
|
+
releases: releases.map((r) => {
|
|
50
|
+
const pkg = packages.get(r.name);
|
|
51
|
+
const pkgConfig = pkg?.bumpy || {};
|
|
52
|
+
return {
|
|
53
|
+
name: r.name,
|
|
54
|
+
type: r.type,
|
|
55
|
+
oldVersion: r.oldVersion,
|
|
56
|
+
newVersion: r.newVersion,
|
|
57
|
+
dir: pkg?.relativeDir,
|
|
58
|
+
bumpFiles: r.bumpFiles,
|
|
59
|
+
isDependencyBump: r.isDependencyBump,
|
|
60
|
+
isCascadeBump: r.isCascadeBump,
|
|
61
|
+
...branchBumpFileIds ? { inCurrentBranch: r.bumpFiles.some((id) => branchBumpFileIds.has(id)) } : {},
|
|
62
|
+
publishTargets: getPublishTargets(pkg, pkgConfig, config)
|
|
63
|
+
};
|
|
64
|
+
}),
|
|
53
65
|
packageNames: releases.map((r) => r.name)
|
|
54
66
|
};
|
|
55
67
|
console.log(JSON.stringify(jsonOutput, null, 2));
|
|
@@ -106,5 +118,14 @@ function printRelease(r, packages) {
|
|
|
106
118
|
const suffix = r.isDependencyBump ? colorize(" ← dependency bump", "dim") : r.isCascadeBump ? colorize(" ← cascade", "dim") : "";
|
|
107
119
|
console.log(` ${r.name}: ${r.oldVersion} → ${colorize(r.newVersion, "cyan")}${suffix}${dir}`);
|
|
108
120
|
}
|
|
121
|
+
/** Determine which publish targets a package will use */
|
|
122
|
+
function getPublishTargets(pkg, pkgConfig, _config) {
|
|
123
|
+
if (!pkg) return [];
|
|
124
|
+
if (pkg.private && !pkgConfig.publishCommand) return [];
|
|
125
|
+
const targets = [];
|
|
126
|
+
if (pkgConfig.publishCommand) targets.push("custom");
|
|
127
|
+
if (!pkgConfig.publishCommand && !pkgConfig.skipNpmPublish) targets.push("npm");
|
|
128
|
+
return targets;
|
|
129
|
+
}
|
|
109
130
|
//#endregion
|
|
110
131
|
export { statusCommand };
|
|
@@ -4,16 +4,20 @@ import { n as detectWorkspaces } from "./package-manager-ByJ0wKYh.mjs";
|
|
|
4
4
|
import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
|
|
5
5
|
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
6
|
import { n as runArgs, s as tryRunArgs } from "./shell-CY7OD48z.mjs";
|
|
7
|
-
import { r as readBumpFiles } from "./bump-file-
|
|
7
|
+
import { r as readBumpFiles } from "./bump-file-C3S_bzSf.mjs";
|
|
8
8
|
import { t as assembleReleasePlan } from "./release-plan-CNOuSI-d.mjs";
|
|
9
|
-
import { t as applyReleasePlan } from "./apply-release-plan-
|
|
9
|
+
import { t as applyReleasePlan } from "./apply-release-plan-B1Wwx3HG.mjs";
|
|
10
10
|
import { t as resolveCommitMessage } from "./commit-message-BwsowSds.mjs";
|
|
11
11
|
//#region src/commands/version.ts
|
|
12
12
|
async function versionCommand(rootDir, opts = {}) {
|
|
13
13
|
const config = await loadConfig(rootDir);
|
|
14
14
|
const packages = await discoverPackages(rootDir, config);
|
|
15
15
|
const depGraph = new DependencyGraph(packages);
|
|
16
|
-
const bumpFiles = await readBumpFiles(rootDir);
|
|
16
|
+
const { bumpFiles, errors: parseErrors } = await readBumpFiles(rootDir);
|
|
17
|
+
if (parseErrors.length > 0) {
|
|
18
|
+
for (const err of parseErrors) log.error(err);
|
|
19
|
+
throw new Error("Bump file parse errors must be fixed before versioning.");
|
|
20
|
+
}
|
|
17
21
|
if (bumpFiles.length === 0) {
|
|
18
22
|
log.info("No pending bump files.");
|
|
19
23
|
return;
|