@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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bumpy",
|
|
3
3
|
"version": "0.0.1",
|
|
4
|
-
"description": "AI-assisted
|
|
4
|
+
"description": "AI-assisted bump file creation for bumpy monorepo versioning",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "DMNO",
|
|
7
7
|
"url": "https://github.com/dmno-dev"
|
|
8
8
|
},
|
|
9
9
|
"repository": "https://github.com/dmno-dev/bumpy",
|
|
10
10
|
"license": "MIT",
|
|
11
|
-
"keywords": ["monorepo", "versioning", "changelog", "
|
|
11
|
+
"keywords": ["monorepo", "versioning", "changelog", "bump-files"],
|
|
12
12
|
"skills": "./skills/"
|
|
13
13
|
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/dmno-dev/bumpy/main/packages/bumpy/config-schema.json",
|
|
4
|
+
"title": "Bumpy Configuration",
|
|
5
|
+
"description": "Configuration for @varlock/bumpy — monorepo versioning and changelog tool",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Path or URL to the JSON schema"
|
|
11
|
+
},
|
|
12
|
+
"baseBranch": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Branch used for release comparisons",
|
|
15
|
+
"default": "main"
|
|
16
|
+
},
|
|
17
|
+
"access": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["public", "restricted"],
|
|
20
|
+
"description": "Default npm publish access level",
|
|
21
|
+
"default": "public"
|
|
22
|
+
},
|
|
23
|
+
"versionCommitMessage": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Customize the commit message used when versioning. A plain string is used as-is. A path starting with \"./\" or \"../\" is loaded as a module that exports a function receiving the release plan and returning a message string."
|
|
26
|
+
},
|
|
27
|
+
"changelog": {
|
|
28
|
+
"description": "Changelog formatter — \"default\", \"github\", or path to a custom formatter. Can also be a tuple of [formatter, options]. Set to false to disable changelog generation.",
|
|
29
|
+
"default": "default",
|
|
30
|
+
"oneOf": [
|
|
31
|
+
{ "type": "boolean", "const": false },
|
|
32
|
+
{ "type": "string" },
|
|
33
|
+
{
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": [{ "type": "string" }, { "type": "object" }],
|
|
36
|
+
"minItems": 2,
|
|
37
|
+
"maxItems": 2
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"changedFilePatterns": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"description": "Glob patterns to filter which changed files count toward marking a package as changed. Can be overridden per-package.",
|
|
44
|
+
"items": { "type": "string" },
|
|
45
|
+
"default": ["**"]
|
|
46
|
+
},
|
|
47
|
+
"fixed": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"description": "Package groups that always bump together to the same version. Each element is an array of package name globs.",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "array",
|
|
52
|
+
"items": { "type": "string" }
|
|
53
|
+
},
|
|
54
|
+
"default": []
|
|
55
|
+
},
|
|
56
|
+
"linked": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"description": "Package groups that share the highest bump level. Each element is an array of package name globs.",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": { "type": "string" }
|
|
62
|
+
},
|
|
63
|
+
"default": []
|
|
64
|
+
},
|
|
65
|
+
"ignore": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"description": "Package name globs to exclude from versioning",
|
|
68
|
+
"items": { "type": "string" },
|
|
69
|
+
"default": []
|
|
70
|
+
},
|
|
71
|
+
"include": {
|
|
72
|
+
"type": "array",
|
|
73
|
+
"description": "Package name globs to explicitly include (overrides ignore and privatePackages)",
|
|
74
|
+
"items": { "type": "string" },
|
|
75
|
+
"default": []
|
|
76
|
+
},
|
|
77
|
+
"updateInternalDependencies": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"enum": ["patch", "minor", "out-of-range"],
|
|
80
|
+
"description": "When to update internal dependency version ranges",
|
|
81
|
+
"default": "out-of-range"
|
|
82
|
+
},
|
|
83
|
+
"dependencyBumpRules": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"description": "Controls how bumps propagate through dependency types",
|
|
86
|
+
"properties": {
|
|
87
|
+
"dependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
88
|
+
"devDependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
89
|
+
"peerDependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
90
|
+
"optionalDependencies": { "$ref": "#/$defs/dependencyBumpRule" }
|
|
91
|
+
},
|
|
92
|
+
"additionalProperties": false
|
|
93
|
+
},
|
|
94
|
+
"privatePackages": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"description": "Whether to version and/or create git tags for private packages",
|
|
97
|
+
"properties": {
|
|
98
|
+
"version": {
|
|
99
|
+
"type": "boolean",
|
|
100
|
+
"description": "Whether to version private packages",
|
|
101
|
+
"default": false
|
|
102
|
+
},
|
|
103
|
+
"tag": {
|
|
104
|
+
"type": "boolean",
|
|
105
|
+
"description": "Whether to create git tags for private packages",
|
|
106
|
+
"default": false
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"additionalProperties": false
|
|
110
|
+
},
|
|
111
|
+
"allowCustomCommands": {
|
|
112
|
+
"description": "Allow per-package custom commands (buildCommand, publishCommand, checkPublished) defined in package.json \"bumpy\" fields. true = allow all, string[] = allow matching package name globs, false = only root-config commands allowed.",
|
|
113
|
+
"default": false,
|
|
114
|
+
"oneOf": [
|
|
115
|
+
{ "type": "boolean" },
|
|
116
|
+
{
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": { "type": "string" }
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
"packages": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"description": "Per-package config overrides, keyed by package name or glob pattern",
|
|
125
|
+
"additionalProperties": { "$ref": "#/$defs/packageConfig" }
|
|
126
|
+
},
|
|
127
|
+
"publish": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"description": "Publishing pipeline configuration",
|
|
130
|
+
"properties": {
|
|
131
|
+
"packManager": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"enum": ["auto", "npm", "pnpm", "bun", "yarn"],
|
|
134
|
+
"description": "Package manager to use for packing. \"auto\" detects from lockfile.",
|
|
135
|
+
"default": "auto"
|
|
136
|
+
},
|
|
137
|
+
"publishManager": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"enum": ["npm", "pnpm", "bun", "yarn"],
|
|
140
|
+
"description": "Command to use for publishing. npm supports OIDC/provenance.",
|
|
141
|
+
"default": "npm"
|
|
142
|
+
},
|
|
143
|
+
"publishArgs": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": { "type": "string" },
|
|
146
|
+
"description": "Extra args appended to the publish command (e.g., \"--provenance\")",
|
|
147
|
+
"default": []
|
|
148
|
+
},
|
|
149
|
+
"protocolResolution": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"enum": ["pack", "in-place", "none"],
|
|
152
|
+
"description": "How to handle workspace:/catalog: protocol resolution. \"pack\" = use PM's pack to build a clean tarball, \"in-place\" = rewrite package.json before publish, \"none\" = don't resolve.",
|
|
153
|
+
"default": "pack"
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": false
|
|
157
|
+
},
|
|
158
|
+
"aggregateRelease": {
|
|
159
|
+
"description": "GitHub release creation (requires gh CLI). false = individual release per package, true = single aggregated release, or an object with enabled and optional title (supports {{date}}).",
|
|
160
|
+
"default": false,
|
|
161
|
+
"oneOf": [
|
|
162
|
+
{ "type": "boolean" },
|
|
163
|
+
{
|
|
164
|
+
"type": "object",
|
|
165
|
+
"properties": {
|
|
166
|
+
"enabled": {
|
|
167
|
+
"type": "boolean",
|
|
168
|
+
"description": "Whether to create an aggregated release"
|
|
169
|
+
},
|
|
170
|
+
"title": {
|
|
171
|
+
"type": "string",
|
|
172
|
+
"description": "Custom title for the aggregated release (supports {{date}})"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"required": ["enabled"],
|
|
176
|
+
"additionalProperties": false
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
"gitUser": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"description": "Git identity used for CI commits",
|
|
183
|
+
"properties": {
|
|
184
|
+
"name": {
|
|
185
|
+
"type": "string",
|
|
186
|
+
"description": "Git user name",
|
|
187
|
+
"default": "bumpy-bot"
|
|
188
|
+
},
|
|
189
|
+
"email": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"description": "Git user email",
|
|
192
|
+
"default": "276066384+bumpy-bot@users.noreply.github.com"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"additionalProperties": false
|
|
196
|
+
},
|
|
197
|
+
"versionPr": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"description": "Customize the version PR created by bumpy ci release",
|
|
200
|
+
"properties": {
|
|
201
|
+
"title": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"description": "PR title",
|
|
204
|
+
"default": "🐸 Versioned release"
|
|
205
|
+
},
|
|
206
|
+
"branch": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"description": "Branch name for the version PR",
|
|
209
|
+
"default": "bumpy/version-packages"
|
|
210
|
+
},
|
|
211
|
+
"preamble": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"description": "HTML/markdown content prepended to the PR body"
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"additionalProperties": false
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"additionalProperties": false,
|
|
220
|
+
"$defs": {
|
|
221
|
+
"bumpType": {
|
|
222
|
+
"type": "string",
|
|
223
|
+
"enum": ["major", "minor", "patch"]
|
|
224
|
+
},
|
|
225
|
+
"dependencyBumpRule": {
|
|
226
|
+
"oneOf": [
|
|
227
|
+
{
|
|
228
|
+
"type": "object",
|
|
229
|
+
"properties": {
|
|
230
|
+
"trigger": {
|
|
231
|
+
"$ref": "#/$defs/bumpType",
|
|
232
|
+
"description": "Minimum bump level that triggers propagation"
|
|
233
|
+
},
|
|
234
|
+
"bumpAs": {
|
|
235
|
+
"description": "What level to bump the dependent (\"match\" mirrors the triggering level)",
|
|
236
|
+
"oneOf": [{ "$ref": "#/$defs/bumpType" }, { "type": "string", "const": "match" }]
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"required": ["trigger", "bumpAs"],
|
|
240
|
+
"additionalProperties": false
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"type": "boolean",
|
|
244
|
+
"const": false,
|
|
245
|
+
"description": "Set to false to disable propagation for this dependency type"
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
"packageConfig": {
|
|
250
|
+
"type": "object",
|
|
251
|
+
"description": "Per-package configuration",
|
|
252
|
+
"properties": {
|
|
253
|
+
"managed": {
|
|
254
|
+
"type": "boolean",
|
|
255
|
+
"description": "Explicitly opt this package in or out of version management"
|
|
256
|
+
},
|
|
257
|
+
"access": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"enum": ["public", "restricted"],
|
|
260
|
+
"description": "Override the global access level"
|
|
261
|
+
},
|
|
262
|
+
"publishCommand": {
|
|
263
|
+
"description": "Custom command(s) to publish this package (replaces npm publish)",
|
|
264
|
+
"oneOf": [
|
|
265
|
+
{ "type": "string" },
|
|
266
|
+
{
|
|
267
|
+
"type": "array",
|
|
268
|
+
"items": { "type": "string" }
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
"buildCommand": {
|
|
273
|
+
"type": "string",
|
|
274
|
+
"description": "Command to run before publishing"
|
|
275
|
+
},
|
|
276
|
+
"registry": {
|
|
277
|
+
"type": "string",
|
|
278
|
+
"description": "Custom npm registry URL"
|
|
279
|
+
},
|
|
280
|
+
"skipNpmPublish": {
|
|
281
|
+
"type": "boolean",
|
|
282
|
+
"description": "Don't publish to npm (still creates git tags)"
|
|
283
|
+
},
|
|
284
|
+
"checkPublished": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"description": "Custom command that outputs the currently published version"
|
|
287
|
+
},
|
|
288
|
+
"changedFilePatterns": {
|
|
289
|
+
"type": "array",
|
|
290
|
+
"description": "Glob patterns to filter which changed files count toward marking this package as changed (overrides root setting)",
|
|
291
|
+
"items": { "type": "string" }
|
|
292
|
+
},
|
|
293
|
+
"dependencyBumpRules": {
|
|
294
|
+
"type": "object",
|
|
295
|
+
"description": "Per-package override for dependency propagation rules",
|
|
296
|
+
"properties": {
|
|
297
|
+
"dependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
298
|
+
"devDependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
299
|
+
"peerDependencies": { "$ref": "#/$defs/dependencyBumpRule" },
|
|
300
|
+
"optionalDependencies": { "$ref": "#/$defs/dependencyBumpRule" }
|
|
301
|
+
},
|
|
302
|
+
"additionalProperties": false
|
|
303
|
+
},
|
|
304
|
+
"cascadeTo": {
|
|
305
|
+
"type": "object",
|
|
306
|
+
"description": "Explicit cascade targets — glob pattern mapped to { trigger, bumpAs }",
|
|
307
|
+
"additionalProperties": {
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {
|
|
310
|
+
"trigger": {
|
|
311
|
+
"$ref": "#/$defs/bumpType",
|
|
312
|
+
"description": "Minimum bump level that triggers the cascade"
|
|
313
|
+
},
|
|
314
|
+
"bumpAs": {
|
|
315
|
+
"description": "What level to bump the target",
|
|
316
|
+
"oneOf": [{ "$ref": "#/$defs/bumpType" }, { "type": "string", "const": "match" }]
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
"required": ["trigger", "bumpAs"],
|
|
320
|
+
"additionalProperties": false
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
"additionalProperties": false
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { n as exists, t as ensureDir } from "./fs-DYR2XuFE.mjs";
|
|
3
|
+
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-B-Qg3DZH.mjs";
|
|
4
|
+
import { t as discoverPackages } from "./workspace-DWXlwcH4.mjs";
|
|
5
|
+
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
6
|
+
import { i as writeBumpFile } from "./bump-file-DVqR3k67.mjs";
|
|
7
|
+
import { r as getChangedFiles } from "./git-YDedMddc.mjs";
|
|
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
|
+
import { n as slugify, t as randomName } from "./names-C-TuOPbd.mjs";
|
|
10
|
+
import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
|
|
11
|
+
import { relative, resolve } from "node:path";
|
|
12
|
+
import * as readline from "node:readline";
|
|
13
|
+
//#region src/prompts/bump-select.ts
|
|
14
|
+
var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
|
|
15
|
+
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
16
|
+
const LEVELS = [
|
|
17
|
+
"none",
|
|
18
|
+
"patch",
|
|
19
|
+
"minor",
|
|
20
|
+
"major"
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Custom interactive prompt for selecting bump levels for multiple packages.
|
|
24
|
+
* - Up/Down arrows to navigate between packages
|
|
25
|
+
* - Left/Right arrows to change the bump level
|
|
26
|
+
* - Changed packages default to "patch", unchanged to "none"
|
|
27
|
+
* - Enter to confirm
|
|
28
|
+
* - Ctrl+C / Escape to cancel
|
|
29
|
+
*/
|
|
30
|
+
async function bumpSelectPrompt(items) {
|
|
31
|
+
const changedEntries = items.map((item, idx) => ({
|
|
32
|
+
item,
|
|
33
|
+
idx
|
|
34
|
+
})).filter(({ item }) => item.changed);
|
|
35
|
+
const unchangedEntries = items.map((item, idx) => ({
|
|
36
|
+
item,
|
|
37
|
+
idx
|
|
38
|
+
})).filter(({ item }) => !item.changed);
|
|
39
|
+
const displayOrder = [...changedEntries, ...unchangedEntries];
|
|
40
|
+
let cursor = 0;
|
|
41
|
+
const levels = items.map((item) => item.changed ? "patch" : "none");
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const { stdin, stdout } = process;
|
|
44
|
+
const rl = readline.createInterface({
|
|
45
|
+
input: stdin,
|
|
46
|
+
terminal: true
|
|
47
|
+
});
|
|
48
|
+
stdout.write("\x1B[?25l");
|
|
49
|
+
let renderedLines = 0;
|
|
50
|
+
function render(final = false) {
|
|
51
|
+
if (renderedLines > 0) {
|
|
52
|
+
stdout.write(`\x1B[${renderedLines}A`);
|
|
53
|
+
stdout.write("\x1B[0J");
|
|
54
|
+
}
|
|
55
|
+
const lines = [];
|
|
56
|
+
if (final) {
|
|
57
|
+
lines.push(`${import_picocolors.default.green("◇")} Bump levels selected`);
|
|
58
|
+
const selected = displayOrder.filter(({ idx }) => levels[idx] !== "none");
|
|
59
|
+
if (selected.length === 0) lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("(none)")}`);
|
|
60
|
+
else for (const { item, idx } of selected) lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan(item.name)} ${import_picocolors.default.dim("→")} ${import_picocolors.default.bold(levels[idx])}`);
|
|
61
|
+
lines.push(import_picocolors.default.dim("│"));
|
|
62
|
+
} else {
|
|
63
|
+
lines.push(`${import_picocolors.default.cyan("◆")} Select bump levels`);
|
|
64
|
+
lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("↑/↓ navigate · ←/→ change level · enter to confirm")}`);
|
|
65
|
+
lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("0 clear current · x clear all · r reset all to defaults")}`);
|
|
66
|
+
lines.push(import_picocolors.default.dim("│"));
|
|
67
|
+
let displayIdx = 0;
|
|
68
|
+
if (changedEntries.length > 0) {
|
|
69
|
+
lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.underline("Changed")}`);
|
|
70
|
+
for (const { item, idx } of changedEntries) {
|
|
71
|
+
lines.push(formatRow(item, levels[idx], cursor === displayIdx));
|
|
72
|
+
displayIdx++;
|
|
73
|
+
}
|
|
74
|
+
if (unchangedEntries.length > 0) lines.push(import_picocolors.default.dim("│"));
|
|
75
|
+
}
|
|
76
|
+
if (unchangedEntries.length > 0) {
|
|
77
|
+
lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.underline("Unchanged")}`);
|
|
78
|
+
for (const { item, idx } of unchangedEntries) {
|
|
79
|
+
lines.push(formatRow(item, levels[idx], cursor === displayIdx));
|
|
80
|
+
displayIdx++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
lines.push(import_picocolors.default.dim("│"));
|
|
84
|
+
const selectedCount = levels.filter((l) => l !== "none").length;
|
|
85
|
+
lines.push(`${import_picocolors.default.dim("│")} ${import_picocolors.default.dim(`${selectedCount} package${selectedCount !== 1 ? "s" : ""} selected`)}`);
|
|
86
|
+
lines.push(`${import_picocolors.default.dim("└")}`);
|
|
87
|
+
}
|
|
88
|
+
const output = lines.join("\n") + "\n";
|
|
89
|
+
stdout.write(output);
|
|
90
|
+
renderedLines = lines.length;
|
|
91
|
+
}
|
|
92
|
+
function cleanup() {
|
|
93
|
+
rl.close();
|
|
94
|
+
stdout.write("\x1B[?25h");
|
|
95
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
96
|
+
}
|
|
97
|
+
function finish(result) {
|
|
98
|
+
render(true);
|
|
99
|
+
cleanup();
|
|
100
|
+
resolve(result);
|
|
101
|
+
}
|
|
102
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
103
|
+
stdin.resume();
|
|
104
|
+
render();
|
|
105
|
+
stdin.on("keypress", (_str, key) => {
|
|
106
|
+
if (!key) return;
|
|
107
|
+
if (key.name === "escape" || key.ctrl && key.name === "c") {
|
|
108
|
+
cleanup();
|
|
109
|
+
if (renderedLines > 0) {
|
|
110
|
+
stdout.write(`\x1B[${renderedLines}A`);
|
|
111
|
+
stdout.write("\x1B[0J");
|
|
112
|
+
}
|
|
113
|
+
stdout.write(`${import_picocolors.default.red("■")} Cancelled\n`);
|
|
114
|
+
resolve(Symbol("cancel"));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (key.name === "return") {
|
|
118
|
+
const results = [];
|
|
119
|
+
for (let i = 0; i < items.length; i++) if (levels[i] !== "none") results.push({
|
|
120
|
+
name: items[i].name,
|
|
121
|
+
type: levels[i]
|
|
122
|
+
});
|
|
123
|
+
finish(results);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (key.name === "up" || key.name === "k") cursor = (cursor - 1 + displayOrder.length) % displayOrder.length;
|
|
127
|
+
else if (key.name === "down" || key.name === "j") cursor = (cursor + 1) % displayOrder.length;
|
|
128
|
+
else if (key.name === "right" || key.name === "l") {
|
|
129
|
+
const entry = displayOrder[cursor];
|
|
130
|
+
const currentLevel = LEVELS.indexOf(levels[entry.idx]);
|
|
131
|
+
if (currentLevel < LEVELS.length - 1) levels[entry.idx] = LEVELS[currentLevel + 1];
|
|
132
|
+
} else if (key.name === "left" || key.name === "h") {
|
|
133
|
+
const entry = displayOrder[cursor];
|
|
134
|
+
const currentLevel = LEVELS.indexOf(levels[entry.idx]);
|
|
135
|
+
if (currentLevel > 0) levels[entry.idx] = LEVELS[currentLevel - 1];
|
|
136
|
+
} else if (_str === "0" || key.name === "backspace") {
|
|
137
|
+
const entry = displayOrder[cursor];
|
|
138
|
+
levels[entry.idx] = "none";
|
|
139
|
+
} else if (_str === "r") for (let i = 0; i < items.length; i++) levels[i] = items[i].changed ? "patch" : "none";
|
|
140
|
+
else if (_str === "x") for (let i = 0; i < items.length; i++) levels[i] = "none";
|
|
141
|
+
render();
|
|
142
|
+
});
|
|
143
|
+
readline.emitKeypressEvents(stdin, rl);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function formatRow(item, level, focused) {
|
|
147
|
+
return `${import_picocolors.default.dim("│")} ${focused ? import_picocolors.default.cyan("›") : " "} ${focused ? import_picocolors.default.cyan(item.name) : item.name} ${import_picocolors.default.dim(`(${item.version})`)} ${formatLevel(level, focused)}`;
|
|
148
|
+
}
|
|
149
|
+
function formatLevel(level, focused) {
|
|
150
|
+
if (!focused) {
|
|
151
|
+
if (level === "none") return import_picocolors.default.dim("·");
|
|
152
|
+
if (level === "major") return import_picocolors.default.red(level);
|
|
153
|
+
if (level === "minor") return import_picocolors.default.yellow(level);
|
|
154
|
+
return import_picocolors.default.green(level);
|
|
155
|
+
}
|
|
156
|
+
return `◄ ${LEVELS.map((l) => {
|
|
157
|
+
if (l === level) {
|
|
158
|
+
if (l === "none") return import_picocolors.default.bold(import_picocolors.default.dim("[none]"));
|
|
159
|
+
if (l === "major") return import_picocolors.default.bold(import_picocolors.default.red(`[${l}]`));
|
|
160
|
+
if (l === "minor") return import_picocolors.default.bold(import_picocolors.default.yellow(`[${l}]`));
|
|
161
|
+
return import_picocolors.default.bold(import_picocolors.default.green(`[${l}]`));
|
|
162
|
+
}
|
|
163
|
+
return import_picocolors.default.dim(l);
|
|
164
|
+
}).join(import_picocolors.default.dim(" · "))} ►`;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/commands/add.ts
|
|
168
|
+
const CASCADE_CHOICES = [
|
|
169
|
+
{
|
|
170
|
+
label: "patch",
|
|
171
|
+
value: "patch"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: "minor",
|
|
175
|
+
value: "minor"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
label: "major",
|
|
179
|
+
value: "major"
|
|
180
|
+
}
|
|
181
|
+
];
|
|
182
|
+
async function addCommand(rootDir, opts) {
|
|
183
|
+
const config = await loadConfig(rootDir);
|
|
184
|
+
const bumpyDir = getBumpyDir(rootDir);
|
|
185
|
+
await ensureDir(bumpyDir);
|
|
186
|
+
if (opts.empty) {
|
|
187
|
+
const filename = opts.name ? slugify(opts.name) : randomName();
|
|
188
|
+
const filePath = resolve(bumpyDir, `${filename}.md`);
|
|
189
|
+
const { writeText } = await import("./fs-DYR2XuFE.mjs").then((n) => n.r);
|
|
190
|
+
await writeText(filePath, "---\n---\n");
|
|
191
|
+
log.success(`🐸 Created empty bump file: .bumpy/${filename}.md`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
let releases;
|
|
195
|
+
let summary;
|
|
196
|
+
let filename;
|
|
197
|
+
if (opts.packages) {
|
|
198
|
+
releases = parsePackagesFlag(opts.packages);
|
|
199
|
+
summary = opts.message || "";
|
|
200
|
+
filename = opts.name ? slugify(opts.name) : randomName();
|
|
201
|
+
} else {
|
|
202
|
+
mt(import_picocolors.default.bgCyan(import_picocolors.default.black(" bumpy add ")));
|
|
203
|
+
const pkgs = await discoverPackages(rootDir, config);
|
|
204
|
+
const depGraph = new DependencyGraph(pkgs);
|
|
205
|
+
if (pkgs.size === 0) {
|
|
206
|
+
pt("No managed packages found in this workspace.");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
const baseBranch = config.baseBranch;
|
|
210
|
+
const changedFiles = getChangedFiles(rootDir, baseBranch);
|
|
211
|
+
const matchers = /* @__PURE__ */ new Map();
|
|
212
|
+
for (const [name, pkg] of pkgs) {
|
|
213
|
+
const patterns = (await loadPackageConfig(pkg.dir, config, name)).changedFilePatterns ?? config.changedFilePatterns;
|
|
214
|
+
matchers.set(name, (0, import_picomatch.default)(patterns));
|
|
215
|
+
}
|
|
216
|
+
const changedPackageNames = /* @__PURE__ */ new Set();
|
|
217
|
+
for (const file of changedFiles) for (const [name, pkg] of pkgs) {
|
|
218
|
+
const pkgRelDir = relative(rootDir, pkg.dir);
|
|
219
|
+
if (file.startsWith(pkgRelDir + "/")) {
|
|
220
|
+
const relToPackage = file.slice(pkgRelDir.length + 1);
|
|
221
|
+
if (matchers.get(name)(relToPackage)) changedPackageNames.add(name);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const bumpSelectResult = await bumpSelectPrompt([...pkgs.values()].map((pkg) => ({
|
|
225
|
+
name: pkg.name,
|
|
226
|
+
version: pkg.version,
|
|
227
|
+
changed: changedPackageNames.has(pkg.name)
|
|
228
|
+
})));
|
|
229
|
+
if (typeof bumpSelectResult === "symbol") {
|
|
230
|
+
pt("Aborted");
|
|
231
|
+
process.exit(0);
|
|
232
|
+
}
|
|
233
|
+
const bumpSelections = bumpSelectResult;
|
|
234
|
+
if (bumpSelections.length === 0) {
|
|
235
|
+
pt("No packages selected.");
|
|
236
|
+
process.exit(0);
|
|
237
|
+
}
|
|
238
|
+
releases = [];
|
|
239
|
+
for (const { name, type: bumpType } of bumpSelections) {
|
|
240
|
+
const release = {
|
|
241
|
+
name,
|
|
242
|
+
type: bumpType
|
|
243
|
+
};
|
|
244
|
+
{
|
|
245
|
+
const dependents = depGraph.getDependents(name);
|
|
246
|
+
const cascadeTargets = pkgs.get(name).bumpy?.cascadeTo;
|
|
247
|
+
if (dependents.length > 0 || cascadeTargets) {
|
|
248
|
+
if (unwrap(await ot({
|
|
249
|
+
message: `${import_picocolors.default.cyan(name)} has ${import_picocolors.default.bold(String(dependents.length))} dependents. Specify explicit cascades?`,
|
|
250
|
+
initialValue: false
|
|
251
|
+
}))) {
|
|
252
|
+
const allTargets = /* @__PURE__ */ new Set();
|
|
253
|
+
for (const d of dependents) allTargets.add(d.name);
|
|
254
|
+
if (cascadeTargets) {
|
|
255
|
+
for (const pattern of Object.keys(cascadeTargets)) for (const [pName] of pkgs) if (matchGlob(pName, pattern)) allTargets.add(pName);
|
|
256
|
+
}
|
|
257
|
+
const cascadeSelected = unwrap(await yt({
|
|
258
|
+
message: "Which packages should cascade?",
|
|
259
|
+
options: [...allTargets].map((n) => ({
|
|
260
|
+
label: n,
|
|
261
|
+
value: n
|
|
262
|
+
})),
|
|
263
|
+
required: false
|
|
264
|
+
}));
|
|
265
|
+
if (cascadeSelected.length > 0) {
|
|
266
|
+
const cascadeBump = unwrap(await _t({
|
|
267
|
+
message: "Cascade bump type",
|
|
268
|
+
options: CASCADE_CHOICES
|
|
269
|
+
}));
|
|
270
|
+
const cascade = {};
|
|
271
|
+
for (const target of cascadeSelected) cascade[target] = cascadeBump;
|
|
272
|
+
release.cascade = cascade;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
releases.push(release);
|
|
278
|
+
}
|
|
279
|
+
summary = unwrap(await Ot({
|
|
280
|
+
message: "Summary (what changed and why)",
|
|
281
|
+
placeholder: "A short description of the change",
|
|
282
|
+
validate: (value) => {
|
|
283
|
+
if (!value || !value.trim()) return "Summary is required";
|
|
284
|
+
}
|
|
285
|
+
}));
|
|
286
|
+
const defaultName = randomName();
|
|
287
|
+
filename = slugify(unwrap(await Ot({
|
|
288
|
+
message: "Bump file name",
|
|
289
|
+
placeholder: defaultName,
|
|
290
|
+
defaultValue: defaultName,
|
|
291
|
+
validate: (value) => {
|
|
292
|
+
if (!value) return void 0;
|
|
293
|
+
if (!slugify(value)) return "Name must contain at least one alphanumeric character";
|
|
294
|
+
}
|
|
295
|
+
}))) || defaultName;
|
|
296
|
+
}
|
|
297
|
+
if (await exists(resolve(bumpyDir, `${filename}.md`))) filename = `${filename}-${Date.now()}`;
|
|
298
|
+
await writeBumpFile(rootDir, filename, releases, summary);
|
|
299
|
+
if (opts.packages) {
|
|
300
|
+
log.success(`🐸 Created bump file: .bumpy/${filename}.md`);
|
|
301
|
+
for (const r of releases) log.dim(` ${r.name}: ${r.type}${formatCascade(r)}`);
|
|
302
|
+
} else {
|
|
303
|
+
wt(releases.map((r) => `${import_picocolors.default.cyan(r.name)} ${import_picocolors.default.dim("→")} ${import_picocolors.default.bold(r.type)}${formatCascade(r)}`).join("\n"), "Bump file");
|
|
304
|
+
gt(import_picocolors.default.green(`🐸 Created .bumpy/${filename}.md`));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function formatCascade(r) {
|
|
308
|
+
if (!("cascade" in r) || Object.keys(r.cascade).length === 0) return "";
|
|
309
|
+
const parts = Object.entries(r.cascade).map(([k, v]) => `${k}:${v}`);
|
|
310
|
+
return import_picocolors.default.dim(` (cascade: ${parts.join(", ")})`);
|
|
311
|
+
}
|
|
312
|
+
function parsePackagesFlag(input) {
|
|
313
|
+
return input.split(",").map((entry) => {
|
|
314
|
+
const [name, type] = entry.trim().split(":");
|
|
315
|
+
if (!name || !type) throw new Error(`Invalid package format: "${entry}". Expected "name:bumpType"`);
|
|
316
|
+
return {
|
|
317
|
+
name: name.trim(),
|
|
318
|
+
type: type.trim()
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
export { addCommand };
|