@ucdjs/release-scripts 0.1.0-beta.33 → 0.1.0-beta.34

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 (2) hide show
  1. package/dist/index.mjs +244 -128
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,21 +1,98 @@
1
1
  import { t as Eta } from "./eta-BV8TCRDW.mjs";
2
2
  import { Console, Context, Data, Effect, Layer, Schema } from "effect";
3
+ import process from "node:process";
3
4
  import path from "node:path";
4
5
  import { Command, CommandExecutor } from "@effect/platform";
5
6
  import { NodeCommandExecutor, NodeFileSystem } from "@effect/platform-node";
6
7
  import * as CommitParser from "commit-parser";
7
- import process from "node:process";
8
8
  import semver from "semver";
9
9
  import fs from "node:fs/promises";
10
10
  import prompts from "prompts";
11
11
 
12
+ //#region src/options.ts
13
+ const DEFAULT_PR_BODY_TEMPLATE = `## Summary\n\nThis PR contains the following changes:\n\n- Updated package versions\n- Updated changelogs\n\n## Packages\n\nThe following packages will be released:\n\n{{packages}}`;
14
+ const DEFAULT_CHANGELOG_TEMPLATE = `# Changelog\n\n{{releases}}`;
15
+ const DEFAULT_TYPES = {
16
+ feat: {
17
+ title: "🚀 Features",
18
+ color: "green"
19
+ },
20
+ fix: {
21
+ title: "🐞 Bug Fixes",
22
+ color: "red"
23
+ },
24
+ refactor: {
25
+ title: "🔧 Code Refactoring",
26
+ color: "blue"
27
+ },
28
+ perf: {
29
+ title: "🏎 Performance",
30
+ color: "orange"
31
+ },
32
+ docs: {
33
+ title: "📚 Documentation",
34
+ color: "purple"
35
+ },
36
+ style: {
37
+ title: "🎨 Styles",
38
+ color: "pink"
39
+ }
40
+ };
41
+ function normalizeReleaseScriptsOptions(options) {
42
+ const { workspaceRoot = process.cwd(), githubToken = "", repo: fullRepo, packages = true, branch = {}, globalCommitMode = "dependencies", pullRequest = {}, changelog = {}, types = {}, dryRun = false, npm = {}, prompts = {} } = options;
43
+ const token = githubToken.trim();
44
+ if (!token) throw new Error("GitHub token is required. Pass it in via options.");
45
+ if (!fullRepo || !fullRepo.trim() || !fullRepo.includes("/")) throw new Error("Repository (repo) is required. Specify in 'owner/repo' format (e.g., 'octocat/hello-world').");
46
+ const [owner, repo] = fullRepo.split("/");
47
+ if (!owner || !repo) throw new Error(`Invalid repo format: "${fullRepo}". Expected format: "owner/repo" (e.g., "octocat/hello-world").`);
48
+ const normalizedPackages = typeof packages === "object" && !Array.isArray(packages) ? {
49
+ exclude: packages.exclude ?? [],
50
+ include: packages.include ?? [],
51
+ excludePrivate: packages.excludePrivate ?? false
52
+ } : packages;
53
+ const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
54
+ return {
55
+ dryRun,
56
+ workspaceRoot,
57
+ githubToken: token,
58
+ owner,
59
+ repo,
60
+ packages: normalizedPackages,
61
+ branch: {
62
+ release: branch.release ?? "release/next",
63
+ default: branch.default ?? "main"
64
+ },
65
+ globalCommitMode,
66
+ pullRequest: {
67
+ title: pullRequest.title ?? "chore: release new version",
68
+ body: pullRequest.body ?? DEFAULT_PR_BODY_TEMPLATE
69
+ },
70
+ changelog: {
71
+ enabled: changelog.enabled ?? true,
72
+ template: changelog.template ?? DEFAULT_CHANGELOG_TEMPLATE,
73
+ emojis: changelog.emojis ?? true
74
+ },
75
+ types: options.types ? {
76
+ ...DEFAULT_TYPES,
77
+ ...types
78
+ } : DEFAULT_TYPES,
79
+ npm: {
80
+ otp: npm.otp,
81
+ provenance: npm.provenance ?? true
82
+ },
83
+ prompts: { versions: prompts.versions ?? !isCI }
84
+ };
85
+ }
86
+ var ReleaseScriptsOptions = class extends Context.Tag("@ucdjs/release-scripts/ReleaseScriptsOptions")() {};
87
+
88
+ //#endregion
12
89
  //#region src/utils/changelog-formatters.ts
13
90
  const eta$1 = new Eta();
14
91
  /**
15
92
  * Pure function to parse commits into changelog entries
16
93
  */
17
94
  function parseCommits(commits) {
18
- return commits.filter((commit) => commit.isConventional).map((commit) => ({
95
+ return commits.filter((commit) => commit.isConventional).filter((commit) => commit.type !== "chore").map((commit) => ({
19
96
  type: commit.type || "other",
20
97
  scope: commit.scope,
21
98
  description: commit.description,
@@ -25,6 +102,11 @@ function parseCommits(commits) {
25
102
  references: commit.references.map((ref) => ({
26
103
  type: ref.type,
27
104
  value: ref.value
105
+ })),
106
+ authors: commit.authors.map((author) => ({
107
+ name: author.name,
108
+ email: author.email,
109
+ profile: author.profile
28
110
  }))
29
111
  }));
30
112
  }
@@ -43,10 +125,7 @@ function groupByType(entries) {
43
125
  /**
44
126
  * Changelog template for Eta rendering
45
127
  */
46
- const CHANGELOG_TEMPLATE = `# <%= it.packageName %> v<%= it.version %>
47
-
48
- **Previous version**: \`<%= it.previousVersion %>\`
49
- **New version**: \`<%= it.version %>\`
128
+ const CHANGELOG_ENTRY_TEMPLATE = `## <%= it.version %>
50
129
 
51
130
  <% if (it.entries.length === 0) { %>
52
131
  *No conventional commits found.*
@@ -55,25 +134,58 @@ const CHANGELOG_TEMPLATE = `# <%= it.packageName %> v<%= it.version %>
55
134
  <% const typeOrder = ["breaking", "feat", "fix", "perf", "docs", "style", "refactor", "test", "build", "ci", "chore"]; %>
56
135
  <% const typeLabels = {
57
136
  breaking: "💥 Breaking Changes",
58
- feat: " Features",
59
- fix: "🐛 Bug Fixes",
137
+ feat: "🚀 Features",
138
+ fix: "🐞 Bug Fixes",
60
139
  perf: "⚡ Performance",
61
- docs: "📝 Documentation",
62
- style: "💄 Styling",
63
- refactor: "♻️ Refactoring",
64
- test: "Tests",
65
- build: "📦 Build",
66
- ci: "👷 CI",
67
- chore: "🔧 Chores"
140
+ docs: "Documentation",
141
+ style: "Styling",
142
+ refactor: "Refactoring",
143
+ test: "Tests",
144
+ build: "Build",
145
+ ci: "CI",
146
+ chore: "Chores"
147
+ }; %>
148
+
149
+ <% const formatAuthor = (entry) => {
150
+ const author = entry.authors && entry.authors.length > 0 ? entry.authors[0] : null;
151
+ if (!author) return "unknown";
152
+ if (author.profile && author.profile.includes("github.com/")) {
153
+ const username = author.profile.split("github.com/")[1];
154
+ return "@" + username;
155
+ }
156
+ return author.name || "unknown";
157
+ }; %>
158
+
159
+ <% const commitUrl = (hash) => it.repo ? "https://github.com/" + it.repo + "/commit/" + hash : ""; %>
160
+
161
+ <% const formatLine = (entry) => {
162
+ const authorText = formatAuthor(entry);
163
+ const commitLink = commitUrl(entry.hash);
164
+ const hashPart = commitLink
165
+ ? " [<samp>(" + entry.shortHash + ")</samp>](" + commitLink + ")"
166
+ : " <samp>(" + entry.shortHash + ")</samp>";
167
+ return entry.description + " &nbsp;-&nbsp; by " + authorText + hashPart;
68
168
  }; %>
69
169
 
70
170
  <% for (const type of typeOrder) { %>
71
171
  <% const entries = groups.get(type); %>
72
172
  <% if (entries && entries.length > 0) { %>
73
- ## <%= typeLabels[type] || type.charAt(0).toUpperCase() + type.slice(1) %>
173
+ ### &nbsp;&nbsp;&nbsp;<%= typeLabels[type] || type.charAt(0).toUpperCase() + type.slice(1) %>
74
174
 
75
- <% for (const entry of entries) { %>
76
- - <% if (entry.scope) { %>**<%= entry.scope %>**: <% } %><%= entry.description %><% if (entry.references.length > 0) { %> (<%= entry.references.map(r => "#" + r.value).join(", ") %>)<% } %> (\`<%= entry.shortHash %>\`)
175
+ <% const unscoped = entries.filter(e => !e.scope); %>
176
+ <% const scoped = entries.filter(e => e.scope); %>
177
+
178
+ <% for (const entry of unscoped) { %>
179
+ - <%= formatLine(entry) %>
180
+ <% } %>
181
+
182
+ <% const scopes = [...new Set(scoped.map(e => e.scope))]; %>
183
+ <% for (const scope of scopes) { %>
184
+ - **<%= scope %>**:
185
+ <% const scopeEntries = scoped.filter(e => e.scope === scope); %>
186
+ <% for (const entry of scopeEntries) { %>
187
+ - <%= formatLine(entry) %>
188
+ <% } %>
77
189
  <% } %>
78
190
 
79
191
  <% } %>
@@ -81,37 +193,56 @@ const CHANGELOG_TEMPLATE = `# <%= it.packageName %> v<%= it.version %>
81
193
 
82
194
  <% for (const [type, entries] of groups) { %>
83
195
  <% if (!typeOrder.includes(type)) { %>
84
- ## <%= type.charAt(0).toUpperCase() + type.slice(1) %>
196
+ ### &nbsp;&nbsp;&nbsp;<%= type.charAt(0).toUpperCase() + type.slice(1) %>
85
197
 
86
198
  <% for (const entry of entries) { %>
87
- - <% if (entry.scope) { %>**<%= entry.scope %>**: <% } %><%= entry.description %> (\`<%= entry.shortHash %>\`)
199
+ - <%= formatLine(entry) %>
88
200
  <% } %>
89
201
 
90
202
  <% } %>
91
203
  <% } %>
204
+
205
+ <% if (it.repo) { %>
206
+ ##### &nbsp;&nbsp;&nbsp;&nbsp;[View changes on GitHub](https://github.com/<%= it.repo %>/compare/v<%= it.previousVersion %>...v<%= it.version %>)
207
+ <% } %>
92
208
  <% } %>`;
93
209
  /**
94
210
  * Pure function to format changelog as markdown
95
211
  */
96
- function formatChangelogMarkdown(changelog) {
212
+ function formatChangelogEntryMarkdown(changelog) {
97
213
  const groups = groupByType(changelog.entries);
98
- return eta$1.renderString(CHANGELOG_TEMPLATE, {
214
+ return eta$1.renderString(CHANGELOG_ENTRY_TEMPLATE, {
99
215
  packageName: changelog.packageName,
100
216
  version: changelog.version,
101
217
  previousVersion: changelog.previousVersion,
102
218
  entries: changelog.entries,
103
- groupedEntries: groups
219
+ groupedEntries: groups,
220
+ repo: changelog.repo
104
221
  });
105
222
  }
223
+ function appendChangelogEntry(existingContent, changelogEntry, packageName) {
224
+ const entry = changelogEntry.trim();
225
+ if (!entry) return existingContent ?? `# ${packageName}\n`;
226
+ if (!existingContent || existingContent.trim() === "") return `# ${packageName}\n\n${entry}\n`;
227
+ const lines = existingContent.split("\n");
228
+ const firstLine = lines[0]?.trim() ?? "";
229
+ if (!firstLine.startsWith("# ")) return `# ${packageName}\n\n${entry}\n\n${existingContent.trim()}\n`;
230
+ let insertIndex = 1;
231
+ while (insertIndex < lines.length && lines[insertIndex]?.trim() === "") insertIndex++;
232
+ const rest = lines.slice(insertIndex).join("\n").trim();
233
+ if (rest) return `${firstLine}\n\n${entry}\n\n${rest}\n`;
234
+ return `${firstLine}\n\n${entry}\n`;
235
+ }
106
236
  /**
107
237
  * Pure function to create a changelog object
108
238
  */
109
- function createChangelog(packageName, version, previousVersion, commits) {
239
+ function createChangelog(packageName, version, previousVersion, commits, repo) {
110
240
  return {
111
241
  packageName,
112
242
  version,
113
243
  previousVersion,
114
- entries: parseCommits(commits)
244
+ entries: parseCommits(commits),
245
+ repo
115
246
  };
116
247
  }
117
248
 
@@ -119,12 +250,19 @@ function createChangelog(packageName, version, previousVersion, commits) {
119
250
  //#region src/services/changelog.service.ts
120
251
  var ChangelogService = class extends Effect.Service()("@ucdjs/release-scripts/ChangelogService", {
121
252
  effect: Effect.gen(function* () {
253
+ const config = yield* ReleaseScriptsOptions;
122
254
  function generateChangelog(pkg, newVersion, commits) {
123
255
  return Effect.gen(function* () {
124
- const changelog = createChangelog(pkg.name, newVersion, pkg.version, commits);
256
+ const changelog = createChangelog(pkg.name, newVersion, pkg.version, commits, `${config.owner}/${config.repo}`);
257
+ const entryMarkdown = formatChangelogEntryMarkdown(changelog);
125
258
  return {
126
259
  changelog,
127
- markdown: formatChangelogMarkdown(changelog),
260
+ markdown: appendChangelogEntry(yield* Effect.tryPromise({
261
+ try: async () => {
262
+ return await (await import("node:fs/promises")).readFile(`${pkg.path}/CHANGELOG.md`, "utf-8");
263
+ },
264
+ catch: (err) => err
265
+ }).pipe(Effect.catchAll(() => Effect.succeed(""))), entryMarkdown, pkg.name),
128
266
  filePath: `${pkg.path}/CHANGELOG.md`
129
267
  };
130
268
  });
@@ -213,83 +351,6 @@ var NPMError = class extends Data.TaggedError("NPMError") {};
213
351
  var PublishError = class extends Data.TaggedError("PublishError") {};
214
352
  var TagError = class extends Data.TaggedError("TagError") {};
215
353
 
216
- //#endregion
217
- //#region src/options.ts
218
- const DEFAULT_PR_BODY_TEMPLATE = `## Summary\n\nThis PR contains the following changes:\n\n- Updated package versions\n- Updated changelogs\n\n## Packages\n\nThe following packages will be released:\n\n{{packages}}`;
219
- const DEFAULT_CHANGELOG_TEMPLATE = `# Changelog\n\n{{releases}}`;
220
- const DEFAULT_TYPES = {
221
- feat: {
222
- title: "🚀 Features",
223
- color: "green"
224
- },
225
- fix: {
226
- title: "🐞 Bug Fixes",
227
- color: "red"
228
- },
229
- refactor: {
230
- title: "🔧 Code Refactoring",
231
- color: "blue"
232
- },
233
- perf: {
234
- title: "🏎 Performance",
235
- color: "orange"
236
- },
237
- docs: {
238
- title: "📚 Documentation",
239
- color: "purple"
240
- },
241
- style: {
242
- title: "🎨 Styles",
243
- color: "pink"
244
- }
245
- };
246
- function normalizeReleaseScriptsOptions(options) {
247
- const { workspaceRoot = process.cwd(), githubToken = "", repo: fullRepo, packages = true, branch = {}, globalCommitMode = "dependencies", pullRequest = {}, changelog = {}, types = {}, dryRun = false, npm = {}, prompts = {} } = options;
248
- const token = githubToken.trim();
249
- if (!token) throw new Error("GitHub token is required. Pass it in via options.");
250
- if (!fullRepo || !fullRepo.trim() || !fullRepo.includes("/")) throw new Error("Repository (repo) is required. Specify in 'owner/repo' format (e.g., 'octocat/hello-world').");
251
- const [owner, repo] = fullRepo.split("/");
252
- if (!owner || !repo) throw new Error(`Invalid repo format: "${fullRepo}". Expected format: "owner/repo" (e.g., "octocat/hello-world").`);
253
- const normalizedPackages = typeof packages === "object" && !Array.isArray(packages) ? {
254
- exclude: packages.exclude ?? [],
255
- include: packages.include ?? [],
256
- excludePrivate: packages.excludePrivate ?? false
257
- } : packages;
258
- const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
259
- return {
260
- dryRun,
261
- workspaceRoot,
262
- githubToken: token,
263
- owner,
264
- repo,
265
- packages: normalizedPackages,
266
- branch: {
267
- release: branch.release ?? "release/next",
268
- default: branch.default ?? "main"
269
- },
270
- globalCommitMode,
271
- pullRequest: {
272
- title: pullRequest.title ?? "chore: release new version",
273
- body: pullRequest.body ?? DEFAULT_PR_BODY_TEMPLATE
274
- },
275
- changelog: {
276
- enabled: changelog.enabled ?? true,
277
- template: changelog.template ?? DEFAULT_CHANGELOG_TEMPLATE,
278
- emojis: changelog.emojis ?? true
279
- },
280
- types: options.types ? {
281
- ...DEFAULT_TYPES,
282
- ...types
283
- } : DEFAULT_TYPES,
284
- npm: {
285
- otp: npm.otp,
286
- provenance: npm.provenance ?? true
287
- },
288
- prompts: { versions: prompts.versions ?? !isCI }
289
- };
290
- }
291
- var ReleaseScriptsOptions = class extends Context.Tag("@ucdjs/release-scripts/ReleaseScriptsOptions")() {};
292
-
293
354
  //#endregion
294
355
  //#region src/services/git.service.ts
295
356
  var GitService = class extends Effect.Service()("@ucdjs/release-scripts/GitService", {
@@ -784,6 +845,9 @@ var WorkspaceService = class extends Effect.Service()("@ucdjs/release-scripts/Wo
784
845
  message: `Invalid package.json for ${pkgPath}`,
785
846
  cause: e,
786
847
  operation: "readPackageJson"
848
+ })), Effect.map((validated) => ({
849
+ ...json,
850
+ ...validated
787
851
  })))));
788
852
  }
789
853
  function writePackageJson(pkgPath, json) {
@@ -1176,8 +1240,18 @@ var VersionPromptService = class extends Effect.Service()("@ucdjs/release-script
1176
1240
  effect: Effect.gen(function* () {
1177
1241
  const config = yield* ReleaseScriptsOptions;
1178
1242
  let applyToAllRemainingChoice = null;
1243
+ let isCancelled = false;
1179
1244
  function promptForVersion(pkg, conventionalBump, remainingCount) {
1180
1245
  return Effect.async((resume) => {
1246
+ if (isCancelled) {
1247
+ resume(Effect.succeed({
1248
+ newVersion: pkg.version,
1249
+ bumpType: "none",
1250
+ applyToAllRemaining: false,
1251
+ cancelled: true
1252
+ }));
1253
+ return;
1254
+ }
1181
1255
  const allCommits = [...pkg.commits, ...pkg.globalCommits];
1182
1256
  const prereleaseInfo = getPrereleaseInfo(pkg.version);
1183
1257
  const commitCount = allCommits.length;
@@ -1189,7 +1263,8 @@ var VersionPromptService = class extends Effect.Service()("@ucdjs/release-script
1189
1263
  const result = {
1190
1264
  newVersion: applyToAllRemainingChoice.version === "custom" ? pkg.version : applyToAllRemainingChoice.version,
1191
1265
  bumpType: applyToAllRemainingChoice.bumpType,
1192
- applyToAllRemaining: false
1266
+ applyToAllRemaining: false,
1267
+ cancelled: false
1193
1268
  };
1194
1269
  resume(Effect.succeed(result));
1195
1270
  return;
@@ -1215,10 +1290,12 @@ var VersionPromptService = class extends Effect.Service()("@ucdjs/release-script
1215
1290
  hint: "Use arrow keys to navigate, enter to select"
1216
1291
  }).then(async (response) => {
1217
1292
  if (!response.choice) {
1293
+ isCancelled = true;
1218
1294
  const result = {
1219
1295
  newVersion: pkg.version,
1220
1296
  bumpType: "none",
1221
- applyToAllRemaining: false
1297
+ applyToAllRemaining: false,
1298
+ cancelled: true
1222
1299
  };
1223
1300
  resume(Effect.succeed(result));
1224
1301
  return;
@@ -1235,37 +1312,63 @@ var VersionPromptService = class extends Effect.Service()("@ucdjs/release-script
1235
1312
  })),
1236
1313
  initial: findDefaultIndex(applyOptions, conventionalBump)
1237
1314
  });
1238
- if (applyResponse.choice) {
1239
- if (applyResponse.choice.version === "custom") {
1240
- const customVersion = await promptForCustomVersion(pkg.version);
1241
- if (customVersion) applyToAllRemainingChoice = {
1242
- version: customVersion,
1243
- bumpType: applyResponse.choice.bumpType
1244
- };
1245
- } else applyToAllRemainingChoice = applyResponse.choice;
1246
- const result = {
1247
- newVersion: applyToAllRemainingChoice?.version || pkg.version,
1248
- bumpType: applyToAllRemainingChoice?.bumpType || "none",
1249
- applyToAllRemaining: true
1315
+ if (!applyResponse.choice) {
1316
+ isCancelled = true;
1317
+ resume(Effect.succeed({
1318
+ newVersion: pkg.version,
1319
+ bumpType: "none",
1320
+ applyToAllRemaining: false,
1321
+ cancelled: true
1322
+ }));
1323
+ return;
1324
+ }
1325
+ if (applyResponse.choice.version === "custom") {
1326
+ const customVersion = await promptForCustomVersion(pkg.version);
1327
+ if (!customVersion) {
1328
+ isCancelled = true;
1329
+ resume(Effect.succeed({
1330
+ newVersion: pkg.version,
1331
+ bumpType: "none",
1332
+ applyToAllRemaining: false,
1333
+ cancelled: true
1334
+ }));
1335
+ return;
1336
+ }
1337
+ applyToAllRemainingChoice = {
1338
+ version: customVersion,
1339
+ bumpType: applyResponse.choice.bumpType
1250
1340
  };
1251
- resume(Effect.succeed(result));
1252
- } else promptForVersion(pkg, conventionalBump, remainingCount).pipe(Effect.runPromise).then((r) => resume(Effect.succeed(r)));
1341
+ } else applyToAllRemainingChoice = applyResponse.choice;
1342
+ const result = {
1343
+ newVersion: applyToAllRemainingChoice?.version || pkg.version,
1344
+ bumpType: applyToAllRemainingChoice?.bumpType || "none",
1345
+ applyToAllRemaining: true,
1346
+ cancelled: false
1347
+ };
1348
+ resume(Effect.succeed(result));
1253
1349
  return;
1254
1350
  }
1255
1351
  let selectedVersion = response.choice.version;
1256
- let selectedBumpType = response.choice.bumpType;
1352
+ const selectedBumpType = response.choice.bumpType;
1257
1353
  if (selectedVersion === "custom") {
1258
1354
  const customVersion = await promptForCustomVersion(pkg.version);
1259
- if (customVersion) selectedVersion = customVersion;
1260
- else {
1261
- selectedVersion = pkg.version;
1262
- selectedBumpType = "none";
1355
+ if (!customVersion) {
1356
+ isCancelled = true;
1357
+ resume(Effect.succeed({
1358
+ newVersion: pkg.version,
1359
+ bumpType: "none",
1360
+ applyToAllRemaining: false,
1361
+ cancelled: true
1362
+ }));
1363
+ return;
1263
1364
  }
1365
+ selectedVersion = customVersion;
1264
1366
  }
1265
1367
  const result = {
1266
1368
  newVersion: selectedVersion,
1267
1369
  bumpType: selectedBumpType,
1268
- applyToAllRemaining: false
1370
+ applyToAllRemaining: false,
1371
+ cancelled: false
1269
1372
  };
1270
1373
  resume(Effect.succeed(result));
1271
1374
  });
@@ -1276,6 +1379,7 @@ var VersionPromptService = class extends Effect.Service()("@ucdjs/release-script
1276
1379
  isEnabled: config.prompts.versions,
1277
1380
  resetApplyToAll: () => {
1278
1381
  applyToAllRemainingChoice = null;
1382
+ isCancelled = false;
1279
1383
  }
1280
1384
  };
1281
1385
  }),
@@ -1479,6 +1583,8 @@ function constructPrepareProgram(config) {
1479
1583
  const versionPrompt = yield* VersionPromptService;
1480
1584
  const workspace = yield* WorkspaceService;
1481
1585
  yield* git.workspace.assertWorkspaceReady;
1586
+ const startingBranch = yield* git.branches.get;
1587
+ if (startingBranch !== config.branch.default) return yield* Effect.fail(/* @__PURE__ */ new Error(`Prepare must be run on the default branch "${config.branch.default}". Current branch: "${startingBranch}"`));
1482
1588
  let releasePullRequest = yield* github.getPullRequestByBranch(config.branch.release);
1483
1589
  const isNewRelease = !releasePullRequest;
1484
1590
  const branchExists = yield* git.branches.exists(config.branch.release);
@@ -1534,6 +1640,14 @@ function constructPrepareProgram(config) {
1534
1640
  continue;
1535
1641
  }
1536
1642
  const result = yield* versionPrompt.promptForVersion(pkg, conventionalBump, remainingCount);
1643
+ if (result.cancelled) {
1644
+ yield* Console.log("\nCancelled by user.");
1645
+ if (startingBranch !== (yield* git.branches.get)) {
1646
+ yield* git.branches.checkout(startingBranch);
1647
+ yield* Console.log(`Switched back to "${startingBranch}".`);
1648
+ }
1649
+ return yield* Effect.fail(/* @__PURE__ */ new Error("Release preparation cancelled."));
1650
+ }
1537
1651
  releases.push({
1538
1652
  package: {
1539
1653
  name: pkg.name,
@@ -1609,8 +1723,10 @@ ${releases.map((r) => ` - ${r.package.name}@${r.newVersion}`).join("\n")}`;
1609
1723
  yield* Console.log("Pull request updated.");
1610
1724
  }
1611
1725
  yield* Console.log(`\nRelease preparation complete! View PR: #${releasePullRequest.number}`);
1612
- yield* git.branches.checkout(config.branch.default);
1613
- yield* Console.log(`Switched back to "${config.branch.default}".`);
1726
+ if (startingBranch !== (yield* git.branches.get)) {
1727
+ yield* git.branches.checkout(startingBranch);
1728
+ yield* Console.log(`Switched back to "${startingBranch}".`);
1729
+ }
1614
1730
  });
1615
1731
  }
1616
1732
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ucdjs/release-scripts",
3
- "version": "0.1.0-beta.33",
3
+ "version": "0.1.0-beta.34",
4
4
  "description": "@ucdjs release scripts",
5
5
  "type": "module",
6
6
  "license": "MIT",