bunset 1.0.6 → 1.0.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.8
4
+
5
+ ### Features
6
+
7
+ - add --push option and proceed with empty changelog entries
8
+
9
+ ## 1.0.7
10
+
11
+ ### Features
12
+
13
+ - prompt for commit/tag when not explicitly set
14
+
15
+ ### Bug Fixes
16
+
17
+ - sync package versions in monorepo when using shared tags
18
+
3
19
  ## 1.0.6
4
20
 
5
21
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunset",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -18,6 +18,7 @@ Options:
18
18
  --per-package-tags Use package-scoped tags (pkg@version) instead of prefixed
19
19
  --tag-prefix <str> Tag prefix (auto-detected from last tag, or "v" if no tags)
20
20
  --sections <list> Comma-separated changelog sections (default: feat,fix,perf)
21
+ --push Push commit and tags to remote after tagging
21
22
  --dry-run Preview changes without writing files, committing, or tagging
22
23
  --debug Show detailed inclusion/exclusion reasoning (implies --dry-run)
23
24
  --no-filter-by-package
@@ -73,6 +74,7 @@ Config file (.bunset.toml):
73
74
  per-package-tags = false # pkg@version tags (monorepo)
74
75
  tag-prefix = "v" # tag prefix (default: auto-detect)
75
76
  sections = ["feat", "fix", "perf"] # changelog sections and order
77
+ push = false # push after tagging (default: false)
76
78
  dry-run = false # preview without writing
77
79
  debug = false # detailed reasoning (implies dry-run)
78
80
  filter-by-package = true # per-package filtering (monorepo)`);
@@ -92,10 +94,11 @@ export function resolveOptions(
92
94
  patch: { type: "boolean", default: false },
93
95
  minor: { type: "boolean", default: false },
94
96
  major: { type: "boolean", default: false },
95
- commit: { type: "boolean", default: true },
96
- tag: { type: "boolean", default: true },
97
+ commit: { type: "boolean" },
98
+ tag: { type: "boolean" },
97
99
  "per-package-tags": { type: "boolean", default: false },
98
100
  sections: { type: "string" },
101
+ push: { type: "boolean", default: false },
99
102
  "dry-run": { type: "boolean", default: false },
100
103
  "filter-by-package": { type: "boolean", default: true },
101
104
  "tag-prefix": { type: "string" },
@@ -124,8 +127,8 @@ export function resolveOptions(
124
127
  const bump = cliBump ?? config.bump ?? null;
125
128
  const scope = cliScope ?? config.scope ?? (isWs ? null : "all");
126
129
 
127
- const commit = values.commit === false ? false : (config.commit ?? true);
128
- const tag = values.tag === false ? false : (config.tag ?? true);
130
+ const commit = values.commit !== undefined ? (values.commit as boolean) : (config.commit ?? null);
131
+ const tag = values.tag !== undefined ? (values.tag as boolean) : (config.tag ?? null);
129
132
  const perPackageTags = values["per-package-tags"]
130
133
  ? true
131
134
  : (config.perPackageTags ?? false);
@@ -134,6 +137,7 @@ export function resolveOptions(
134
137
  ?? config.sections
135
138
  ?? DEFAULT_SECTIONS;
136
139
 
140
+ const push = values.push ? true : (config.push ?? false);
137
141
  const debug = values.debug ? true : (config.debug ?? false);
138
142
  const dryRun = debug || values["dry-run"] ? true : (config.dryRun ?? false);
139
143
 
@@ -145,12 +149,12 @@ export function resolveOptions(
145
149
  ?? config.tagPrefix
146
150
  ?? null;
147
151
 
148
- if (bump && scope) {
149
- return { scope, bump, commit, tag, perPackageTags, sections, dryRun, filterByPackage, tagPrefix, debug };
152
+ if (bump && scope && commit !== null && tag !== null) {
153
+ return { scope, bump, commit, tag, perPackageTags, sections, dryRun, filterByPackage, tagPrefix, push, debug };
150
154
  }
151
155
 
152
156
  return promptForMissing(
153
- { commit, tag, perPackageTags, sections, dryRun, filterByPackage, tagPrefix, debug },
157
+ { commit, tag, perPackageTags, sections, dryRun, filterByPackage, tagPrefix, push, debug },
154
158
  bump,
155
159
  scope,
156
160
  isWs,
@@ -185,13 +189,14 @@ function parseSections(raw: string | undefined): CommitType[] | null {
185
189
  }
186
190
 
187
191
  interface MergedDefaults {
188
- commit: boolean;
189
- tag: boolean;
192
+ commit: boolean | null;
193
+ tag: boolean | null;
190
194
  perPackageTags: boolean;
191
195
  sections: CommitType[];
192
196
  dryRun: boolean;
193
197
  filterByPackage: boolean;
194
198
  tagPrefix: string | null;
199
+ push: boolean;
195
200
  debug: boolean;
196
201
  }
197
202
 
@@ -220,10 +225,26 @@ async function promptForMissing(
220
225
  else bump = "patch";
221
226
  }
222
227
 
228
+ let { commit, tag } = merged;
229
+
230
+ if (commit === null) {
231
+ process.stdout.write("Commit changes? (y/n) [default: y]: ");
232
+ const answer = await readLine();
233
+ commit = answer.trim().toLowerCase() !== "n";
234
+ }
235
+
236
+ if (tag === null) {
237
+ process.stdout.write("Tag release? (y/n) [default: y]: ");
238
+ const answer = await readLine();
239
+ tag = answer.trim().toLowerCase() !== "n";
240
+ }
241
+
223
242
  return {
224
243
  scope: scope ?? "all",
225
244
  bump,
226
245
  ...merged,
246
+ commit,
247
+ tag,
227
248
  };
228
249
  }
229
250
 
package/src/config.ts CHANGED
@@ -49,6 +49,10 @@ export async function loadConfig(
49
49
  config.tagPrefix = raw["tag-prefix"];
50
50
  }
51
51
 
52
+ if (typeof raw.push === "boolean") {
53
+ config.push = raw.push;
54
+ }
55
+
52
56
  if (typeof raw.debug === "boolean") {
53
57
  config.debug = raw.debug;
54
58
  }
package/src/git.ts CHANGED
@@ -79,3 +79,13 @@ export async function commitAndTag(
79
79
  console.warn(`⚠ Skipped existing tags: ${skipped.join(", ")}`);
80
80
  }
81
81
  }
82
+
83
+ export async function gitPush(
84
+ cwd: string,
85
+ tags: string[] = [],
86
+ ): Promise<void> {
87
+ await $`git -C ${cwd} push`.quiet();
88
+ if (tags.length > 0) {
89
+ await $`git -C ${cwd} push --tags`.quiet();
90
+ }
91
+ }
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  getCommitsSince,
15
15
  getCommitFiles,
16
16
  commitAndTag,
17
+ gitPush,
17
18
  } from "./git.ts";
18
19
  import { getUpdatedDependencies } from "./deps.ts";
19
20
  import {
@@ -21,7 +22,7 @@ import {
21
22
  getAllPackages,
22
23
  getChangedPackages,
23
24
  } from "./workspace.ts";
24
- import { bumpVersion, updatePackageVersion } from "./version.ts";
25
+ import { bumpVersion, parseSemver, updatePackageVersion, setPackageVersion } from "./version.ts";
25
26
  import type { ParsedCommit, GroupedCommits } from "./types.ts";
26
27
 
27
28
  const cwd = process.cwd();
@@ -115,11 +116,6 @@ if (shouldFilter) {
115
116
 
116
117
  const globalGroups = groupCommits(parsed);
117
118
 
118
- if (options.sections.every((type) => globalGroups[type].length === 0)) {
119
- console.log("No categorized commits found. Nothing to do.");
120
- process.exit(0);
121
- }
122
-
123
119
  let packages =
124
120
  options.scope === "changed"
125
121
  ? await getChangedPackages(cwd, allPackages, lastTag)
@@ -145,6 +141,22 @@ function packageHasChanges(groups: GroupedCommits): boolean {
145
141
  return options.sections.some((type) => groups[type].length > 0);
146
142
  }
147
143
 
144
+ // When using shared tags, sync all packages to the same target version
145
+ let targetVersion: string | null = null;
146
+ if (!options.perPackageTags && packages.length > 1) {
147
+ const maxVersion = packages.reduce((max, pkg) => {
148
+ const v = pkg.version ?? "0.0.0";
149
+ const [mj1, mn1, p1] = parseSemver(max);
150
+ const [mj2, mn2, p2] = parseSemver(v);
151
+ if (mj2 > mj1) return v;
152
+ if (mj2 === mj1 && mn2 > mn1) return v;
153
+ if (mj2 === mj1 && mn2 === mn1 && p2 > p1) return v;
154
+ return max;
155
+ }, "0.0.0");
156
+ targetVersion = bumpVersion(maxVersion, options.bump);
157
+ debug(`shared tag mode: max version = ${maxVersion}, target version = ${targetVersion}`);
158
+ }
159
+
148
160
  if (options.dryRun) {
149
161
  if (!dbg) console.log("--- Dry Run ---\n");
150
162
 
@@ -179,7 +191,7 @@ if (options.dryRun) {
179
191
  }
180
192
 
181
193
  const oldVersion = pkg.version ?? "0.0.0";
182
- const newVersion = bumpVersion(oldVersion, options.bump);
194
+ const newVersion = targetVersion ?? bumpVersion(oldVersion, options.bump);
183
195
  console.log(`${pkg.name}: ${oldVersion} → ${newVersion}`);
184
196
  filesToCommit.push(pkg.packageJsonPath, `${pkg.path}/CHANGELOG.md`);
185
197
 
@@ -212,9 +224,10 @@ if (options.dryRun) {
212
224
  filesToCommit.push(`${cwd}/bun.lock`);
213
225
 
214
226
  if (options.commit) {
227
+ const releaseVersion = targetVersion ?? bumpVersion(packages[0]!.version ?? "0.0.0", options.bump);
215
228
  const msg =
216
229
  packages.length === 1
217
- ? `chore: release ${packages[0]!.name}@${bumpVersion(packages[0]!.version ?? "0.0.0", options.bump)}`
230
+ ? `chore: release ${packages[0]!.name}@${releaseVersion}`
218
231
  : `chore: release ${packages.length} packages`;
219
232
  console.log(`Would commit: ${msg}`);
220
233
  } else {
@@ -227,6 +240,10 @@ if (options.dryRun) {
227
240
  console.log("Will not tag (--tag not set).");
228
241
  }
229
242
 
243
+ if (options.push) {
244
+ console.log("Would push commit and tags to remote.");
245
+ }
246
+
230
247
  console.log(`\nFiles that would be modified (${filesToCommit.length}):`);
231
248
  for (const f of filesToCommit) {
232
249
  console.log(` ${f}`);
@@ -247,10 +264,9 @@ for (const pkg of packages) {
247
264
  continue;
248
265
  }
249
266
 
250
- const { oldVersion, newVersion } = await updatePackageVersion(
251
- pkg.packageJsonPath,
252
- options.bump,
253
- );
267
+ const { oldVersion, newVersion } = targetVersion
268
+ ? await setPackageVersion(pkg.packageJsonPath, targetVersion)
269
+ : await updatePackageVersion(pkg.packageJsonPath, options.bump);
254
270
  changedFiles.push(pkg.packageJsonPath);
255
271
  console.log(`${pkg.name}: ${oldVersion} → ${newVersion}`);
256
272
 
@@ -299,6 +315,11 @@ if (options.commit) {
299
315
  if (uniqueTags.length > 0) {
300
316
  console.log(`Tagged: ${uniqueTags.join(", ")}`);
301
317
  }
318
+
319
+ if (options.push) {
320
+ await gitPush(cwd, uniqueTags);
321
+ console.log("Pushed to remote.");
322
+ }
302
323
  }
303
324
 
304
325
  console.log("Done.");
package/src/types.ts CHANGED
@@ -23,6 +23,7 @@ export interface CliOptions {
23
23
  dryRun: boolean;
24
24
  filterByPackage: boolean;
25
25
  tagPrefix: string | null;
26
+ push: boolean;
26
27
  debug: boolean;
27
28
  }
28
29
 
package/src/version.ts CHANGED
@@ -30,3 +30,15 @@ export async function updatePackageVersion(
30
30
  await Bun.write(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
31
31
  return { oldVersion, newVersion };
32
32
  }
33
+
34
+ export async function setPackageVersion(
35
+ packageJsonPath: string,
36
+ newVersion: string,
37
+ ): Promise<{ oldVersion: string; newVersion: string }> {
38
+ const file = Bun.file(packageJsonPath);
39
+ const pkg = await file.json();
40
+ const oldVersion = pkg.version ?? "0.0.0";
41
+ pkg.version = newVersion;
42
+ await Bun.write(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
43
+ return { oldVersion, newVersion };
44
+ }