@varlock/bumpy 0.0.1 → 1.0.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.
Files changed (44) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/dist/add-CgCjs4d-.mjs +313 -0
  3. package/dist/{ai-B8ZL2x8z.mjs → ai-sMYUf3lP.mjs} +22 -5
  4. package/dist/{apply-release-plan-DtU3rVyL.mjs → apply-release-plan-CczGWJTk.mjs} +34 -25
  5. package/dist/bump-file-CCLXMLA8.mjs +143 -0
  6. package/dist/changelog-github-Cd8uJHZI.mjs +195 -0
  7. package/dist/{check-CkRubvuk.mjs → check-BOoxpWqk.mjs} +11 -17
  8. package/dist/ci-Bhx--Tj6.mjs +629 -0
  9. package/dist/ci-setup-qz4Y3v7T.mjs +211 -0
  10. package/dist/clack-CDRCHrC-.mjs +1216 -0
  11. package/dist/cli.mjs +37 -31
  12. package/dist/{config-CJ2orhTL.mjs → config-XZWUL3ma.mjs} +28 -23
  13. package/dist/fs-DYR2XuFE.mjs +81 -0
  14. package/dist/{generate-oOFD9ABC.mjs → generate-gYKTpvex.mjs} +31 -12
  15. package/dist/git-CGHVXXKw.mjs +78 -0
  16. package/dist/index.d.mts +63 -37
  17. package/dist/index.mjs +9 -9
  18. package/dist/{init-Blw2GfC_.mjs → init-lA9E5pEc.mjs} +3 -3
  19. package/dist/logger-C2dEe5Su.mjs +135 -0
  20. package/dist/{migrate-DvOrXSw0.mjs → migrate-DmOYgmfD.mjs} +23 -16
  21. package/dist/{names-C-u50ofE.mjs → names-9VubBmL0.mjs} +3 -2
  22. package/dist/package-manager-VCe10bjc.mjs +80 -0
  23. package/dist/{publish-DZ3m7qkX.mjs → publish-Cun-zQ1b.mjs} +90 -35
  24. package/dist/{publish-pipeline-1M5GmbdP.mjs → publish-pipeline-BwBuKCIk.mjs} +56 -65
  25. package/dist/release-plan-Bi5QNSEo.mjs +264 -0
  26. package/dist/{semver-DWO6NFKN.mjs → semver-DfQyVLM_.mjs} +14 -4
  27. package/dist/shell-Dj7JRD_q.mjs +92 -0
  28. package/dist/{status-DRpq_Mha.mjs → status-CfE63ti5.mjs} +27 -23
  29. package/dist/version-19vVt9dv.mjs +124 -0
  30. package/dist/workspace-C5ULTyUN.mjs +107 -0
  31. package/package.json +16 -2
  32. package/skills/add-change/SKILL.md +8 -12
  33. package/dist/add-u5V9V3L7.mjs +0 -131
  34. package/dist/changelog-github-n-3zV1p9.mjs +0 -59
  35. package/dist/changeset-ClCYsChu.mjs +0 -75
  36. package/dist/ci-8KWWhjXl.mjs +0 -224
  37. package/dist/fs-DbNNEyzq.mjs +0 -51
  38. package/dist/logger-ZqggsyGZ.mjs +0 -176
  39. package/dist/prompt-BP8toAOI.mjs +0 -46
  40. package/dist/release-plan-CFnutSHD.mjs +0 -173
  41. package/dist/shell-DPlltpzb.mjs +0 -44
  42. package/dist/version-CJwf8XIA.mjs +0 -81
  43. package/dist/workspace-mVjawG8g.mjs +0 -183
  44. /package/dist/{dep-graph-DiLeAhl9.mjs → dep-graph-E-9-eQ2J.mjs} +0 -0
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, t as colorize } from "./logger-ZqggsyGZ.mjs";
3
- import { n as findRoot } from "./config-CJ2orhTL.mjs";
2
+ import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
3
+ import { n as findRoot } from "./config-XZWUL3ma.mjs";
4
4
  //#region src/cli.ts
5
5
  const args = process.argv.slice(2);
6
6
  const command = args[0];
@@ -25,13 +25,13 @@ async function main() {
25
25
  switch (command) {
26
26
  case "init": {
27
27
  const rootDir = await findRoot();
28
- const { initCommand } = await import("./init-Blw2GfC_.mjs");
28
+ const { initCommand } = await import("./init-lA9E5pEc.mjs");
29
29
  await initCommand(rootDir);
30
30
  break;
31
31
  }
32
32
  case "add": {
33
33
  const rootDir = await findRoot();
34
- const { addCommand } = await import("./add-u5V9V3L7.mjs");
34
+ const { addCommand } = await import("./add-CgCjs4d-.mjs");
35
35
  await addCommand(rootDir, {
36
36
  packages: flags.packages,
37
37
  message: flags.message,
@@ -42,7 +42,7 @@ async function main() {
42
42
  }
43
43
  case "status": {
44
44
  const rootDir = await findRoot();
45
- const { statusCommand } = await import("./status-DRpq_Mha.mjs");
45
+ const { statusCommand } = await import("./status-CfE63ti5.mjs");
46
46
  await statusCommand(rootDir, {
47
47
  json: flags.json === true,
48
48
  packagesOnly: flags.packages === true,
@@ -54,13 +54,13 @@ async function main() {
54
54
  }
55
55
  case "version": {
56
56
  const rootDir = await findRoot();
57
- const { versionCommand } = await import("./version-CJwf8XIA.mjs");
57
+ const { versionCommand } = await import("./version-19vVt9dv.mjs");
58
58
  await versionCommand(rootDir);
59
59
  break;
60
60
  }
61
61
  case "generate": {
62
62
  const rootDir = await findRoot();
63
- const { generateCommand } = await import("./generate-oOFD9ABC.mjs");
63
+ const { generateCommand } = await import("./generate-gYKTpvex.mjs");
64
64
  await generateCommand(rootDir, {
65
65
  from: flags.from,
66
66
  dryRun: flags["dry-run"] === true,
@@ -70,13 +70,13 @@ async function main() {
70
70
  }
71
71
  case "migrate": {
72
72
  const rootDir = await findRoot();
73
- const { migrateCommand } = await import("./migrate-DvOrXSw0.mjs");
73
+ const { migrateCommand } = await import("./migrate-DmOYgmfD.mjs");
74
74
  await migrateCommand(rootDir, { force: flags.force === true });
75
75
  break;
76
76
  }
77
77
  case "check": {
78
78
  const rootDir = await findRoot();
79
- const { checkCommand } = await import("./check-CkRubvuk.mjs");
79
+ const { checkCommand } = await import("./check-BOoxpWqk.mjs");
80
80
  await checkCommand(rootDir);
81
81
  break;
82
82
  }
@@ -85,27 +85,32 @@ async function main() {
85
85
  const subcommand = args[1];
86
86
  const ciFlags = parseFlags(args.slice(2));
87
87
  if (subcommand === "check") {
88
- const { ciCheckCommand } = await import("./ci-8KWWhjXl.mjs");
88
+ const { ciCheckCommand } = await import("./ci-Bhx--Tj6.mjs");
89
89
  await ciCheckCommand(rootDir, {
90
90
  comment: ciFlags.comment !== void 0 ? ciFlags.comment === true : void 0,
91
- failOnMissing: ciFlags["fail-on-missing"] === true
91
+ failOnMissing: ciFlags["fail-on-missing"] === true,
92
+ patComments: ciFlags["pat-comments"] === true
92
93
  });
93
94
  } else if (subcommand === "release") {
94
- const { ciReleaseCommand } = await import("./ci-8KWWhjXl.mjs");
95
+ const { ciReleaseCommand } = await import("./ci-Bhx--Tj6.mjs");
95
96
  await ciReleaseCommand(rootDir, {
96
97
  mode: ciFlags["auto-publish"] === true ? "auto-publish" : "version-pr",
97
98
  tag: ciFlags.tag,
98
- branch: ciFlags.branch
99
+ branch: ciFlags.branch,
100
+ patPr: ciFlags["pat-pr"] === true
99
101
  });
102
+ } else if (subcommand === "setup") {
103
+ const { ciSetupCommand } = await import("./ci-setup-qz4Y3v7T.mjs");
104
+ await ciSetupCommand(rootDir);
100
105
  } else {
101
- log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check" or "ci release".`);
106
+ log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci release", or "ci setup".`);
102
107
  process.exit(1);
103
108
  }
104
109
  break;
105
110
  }
106
111
  case "publish": {
107
112
  const rootDir = await findRoot();
108
- const { publishCommand } = await import("./publish-DZ3m7qkX.mjs");
113
+ const { publishCommand } = await import("./publish-Cun-zQ1b.mjs");
109
114
  await publishCommand(rootDir, {
110
115
  dryRun: flags["dry-run"] === true,
111
116
  tag: flags.tag,
@@ -119,7 +124,7 @@ async function main() {
119
124
  const subcommand = args[1];
120
125
  const aiFlags = parseFlags(args.slice(2));
121
126
  if (subcommand === "setup") {
122
- const { aiSetupCommand } = await import("./ai-B8ZL2x8z.mjs");
127
+ const { aiSetupCommand } = await import("./ai-sMYUf3lP.mjs");
123
128
  await aiSetupCommand(rootDir, { target: aiFlags.target });
124
129
  } else {
125
130
  log.error(`Unknown ai subcommand: ${subcommand}. Use "ai setup".`);
@@ -129,7 +134,7 @@ async function main() {
129
134
  }
130
135
  case "--version":
131
136
  case "-v":
132
- console.log(`bumpy 0.0.1`);
137
+ console.log(`bumpy 1.0.0`);
133
138
  break;
134
139
  case "help":
135
140
  case "--help":
@@ -149,40 +154,41 @@ async function main() {
149
154
  }
150
155
  function printHelp() {
151
156
  console.log(`
152
- ${colorize(`🐸 bumpy v0.0.1`, "bold")} - Modern monorepo versioning
157
+ ${colorize(`🐸 bumpy v1.0.0`, "bold")} - Modern monorepo versioning
153
158
 
154
159
  Usage: bumpy <command> [options]
155
160
 
156
161
  Commands:
157
162
  init Initialize .bumpy/ directory
158
- add Create a new changeset
159
- generate Generate changeset from conventional commits
163
+ add Create a new bump file
164
+ generate Generate bump file from conventional commits
160
165
  status Show pending releases
161
- check Verify changed packages have changesets (for pre-push hooks)
162
- version Apply changesets and bump versions
166
+ check Verify changed packages have bump files (for pre-push hooks)
167
+ version Apply bump files and bump versions
163
168
  publish Publish versioned packages
164
169
  ci check PR check — report pending releases, comment on PR
165
170
  ci release Release — create version PR or auto-publish
171
+ ci setup Set up a token for triggering CI on version PRs
166
172
  migrate Migrate from .changeset/ to .bumpy/
167
- ai setup Install AI skill for creating changesets
173
+ ai setup Install AI skill for creating bump files
168
174
 
169
175
  Add options:
170
176
  --packages <list> Package bumps (e.g., "pkg-a:minor,pkg-b:patch")
171
- --message <text> Changeset summary
172
- --name <name> Changeset filename
173
- --empty Create an empty changeset
177
+ --message <text> Bump file summary
178
+ --name <name> Bump file filename
179
+ --empty Create an empty bump file
174
180
 
175
181
  Generate options:
176
182
  --from <ref> Git ref to scan from (default: last version tag)
177
- --dry-run Preview without creating a changeset
178
- --name <name> Changeset filename
183
+ --dry-run Preview without creating a bump file
184
+ --name <name> Bump file filename
179
185
 
180
186
  Status options:
181
- --json Output as JSON (includes dirs, changesets, packageNames)
187
+ --json Output as JSON (includes dirs, bumpFiles, packageNames)
182
188
  --packages Output only package names, one per line
183
189
  --bump <types> Filter by bump type (e.g., "major", "minor,patch")
184
190
  --filter <names> Filter by package name/glob (e.g., "@myorg/*")
185
- --verbose Show changeset details
191
+ --verbose Show bump file details
186
192
 
187
193
  Publish options:
188
194
  --dry-run Preview without publishing
@@ -192,7 +198,7 @@ function printHelp() {
192
198
 
193
199
  CI check options:
194
200
  --comment Force PR comment on/off (auto-detected in CI)
195
- --fail-on-missing Exit 1 if no changesets found
201
+ --fail-on-missing Exit 1 if no bump files found
196
202
 
197
203
  CI release options:
198
204
  --auto-publish Version + publish directly (default: create version PR)
@@ -1,5 +1,5 @@
1
- import { i as __exportAll } from "./logger-ZqggsyGZ.mjs";
2
- import { a as readJson, n as exists } from "./fs-DbNNEyzq.mjs";
1
+ import { a as __exportAll } from "./logger-C2dEe5Su.mjs";
2
+ import { a as readJson, n as exists } from "./fs-DYR2XuFE.mjs";
3
3
  import { resolve } from "node:path";
4
4
  //#region src/types.ts
5
5
  const BUMP_LEVELS = {
@@ -10,16 +10,6 @@ const BUMP_LEVELS = {
10
10
  function bumpLevel(type) {
11
11
  return BUMP_LEVELS[type];
12
12
  }
13
- function parseIsolatedBump(type) {
14
- if (type.endsWith("-isolated")) return {
15
- bump: type.replace("-isolated", ""),
16
- isolated: true
17
- };
18
- return {
19
- bump: type,
20
- isolated: false
21
- };
22
- }
23
13
  function maxBump(a, b) {
24
14
  if (!a) return b;
25
15
  return bumpLevel(a) >= bumpLevel(b) ? a : b;
@@ -31,12 +21,9 @@ const DEFAULT_BUMP_RULES = {
31
21
  },
32
22
  peerDependencies: {
33
23
  trigger: "major",
34
- bumpAs: "major"
35
- },
36
- devDependencies: {
37
- trigger: "none",
38
- bumpAs: "patch"
24
+ bumpAs: "match"
39
25
  },
26
+ devDependencies: false,
40
27
  optionalDependencies: {
41
28
  trigger: "minor",
42
29
  bumpAs: "patch"
@@ -69,6 +56,7 @@ const DEFAULT_CONFIG = {
69
56
  version: false,
70
57
  tag: false
71
58
  },
59
+ allowCustomCommands: false,
72
60
  packages: {},
73
61
  publish: { ...DEFAULT_PUBLISH_CONFIG },
74
62
  aggregateRelease: false,
@@ -82,7 +70,7 @@ const DEFAULT_CONFIG = {
82
70
  preamble: [
83
71
  `<a href="https://github.com/dmno-dev/bumpy"><img src="https://raw.githubusercontent.com/dmno-dev/bumpy/main/images/frog-talking.png" alt="bumpy-frog" width="60" align="left" style="image-rendering: pixelated;" title="Hi! I'm bumpy!" /></a>`,
84
72
  "",
85
- `This PR was created and will be kept in sync by [bumpy](https://github.com/dmno-dev/bumpy) based on your .bumpy changeset files. Merge it when you are ready to release the packages listed below:`,
73
+ `This PR was created and will be kept in sync by [bumpy](https://github.com/dmno-dev/bumpy) based on your .bumpy bump files. Merge it when you are ready to release the packages listed below:`,
86
74
  "<br clear=\"left\" />"
87
75
  ].join("\n")
88
76
  }
@@ -131,6 +119,20 @@ async function loadPackageConfig(pkgDir, rootConfig, pkgName) {
131
119
  const pkg = await readJson(resolve(pkgDir, "package.json"));
132
120
  if (pkg.bumpy && typeof pkg.bumpy === "object") pkgJsonConfig = pkg.bumpy;
133
121
  } catch {}
122
+ const disallowedKeys = [
123
+ "buildCommand",
124
+ "publishCommand",
125
+ "checkPublished"
126
+ ].filter((k) => pkgJsonConfig[k] != null);
127
+ if (disallowedKeys.length > 0 && !isCustomCommandAllowed(pkgName, rootConfig)) {
128
+ const fields = disallowedKeys.map((k) => `"${k}"`).join(", ");
129
+ throw new Error(`Package "${pkgName}" defines custom command(s) (${fields}) in its package.json "bumpy" config, but the root config does not allow this.
130
+ Custom commands execute shell commands during publishing and must be explicitly enabled.
131
+
132
+ To fix this, either:
133
+ 1. Move the command(s) to .bumpy/_config.json under "packages" (always trusted)
134
+ 2. Add "allowCustomCommands": true (or ["${pkgName}"]) to .bumpy/_config.json`);
135
+ }
134
136
  return mergePackageConfig(rootPkgConfig, pkgJsonConfig);
135
137
  }
136
138
  /** Find a package config from the root config, supporting glob patterns */
@@ -175,10 +177,6 @@ function mergePackageConfig(...configs) {
175
177
  ...result.dependencyBumpRules,
176
178
  ...cfg.dependencyBumpRules
177
179
  };
178
- if (cfg.specificDependencyRules) result.specificDependencyRules = {
179
- ...result.specificDependencyRules,
180
- ...cfg.specificDependencyRules
181
- };
182
180
  if (cfg.cascadeTo) result.cascadeTo = {
183
181
  ...result.cascadeTo,
184
182
  ...cfg.cascadeTo
@@ -186,6 +184,13 @@ function mergePackageConfig(...configs) {
186
184
  }
187
185
  return result;
188
186
  }
187
+ /** Check if a package is allowed to define custom commands via package.json */
188
+ function isCustomCommandAllowed(pkgName, config) {
189
+ const { allowCustomCommands } = config;
190
+ if (allowCustomCommands === true) return true;
191
+ if (Array.isArray(allowCustomCommands)) return allowCustomCommands.some((pattern) => matchGlob(pkgName, pattern));
192
+ return false;
193
+ }
189
194
  function getBumpyDir(rootDir) {
190
195
  return resolve(rootDir, BUMPY_DIR);
191
196
  }
@@ -212,4 +217,4 @@ function isPackageManaged(pkgName, isPrivate, config, pkgBumpy) {
212
217
  return true;
213
218
  }
214
219
  //#endregion
215
- export { loadConfig as a, BUMP_LEVELS as c, DEFAULT_PUBLISH_CONFIG as d, DEP_TYPES as f, parseIsolatedBump as g, maxBump as h, isPackageManaged as i, DEFAULT_BUMP_RULES as l, hasCascade as m, findRoot as n, loadPackageConfig as o, bumpLevel as p, getBumpyDir as r, matchGlob as s, config_exports as t, DEFAULT_CONFIG as u };
220
+ export { loadConfig as a, BUMP_LEVELS as c, DEFAULT_PUBLISH_CONFIG as d, DEP_TYPES as f, maxBump as h, isPackageManaged as i, DEFAULT_BUMP_RULES as l, hasCascade as m, findRoot as n, loadPackageConfig as o, bumpLevel as p, getBumpyDir as r, matchGlob as s, config_exports as t, DEFAULT_CONFIG as u };
@@ -0,0 +1,81 @@
1
+ import { a as __exportAll } from "./logger-C2dEe5Su.mjs";
2
+ import { access, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
3
+ //#region src/utils/fs.ts
4
+ var fs_exports = /* @__PURE__ */ __exportAll({
5
+ ensureDir: () => ensureDir,
6
+ exists: () => exists,
7
+ listFiles: () => listFiles,
8
+ readJson: () => readJson,
9
+ readText: () => readText,
10
+ removeFile: () => removeFile,
11
+ updateJsonFields: () => updateJsonFields,
12
+ updateJsonNestedField: () => updateJsonNestedField,
13
+ writeJson: () => writeJson,
14
+ writeText: () => writeText
15
+ });
16
+ async function readJson(filePath) {
17
+ const content = await readFile(filePath, "utf-8");
18
+ return JSON.parse(content);
19
+ }
20
+ async function writeJson(filePath, data, indent = 2) {
21
+ await writeFile(filePath, JSON.stringify(data, null, indent) + "\n", "utf-8");
22
+ }
23
+ /**
24
+ * Update specific top-level string fields in a JSON file without reformatting.
25
+ * Reads the raw text, does targeted regex replacements, and writes it back.
26
+ */
27
+ async function updateJsonFields(filePath, updates) {
28
+ let content = await readFile(filePath, "utf-8");
29
+ for (const [key, newValue] of Object.entries(updates)) {
30
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
31
+ const pattern = new RegExp(`("${escaped}"\\s*:\\s*)"[^"]*"`);
32
+ content = content.replace(pattern, `$1"${newValue}"`);
33
+ }
34
+ await writeFile(filePath, content, "utf-8");
35
+ }
36
+ /**
37
+ * Update a nested string field inside a top-level object in a JSON file without reformatting.
38
+ * e.g., updateJsonNestedField(path, 'dependencies', 'core', '^2.0.0')
39
+ */
40
+ async function updateJsonNestedField(filePath, parentKey, childKey, newValue) {
41
+ let content = await readFile(filePath, "utf-8");
42
+ const parentEscaped = parentKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
43
+ const childEscaped = childKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
44
+ const parentPattern = new RegExp(`("${parentEscaped}"\\s*:\\s*\\{)([^}]*)\\}`, "s");
45
+ content = content.replace(parentPattern, (match, prefix, body) => {
46
+ const childPattern = new RegExp(`("${childEscaped}"\\s*:\\s*)"[^"]*"`);
47
+ return `${prefix}${body.replace(childPattern, `$1"${newValue}"`)}}`;
48
+ });
49
+ await writeFile(filePath, content, "utf-8");
50
+ }
51
+ async function readText(filePath) {
52
+ return readFile(filePath, "utf-8");
53
+ }
54
+ async function writeText(filePath, content) {
55
+ await writeFile(filePath, content, "utf-8");
56
+ }
57
+ async function exists(filePath) {
58
+ try {
59
+ await access(filePath);
60
+ return true;
61
+ } catch {
62
+ return false;
63
+ }
64
+ }
65
+ async function listFiles(dir, ext) {
66
+ try {
67
+ const entries = await readdir(dir);
68
+ if (ext) return entries.filter((e) => e.endsWith(ext));
69
+ return entries;
70
+ } catch {
71
+ return [];
72
+ }
73
+ }
74
+ async function removeFile(filePath) {
75
+ await unlink(filePath);
76
+ }
77
+ async function ensureDir(dir) {
78
+ await mkdir(dir, { recursive: true });
79
+ }
80
+ //#endregion
81
+ export { readJson as a, updateJsonFields as c, writeText as d, listFiles as i, updateJsonNestedField as l, exists as n, readText as o, fs_exports as r, removeFile as s, ensureDir as t, writeJson as u };
@@ -1,10 +1,10 @@
1
- import { n as log, t as colorize } from "./logger-ZqggsyGZ.mjs";
2
- import { t as ensureDir } from "./fs-DbNNEyzq.mjs";
3
- import { a as loadConfig, r as getBumpyDir } from "./config-CJ2orhTL.mjs";
4
- import { t as discoverPackages } from "./workspace-mVjawG8g.mjs";
5
- import { i as writeChangeset } from "./changeset-ClCYsChu.mjs";
6
- import { i as tryRun } from "./shell-DPlltpzb.mjs";
7
- import { n as slugify, t as randomName } from "./names-C-u50ofE.mjs";
1
+ import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
2
+ import { t as ensureDir } from "./fs-DYR2XuFE.mjs";
3
+ import { a as loadConfig, r as getBumpyDir } from "./config-XZWUL3ma.mjs";
4
+ import { t as discoverPackages } from "./workspace-C5ULTyUN.mjs";
5
+ import { o as tryRunArgs } from "./shell-Dj7JRD_q.mjs";
6
+ import { i as writeBumpFile } from "./bump-file-CCLXMLA8.mjs";
7
+ import { n as slugify, t as randomName } from "./names-9VubBmL0.mjs";
8
8
  //#region src/commands/generate.ts
9
9
  const BUMP_MAP = {
10
10
  feat: "minor",
@@ -27,7 +27,12 @@ async function generateCommand(rootDir, opts) {
27
27
  process.exit(1);
28
28
  }
29
29
  log.step(`Scanning commits from ${colorize(from, "cyan")}...`);
30
- const rawLog = tryRun(`git log ${from}..HEAD --format="%H%n%s%n%b%n---END---"`, { cwd: rootDir });
30
+ const rawLog = tryRunArgs([
31
+ "git",
32
+ "log",
33
+ `${from}..HEAD`,
34
+ "--format=%H%n%s%n%b%n---END---"
35
+ ], { cwd: rootDir });
31
36
  if (!rawLog) {
32
37
  log.info("No commits found since " + from);
33
38
  return;
@@ -79,7 +84,7 @@ async function generateCommand(rootDir, opts) {
79
84
  for (const msg of info.messages) summaryLines.push(`- ${name}: ${msg}`);
80
85
  }
81
86
  if (opts.dryRun) {
82
- log.bold("Would create changeset:");
87
+ log.bold("Would create bump file:");
83
88
  for (const r of releases) console.log(` ${r.name}: ${colorize(r.type, r.type === "major" ? "red" : r.type === "minor" ? "yellow" : "green")}`);
84
89
  console.log();
85
90
  log.dim("Summary:");
@@ -88,8 +93,8 @@ async function generateCommand(rootDir, opts) {
88
93
  }
89
94
  await ensureDir(getBumpyDir(rootDir));
90
95
  const filename = opts.name ? slugify(opts.name) : randomName();
91
- await writeChangeset(rootDir, filename, releases, summaryLines.join("\n"));
92
- log.success(`Created changeset: .bumpy/${filename}.md`);
96
+ await writeBumpFile(rootDir, filename, releases, summaryLines.join("\n"));
97
+ log.success(`Created bump file: .bumpy/${filename}.md`);
93
98
  for (const r of releases) log.dim(` ${r.name}: ${r.type}`);
94
99
  }
95
100
  /** Parse raw git log output into individual commits */
@@ -152,7 +157,21 @@ function bumpPriority(type) {
152
157
  }
153
158
  /** Find the most recent version tag in the repo */
154
159
  function findLastVersionTag(rootDir) {
155
- return tryRun("git describe --tags --abbrev=0 --match \"v*\" 2>/dev/null || git describe --tags --abbrev=0 --match \"*@*\" 2>/dev/null", { cwd: rootDir }) || null;
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;
156
175
  }
157
176
  //#endregion
158
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 };