@varlock/bumpy 0.0.0 → 0.0.2
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/.claude-plugin/plugin.json +13 -0
- package/dist/add-BjyVIUlr.mjs +175 -0
- package/dist/ai-CQhUyHAG.mjs +82 -0
- package/dist/apply-release-plan-D6TSrcwX.mjs +137 -0
- package/dist/changelog-github-Du62krXi.mjs +193 -0
- package/dist/changeset-UCZdSRDv.mjs +108 -0
- package/dist/check-jIwike9F.mjs +51 -0
- package/dist/ci-D6LQbR38.mjs +585 -0
- package/dist/ci-setup-C6FlOfW5.mjs +211 -0
- package/dist/clack-CDRCHrC-.mjs +1216 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +214 -0
- package/dist/config-BkwIEaQg.mjs +215 -0
- package/dist/dep-graph-E-9-eQ2J.mjs +64 -0
- package/dist/fs-0AtnPUUe.mjs +51 -0
- package/dist/generate-Btrsn1qi.mjs +177 -0
- package/dist/git-CGHVXXKw.mjs +78 -0
- package/dist/index.d.mts +262 -0
- package/dist/index.mjs +9 -0
- package/dist/init-B0q3wEQW.mjs +22 -0
- package/dist/js-yaml-DpZfOoD4.mjs +2031 -0
- package/dist/logger-C2dEe5Su.mjs +135 -0
- package/dist/migrate-CfQNwD0T.mjs +121 -0
- package/dist/names-Ck8cun7B.mjs +144 -0
- package/dist/package-manager-DcI5TdDE.mjs +80 -0
- package/dist/publish-D_7RqEYL.mjs +251 -0
- package/dist/publish-pipeline-ChnqW8nR.mjs +277 -0
- package/dist/release-plan-BEzwApuK.mjs +173 -0
- package/dist/semver-BTzYh8vc.mjs +1360 -0
- package/dist/shell-Dj7JRD_q.mjs +92 -0
- package/dist/status--Q8yAxQ4.mjs +106 -0
- package/dist/version-cAUkfYPx.mjs +120 -0
- package/dist/workspace-CxEKakDm.mjs +107 -0
- package/package.json +38 -6
- package/skills/add-change/SKILL.md +108 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { t as ensureDir } from "./fs-0AtnPUUe.mjs";
|
|
3
|
+
import { a as loadConfig, r as getBumpyDir } from "./config-BkwIEaQg.mjs";
|
|
4
|
+
import { t as discoverPackages } from "./workspace-CxEKakDm.mjs";
|
|
5
|
+
import { o as tryRunArgs } from "./shell-Dj7JRD_q.mjs";
|
|
6
|
+
import { i as writeChangeset } from "./changeset-UCZdSRDv.mjs";
|
|
7
|
+
import { n as slugify, t as randomName } from "./names-Ck8cun7B.mjs";
|
|
8
|
+
//#region src/commands/generate.ts
|
|
9
|
+
const BUMP_MAP = {
|
|
10
|
+
feat: "minor",
|
|
11
|
+
fix: "patch",
|
|
12
|
+
perf: "patch",
|
|
13
|
+
refactor: "patch",
|
|
14
|
+
docs: "patch",
|
|
15
|
+
style: "patch",
|
|
16
|
+
test: "patch",
|
|
17
|
+
build: "patch",
|
|
18
|
+
ci: "patch",
|
|
19
|
+
chore: "patch"
|
|
20
|
+
};
|
|
21
|
+
async function generateCommand(rootDir, opts) {
|
|
22
|
+
const config = await loadConfig(rootDir);
|
|
23
|
+
const packages = await discoverPackages(rootDir, config);
|
|
24
|
+
const from = opts.from || findLastVersionTag(rootDir);
|
|
25
|
+
if (!from) {
|
|
26
|
+
log.error("Could not detect last version tag. Use --from <ref> to specify.");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
log.step(`Scanning commits from ${colorize(from, "cyan")}...`);
|
|
30
|
+
const rawLog = tryRunArgs([
|
|
31
|
+
"git",
|
|
32
|
+
"log",
|
|
33
|
+
`${from}..HEAD`,
|
|
34
|
+
"--format=%H%n%s%n%b%n---END---"
|
|
35
|
+
], { cwd: rootDir });
|
|
36
|
+
if (!rawLog) {
|
|
37
|
+
log.info("No commits found since " + from);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const conventional = parseGitLog(rawLog).map(parseConventionalCommit).filter((c) => c !== null);
|
|
41
|
+
if (conventional.length === 0) {
|
|
42
|
+
log.info("No conventional commits found. Commits must follow the format: type(scope): description");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
log.dim(` Found ${conventional.length} conventional commit(s)`);
|
|
46
|
+
const scopeMap = buildScopeMap(packages, config);
|
|
47
|
+
const releaseMap = /* @__PURE__ */ new Map();
|
|
48
|
+
for (const commit of conventional) {
|
|
49
|
+
const bump = commit.breaking ? "major" : BUMP_MAP[commit.type] || "patch";
|
|
50
|
+
let pkgNames = [];
|
|
51
|
+
if (commit.scope) {
|
|
52
|
+
const resolved = resolveScope(commit.scope, scopeMap, packages);
|
|
53
|
+
if (resolved.length > 0) pkgNames = resolved;
|
|
54
|
+
else {
|
|
55
|
+
log.dim(` Skipping: unknown scope "${commit.scope}" in: ${commit.description}`);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
log.dim(` Skipping (no scope): ${commit.type}: ${commit.description}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
for (const name of pkgNames) {
|
|
63
|
+
const existing = releaseMap.get(name);
|
|
64
|
+
if (existing) {
|
|
65
|
+
if (bumpPriority(bump) > bumpPriority(existing.type)) existing.type = bump;
|
|
66
|
+
existing.messages.push(commit.description);
|
|
67
|
+
} else releaseMap.set(name, {
|
|
68
|
+
type: bump,
|
|
69
|
+
messages: [commit.description]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (releaseMap.size === 0) {
|
|
74
|
+
log.info("No package bumps detected from conventional commits.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const releases = [];
|
|
78
|
+
const summaryLines = [];
|
|
79
|
+
for (const [name, info] of releaseMap) {
|
|
80
|
+
releases.push({
|
|
81
|
+
name,
|
|
82
|
+
type: info.type
|
|
83
|
+
});
|
|
84
|
+
for (const msg of info.messages) summaryLines.push(`- ${name}: ${msg}`);
|
|
85
|
+
}
|
|
86
|
+
if (opts.dryRun) {
|
|
87
|
+
log.bold("Would create changeset:");
|
|
88
|
+
for (const r of releases) console.log(` ${r.name}: ${colorize(r.type, r.type === "major" ? "red" : r.type === "minor" ? "yellow" : "green")}`);
|
|
89
|
+
console.log();
|
|
90
|
+
log.dim("Summary:");
|
|
91
|
+
for (const line of summaryLines) log.dim(` ${line}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
await ensureDir(getBumpyDir(rootDir));
|
|
95
|
+
const filename = opts.name ? slugify(opts.name) : randomName();
|
|
96
|
+
await writeChangeset(rootDir, filename, releases, summaryLines.join("\n"));
|
|
97
|
+
log.success(`Created changeset: .bumpy/${filename}.md`);
|
|
98
|
+
for (const r of releases) log.dim(` ${r.name}: ${r.type}`);
|
|
99
|
+
}
|
|
100
|
+
/** Parse raw git log output into individual commits */
|
|
101
|
+
function parseGitLog(raw) {
|
|
102
|
+
const commits = [];
|
|
103
|
+
const entries = raw.split("---END---").filter((e) => e.trim());
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
const lines = entry.trim().split("\n");
|
|
106
|
+
if (lines.length < 2) continue;
|
|
107
|
+
commits.push({
|
|
108
|
+
hash: lines[0].trim(),
|
|
109
|
+
subject: lines[1].trim(),
|
|
110
|
+
body: lines.slice(2).join("\n").trim()
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return commits;
|
|
114
|
+
}
|
|
115
|
+
/** Parse a commit subject into conventional commit format */
|
|
116
|
+
function parseConventionalCommit(commit) {
|
|
117
|
+
const match = commit.subject.match(/^(\w+)(!)?(?:\(([^)]+)\))?(!)?\s*:\s*(.+)$/);
|
|
118
|
+
if (!match) return null;
|
|
119
|
+
const [, type, bang1, scope, bang2, description] = match;
|
|
120
|
+
const breaking = !!bang1 || !!bang2 || commit.body.includes("BREAKING CHANGE");
|
|
121
|
+
return {
|
|
122
|
+
hash: commit.hash,
|
|
123
|
+
type: type.toLowerCase(),
|
|
124
|
+
scope: scope || null,
|
|
125
|
+
breaking,
|
|
126
|
+
description: description.trim(),
|
|
127
|
+
body: commit.body
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Build a map of scope aliases → package names from config and package names */
|
|
131
|
+
function buildScopeMap(packages, _config) {
|
|
132
|
+
const map = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [name, pkg] of packages) {
|
|
134
|
+
const shortName = name.includes("/") ? name.split("/").pop() : name;
|
|
135
|
+
if (!map.has(shortName)) map.set(shortName, []);
|
|
136
|
+
map.get(shortName).push(name);
|
|
137
|
+
if (!map.has(name)) map.set(name, []);
|
|
138
|
+
map.get(name).push(name);
|
|
139
|
+
const dirName = pkg.relativeDir.split("/").pop();
|
|
140
|
+
if (dirName !== shortName) {
|
|
141
|
+
if (!map.has(dirName)) map.set(dirName, []);
|
|
142
|
+
map.get(dirName).push(name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return map;
|
|
146
|
+
}
|
|
147
|
+
/** Resolve a scope string to package name(s) */
|
|
148
|
+
function resolveScope(scope, scopeMap, packages) {
|
|
149
|
+
const mapped = scopeMap.get(scope);
|
|
150
|
+
if (mapped) return [...new Set(mapped)];
|
|
151
|
+
for (const [key, value] of scopeMap) if (key.toLowerCase() === scope.toLowerCase()) return [...new Set(value)];
|
|
152
|
+
if (packages.has(scope)) return [scope];
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
function bumpPriority(type) {
|
|
156
|
+
return type === "major" ? 2 : type === "minor" ? 1 : 0;
|
|
157
|
+
}
|
|
158
|
+
/** Find the most recent version tag in the repo */
|
|
159
|
+
function findLastVersionTag(rootDir) {
|
|
160
|
+
return tryRunArgs([
|
|
161
|
+
"git",
|
|
162
|
+
"describe",
|
|
163
|
+
"--tags",
|
|
164
|
+
"--abbrev=0",
|
|
165
|
+
"--match",
|
|
166
|
+
"v*"
|
|
167
|
+
], { cwd: rootDir }) || tryRunArgs([
|
|
168
|
+
"git",
|
|
169
|
+
"describe",
|
|
170
|
+
"--tags",
|
|
171
|
+
"--abbrev=0",
|
|
172
|
+
"--match",
|
|
173
|
+
"*@*"
|
|
174
|
+
], { cwd: rootDir }) || null;
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
export { generateCommand };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { o as tryRunArgs, t as runArgs } from "./shell-Dj7JRD_q.mjs";
|
|
2
|
+
//#region src/core/git.ts
|
|
3
|
+
/** Create a git tag */
|
|
4
|
+
function createTag(tag, opts) {
|
|
5
|
+
runArgs([
|
|
6
|
+
"git",
|
|
7
|
+
"tag",
|
|
8
|
+
tag
|
|
9
|
+
], opts);
|
|
10
|
+
}
|
|
11
|
+
/** Push commits and tags to remote */
|
|
12
|
+
function pushWithTags(opts) {
|
|
13
|
+
runArgs(["git", "push"], opts);
|
|
14
|
+
runArgs([
|
|
15
|
+
"git",
|
|
16
|
+
"push",
|
|
17
|
+
"--tags"
|
|
18
|
+
], opts);
|
|
19
|
+
}
|
|
20
|
+
/** Check if there are uncommitted changes */
|
|
21
|
+
function hasUncommittedChanges(opts) {
|
|
22
|
+
const result = tryRunArgs([
|
|
23
|
+
"git",
|
|
24
|
+
"status",
|
|
25
|
+
"--porcelain"
|
|
26
|
+
], opts);
|
|
27
|
+
return result !== null && result.length > 0;
|
|
28
|
+
}
|
|
29
|
+
/** Check if a tag already exists */
|
|
30
|
+
function tagExists(tag, opts) {
|
|
31
|
+
return tryRunArgs([
|
|
32
|
+
"git",
|
|
33
|
+
"tag",
|
|
34
|
+
"-l",
|
|
35
|
+
tag
|
|
36
|
+
], opts) === tag;
|
|
37
|
+
}
|
|
38
|
+
/** Get files changed on this branch compared to a base branch */
|
|
39
|
+
function getChangedFiles(rootDir, baseBranch) {
|
|
40
|
+
if (!tryRunArgs([
|
|
41
|
+
"git",
|
|
42
|
+
"rev-parse",
|
|
43
|
+
"--verify",
|
|
44
|
+
`origin/${baseBranch}`
|
|
45
|
+
], { cwd: rootDir })) tryRunArgs([
|
|
46
|
+
"git",
|
|
47
|
+
"fetch",
|
|
48
|
+
"origin",
|
|
49
|
+
baseBranch,
|
|
50
|
+
"--depth=1"
|
|
51
|
+
], { cwd: rootDir });
|
|
52
|
+
const diff = tryRunArgs([
|
|
53
|
+
"git",
|
|
54
|
+
"diff",
|
|
55
|
+
"--name-only",
|
|
56
|
+
tryRunArgs([
|
|
57
|
+
"git",
|
|
58
|
+
"merge-base",
|
|
59
|
+
"HEAD",
|
|
60
|
+
`origin/${baseBranch}`
|
|
61
|
+
], { cwd: rootDir }) || `origin/${baseBranch}`
|
|
62
|
+
], { cwd: rootDir });
|
|
63
|
+
if (!diff) return [];
|
|
64
|
+
return diff.split("\n").filter(Boolean);
|
|
65
|
+
}
|
|
66
|
+
/** Get all tags matching a pattern */
|
|
67
|
+
function listTags(pattern, opts) {
|
|
68
|
+
const result = tryRunArgs([
|
|
69
|
+
"git",
|
|
70
|
+
"tag",
|
|
71
|
+
"-l",
|
|
72
|
+
pattern
|
|
73
|
+
], opts);
|
|
74
|
+
if (!result) return [];
|
|
75
|
+
return result.split("\n").filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { pushWithTags as a, listTags as i, getChangedFiles as n, tagExists as o, hasUncommittedChanges as r, createTag as t };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
type BumpType = 'major' | 'minor' | 'patch';
|
|
3
|
+
type BumpTypeWithIsolated = BumpType | 'minor-isolated' | 'patch-isolated';
|
|
4
|
+
declare const BUMP_LEVELS: Record<BumpType, number>;
|
|
5
|
+
declare function bumpLevel(type: BumpType): number;
|
|
6
|
+
declare function parseIsolatedBump(type: BumpTypeWithIsolated): {
|
|
7
|
+
bump: BumpType;
|
|
8
|
+
isolated: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare function maxBump(a: BumpType | undefined, b: BumpType): BumpType;
|
|
11
|
+
interface DependencyBumpRule {
|
|
12
|
+
/** What bump level in the dependency triggers propagation */
|
|
13
|
+
trigger: BumpType | 'none';
|
|
14
|
+
/** What bump to apply to the dependent */
|
|
15
|
+
bumpAs: BumpType | 'match';
|
|
16
|
+
}
|
|
17
|
+
declare const DEFAULT_BUMP_RULES: Record<string, DependencyBumpRule>;
|
|
18
|
+
type DepType = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies';
|
|
19
|
+
declare const DEP_TYPES: DepType[];
|
|
20
|
+
interface PublishConfig {
|
|
21
|
+
/** Package manager to use for packing. "auto" detects from lockfile. Default: "auto" */
|
|
22
|
+
packManager: 'auto' | 'npm' | 'pnpm' | 'bun' | 'yarn';
|
|
23
|
+
/** Command to use for publishing. "npm" uses npm publish (supports OIDC). Default: "npm" */
|
|
24
|
+
publishManager: 'npm' | 'pnpm' | 'bun' | 'yarn';
|
|
25
|
+
/** Extra args appended to the publish command (e.g., "--provenance") */
|
|
26
|
+
publishArgs: string[];
|
|
27
|
+
/**
|
|
28
|
+
* How to handle workspace:/catalog: protocol resolution.
|
|
29
|
+
* "pack" = use PM's pack to build a clean tarball, then publish the tarball (recommended)
|
|
30
|
+
* "in-place" = resolve protocols by rewriting package.json before publish
|
|
31
|
+
* "none" = don't resolve (only if PM's publish handles it natively)
|
|
32
|
+
* Default: "pack"
|
|
33
|
+
*/
|
|
34
|
+
protocolResolution: 'pack' | 'in-place' | 'none';
|
|
35
|
+
}
|
|
36
|
+
interface BumpyConfig {
|
|
37
|
+
baseBranch: string;
|
|
38
|
+
access: 'public' | 'restricted';
|
|
39
|
+
commit: boolean;
|
|
40
|
+
changelog: string | [string, Record<string, unknown>];
|
|
41
|
+
fixed: string[][];
|
|
42
|
+
linked: string[][];
|
|
43
|
+
/** Package names/globs to exclude from version management */
|
|
44
|
+
ignore: string[];
|
|
45
|
+
/** Package names/globs to explicitly include (overrides private + ignore) */
|
|
46
|
+
include: string[];
|
|
47
|
+
updateInternalDependencies: 'patch' | 'minor' | 'out-of-range' | 'none';
|
|
48
|
+
dependencyBumpRules: Partial<Record<DepType, DependencyBumpRule>>;
|
|
49
|
+
privatePackages: {
|
|
50
|
+
version: boolean;
|
|
51
|
+
tag: boolean;
|
|
52
|
+
};
|
|
53
|
+
packages: Record<string, PackageConfig>;
|
|
54
|
+
publish: PublishConfig;
|
|
55
|
+
/**
|
|
56
|
+
* GitHub release creation (requires `gh` CLI).
|
|
57
|
+
* false = individual release per package (default)
|
|
58
|
+
* true = single aggregated release for all packages
|
|
59
|
+
* { enabled: true, title: "..." } = aggregate with custom title (supports {{date}})
|
|
60
|
+
*/
|
|
61
|
+
aggregateRelease: boolean | {
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
title?: string;
|
|
64
|
+
};
|
|
65
|
+
/** Git identity used for CI commits. Defaults to bumpy-bot. */
|
|
66
|
+
gitUser: {
|
|
67
|
+
name: string;
|
|
68
|
+
email: string;
|
|
69
|
+
};
|
|
70
|
+
/** Version PR settings */
|
|
71
|
+
versionPr: {
|
|
72
|
+
/** PR title. Default: "🐸 Versioned release" */title: string; /** Branch name. Default: "bumpy/version-packages" */
|
|
73
|
+
branch: string; /** Preamble text shown at the top of the PR body */
|
|
74
|
+
preamble: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
interface PackageConfig {
|
|
78
|
+
/** Explicitly opt in or out of version management (overrides private/ignore/include) */
|
|
79
|
+
managed?: boolean;
|
|
80
|
+
access?: 'public' | 'restricted';
|
|
81
|
+
publishCommand?: string | string[];
|
|
82
|
+
buildCommand?: string;
|
|
83
|
+
registry?: string;
|
|
84
|
+
skipNpmPublish?: boolean;
|
|
85
|
+
/** Command to check if a version is already published. Should output the published version string. */
|
|
86
|
+
checkPublished?: string;
|
|
87
|
+
dependencyBumpRules?: Partial<Record<DepType, DependencyBumpRule>>;
|
|
88
|
+
specificDependencyRules?: Record<string, DependencyBumpRule>;
|
|
89
|
+
cascadeTo?: Record<string, DependencyBumpRule>;
|
|
90
|
+
}
|
|
91
|
+
declare const DEFAULT_PUBLISH_CONFIG: PublishConfig;
|
|
92
|
+
declare const DEFAULT_CONFIG: BumpyConfig;
|
|
93
|
+
interface ChangesetReleaseSimple {
|
|
94
|
+
name: string;
|
|
95
|
+
type: BumpTypeWithIsolated;
|
|
96
|
+
}
|
|
97
|
+
interface ChangesetReleaseCascade {
|
|
98
|
+
name: string;
|
|
99
|
+
type: BumpTypeWithIsolated;
|
|
100
|
+
cascade: Record<string, BumpType>;
|
|
101
|
+
}
|
|
102
|
+
type ChangesetRelease = ChangesetReleaseSimple | ChangesetReleaseCascade;
|
|
103
|
+
declare function hasCascade(r: ChangesetRelease): r is ChangesetReleaseCascade;
|
|
104
|
+
interface Changeset {
|
|
105
|
+
id: string;
|
|
106
|
+
releases: ChangesetRelease[];
|
|
107
|
+
summary: string;
|
|
108
|
+
}
|
|
109
|
+
interface WorkspacePackage {
|
|
110
|
+
name: string;
|
|
111
|
+
version: string;
|
|
112
|
+
dir: string;
|
|
113
|
+
relativeDir: string;
|
|
114
|
+
packageJson: Record<string, unknown>;
|
|
115
|
+
private: boolean;
|
|
116
|
+
dependencies: Record<string, string>;
|
|
117
|
+
devDependencies: Record<string, string>;
|
|
118
|
+
peerDependencies: Record<string, string>;
|
|
119
|
+
optionalDependencies: Record<string, string>;
|
|
120
|
+
bumpy?: PackageConfig;
|
|
121
|
+
}
|
|
122
|
+
type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
123
|
+
interface DependentInfo {
|
|
124
|
+
/** The package that depends on the source */
|
|
125
|
+
name: string;
|
|
126
|
+
depType: DepType;
|
|
127
|
+
versionRange: string;
|
|
128
|
+
}
|
|
129
|
+
interface PlannedRelease {
|
|
130
|
+
name: string;
|
|
131
|
+
type: BumpType;
|
|
132
|
+
oldVersion: string;
|
|
133
|
+
newVersion: string;
|
|
134
|
+
changesets: string[];
|
|
135
|
+
isDependencyBump: boolean;
|
|
136
|
+
isCascadeBump: boolean;
|
|
137
|
+
}
|
|
138
|
+
interface ReleasePlan {
|
|
139
|
+
changesets: Changeset[];
|
|
140
|
+
releases: PlannedRelease[];
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/core/config.d.ts
|
|
144
|
+
/** Find the monorepo root by walking up from cwd looking for .bumpy/ */
|
|
145
|
+
declare function findRoot(startDir?: string): Promise<string>;
|
|
146
|
+
/** Load the root bumpy config, merging with defaults */
|
|
147
|
+
declare function loadConfig(rootDir: string): Promise<BumpyConfig>;
|
|
148
|
+
/** Simple glob matching for package names (supports * and **) */
|
|
149
|
+
declare function matchGlob(name: string, pattern: string): boolean;
|
|
150
|
+
declare function getBumpyDir(rootDir: string): string;
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/utils/package-manager.d.ts
|
|
153
|
+
/** Map of catalog name → { depName → version }. Default catalog uses "" as key. */
|
|
154
|
+
type CatalogMap = Map<string, Record<string, string>>;
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/core/workspace.d.ts
|
|
157
|
+
/** Convenience wrapper that returns just packages (backwards compat) */
|
|
158
|
+
declare function discoverPackages(rootDir: string, config: BumpyConfig): Promise<Map<string, WorkspacePackage>>;
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/core/dep-graph.d.ts
|
|
161
|
+
declare class DependencyGraph {
|
|
162
|
+
/** Map from package name → packages that depend on it */
|
|
163
|
+
private dependents;
|
|
164
|
+
/** Set of all internal package names */
|
|
165
|
+
private internalPackages;
|
|
166
|
+
constructor(packages: Map<string, WorkspacePackage>);
|
|
167
|
+
private build;
|
|
168
|
+
/** Get all packages that depend on the given package */
|
|
169
|
+
getDependents(pkgName: string): DependentInfo[];
|
|
170
|
+
/** Check if a package is an internal workspace package */
|
|
171
|
+
isInternal(pkgName: string): boolean;
|
|
172
|
+
/** Get all internal package names */
|
|
173
|
+
allPackages(): string[];
|
|
174
|
+
/** Topological sort — returns packages in dependency order (deps first) */
|
|
175
|
+
topologicalSort(packages: Map<string, WorkspacePackage>): string[];
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/core/changeset.d.ts
|
|
179
|
+
/** Read all changeset files from .bumpy/ directory, sorted by git creation order */
|
|
180
|
+
declare function readChangesets(rootDir: string): Promise<Changeset[]>;
|
|
181
|
+
/** Parse changeset content (for testing) */
|
|
182
|
+
declare function parseChangeset(content: string, id: string): Changeset | null;
|
|
183
|
+
/** Write a changeset file */
|
|
184
|
+
declare function writeChangeset(rootDir: string, filename: string, releases: ChangesetRelease[], summary: string): Promise<string>;
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/core/release-plan.d.ts
|
|
187
|
+
/**
|
|
188
|
+
* Build a release plan from pending changesets, the dependency graph, and config.
|
|
189
|
+
* This is the core algorithm of bumpy.
|
|
190
|
+
*/
|
|
191
|
+
declare function assembleReleasePlan(changesets: Changeset[], packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig): ReleasePlan;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/core/apply-release-plan.d.ts
|
|
194
|
+
/** Apply the release plan: bump versions, update changelogs, delete changesets */
|
|
195
|
+
declare function applyReleasePlan(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, rootDir: string, config: BumpyConfig): Promise<void>;
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/core/changelog.d.ts
|
|
198
|
+
interface ChangelogContext {
|
|
199
|
+
release: PlannedRelease;
|
|
200
|
+
/** Changesets that contributed to this release */
|
|
201
|
+
changesets: Changeset[];
|
|
202
|
+
/** ISO date string (YYYY-MM-DD) */
|
|
203
|
+
date: string;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* A changelog formatter receives full context and returns the complete
|
|
207
|
+
* changelog entry string for a single release.
|
|
208
|
+
*/
|
|
209
|
+
type ChangelogFormatter = (ctx: ChangelogContext) => string | Promise<string>;
|
|
210
|
+
/** Default formatter — version heading, date, bullet points */
|
|
211
|
+
declare const defaultFormatter: ChangelogFormatter;
|
|
212
|
+
/**
|
|
213
|
+
* Load a changelog formatter from config.
|
|
214
|
+
* Supports: "default", "./path/to/formatter.ts", or a module name.
|
|
215
|
+
*/
|
|
216
|
+
declare function loadFormatter(changelog: BumpyConfig['changelog'], rootDir: string): Promise<ChangelogFormatter>;
|
|
217
|
+
/** Generate a changelog entry using the configured formatter */
|
|
218
|
+
declare function generateChangelogEntry(release: PlannedRelease, changesets: Changeset[], formatter?: ChangelogFormatter, date?: string): Promise<string>;
|
|
219
|
+
/** Prepend a new entry to an existing CHANGELOG.md content */
|
|
220
|
+
declare function prependToChangelog(existingContent: string, newEntry: string): string;
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/core/changelog-github.d.ts
|
|
223
|
+
interface GithubChangelogOptions {
|
|
224
|
+
/** "owner/repo" — auto-detected from gh CLI if not provided */
|
|
225
|
+
repo?: string;
|
|
226
|
+
/** GitHub usernames (without @) to skip "Thanks" messages for (e.g. internal team members) */
|
|
227
|
+
internalAuthors?: string[];
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/core/semver.d.ts
|
|
231
|
+
declare function bumpVersion(version: string, type: BumpType): string;
|
|
232
|
+
/** Check if a version satisfies a range */
|
|
233
|
+
declare function satisfies(version: string, range: string): boolean;
|
|
234
|
+
/** Strip workspace: protocol from version ranges */
|
|
235
|
+
declare function stripProtocol(range: string): string;
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/core/publish-pipeline.d.ts
|
|
238
|
+
interface PublishOptions {
|
|
239
|
+
dryRun?: boolean;
|
|
240
|
+
tag?: string;
|
|
241
|
+
}
|
|
242
|
+
interface PublishResult {
|
|
243
|
+
published: {
|
|
244
|
+
name: string;
|
|
245
|
+
version: string;
|
|
246
|
+
}[];
|
|
247
|
+
skipped: {
|
|
248
|
+
name: string;
|
|
249
|
+
reason: string;
|
|
250
|
+
}[];
|
|
251
|
+
failed: {
|
|
252
|
+
name: string;
|
|
253
|
+
error: string;
|
|
254
|
+
}[];
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Publish all packages in the release plan.
|
|
258
|
+
* Order: topological (dependencies published before dependents).
|
|
259
|
+
*/
|
|
260
|
+
declare function publishPackages(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig, rootDir: string, opts?: PublishOptions, catalogs?: CatalogMap, detectedPm?: PackageManager): Promise<PublishResult>;
|
|
261
|
+
//#endregion
|
|
262
|
+
export { BUMP_LEVELS, BumpType, BumpTypeWithIsolated, BumpyConfig, type ChangelogContext, type ChangelogFormatter, Changeset, ChangesetRelease, ChangesetReleaseCascade, ChangesetReleaseSimple, 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, parseChangeset, parseIsolatedBump, prependToChangelog, publishPackages, readChangesets, satisfies, stripProtocol, writeChangeset };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { a as loadConfig, c as BUMP_LEVELS, d as DEFAULT_PUBLISH_CONFIG, f as DEP_TYPES, g as parseIsolatedBump, 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-BkwIEaQg.mjs";
|
|
2
|
+
import { t as discoverPackages } from "./workspace-CxEKakDm.mjs";
|
|
3
|
+
import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
|
|
4
|
+
import { i as writeChangeset, n as parseChangeset, r as readChangesets } from "./changeset-UCZdSRDv.mjs";
|
|
5
|
+
import { n as satisfies, r as stripProtocol, t as bumpVersion } from "./semver-BTzYh8vc.mjs";
|
|
6
|
+
import { t as assembleReleasePlan } from "./release-plan-BEzwApuK.mjs";
|
|
7
|
+
import { a as prependToChangelog, i as loadFormatter, n as defaultFormatter, r as generateChangelogEntry, t as applyReleasePlan } from "./apply-release-plan-D6TSrcwX.mjs";
|
|
8
|
+
import { t as publishPackages } from "./publish-pipeline-ChnqW8nR.mjs";
|
|
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, parseChangeset, parseIsolatedBump, prependToChangelog, publishPackages, readChangesets, satisfies, stripProtocol, writeChangeset };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { n as log } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { c as writeJson, l as writeText, n as exists, t as ensureDir } from "./fs-0AtnPUUe.mjs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
//#region src/commands/init.ts
|
|
5
|
+
async function initCommand(rootDir) {
|
|
6
|
+
const bumpyDir = resolve(rootDir, ".bumpy");
|
|
7
|
+
if (await exists(resolve(bumpyDir, "_config.json"))) {
|
|
8
|
+
log.warn(".bumpy/_config.json already exists");
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
await ensureDir(bumpyDir);
|
|
12
|
+
await writeJson(resolve(bumpyDir, "_config.json"), {
|
|
13
|
+
baseBranch: "main",
|
|
14
|
+
changelog: "default"
|
|
15
|
+
});
|
|
16
|
+
await writeText(resolve(bumpyDir, "README.md"), `# 🐸 Bumpy\n\nThis directory is used by [bumpy](https://github.com/dmno-dev/bumpy) to manage versioning.\n\nChangeset files (\`.md\`) in this directory describe pending version bumps.\nRun \`bumpy add\` to create a new changeset.\n`);
|
|
17
|
+
log.success("Initialized .bumpy/ directory");
|
|
18
|
+
log.dim(" Created .bumpy/_config.json");
|
|
19
|
+
log.dim(" Created .bumpy/README.md");
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { initCommand };
|