@varlock/bumpy 0.0.2 → 1.1.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/.claude-plugin/plugin.json +2 -2
- package/config-schema.json +327 -0
- package/dist/add-BmNL5VwL.mjs +323 -0
- package/dist/{ai-CQhUyHAG.mjs → ai-sMYUf3lP.mjs} +21 -4
- package/dist/{apply-release-plan-D6TSrcwX.mjs → apply-release-plan-0kH62jhu.mjs} +35 -26
- package/dist/bump-file-DVqR3k67.mjs +157 -0
- package/dist/{changelog-github-Du62krXi.mjs → changelog-github-DkACMj0j.mjs} +23 -21
- package/dist/check-BjWF6SJm.mjs +65 -0
- package/dist/{ci-D6LQbR38.mjs → ci-DY58ugIi.mjs} +138 -91
- package/dist/{ci-setup-C6FlOfW5.mjs → ci-setup-BQwktQEe.mjs} +3 -3
- package/dist/cli.mjs +36 -41
- package/dist/commit-message-BwsowSds.mjs +23 -0
- package/dist/{config-BkwIEaQg.mjs → config-B-Qg3DZH.mjs} +30 -24
- package/dist/fs-DYR2XuFE.mjs +81 -0
- package/dist/generate-DX46X-rW.mjs +186 -0
- package/dist/{git-CGHVXXKw.mjs → git-YDedMddc.mjs} +54 -2
- package/dist/index.d.mts +68 -39
- package/dist/index.mjs +9 -9
- package/dist/init-DkTPs_WQ.mjs +196 -0
- package/dist/{names-Ck8cun7B.mjs → names-C-TuOPbd.mjs} +1 -1
- package/dist/{js-yaml-DpZfOoD4.mjs → package-manager-Clsmr-9r.mjs} +79 -1
- package/dist/picomatch-DMmqYjgq.mjs +1870 -0
- package/dist/{publish-D_7RqEYL.mjs → publish-CGB4TIKD.mjs} +26 -25
- package/dist/{publish-pipeline-ChnqW8nR.mjs → publish-pipeline-CXuqce1N.mjs} +24 -19
- package/dist/release-plan-JNir7bSM.mjs +264 -0
- package/dist/{semver-BTzYh8vc.mjs → semver-BJzWIuRz.mjs} +13 -3
- package/dist/{shell-Dj7JRD_q.mjs → shell-CY7OD48z.mjs} +20 -2
- package/dist/{status--Q8yAxQ4.mjs → status-EGYqULJg.mjs} +26 -22
- package/dist/{version-cAUkfYPx.mjs → version-BcfidiVX.mjs} +23 -22
- package/dist/{workspace-CxEKakDm.mjs → workspace-DWXlwcH4.mjs} +3 -3
- package/package.json +16 -1
- package/skills/add-change/SKILL.md +18 -14
- package/dist/add-BjyVIUlr.mjs +0 -175
- package/dist/changeset-UCZdSRDv.mjs +0 -108
- package/dist/check-jIwike9F.mjs +0 -51
- package/dist/fs-0AtnPUUe.mjs +0 -51
- package/dist/generate-Btrsn1qi.mjs +0 -177
- package/dist/init-B0q3wEQW.mjs +0 -22
- package/dist/migrate-CfQNwD0T.mjs +0 -121
- package/dist/package-manager-DcI5TdDE.mjs +0 -80
- package/dist/release-plan-BEzwApuK.mjs +0 -173
- /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/index.d.mts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
2
|
type BumpType = 'major' | 'minor' | 'patch';
|
|
3
|
-
type
|
|
3
|
+
type BumpTypeWithNone = BumpType | 'none';
|
|
4
4
|
declare const BUMP_LEVELS: Record<BumpType, number>;
|
|
5
5
|
declare function bumpLevel(type: BumpType): number;
|
|
6
|
-
declare function parseIsolatedBump(type: BumpTypeWithIsolated): {
|
|
7
|
-
bump: BumpType;
|
|
8
|
-
isolated: boolean;
|
|
9
|
-
};
|
|
10
6
|
declare function maxBump(a: BumpType | undefined, b: BumpType): BumpType;
|
|
11
7
|
interface DependencyBumpRule {
|
|
12
8
|
/** What bump level in the dependency triggers propagation */
|
|
13
|
-
trigger: BumpType
|
|
9
|
+
trigger: BumpType;
|
|
14
10
|
/** What bump to apply to the dependent */
|
|
15
11
|
bumpAs: BumpType | 'match';
|
|
16
12
|
}
|
|
17
|
-
declare const DEFAULT_BUMP_RULES: Record<string, DependencyBumpRule>;
|
|
13
|
+
declare const DEFAULT_BUMP_RULES: Record<string, DependencyBumpRule | false>;
|
|
18
14
|
type DepType = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies';
|
|
19
15
|
declare const DEP_TYPES: DepType[];
|
|
20
16
|
interface PublishConfig {
|
|
@@ -36,20 +32,39 @@ interface PublishConfig {
|
|
|
36
32
|
interface BumpyConfig {
|
|
37
33
|
baseBranch: string;
|
|
38
34
|
access: 'public' | 'restricted';
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Customize the commit message used when versioning.
|
|
37
|
+
* A string starting with "./" is treated as a path to a module that exports
|
|
38
|
+
* a function receiving the release plan and returning a message string.
|
|
39
|
+
* Any other string is used as a static commit message.
|
|
40
|
+
* Omit to use the default: "Version packages\n\npkg@version..."
|
|
41
|
+
*/
|
|
42
|
+
versionCommitMessage?: string;
|
|
43
|
+
changelog: false | string | [string, Record<string, unknown>];
|
|
41
44
|
fixed: string[][];
|
|
42
45
|
linked: string[][];
|
|
46
|
+
/** Glob patterns to filter which changed files count toward marking a package as changed */
|
|
47
|
+
changedFilePatterns: string[];
|
|
43
48
|
/** Package names/globs to exclude from version management */
|
|
44
49
|
ignore: string[];
|
|
45
50
|
/** Package names/globs to explicitly include (overrides private + ignore) */
|
|
46
51
|
include: string[];
|
|
47
|
-
updateInternalDependencies: 'patch' | 'minor' | 'out-of-range'
|
|
48
|
-
dependencyBumpRules: Partial<Record<DepType, DependencyBumpRule>>;
|
|
52
|
+
updateInternalDependencies: 'patch' | 'minor' | 'out-of-range';
|
|
53
|
+
dependencyBumpRules: Partial<Record<DepType, DependencyBumpRule | false>>;
|
|
49
54
|
privatePackages: {
|
|
50
55
|
version: boolean;
|
|
51
56
|
tag: boolean;
|
|
52
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Allow per-package custom commands (buildCommand, publishCommand, checkPublished)
|
|
60
|
+
* defined in package.json "bumpy" fields.
|
|
61
|
+
* Commands defined in the root config's `packages` map are always trusted.
|
|
62
|
+
*
|
|
63
|
+
* true = allow all packages to define custom commands
|
|
64
|
+
* string[] = allow only matching package names/globs
|
|
65
|
+
* false = only root-config commands are allowed (default)
|
|
66
|
+
*/
|
|
67
|
+
allowCustomCommands: boolean | string[];
|
|
53
68
|
packages: Record<string, PackageConfig>;
|
|
54
69
|
publish: PublishConfig;
|
|
55
70
|
/**
|
|
@@ -84,26 +99,27 @@ interface PackageConfig {
|
|
|
84
99
|
skipNpmPublish?: boolean;
|
|
85
100
|
/** Command to check if a version is already published. Should output the published version string. */
|
|
86
101
|
checkPublished?: string;
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
/** Glob patterns to filter which changed files count toward marking this package as changed */
|
|
103
|
+
changedFilePatterns?: string[];
|
|
104
|
+
dependencyBumpRules?: Partial<Record<DepType, DependencyBumpRule | false>>;
|
|
89
105
|
cascadeTo?: Record<string, DependencyBumpRule>;
|
|
90
106
|
}
|
|
91
107
|
declare const DEFAULT_PUBLISH_CONFIG: PublishConfig;
|
|
92
108
|
declare const DEFAULT_CONFIG: BumpyConfig;
|
|
93
|
-
interface
|
|
109
|
+
interface BumpFileReleaseSimple {
|
|
94
110
|
name: string;
|
|
95
|
-
type:
|
|
111
|
+
type: BumpTypeWithNone;
|
|
96
112
|
}
|
|
97
|
-
interface
|
|
113
|
+
interface BumpFileReleaseCascade {
|
|
98
114
|
name: string;
|
|
99
|
-
type:
|
|
115
|
+
type: BumpTypeWithNone;
|
|
100
116
|
cascade: Record<string, BumpType>;
|
|
101
117
|
}
|
|
102
|
-
type
|
|
103
|
-
declare function hasCascade(r:
|
|
104
|
-
interface
|
|
118
|
+
type BumpFileRelease = BumpFileReleaseSimple | BumpFileReleaseCascade;
|
|
119
|
+
declare function hasCascade(r: BumpFileRelease): r is BumpFileReleaseCascade;
|
|
120
|
+
interface BumpFile {
|
|
105
121
|
id: string;
|
|
106
|
-
releases:
|
|
122
|
+
releases: BumpFileRelease[];
|
|
107
123
|
summary: string;
|
|
108
124
|
}
|
|
109
125
|
interface WorkspacePackage {
|
|
@@ -131,13 +147,14 @@ interface PlannedRelease {
|
|
|
131
147
|
type: BumpType;
|
|
132
148
|
oldVersion: string;
|
|
133
149
|
newVersion: string;
|
|
134
|
-
|
|
150
|
+
bumpFiles: string[];
|
|
135
151
|
isDependencyBump: boolean;
|
|
136
152
|
isCascadeBump: boolean;
|
|
137
153
|
}
|
|
138
154
|
interface ReleasePlan {
|
|
139
|
-
|
|
155
|
+
bumpFiles: BumpFile[];
|
|
140
156
|
releases: PlannedRelease[];
|
|
157
|
+
warnings: string[];
|
|
141
158
|
}
|
|
142
159
|
//#endregion
|
|
143
160
|
//#region src/core/config.d.ts
|
|
@@ -175,30 +192,35 @@ declare class DependencyGraph {
|
|
|
175
192
|
topologicalSort(packages: Map<string, WorkspacePackage>): string[];
|
|
176
193
|
}
|
|
177
194
|
//#endregion
|
|
178
|
-
//#region src/core/
|
|
179
|
-
/** Read all
|
|
180
|
-
declare function
|
|
181
|
-
/** Parse
|
|
182
|
-
declare function
|
|
183
|
-
/** Write a
|
|
184
|
-
declare function
|
|
195
|
+
//#region src/core/bump-file.d.ts
|
|
196
|
+
/** Read all bump files from .bumpy/ directory, sorted by git creation order */
|
|
197
|
+
declare function readBumpFiles(rootDir: string): Promise<BumpFile[]>;
|
|
198
|
+
/** Parse bump file content (for testing) */
|
|
199
|
+
declare function parseBumpFile(content: string, id: string): BumpFile | null;
|
|
200
|
+
/** Write a bump file */
|
|
201
|
+
declare function writeBumpFile(rootDir: string, filename: string, releases: BumpFileRelease[], summary: string): Promise<string>;
|
|
185
202
|
//#endregion
|
|
186
203
|
//#region src/core/release-plan.d.ts
|
|
187
204
|
/**
|
|
188
|
-
* Build a release plan from pending
|
|
205
|
+
* Build a release plan from pending bump files, the dependency graph, and config.
|
|
189
206
|
* This is the core algorithm of bumpy.
|
|
207
|
+
*
|
|
208
|
+
* The propagation loop runs three phases until stable:
|
|
209
|
+
* Phase A — fix out-of-range dependencies (always runs)
|
|
210
|
+
* Phase B — enforce fixed/linked group constraints
|
|
211
|
+
* Phase C — apply cascades and proactive propagation rules
|
|
190
212
|
*/
|
|
191
|
-
declare function assembleReleasePlan(
|
|
213
|
+
declare function assembleReleasePlan(bumpFiles: BumpFile[], packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig): ReleasePlan;
|
|
192
214
|
//#endregion
|
|
193
215
|
//#region src/core/apply-release-plan.d.ts
|
|
194
|
-
/** Apply the release plan: bump versions, update changelogs, delete
|
|
216
|
+
/** Apply the release plan: bump versions, update changelogs, delete bump files */
|
|
195
217
|
declare function applyReleasePlan(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, rootDir: string, config: BumpyConfig): Promise<void>;
|
|
196
218
|
//#endregion
|
|
197
219
|
//#region src/core/changelog.d.ts
|
|
198
220
|
interface ChangelogContext {
|
|
199
221
|
release: PlannedRelease;
|
|
200
|
-
/**
|
|
201
|
-
|
|
222
|
+
/** Bump files that contributed to this release */
|
|
223
|
+
bumpFiles: BumpFile[];
|
|
202
224
|
/** ISO date string (YYYY-MM-DD) */
|
|
203
225
|
date: string;
|
|
204
226
|
}
|
|
@@ -215,7 +237,7 @@ declare const defaultFormatter: ChangelogFormatter;
|
|
|
215
237
|
*/
|
|
216
238
|
declare function loadFormatter(changelog: BumpyConfig['changelog'], rootDir: string): Promise<ChangelogFormatter>;
|
|
217
239
|
/** Generate a changelog entry using the configured formatter */
|
|
218
|
-
declare function generateChangelogEntry(release: PlannedRelease,
|
|
240
|
+
declare function generateChangelogEntry(release: PlannedRelease, bumpFiles: BumpFile[], formatter?: ChangelogFormatter, date?: string): Promise<string>;
|
|
219
241
|
/** Prepend a new entry to an existing CHANGELOG.md content */
|
|
220
242
|
declare function prependToChangelog(existingContent: string, newEntry: string): string;
|
|
221
243
|
//#endregion
|
|
@@ -223,14 +245,21 @@ declare function prependToChangelog(existingContent: string, newEntry: string):
|
|
|
223
245
|
interface GithubChangelogOptions {
|
|
224
246
|
/** "owner/repo" — auto-detected from gh CLI if not provided */
|
|
225
247
|
repo?: string;
|
|
248
|
+
/** Whether to include "Thanks @user" messages for contributors (default: true) */
|
|
249
|
+
thankContributors?: boolean;
|
|
226
250
|
/** GitHub usernames (without @) to skip "Thanks" messages for (e.g. internal team members) */
|
|
227
251
|
internalAuthors?: string[];
|
|
228
252
|
}
|
|
229
253
|
//#endregion
|
|
230
254
|
//#region src/core/semver.d.ts
|
|
231
255
|
declare function bumpVersion(version: string, type: BumpType): string;
|
|
232
|
-
/**
|
|
233
|
-
|
|
256
|
+
/**
|
|
257
|
+
* Check if a version satisfies a range.
|
|
258
|
+
* @param version - The version to check
|
|
259
|
+
* @param range - The version range (may include workspace: or catalog: protocol)
|
|
260
|
+
* @param currentVersion - The dependency's current version, used to resolve workspace:^ and workspace:~
|
|
261
|
+
*/
|
|
262
|
+
declare function satisfies(version: string, range: string, currentVersion?: string): boolean;
|
|
234
263
|
/** Strip workspace: protocol from version ranges */
|
|
235
264
|
declare function stripProtocol(range: string): string;
|
|
236
265
|
//#endregion
|
|
@@ -259,4 +288,4 @@ interface PublishResult {
|
|
|
259
288
|
*/
|
|
260
289
|
declare function publishPackages(releasePlan: ReleasePlan, packages: Map<string, WorkspacePackage>, depGraph: DependencyGraph, config: BumpyConfig, rootDir: string, opts?: PublishOptions, catalogs?: CatalogMap, detectedPm?: PackageManager): Promise<PublishResult>;
|
|
261
290
|
//#endregion
|
|
262
|
-
export { BUMP_LEVELS, BumpType,
|
|
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as loadConfig, c as BUMP_LEVELS, d as DEFAULT_PUBLISH_CONFIG, f as DEP_TYPES,
|
|
2
|
-
import { t as discoverPackages } from "./workspace-
|
|
3
|
-
import { t as DependencyGraph } from "./dep-graph-
|
|
4
|
-
import { i as
|
|
5
|
-
import { n as satisfies, r as stripProtocol, t as bumpVersion } from "./semver-
|
|
6
|
-
import { t as assembleReleasePlan } from "./release-plan-
|
|
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-
|
|
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,
|
|
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-B-Qg3DZH.mjs";
|
|
2
|
+
import { t as discoverPackages } from "./workspace-DWXlwcH4.mjs";
|
|
3
|
+
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
4
|
+
import { i as writeBumpFile, n as parseBumpFile, r as readBumpFiles } from "./bump-file-DVqR3k67.mjs";
|
|
5
|
+
import { n as satisfies, r as stripProtocol, t as bumpVersion } from "./semver-BJzWIuRz.mjs";
|
|
6
|
+
import { t as assembleReleasePlan } from "./release-plan-JNir7bSM.mjs";
|
|
7
|
+
import { a as prependToChangelog, i as loadFormatter, n as defaultFormatter, r as generateChangelogEntry, t as applyReleasePlan } from "./apply-release-plan-0kH62jhu.mjs";
|
|
8
|
+
import { t as publishPackages } from "./publish-pipeline-CXuqce1N.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, parseBumpFile, prependToChangelog, publishPackages, readBumpFiles, satisfies, stripProtocol, writeBumpFile };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { a as readJson, d as writeText, i as listFiles, n as exists, o as readText, t as ensureDir, u as writeJson } from "./fs-DYR2XuFE.mjs";
|
|
3
|
+
import { t as detectPackageManager } from "./package-manager-Clsmr-9r.mjs";
|
|
4
|
+
import { t as run } from "./shell-CY7OD48z.mjs";
|
|
5
|
+
import { c as ot, o as gt, s as mt, t as unwrap } from "./clack-C6bVkGxf.mjs";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import { readdir, rename, rm } from "node:fs/promises";
|
|
8
|
+
//#region ../../.bumpy/README.md
|
|
9
|
+
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
10
|
+
var README_default = "# 🐸 Bumpy\n\nThis directory is used by [bumpy](https://bumpy.varlock.dev) to manage versioning and changelogs.\n\nBumpy is a modern versioning tool for JavaScript/TypeScript projects (monorepos and single packages). It uses **bump files** — small markdown files in this directory — to declare pending version changes. These files are consumed during the release process to compute version bumps, update changelogs, and publish packages.\n\n## How it works\n\n1. When you make a change that should trigger a release, create a bump file (typically one per PR)\n2. Bump files accumulate on your main branch until you're ready to release\n3. At release time, bumpy merges all pending bumps into a release plan, updates versions and changelogs, and publishes packages\n\n## Creating bump files\n\n### Interactive\n\n```bash\nbunx bumpy add\n```\n\n### Non-interactive (useful for AI-assisted development)\n\n```bash\nbunx bumpy add --packages \"package-name:minor,other-package:patch\" --message \"Description of changes\" --name \"my-change\"\n```\n\n### By hand\n\nCreate a `.md` file in this directory with YAML frontmatter mapping package names to bump levels (`major`, `minor`, or `patch`), and a markdown body for the changelog entry:\n\n```markdown\n---\n'package-name': minor\n---\n\nAdded a new feature.\n```\n\n### From conventional commits\n\n```bash\nbunx bumpy generate\n```\n\n### Empty bump files\n\nFor PRs that intentionally don't need a release (docs, CI, etc.):\n\n```bash\nbunx bumpy add --empty --name \"docs-update\"\n```\n\n## Keeping bump files up to date\n\nAs a PR evolves, make sure its bump file stays in sync. If the scope of changes grows (e.g., a patch becomes a new feature), update the bump level and description to match. Reviewers and AI assistants should treat the bump file as part of the PR — just like tests and docs.\n\n## Files in this directory\n\n- `_config.json` — bumpy configuration\n- `README.md` — this file\n- `*.md` (other than README.md) — pending bump files\n\n📖 Full documentation: https://bumpy.varlock.dev\n";
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/commands/init.ts
|
|
13
|
+
const PM_RUNNER = {
|
|
14
|
+
bun: "bunx bumpy",
|
|
15
|
+
pnpm: "pnpm bumpy",
|
|
16
|
+
yarn: "yarn bumpy",
|
|
17
|
+
npm: "npx bumpy"
|
|
18
|
+
};
|
|
19
|
+
const PM_ADD_DEV = {
|
|
20
|
+
bun: "bun add -d",
|
|
21
|
+
pnpm: "pnpm add -Dw",
|
|
22
|
+
yarn: "yarn add -D -W",
|
|
23
|
+
npm: "npm install -D"
|
|
24
|
+
};
|
|
25
|
+
const PM_REMOVE = {
|
|
26
|
+
bun: "bun remove",
|
|
27
|
+
pnpm: "pnpm remove -w",
|
|
28
|
+
yarn: "yarn remove -W",
|
|
29
|
+
npm: "npm uninstall"
|
|
30
|
+
};
|
|
31
|
+
async function initCommand(rootDir, opts = {}) {
|
|
32
|
+
const bumpyDir = resolve(rootDir, ".bumpy");
|
|
33
|
+
const changesetDir = resolve(rootDir, ".changeset");
|
|
34
|
+
const hasChangeset = await exists(changesetDir);
|
|
35
|
+
if (await exists(resolve(bumpyDir, "_config.json"))) {
|
|
36
|
+
log.info("🐸 Detected .bumpy/ directory - looks like we're ready to go!");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const pm = await detectPackageManager(rootDir);
|
|
40
|
+
if (!opts.force) mt(import_picocolors.default.bgCyan(import_picocolors.default.black(" bumpy init ")));
|
|
41
|
+
if (hasChangeset) {
|
|
42
|
+
log.step("🦋 Detected .changeset/ directory — migrating to .bumpy/ 🐸");
|
|
43
|
+
await rename(changesetDir, bumpyDir);
|
|
44
|
+
log.dim(" Renamed .changeset/ → .bumpy/");
|
|
45
|
+
const oldConfigPath = resolve(bumpyDir, "config.json");
|
|
46
|
+
if (await exists(oldConfigPath)) {
|
|
47
|
+
const bumpyConfig = migrateChangesetConfig(await readJson(oldConfigPath));
|
|
48
|
+
await writeJson(resolve(bumpyDir, "_config.json"), bumpyConfig);
|
|
49
|
+
await rm(oldConfigPath);
|
|
50
|
+
log.dim(" Migrated config.json → _config.json");
|
|
51
|
+
const migratedFields = Object.keys(bumpyConfig).filter((k) => k !== "$schema");
|
|
52
|
+
if (migratedFields.length > 0) log.dim(" Migrated fields: " + migratedFields.join(", "));
|
|
53
|
+
} else await writeJson(resolve(bumpyDir, "_config.json"), makeDefaultConfig());
|
|
54
|
+
const readmeContent = README_default.replaceAll("bunx bumpy", PM_RUNNER[pm] || "npx bumpy");
|
|
55
|
+
await writeText(resolve(bumpyDir, "README.md"), readmeContent);
|
|
56
|
+
log.dim(" Replaced README.md");
|
|
57
|
+
const pendingFiles = (await readdir(bumpyDir)).filter((f) => f.endsWith(".md") && f !== "README.md");
|
|
58
|
+
if (pendingFiles.length > 0) log.dim(` Kept ${pendingFiles.length} pending bump file(s)`);
|
|
59
|
+
if (await isPackageInstalled(rootDir, "@changesets/cli")) {
|
|
60
|
+
if (opts.force) await uninstallPackage(pm, "@changesets/cli", rootDir);
|
|
61
|
+
else if (unwrap(await ot({
|
|
62
|
+
message: "Uninstall @changesets/cli?",
|
|
63
|
+
initialValue: true
|
|
64
|
+
}))) await uninstallPackage(pm, "@changesets/cli", rootDir);
|
|
65
|
+
}
|
|
66
|
+
await warnChangesetWorkflows(rootDir, pm);
|
|
67
|
+
} else {
|
|
68
|
+
await ensureDir(bumpyDir);
|
|
69
|
+
await writeJson(resolve(bumpyDir, "_config.json"), makeDefaultConfig());
|
|
70
|
+
const readmeContent = README_default.replaceAll("bunx bumpy", PM_RUNNER[pm] || "npx bumpy");
|
|
71
|
+
await writeText(resolve(bumpyDir, "README.md"), readmeContent);
|
|
72
|
+
log.success("Initialized .bumpy/ directory");
|
|
73
|
+
log.dim(" Created .bumpy/_config.json");
|
|
74
|
+
log.dim(" Created .bumpy/README.md");
|
|
75
|
+
}
|
|
76
|
+
if (!await isPackageInstalled(rootDir, "@varlock/bumpy")) {
|
|
77
|
+
if (opts.force) await installPackage(pm, "@varlock/bumpy", rootDir);
|
|
78
|
+
else if (unwrap(await ot({
|
|
79
|
+
message: "Install @varlock/bumpy as a dev dependency?",
|
|
80
|
+
initialValue: true
|
|
81
|
+
}))) await installPackage(pm, "@varlock/bumpy", rootDir);
|
|
82
|
+
}
|
|
83
|
+
if (!opts.force) gt(import_picocolors.default.green("bumpy is ready!"));
|
|
84
|
+
else if (hasChangeset) log.success("Migration complete!");
|
|
85
|
+
}
|
|
86
|
+
function makeDefaultConfig() {
|
|
87
|
+
return {
|
|
88
|
+
$schema: "../node_modules/@varlock/bumpy/config-schema.json",
|
|
89
|
+
baseBranch: "main",
|
|
90
|
+
changelog: "default"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function migrateChangesetConfig(csConfig) {
|
|
94
|
+
const bumpyConfig = makeDefaultConfig();
|
|
95
|
+
for (const field of [
|
|
96
|
+
"baseBranch",
|
|
97
|
+
"access",
|
|
98
|
+
"fixed",
|
|
99
|
+
"linked",
|
|
100
|
+
"ignore",
|
|
101
|
+
"updateInternalDependencies",
|
|
102
|
+
"privatePackages"
|
|
103
|
+
]) if (csConfig[field] !== void 0) bumpyConfig[field] = csConfig[field];
|
|
104
|
+
return bumpyConfig;
|
|
105
|
+
}
|
|
106
|
+
async function isPackageInstalled(rootDir, pkgName) {
|
|
107
|
+
try {
|
|
108
|
+
const pkg = await readJson(resolve(rootDir, "package.json"));
|
|
109
|
+
return !!(pkg.devDependencies?.[pkgName] || pkg.dependencies?.[pkgName]);
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function installPackage(pm, pkgName, rootDir) {
|
|
115
|
+
const cmd = `${PM_ADD_DEV[pm] || "npm install -D"} ${pkgName}`;
|
|
116
|
+
log.step(`Installing ${pkgName}...`);
|
|
117
|
+
try {
|
|
118
|
+
run(cmd, { cwd: rootDir });
|
|
119
|
+
log.dim(` ${cmd}`);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
log.warn(`Failed to install ${pkgName}: ${err instanceof Error ? err.message : err}`);
|
|
122
|
+
log.dim(` Run manually: ${cmd}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function uninstallPackage(pm, pkgName, rootDir) {
|
|
126
|
+
const cmd = `${PM_REMOVE[pm] || "npm uninstall"} ${pkgName}`;
|
|
127
|
+
log.step(`Uninstalling ${pkgName}...`);
|
|
128
|
+
try {
|
|
129
|
+
run(cmd, { cwd: rootDir });
|
|
130
|
+
log.dim(` ${cmd}`);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
log.warn(`Failed to uninstall ${pkgName}: ${err instanceof Error ? err.message : err}`);
|
|
133
|
+
log.dim(` Run manually: ${cmd}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Patterns to detect in workflow files, with suggested replacements */
|
|
137
|
+
const CHANGESET_PATTERNS = [
|
|
138
|
+
{
|
|
139
|
+
pattern: /changesets\/action/,
|
|
140
|
+
replacement: "see https://bumpy.varlock.dev/ci for bumpy CI setup"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
pattern: /changeset publish/,
|
|
144
|
+
replacement: "bumpy publish"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
pattern: /changeset version/,
|
|
148
|
+
replacement: "bumpy version"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
pattern: /changeset status/,
|
|
152
|
+
replacement: "bumpy status"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
pattern: /@changesets\//,
|
|
156
|
+
replacement: "replace with @varlock/bumpy"
|
|
157
|
+
}
|
|
158
|
+
];
|
|
159
|
+
async function warnChangesetWorkflows(rootDir, pm) {
|
|
160
|
+
const workflowDir = resolve(rootDir, ".github", "workflows");
|
|
161
|
+
if (!await exists(workflowDir)) return;
|
|
162
|
+
const yamlFiles = (await listFiles(workflowDir)).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
163
|
+
if (yamlFiles.length === 0) return;
|
|
164
|
+
const runner = PM_RUNNER[pm] || "npx bumpy";
|
|
165
|
+
const hits = [];
|
|
166
|
+
for (const file of yamlFiles) {
|
|
167
|
+
const lines = (await readText(resolve(workflowDir, file))).split("\n");
|
|
168
|
+
const fileMatches = [];
|
|
169
|
+
for (let i = 0; i < lines.length; i++) {
|
|
170
|
+
const line = lines[i];
|
|
171
|
+
for (const { pattern, replacement } of CHANGESET_PATTERNS) {
|
|
172
|
+
const match = line.match(pattern);
|
|
173
|
+
if (match) fileMatches.push({
|
|
174
|
+
line: i + 1,
|
|
175
|
+
found: match[0],
|
|
176
|
+
suggestion: replacement
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (fileMatches.length > 0) hits.push({
|
|
181
|
+
file,
|
|
182
|
+
matches: fileMatches
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (hits.length === 0) return;
|
|
186
|
+
console.log();
|
|
187
|
+
log.warn("Found changeset references in GitHub workflows:");
|
|
188
|
+
for (const { file, matches } of hits) {
|
|
189
|
+
log.dim(` .github/workflows/${file}`);
|
|
190
|
+
for (const { line, found, suggestion } of matches) log.dim(` L${line}: ${import_picocolors.default.red(found)} → ${import_picocolors.default.green(suggestion)}`);
|
|
191
|
+
}
|
|
192
|
+
console.log();
|
|
193
|
+
log.dim(` Run ${import_picocolors.default.cyan(`${runner} ci setup`)} for help configuring CI workflows.`);
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
export { initCommand };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/utils/names.ts
|
|
2
|
-
/** Generate a random adjective-noun name for
|
|
2
|
+
/** Generate a random adjective-noun name for bump files */
|
|
3
3
|
function randomName() {
|
|
4
4
|
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
5
5
|
return `${pick(ADJECTIVES)}-${pick(ADJECTIVES)}-${pick(NOUNS)}`;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { a as readJson, n as exists, o as readText } from "./fs-DYR2XuFE.mjs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
1
3
|
//#region ../../node_modules/.bun/js-yaml@4.1.1/node_modules/js-yaml/dist/js-yaml.mjs
|
|
2
4
|
/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
|
|
3
5
|
function isNothing(subject) {
|
|
@@ -2028,4 +2030,80 @@ var jsYaml = {
|
|
|
2028
2030
|
safeDump: renamed("safeDump", "dump")
|
|
2029
2031
|
};
|
|
2030
2032
|
//#endregion
|
|
2031
|
-
|
|
2033
|
+
//#region src/utils/package-manager.ts
|
|
2034
|
+
/** Detect the package manager, extract workspace globs, and load catalogs */
|
|
2035
|
+
async function detectWorkspaces(rootDir) {
|
|
2036
|
+
const pm = await detectPackageManager(rootDir);
|
|
2037
|
+
return {
|
|
2038
|
+
packageManager: pm,
|
|
2039
|
+
globs: await getWorkspaceGlobs(rootDir, pm),
|
|
2040
|
+
catalogs: await loadCatalogs(rootDir, pm)
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
async function detectPackageManager(rootDir) {
|
|
2044
|
+
if (await exists(resolve(rootDir, "bun.lock")) || await exists(resolve(rootDir, "bun.lockb"))) return "bun";
|
|
2045
|
+
if (await exists(resolve(rootDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
2046
|
+
if (await exists(resolve(rootDir, "yarn.lock"))) return "yarn";
|
|
2047
|
+
try {
|
|
2048
|
+
const pkg = await readJson(resolve(rootDir, "package.json"));
|
|
2049
|
+
if (typeof pkg.packageManager === "string") {
|
|
2050
|
+
const name = pkg.packageManager.split("@")[0];
|
|
2051
|
+
if (name === "pnpm" || name === "yarn" || name === "bun") return name;
|
|
2052
|
+
}
|
|
2053
|
+
} catch {}
|
|
2054
|
+
return "npm";
|
|
2055
|
+
}
|
|
2056
|
+
async function getWorkspaceGlobs(rootDir, pm) {
|
|
2057
|
+
if (pm === "pnpm") {
|
|
2058
|
+
const wsFile = resolve(rootDir, "pnpm-workspace.yaml");
|
|
2059
|
+
if (await exists(wsFile)) {
|
|
2060
|
+
const content = await readText(wsFile);
|
|
2061
|
+
const parsed = jsYaml.load(content);
|
|
2062
|
+
if (parsed?.packages) return parsed.packages;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
try {
|
|
2066
|
+
const workspaces = (await readJson(resolve(rootDir, "package.json"))).workspaces;
|
|
2067
|
+
if (Array.isArray(workspaces)) return workspaces;
|
|
2068
|
+
if (workspaces && typeof workspaces === "object" && "packages" in workspaces) {
|
|
2069
|
+
const pkgs = workspaces.packages;
|
|
2070
|
+
if (Array.isArray(pkgs)) return pkgs;
|
|
2071
|
+
}
|
|
2072
|
+
} catch {}
|
|
2073
|
+
return [];
|
|
2074
|
+
}
|
|
2075
|
+
/** Load catalog definitions from pnpm-workspace.yaml or root package.json */
|
|
2076
|
+
async function loadCatalogs(rootDir, pm) {
|
|
2077
|
+
const catalogs = /* @__PURE__ */ new Map();
|
|
2078
|
+
if (pm === "pnpm") {
|
|
2079
|
+
const wsFile = resolve(rootDir, "pnpm-workspace.yaml");
|
|
2080
|
+
if (await exists(wsFile)) {
|
|
2081
|
+
const content = await readText(wsFile);
|
|
2082
|
+
const parsed = jsYaml.load(content);
|
|
2083
|
+
if (parsed?.catalog) catalogs.set("", parsed.catalog);
|
|
2084
|
+
if (parsed?.catalogs) for (const [name, deps] of Object.entries(parsed.catalogs)) catalogs.set(name, deps);
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
try {
|
|
2088
|
+
const pkg = await readJson(resolve(rootDir, "package.json"));
|
|
2089
|
+
if (pkg.catalog && typeof pkg.catalog === "object") catalogs.set("", pkg.catalog);
|
|
2090
|
+
if (pkg.catalogs && typeof pkg.catalogs === "object") for (const [name, deps] of Object.entries(pkg.catalogs)) catalogs.set(name, deps);
|
|
2091
|
+
const workspaces = pkg.workspaces;
|
|
2092
|
+
if (workspaces && typeof workspaces === "object" && !Array.isArray(workspaces)) {
|
|
2093
|
+
const ws = workspaces;
|
|
2094
|
+
if (ws.catalog && typeof ws.catalog === "object") catalogs.set("", ws.catalog);
|
|
2095
|
+
if (ws.catalogs && typeof ws.catalogs === "object") for (const [name, deps] of Object.entries(ws.catalogs)) catalogs.set(name, deps);
|
|
2096
|
+
}
|
|
2097
|
+
} catch {}
|
|
2098
|
+
return catalogs;
|
|
2099
|
+
}
|
|
2100
|
+
/** Resolve a specific dependency's catalog: reference */
|
|
2101
|
+
function resolveCatalogDep(depName, range, catalogs) {
|
|
2102
|
+
if (!range.startsWith("catalog:")) return null;
|
|
2103
|
+
const catalogName = range.slice(8).trim() || "";
|
|
2104
|
+
const catalog = catalogs.get(catalogName);
|
|
2105
|
+
if (!catalog) return null;
|
|
2106
|
+
return catalog[depName] ?? null;
|
|
2107
|
+
}
|
|
2108
|
+
//#endregion
|
|
2109
|
+
export { jsYaml as i, detectWorkspaces as n, resolveCatalogDep as r, detectPackageManager as t };
|