relizy 1.4.5 → 1.4.7

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.
@@ -7,7 +7,7 @@ import { getGitDiff, parseCommits, resolveRepoConfig, getRepoConfig, formatCompa
7
7
  import { defu } from 'defu';
8
8
  import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
9
9
  import path, { join, relative, sep } from 'node:path';
10
- import { confirm, input } from '@inquirer/prompts';
10
+ import { select, confirm, input } from '@inquirer/prompts';
11
11
  import fastGlob from 'fast-glob';
12
12
  import * as semver from 'semver';
13
13
  import { convert } from 'convert-gitmoji';
@@ -131,6 +131,250 @@ function topologicalSort(packages) {
131
131
  return sorted;
132
132
  }
133
133
 
134
+ function shellSingleQuote(value) {
135
+ return `'${value.replaceAll("'", "'\\''")}'`;
136
+ }
137
+ async function isAncestor(ancestor, descendant, cwd) {
138
+ try {
139
+ await execPromise(
140
+ `git merge-base --is-ancestor ${shellSingleQuote(ancestor)} ${shellSingleQuote(descendant)}`,
141
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
142
+ );
143
+ return true;
144
+ } catch {
145
+ return false;
146
+ }
147
+ }
148
+ async function getCommitSubject(ref, cwd) {
149
+ try {
150
+ const { stdout } = await execPromise(
151
+ `git log -1 --format=%s ${shellSingleQuote(ref)}`,
152
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
153
+ );
154
+ return stdout.trim() || null;
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ async function findReachableCommitBySubject(subject, to, cwd) {
160
+ try {
161
+ const { stdout } = await execPromise(
162
+ `git log ${shellSingleQuote(to)} --grep=${shellSingleQuote(subject)} --fixed-strings --format=%H -n 1`,
163
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
164
+ );
165
+ return stdout.trim().split("\n")[0]?.trim() || null;
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+ async function tagExists(tag, cwd) {
171
+ try {
172
+ const tagRef = `refs/tags/${tag}`;
173
+ await execPromise(
174
+ `git rev-parse --verify --quiet ${shellSingleQuote(tagRef)}`,
175
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
176
+ );
177
+ return true;
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+ async function retagAnnotatedLocal({
183
+ tag,
184
+ commit,
185
+ message,
186
+ signed,
187
+ cwd,
188
+ logLevel
189
+ }) {
190
+ const sign = signed ? "-s " : "";
191
+ await execPromise(
192
+ `git tag -f ${sign}-a ${shellSingleQuote(tag)} ${shellSingleQuote(commit)} -m ${shellSingleQuote(message)}`,
193
+ { cwd, logLevel, noStderr: true, noStdout: true }
194
+ );
195
+ }
196
+ async function pushTagForce(tag, cwd, logLevel) {
197
+ await execPromise(
198
+ `git push origin ${shellSingleQuote(tag)} --force`,
199
+ { cwd, logLevel, noStderr: true, noStdout: true }
200
+ );
201
+ }
202
+
203
+ const sessionCache = /* @__PURE__ */ new Map();
204
+ function resetRewrittenTagCache() {
205
+ sessionCache.clear();
206
+ }
207
+ function short(sha) {
208
+ return sha.slice(0, 9);
209
+ }
210
+ function extractVersionFromRef(ref) {
211
+ const atIndex = ref.lastIndexOf("@");
212
+ const candidate = atIndex >= 0 ? ref.slice(atIndex + 1) : ref;
213
+ return candidate.startsWith("v") ? candidate.slice(1) : candidate;
214
+ }
215
+ function resolveStrategy(config) {
216
+ const isTTY = Boolean(process$1.stdout?.isTTY);
217
+ const strategy = config.onRewrittenTag ?? (!config.bump?.yes && isTTY ? "prompt" : "ephemeral");
218
+ if (strategy === "prompt" && !isTTY) {
219
+ return "ephemeral";
220
+ }
221
+ return strategy;
222
+ }
223
+ function buildExplanation({
224
+ from,
225
+ to,
226
+ twin,
227
+ subject
228
+ }) {
229
+ const lines = [
230
+ `\u26A0\uFE0F Tag "${from}" points to a commit that is no longer in the history of "${to}".`,
231
+ `It was most likely rewritten by a "git rebase" after the tag was created.`,
232
+ `Generating a changelog from it would span the whole divergent range (often the entire history since the last stable release, with duplicated commits) instead of the real changes.`
233
+ ];
234
+ if (twin) {
235
+ const subjectSuffix = subject ? ` ("${subject}")` : "";
236
+ lines.push(`Equivalent commit found on "${to}": ${short(twin)}${subjectSuffix}.`);
237
+ } else {
238
+ lines.push(`No equivalent commit could be found on "${to}".`);
239
+ }
240
+ lines.push(`Tip: never rebase "develop"/"main" (commits that are tagged or pushed are immutable). Integrate branches via merge or fast-forward instead.`);
241
+ return lines.join("\n");
242
+ }
243
+ async function rebind({
244
+ from,
245
+ twin,
246
+ config,
247
+ dryRun,
248
+ push
249
+ }) {
250
+ const message = config.templates?.tagMessage?.replaceAll("{{newVersion}}", extractVersionFromRef(from)) || from;
251
+ if (dryRun) {
252
+ logger.info(`[dry-run] git tag -f -a ${from} ${short(twin)} -m "${message}" (re-bind orphaned tag)`);
253
+ if (push) {
254
+ logger.info(`[dry-run] git push origin ${from} --force`);
255
+ }
256
+ return from;
257
+ }
258
+ await retagAnnotatedLocal({
259
+ tag: from,
260
+ commit: twin,
261
+ message,
262
+ signed: config.signTags,
263
+ cwd: config.cwd,
264
+ logLevel: config.logLevel
265
+ });
266
+ logger.success(`Re-bound tag "${from}" -> ${short(twin)} locally.`);
267
+ if (push) {
268
+ await pushTagForce(from, config.cwd, config.logLevel);
269
+ logger.success(`Force-pushed tag "${from}" to origin.`);
270
+ } else {
271
+ logger.info(`To publish the corrected tag later: git push origin ${from} --force`);
272
+ }
273
+ return from;
274
+ }
275
+ async function promptOrphan({
276
+ from,
277
+ twin,
278
+ config,
279
+ dryRun,
280
+ explanation
281
+ }) {
282
+ logger.warn(explanation);
283
+ const choices = [];
284
+ if (twin) {
285
+ choices.push({ name: `Use equivalent commit ${short(twin)} for this run only (recommended, non-destructive)`, value: "ephemeral" });
286
+ choices.push({ name: `Re-bind tag "${from}" -> ${short(twin)} locally (push it manually later)`, value: "rebind-local" });
287
+ choices.push({ name: `Re-bind tag "${from}" -> ${short(twin)} locally AND force-push to origin`, value: "rebind-push" });
288
+ }
289
+ choices.push({ name: `Keep the orphaned tag (changelog will span the full divergent range)`, value: "keep" });
290
+ choices.push({ name: `Abort`, value: "abort" });
291
+ let answer;
292
+ try {
293
+ answer = await select({
294
+ message: `How should relizy handle the rewritten tag "${from}"?`,
295
+ choices,
296
+ default: twin ? "ephemeral" : "keep"
297
+ });
298
+ } catch (error) {
299
+ const userHasExited = error instanceof Error && error.name === "ExitPromptError";
300
+ logger.log("");
301
+ logger.fail(userHasExited ? "Cancelled" : "Error while resolving rewritten tag");
302
+ process$1.exit(userHasExited ? 0 : 1);
303
+ }
304
+ switch (answer) {
305
+ case "ephemeral":
306
+ logger.info(`Using equivalent commit ${short(twin)} as the changelog base for this run.`);
307
+ return twin;
308
+ case "rebind-local":
309
+ return rebind({ from, twin, config, dryRun, push: false });
310
+ case "rebind-push": {
311
+ const confirmed = await confirm({
312
+ message: `Force-push tag "${from}" to origin? This rewrites the already-published tag.`,
313
+ default: false
314
+ }).catch(() => false);
315
+ if (!confirmed) {
316
+ logger.info("Skipping force-push; re-binding the tag locally only.");
317
+ return rebind({ from, twin, config, dryRun, push: false });
318
+ }
319
+ return rebind({ from, twin, config, dryRun, push: true });
320
+ }
321
+ case "keep":
322
+ logger.warn(`Keeping orphaned tag "${from}"; the changelog range may be incorrect.`);
323
+ return from;
324
+ case "abort":
325
+ default:
326
+ logger.log("");
327
+ logger.fail("Aborted. Re-bind the tag or fix your history, then retry.");
328
+ process$1.exit(0);
329
+ }
330
+ }
331
+ async function reconcileFromTag({
332
+ from,
333
+ to,
334
+ config,
335
+ dryRun = false
336
+ }) {
337
+ if (config.detectRewrittenTags === false || !from || from === to) {
338
+ return from;
339
+ }
340
+ const cwd = config.cwd;
341
+ if (!await tagExists(from, cwd)) {
342
+ return from;
343
+ }
344
+ const cached = sessionCache.get(from);
345
+ if (cached !== void 0) {
346
+ return cached;
347
+ }
348
+ if (await isAncestor(from, to, cwd)) {
349
+ sessionCache.set(from, from);
350
+ return from;
351
+ }
352
+ const subject = await getCommitSubject(from, cwd);
353
+ const twin = subject ? await findReachableCommitBySubject(subject, to, cwd) : null;
354
+ const explanation = buildExplanation({ from, to, twin, subject });
355
+ const strategy = resolveStrategy(config);
356
+ let result;
357
+ if (strategy === "error") {
358
+ logger.error(explanation);
359
+ throw new Error(`Tag "${from}" was rewritten (rebased) and is no longer reachable from "${to}". Re-bind the tag or fix your history.`);
360
+ } else if (strategy === "prompt") {
361
+ result = await promptOrphan({ from, twin, config, dryRun, explanation });
362
+ } else if (!twin) {
363
+ logger.warn(explanation);
364
+ logger.warn(`Falling back to the original tag "${from}"; the changelog range may be incorrect.`);
365
+ result = from;
366
+ } else if (strategy === "rebind") {
367
+ logger.warn(explanation);
368
+ result = await rebind({ from, twin, config, dryRun, push: false });
369
+ } else {
370
+ logger.warn(explanation);
371
+ logger.info(`Using equivalent commit ${short(twin)} as the changelog base for this run (tag "${from}" left untouched).`);
372
+ result = twin;
373
+ }
374
+ sessionCache.set(from, result);
375
+ return result;
376
+ }
377
+
134
378
  function getFirstPackageCommitHash(packagePath, cwd) {
135
379
  const relativePath = relative(cwd, packagePath);
136
380
  try {
@@ -175,7 +419,8 @@ async function getRootPackage({
175
419
  from,
176
420
  to,
177
421
  suffix,
178
- changelog
422
+ changelog,
423
+ dryRun = false
179
424
  }) {
180
425
  try {
181
426
  const packageJson = readPackageJson(config.cwd);
@@ -187,7 +432,8 @@ async function getRootPackage({
187
432
  from,
188
433
  to,
189
434
  config,
190
- changelog
435
+ changelog,
436
+ dryRun
191
437
  });
192
438
  let newVersion;
193
439
  if (config.monorepo?.versionMode !== "independent") {
@@ -296,7 +542,8 @@ async function getPackages({
296
542
  config,
297
543
  suffix,
298
544
  force,
299
- includeAll = false
545
+ includeAll = false,
546
+ dryRun = false
300
547
  }) {
301
548
  const patterns = config.monorepo?.packages;
302
549
  const readedPackages = readPackages({
@@ -349,7 +596,8 @@ async function getPackages({
349
596
  from,
350
597
  to,
351
598
  config,
352
- changelog: false
599
+ changelog: false,
600
+ dryRun
353
601
  });
354
602
  foundPaths.add(matchPath);
355
603
  const dependencies = getPackageDependencies({
@@ -427,19 +675,21 @@ async function getPackageCommits({
427
675
  from,
428
676
  to,
429
677
  config,
430
- changelog
678
+ changelog,
679
+ dryRun = false
431
680
  }) {
432
681
  logger.debug(`Analyzing commits for ${pkg.name} since ${from} to ${to}`);
433
- let actualFrom = from;
682
+ let actualFrom;
434
683
  if (from === NEW_PACKAGE_MARKER) {
435
684
  const firstPackageCommit = getFirstPackageCommitHash(pkg.path, config.cwd);
436
- if (firstPackageCommit) {
437
- logger.debug(`${pkg.name} is a new package, using first package commit: ${firstPackageCommit.slice(0, 8)}`);
438
- actualFrom = `${firstPackageCommit}^`;
439
- } else {
685
+ if (!firstPackageCommit) {
440
686
  logger.debug(`${pkg.name} has no commits yet, returning empty`);
441
687
  return [];
442
688
  }
689
+ logger.debug(`${pkg.name} is a new package, using first package commit: ${firstPackageCommit.slice(0, 8)}`);
690
+ actualFrom = `${firstPackageCommit}^`;
691
+ } else {
692
+ actualFrom = await reconcileFromTag({ from, to, config, dryRun });
443
693
  }
444
694
  const changelogConfig = {
445
695
  ...config,
@@ -1536,7 +1786,8 @@ async function getPackagesOrBumpedPackages({
1536
1786
  config,
1537
1787
  bumpResult,
1538
1788
  suffix,
1539
- force
1789
+ force,
1790
+ dryRun = false
1540
1791
  }) {
1541
1792
  if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
1542
1793
  return bumpResult.bumpedPackages;
@@ -1544,7 +1795,8 @@ async function getPackagesOrBumpedPackages({
1544
1795
  return await getPackages({
1545
1796
  config,
1546
1797
  suffix,
1547
- force
1798
+ force,
1799
+ dryRun
1548
1800
  });
1549
1801
  }
1550
1802
 
@@ -1975,7 +2227,8 @@ function getDefaultConfig() {
1975
2227
  }
1976
2228
  },
1977
2229
  logLevel: "default",
1978
- safetyCheck: true
2230
+ safetyCheck: true,
2231
+ detectRewrittenTags: true
1979
2232
  };
1980
2233
  }
1981
2234
  function resolveTemplateDefaults(config) {
@@ -2589,68 +2842,139 @@ function groupBy(items, key) {
2589
2842
  return groups;
2590
2843
  }
2591
2844
 
2592
- function fromTagIsFirstCommit(fromTag, cwd) {
2593
- return fromTag === getFirstCommit(cwd);
2845
+ function resolveSections(include) {
2846
+ return {
2847
+ title: include?.title ?? true,
2848
+ compareLink: include?.compareLink ?? true,
2849
+ body: include?.body ?? true,
2850
+ contributors: include?.contributors ?? true
2851
+ };
2594
2852
  }
2595
- async function generateChangelog({
2853
+ function resolveChangelogTags({
2596
2854
  pkg,
2597
2855
  config,
2598
- dryRun,
2599
- newVersion,
2600
- minify
2856
+ newVersion
2601
2857
  }) {
2602
- let fromTag = config.from || pkg.fromTag || getFirstCommit(config.cwd);
2603
- const isFirstCommit = fromTagIsFirstCommit(fromTag, config.cwd);
2604
- if (isFirstCommit) {
2605
- fromTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: "0.0.0", name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", "0.0.0");
2858
+ const isIndependent = config.monorepo?.versionMode === "independent";
2859
+ const gitFromRef = config.from || pkg.fromTag || getFirstCommit(config.cwd);
2860
+ const isFirstCommit = gitFromRef === getFirstCommit(config.cwd);
2861
+ const displayFromTag = isFirstCommit ? isIndependent ? getIndependentTag({ version: "0.0.0", name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", "0.0.0") : gitFromRef;
2862
+ const gitToRef = config.to || getCurrentGitRef(config.cwd);
2863
+ const displayToTag = config.to || (isIndependent ? getIndependentTag({ version: newVersion, name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", newVersion));
2864
+ if (!displayToTag) {
2865
+ throw new Error(`No tag found for ${pkg.name}`);
2606
2866
  }
2607
- let toTag = config.to;
2608
- if (!toTag) {
2609
- toTag = config.monorepo?.versionMode === "independent" ? getIndependentTag({ version: newVersion, name: pkg.name }) : config.templates.tagBody.replace("{{newVersion}}", newVersion);
2867
+ return { gitFromRef, gitToRef, displayFromTag, displayToTag, isFirstCommit };
2868
+ }
2869
+ function renderTitle({
2870
+ fromTag,
2871
+ toTag,
2872
+ config
2873
+ }) {
2874
+ const template = config.templates?.changelogTitle || "{{oldVersion}}...{{newVersion}}";
2875
+ const changelogTitle = template.replace("{{oldVersion}}", fromTag).replace("{{newVersion}}", toTag).replace("{{date}}", (/* @__PURE__ */ new Date()).toISOString().split("T")[0]);
2876
+ return `## ${changelogTitle}`;
2877
+ }
2878
+ async function renderChangelogParts({
2879
+ commits,
2880
+ config,
2881
+ fromTag,
2882
+ toTag,
2883
+ isFirstCommit,
2884
+ sections,
2885
+ minify,
2886
+ transformBody
2887
+ }) {
2888
+ const parts = [];
2889
+ if (sections.title) {
2890
+ parts.push(renderTitle({ fromTag, toTag, config }));
2610
2891
  }
2611
- if (!toTag) {
2612
- throw new Error(`No tag found for ${pkg.name}`);
2892
+ if (sections.compareLink && !minify) {
2893
+ const compareLink = buildCompareLink({ config, from: fromTag, to: toTag, isFirstCommit });
2894
+ if (compareLink) {
2895
+ parts.push(compareLink);
2896
+ }
2613
2897
  }
2614
- logger.debug(`Generating changelog for ${pkg.name} - from ${fromTag} to ${toTag}`);
2898
+ if (sections.body) {
2899
+ let body = buildChangelogBody({ commits, config, minify });
2900
+ if (transformBody && body) {
2901
+ body = await transformBody(body);
2902
+ }
2903
+ if (body) {
2904
+ parts.push(body);
2905
+ }
2906
+ }
2907
+ if (sections.contributors && !minify) {
2908
+ const contributors = await buildContributors({ commits, config });
2909
+ if (contributors) {
2910
+ parts.push(contributors);
2911
+ }
2912
+ }
2913
+ return parts;
2914
+ }
2915
+ function isFullChangelogOutput(sections, minify) {
2916
+ return !minify && sections.title && sections.compareLink && sections.body && sections.contributors;
2917
+ }
2918
+ async function generateChangelog({
2919
+ pkg,
2920
+ config,
2921
+ dryRun,
2922
+ newVersion,
2923
+ minify,
2924
+ include,
2925
+ transformBody
2926
+ }) {
2927
+ const sections = resolveSections(include);
2928
+ const { gitFromRef, gitToRef, displayFromTag, displayToTag, isFirstCommit } = resolveChangelogTags({ pkg, config, newVersion });
2929
+ logger.debug(`Generating changelog for ${pkg.name} - git ${gitFromRef}..${gitToRef} - display ${displayFromTag}...${displayToTag}`);
2615
2930
  try {
2616
- config = {
2617
- ...config,
2618
- from: fromTag,
2619
- to: toTag
2620
- };
2621
- const generatedChangelog = await generateMarkDown({
2622
- commits: pkg.commits,
2623
- config,
2624
- from: fromTag,
2931
+ const commits = await getPackageCommits({
2932
+ pkg,
2933
+ from: gitFromRef,
2934
+ to: gitToRef,
2935
+ config: { ...config, from: gitFromRef, to: gitToRef },
2936
+ changelog: true,
2937
+ dryRun
2938
+ });
2939
+ const displayConfig = { ...config, from: displayFromTag, to: displayToTag };
2940
+ const parts = await renderChangelogParts({
2941
+ commits,
2942
+ config: displayConfig,
2943
+ fromTag: displayFromTag,
2944
+ toTag: displayToTag,
2625
2945
  isFirstCommit,
2626
- to: toTag,
2627
- minify
2946
+ sections,
2947
+ minify,
2948
+ transformBody
2628
2949
  });
2629
- let changelog = generatedChangelog;
2630
- if (pkg.commits.length === 0) {
2950
+ let changelog = parts.filter(Boolean).join("\n\n").trim();
2951
+ const isFullOutput = isFullChangelogOutput(sections, minify);
2952
+ if (commits.length === 0 && sections.body && isFullOutput) {
2631
2953
  changelog = `${changelog}
2632
2954
 
2633
- ${config.templates.emptyChangelogContent}`;
2955
+ ${displayConfig.templates.emptyChangelogContent}`;
2956
+ }
2957
+ if (isFullOutput) {
2958
+ const changelogResult = await executeHook("generate:changelog", displayConfig, dryRun, {
2959
+ commits,
2960
+ changelog
2961
+ });
2962
+ changelog = changelogResult || changelog;
2634
2963
  }
2635
- const changelogResult = await executeHook("generate:changelog", config, dryRun, {
2636
- commits: pkg.commits,
2637
- changelog
2638
- });
2639
- changelog = changelogResult || changelog;
2640
2964
  logger.verbose(`Output changelog for ${pkg.name}:
2641
2965
  ${changelog}`);
2642
- logger.debug(`Changelog generated for ${pkg.name} (${pkg.commits.length} commits)`);
2966
+ logger.debug(`Changelog generated for ${pkg.name} (${commits.length} commits)`);
2643
2967
  logger.verbose(`Final changelog for ${pkg.name}:
2644
2968
 
2645
2969
  ${changelog}
2646
2970
 
2647
2971
  `);
2648
2972
  if (dryRun) {
2649
- logger.info(`[dry-run] ${pkg.name} - Generate changelog ${fromTag}...${toTag}`);
2973
+ logger.info(`[dry-run] ${pkg.name} - Generate changelog ${displayFromTag}...${displayToTag}`);
2650
2974
  }
2651
2975
  return changelog;
2652
2976
  } catch (error) {
2653
- throw new Error(`Error generating changelog for ${pkg.name} (${fromTag}...${toTag}): ${getErrorMessage(error)}`, { cause: error });
2977
+ throw new Error(`Error generating changelog for ${pkg.name}: ${getErrorMessage(error)}`, { cause: error });
2654
2978
  }
2655
2979
  }
2656
2980
  function writeChangelogToFile({
@@ -2900,6 +3224,52 @@ function handleFallback(config, rawBody, error) {
2900
3224
  return rawBody;
2901
3225
  }
2902
3226
 
3227
+ async function publishIndependentRelease({
3228
+ pkg,
3229
+ config,
3230
+ dryRun,
3231
+ repoConfig
3232
+ }) {
3233
+ const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
3234
+ const from = config.from || pkg.fromTag;
3235
+ const to = config.to || getIndependentTag({ version: newVersion, name: pkg.name });
3236
+ if (!from) {
3237
+ logger.warn(`No from tag found for ${pkg.name}, skipping release`);
3238
+ return void 0;
3239
+ }
3240
+ const toTag = dryRun ? "HEAD" : to;
3241
+ logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${toTag}`);
3242
+ const releaseBody = await generateChangelog({
3243
+ pkg: { ...pkg, fromTag: from },
3244
+ config,
3245
+ dryRun,
3246
+ newVersion,
3247
+ include: { title: false, compareLink: true, body: true, contributors: true },
3248
+ transformBody: isAIProviderReleaseEnabled(config) ? (body) => generateAIProviderReleaseBody({ config, rawBody: body }) : void 0
3249
+ });
3250
+ const release = {
3251
+ tag_name: to,
3252
+ name: to,
3253
+ body: releaseBody,
3254
+ prerelease: isPrerelease(newVersion)
3255
+ };
3256
+ logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
3257
+ if (dryRun) {
3258
+ logger.info(`[dry-run] Publish GitHub release for ${release.tag_name}`);
3259
+ logger.box("[dry-run] Release Preview", `Tag: ${release.tag_name}
3260
+
3261
+ ${releaseBody}`);
3262
+ } else {
3263
+ logger.debug(`Publishing release ${to} to GitHub...`);
3264
+ await createGithubRelease({ ...config, from, to, repo: repoConfig }, release);
3265
+ }
3266
+ return {
3267
+ name: pkg.name,
3268
+ tag: release.tag_name,
3269
+ version: newVersion,
3270
+ prerelease: release.prerelease
3271
+ };
3272
+ }
2903
3273
  async function githubIndependentMode({
2904
3274
  config,
2905
3275
  dryRun,
@@ -2919,60 +3289,15 @@ async function githubIndependentMode({
2919
3289
  config,
2920
3290
  bumpResult,
2921
3291
  suffix,
2922
- force
3292
+ force,
3293
+ dryRun
2923
3294
  }));
2924
3295
  logger.info(`Creating ${packages.length} GitHub release(s)`);
2925
3296
  const postedReleases = [];
2926
3297
  for (const pkg of packages) {
2927
- const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
2928
- const from = config.from || pkg.fromTag;
2929
- const to = config.to || getIndependentTag({ version: newVersion, name: pkg.name });
2930
- if (!from) {
2931
- logger.warn(`No from tag found for ${pkg.name}, skipping release`);
2932
- continue;
2933
- }
2934
- const toTag = dryRun ? "HEAD" : to;
2935
- logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${toTag}`);
2936
- const isFirstCommit = from === getFirstCommit(config.cwd);
2937
- const compareLink = buildCompareLink({ config, from, to, isFirstCommit });
2938
- let body = buildChangelogBody({ commits: pkg.commits, config });
2939
- const contributors = await buildContributors({ commits: pkg.commits, config });
2940
- if (isAIProviderReleaseEnabled(config)) {
2941
- body = await generateAIProviderReleaseBody({ config, rawBody: body });
2942
- }
2943
- const releaseBody = [compareLink, body, contributors].filter(Boolean).join("\n\n").trim();
2944
- const release = {
2945
- tag_name: to,
2946
- name: to,
2947
- body: releaseBody,
2948
- prerelease: isPrerelease(newVersion)
2949
- };
2950
- logger.debug(`Creating release for ${to}${release.prerelease ? " (prerelease)" : ""}`);
2951
- if (dryRun) {
2952
- logger.info(`[dry-run] Publish GitHub release for ${release.tag_name}`);
2953
- postedReleases.push({
2954
- name: pkg.name,
2955
- tag: release.tag_name,
2956
- version: newVersion,
2957
- prerelease: release.prerelease
2958
- });
2959
- logger.box("[dry-run] Release Preview", `Tag: ${release.tag_name}
2960
-
2961
- ${releaseBody}`);
2962
- } else {
2963
- logger.debug(`Publishing release ${to} to GitHub...`);
2964
- await createGithubRelease({
2965
- ...config,
2966
- from,
2967
- to,
2968
- repo: repoConfig
2969
- }, release);
2970
- postedReleases.push({
2971
- name: pkg.name,
2972
- tag: release.tag_name,
2973
- version: newVersion,
2974
- prerelease: release.prerelease
2975
- });
3298
+ const posted = await publishIndependentRelease({ pkg, config, dryRun, repoConfig });
3299
+ if (posted) {
3300
+ postedReleases.push(posted);
2976
3301
  }
2977
3302
  }
2978
3303
  if (postedReleases.length === 0) {
@@ -3000,14 +3325,14 @@ async function githubUnified({
3000
3325
  const to = config.to || config.templates.tagBody.replace("{{newVersion}}", newVersion);
3001
3326
  const firstCommit = getFirstCommit(config.cwd);
3002
3327
  const from = config.from || rootPackage.fromTag || firstCommit;
3003
- const isFirstCommit = from === firstCommit;
3004
- const compareLink = buildCompareLink({ config, from, to, isFirstCommit });
3005
- let body = buildChangelogBody({ commits: rootPackage.commits, config });
3006
- const contributors = await buildContributors({ commits: rootPackage.commits, config });
3007
- if (isAIProviderReleaseEnabled(config)) {
3008
- body = await generateAIProviderReleaseBody({ config, rawBody: body });
3009
- }
3010
- const releaseBody = [compareLink, body, contributors].filter(Boolean).join("\n\n").trim();
3328
+ const releaseBody = await generateChangelog({
3329
+ pkg: { ...rootPackage, fromTag: from },
3330
+ config,
3331
+ dryRun,
3332
+ newVersion,
3333
+ include: { title: false, compareLink: true, body: true, contributors: true },
3334
+ transformBody: isAIProviderReleaseEnabled(config) ? (body) => generateAIProviderReleaseBody({ config, rawBody: body }) : void 0
3335
+ });
3011
3336
  const release = {
3012
3337
  tag_name: to,
3013
3338
  name: to,
@@ -3086,7 +3411,8 @@ async function github(options) {
3086
3411
  suffix: options.suffix,
3087
3412
  changelog: true,
3088
3413
  from,
3089
- to
3414
+ to,
3415
+ dryRun
3090
3416
  });
3091
3417
  return await githubUnified({
3092
3418
  config,
@@ -3173,7 +3499,8 @@ async function gitlabIndependentMode({
3173
3499
  config,
3174
3500
  bumpResult,
3175
3501
  suffix,
3176
- force
3502
+ force,
3503
+ dryRun
3177
3504
  }));
3178
3505
  logger.info(`Creating ${packages.length} GitLab release(s) for independent packages`);
3179
3506
  logger.debug("Getting current branch...");
@@ -3193,18 +3520,25 @@ async function gitlabIndependentMode({
3193
3520
  continue;
3194
3521
  }
3195
3522
  logger.debug(`Processing ${pkg.name}: ${from} \u2192 ${to}`);
3196
- const isFirstCommit = from === getFirstCommit(config.cwd);
3197
- const compareLink = buildCompareLink({ config, from, to, isFirstCommit });
3198
- let body = buildChangelogBody({ commits: pkg.commits, config });
3199
- const contributors = await buildContributors({ commits: pkg.commits, config });
3200
- if (!body) {
3523
+ const bodyOnly = await generateChangelog({
3524
+ pkg: { ...pkg, fromTag: from },
3525
+ config,
3526
+ dryRun,
3527
+ newVersion,
3528
+ include: { title: false, compareLink: false, body: true, contributors: false }
3529
+ });
3530
+ if (!bodyOnly.trim()) {
3201
3531
  logger.warn(`No changelog found for ${pkg.name}`);
3202
3532
  continue;
3203
3533
  }
3204
- if (isAIProviderReleaseEnabled(config)) {
3205
- body = await generateAIProviderReleaseBody({ config, rawBody: body });
3206
- }
3207
- const releaseBody = [compareLink, body, contributors].filter(Boolean).join("\n\n").trim();
3534
+ const releaseBody = await generateChangelog({
3535
+ pkg: { ...pkg, fromTag: from },
3536
+ config,
3537
+ dryRun,
3538
+ newVersion,
3539
+ include: { title: false, compareLink: true, body: true, contributors: true },
3540
+ transformBody: isAIProviderReleaseEnabled(config) ? (body) => generateAIProviderReleaseBody({ config, rawBody: body }) : void 0
3541
+ });
3208
3542
  const release = {
3209
3543
  tag_name: to,
3210
3544
  name: to,
@@ -3250,14 +3584,14 @@ async function gitlabUnified({
3250
3584
  const to = config.templates.tagBody.replace("{{newVersion}}", newVersion);
3251
3585
  const firstCommit = getFirstCommit(config.cwd);
3252
3586
  const from = config.from || rootPackage.fromTag || firstCommit;
3253
- const isFirstCommit = from === firstCommit;
3254
- const compareLink = buildCompareLink({ config, from, to, isFirstCommit });
3255
- let body = buildChangelogBody({ commits: rootPackage.commits, config });
3256
- const contributors = await buildContributors({ commits: rootPackage.commits, config });
3257
- if (isAIProviderReleaseEnabled(config)) {
3258
- body = await generateAIProviderReleaseBody({ config, rawBody: body });
3259
- }
3260
- const releaseBody = [compareLink, body, contributors].filter(Boolean).join("\n\n").trim();
3587
+ const releaseBody = await generateChangelog({
3588
+ pkg: { ...rootPackage, fromTag: from },
3589
+ config,
3590
+ dryRun,
3591
+ newVersion,
3592
+ include: { title: false, compareLink: true, body: true, contributors: true },
3593
+ transformBody: isAIProviderReleaseEnabled(config) ? (body) => generateAIProviderReleaseBody({ config, rawBody: body }) : void 0
3594
+ });
3261
3595
  logger.debug("Getting current branch...");
3262
3596
  const { stdout: currentBranch } = await execPromise("git rev-parse --abbrev-ref HEAD", {
3263
3597
  noSuccess: true,
@@ -3340,7 +3674,8 @@ async function gitlab(options = {}) {
3340
3674
  suffix: options.suffix,
3341
3675
  changelog: true,
3342
3676
  from,
3343
- to
3677
+ to,
3678
+ dryRun
3344
3679
  });
3345
3680
  logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version: newVersion })}`);
3346
3681
  return await gitlabUnified({
@@ -3754,7 +4089,7 @@ function extractChangelogSummary(changelog, { stripBoldMarkers = false, maxLengt
3754
4089
  if (changelog.trim() === "") {
3755
4090
  return "";
3756
4091
  }
3757
- let cleaned = changelog.split("\n").filter((line) => !line.startsWith("#")).join("\n");
4092
+ let cleaned = changelog.split("\n").filter((line) => !line.startsWith("#") && line.trim() !== "").join("\n");
3758
4093
  if (stripBoldMarkers) {
3759
4094
  cleaned = cleaned.replace(/\*\*([^*]+):\*\*/g, "$1:");
3760
4095
  }
@@ -3814,7 +4149,7 @@ function formatPackagesForSlack(packages) {
3814
4149
  return "";
3815
4150
  }
3816
4151
  return packages.map(
3817
- (pkg) => pkg.hasTransition ? `\u2022 **${pkg.name}** : \`${pkg.oldVersion}\` \u2192 \`${pkg.newVersion}\`` : `\u2022 **${pkg.name}** : \`${pkg.version}\``
4152
+ (pkg) => pkg.hasTransition ? `\u2022 *${pkg.name}* : \`${pkg.oldVersion}\` \u2192 \`${pkg.newVersion}\`` : `\u2022 *${pkg.name}* : \`${pkg.version}\``
3818
4153
  ).join("\n");
3819
4154
  }
3820
4155
  function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template, contributors = [], packages = [], postMaxLength = 2500 }) {
@@ -4188,7 +4523,8 @@ async function bumpUnifiedMode({
4188
4523
  from,
4189
4524
  to,
4190
4525
  suffix,
4191
- changelog: false
4526
+ changelog: false,
4527
+ dryRun
4192
4528
  });
4193
4529
  const currentVersion = rootPackage.version;
4194
4530
  const newVersion = rootPackage.newVersion;
@@ -4202,7 +4538,8 @@ async function bumpUnifiedMode({
4202
4538
  config,
4203
4539
  suffix,
4204
4540
  force,
4205
- includeAll: true
4541
+ includeAll: true,
4542
+ dryRun
4206
4543
  });
4207
4544
  if (packages.length === 0) {
4208
4545
  logger.debug("No packages to bump");
@@ -4272,7 +4609,8 @@ async function bumpSelectiveMode({
4272
4609
  from,
4273
4610
  to,
4274
4611
  suffix,
4275
- changelog: false
4612
+ changelog: false,
4613
+ dryRun
4276
4614
  });
4277
4615
  const currentVersion = rootPackage.version;
4278
4616
  const newVersion = rootPackage.newVersion;
@@ -4285,7 +4623,8 @@ async function bumpSelectiveMode({
4285
4623
  const packages = await getPackages({
4286
4624
  config,
4287
4625
  suffix,
4288
- force
4626
+ force,
4627
+ dryRun
4289
4628
  });
4290
4629
  if (packages.length === 0) {
4291
4630
  logger.debug("No packages to bump");
@@ -4353,7 +4692,8 @@ async function bumpIndependentMode({
4353
4692
  const packagesToBump = await getPackages({
4354
4693
  config,
4355
4694
  suffix,
4356
- force
4695
+ force,
4696
+ dryRun
4357
4697
  });
4358
4698
  if (packagesToBump.length === 0) {
4359
4699
  logger.debug("No packages to bump");
@@ -4406,7 +4746,7 @@ async function bumpCanaryMode({
4406
4746
  logger.debug("Starting bump in canary mode");
4407
4747
  if (config.monorepo?.versionMode === "independent") {
4408
4748
  const sha2 = getShortCommitSha(config.cwd);
4409
- const packages2 = await getPackages({ config, suffix: void 0, force: false });
4749
+ const packages2 = await getPackages({ config, suffix: void 0, force: false, dryRun });
4410
4750
  if (packages2.length === 0) {
4411
4751
  logger.debug("No packages to bump");
4412
4752
  return { bumped: false };
@@ -4429,7 +4769,8 @@ async function bumpCanaryMode({
4429
4769
  from,
4430
4770
  to,
4431
4771
  config,
4432
- changelog: false
4772
+ changelog: false,
4773
+ dryRun
4433
4774
  });
4434
4775
  const releaseType = determineSemverChange(commits, config.types);
4435
4776
  const sha = getShortCommitSha(config.cwd);
@@ -4446,7 +4787,8 @@ async function bumpCanaryMode({
4446
4787
  config,
4447
4788
  suffix: void 0,
4448
4789
  force: false,
4449
- includeAll: isUnified
4790
+ includeAll: isUnified,
4791
+ dryRun
4450
4792
  });
4451
4793
  if (packages.length === 0) {
4452
4794
  logger.debug("No packages to bump");
@@ -4627,11 +4969,12 @@ async function generateIndependentRootChangelog({
4627
4969
  logger.debug("Generating aggregated root changelog for independent mode");
4628
4970
  const packageChangelogs = [];
4629
4971
  for (const pkg of packages) {
4972
+ const newVersion = isBumpedPackage(pkg) && pkg.newVersion || pkg.version;
4630
4973
  const changelog2 = await generateChangelog({
4631
4974
  pkg,
4632
4975
  config,
4633
4976
  dryRun,
4634
- newVersion: isBumpedPackage(pkg) && pkg.newVersion || pkg.version
4977
+ newVersion
4635
4978
  });
4636
4979
  if (changelog2) {
4637
4980
  packageChangelogs.push(changelog2);
@@ -4694,7 +5037,8 @@ async function generateSimpleRootChangelog({
4694
5037
  suffix,
4695
5038
  changelog: true,
4696
5039
  from: fromTag,
4697
- to
5040
+ to,
5041
+ dryRun
4698
5042
  });
4699
5043
  logger.debug(`Generating ${rootPackage.name} changelog (${fromTag}...${to})`);
4700
5044
  const rootChangelog = await generateChangelog({
@@ -4743,7 +5087,8 @@ async function changelog(options = {}) {
4743
5087
  config,
4744
5088
  bumpResult: options.bumpResult,
4745
5089
  suffix: options.suffix,
4746
- force: options.force ?? false
5090
+ force: options.force ?? false,
5091
+ dryRun
4747
5092
  });
4748
5093
  if (config.changelog?.rootChangelog && config.monorepo?.versionMode) {
4749
5094
  if (config.monorepo.versionMode === "independent") {
@@ -4769,13 +5114,7 @@ async function changelog(options = {}) {
4769
5114
  let generatedCount = 0;
4770
5115
  for await (const pkg of packages) {
4771
5116
  const newVersion = options.bumpResult?.bumpedPackages?.find((p) => p.name === pkg.name)?.newVersion || pkg.newVersion || pkg.version;
4772
- const { from, to } = await resolveTags({
4773
- config,
4774
- step: "changelog",
4775
- pkg,
4776
- newVersion
4777
- });
4778
- logger.debug(`Processing ${pkg.name} (${from}...${to})`);
5117
+ logger.debug(`Processing ${pkg.name}`);
4779
5118
  const changelog2 = await generateChangelog({
4780
5119
  pkg,
4781
5120
  config,
@@ -5242,7 +5581,8 @@ async function publish(options = {}) {
5242
5581
  config,
5243
5582
  bumpResult: options.bumpResult,
5244
5583
  suffix: options.suffix,
5245
- force: options.force ?? false
5584
+ force: options.force ?? false,
5585
+ dryRun
5246
5586
  });
5247
5587
  const packages = filterOutPrivatePackages(discoveredPackages);
5248
5588
  if (discoveredPackages.length !== packages.length) {
@@ -5572,10 +5912,25 @@ async function social(options = {}) {
5572
5912
  suffix: void 0,
5573
5913
  changelog: true,
5574
5914
  from: fromTag,
5575
- to
5915
+ to,
5916
+ dryRun
5917
+ });
5918
+ const minifiedBody = await generateChangelog({
5919
+ pkg: { ...rootPackage, fromTag },
5920
+ config,
5921
+ dryRun,
5922
+ newVersion,
5923
+ include: { title: false, compareLink: false, body: true, contributors: false },
5924
+ minify: true
5925
+ });
5926
+ const richBody = await generateChangelog({
5927
+ pkg: { ...rootPackage, fromTag },
5928
+ config,
5929
+ dryRun,
5930
+ newVersion,
5931
+ include: { title: false, compareLink: false, body: true, contributors: false },
5932
+ minify: false
5576
5933
  });
5577
- const minifiedBody = buildChangelogBody({ commits: rootPackage.commits, config, minify: true });
5578
- const richBody = buildChangelogBody({ commits: rootPackage.commits, config, minify: false });
5579
5934
  const hasContent = !!minifiedBody.trim();
5580
5935
  const twitterReleaseUrl = getReleaseUrl(config, to);
5581
5936
  const twitterChangelogUrl = config.social?.changelogUrl;
@@ -5625,13 +5980,21 @@ ${twitterChangelog}`);
5625
5980
  newVersion,
5626
5981
  tag: to
5627
5982
  });
5983
+ const changelogCommits = await getPackageCommits({
5984
+ pkg: rootPackage,
5985
+ from: fromTag,
5986
+ to: "HEAD",
5987
+ config,
5988
+ changelog: true,
5989
+ dryRun
5990
+ });
5628
5991
  const slackResponse = await handleSlackPost({
5629
5992
  config,
5630
5993
  changelog: slackChangelog,
5631
5994
  dryRun,
5632
5995
  newVersion,
5633
5996
  tag: to,
5634
- commits: rootPackage.commits,
5997
+ commits: changelogCommits,
5635
5998
  bumpedPackages: options.bumpResult?.bumpedPackages
5636
5999
  });
5637
6000
  const results = [];
@@ -6002,4 +6365,4 @@ Git provider: ${provider}`);
6002
6365
  }
6003
6366
  }
6004
6367
 
6005
- export { PR_COMMENT_MARKER as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, github as I, createGitlabRelease as J, gitlab as K, buildCompareLink as L, buildChangelogBody as M, collectContributorNames as N, buildContributors as O, generateMarkDown as P, parseChangelogMarkdown as Q, detectPackageManager as R, determinePublishTag as S, getPackagesToPublishInSelectiveMode as T, getPackagesToPublishInIndependentMode as U, getAuthCommand as V, publishPackage as W, collectPackageBumps as X, findGitHubPR as Y, findGitLabMR as Z, detectPullRequest as _, buildCommentBody as a, postPrComment as a0, readPackageJson as a1, getRootPackage as a2, readPackages as a3, getPackages as a4, getPackageCommits as a5, hasLernaJson as a6, getSlackToken as a7, getSlackWebhookUrl as a8, formatChangelogForSlack as a9, determineReleaseType as aA, writeVersion as aB, getPackageNewVersion as aC, updateLernaVersion as aD, extractVersionFromPackageTag as aE, isPrerelease as aF, isStableReleaseType as aG, isPrereleaseReleaseType as aH, isGraduating as aI, getPreid as aJ, isChangedPreid as aK, getBumpedPackageIndependently as aL, confirmBump as aM, getBumpedIndependentPackages as aN, shouldFilterPrereleaseTags as aO, extractVersionFromTag as aP, getCanaryVersion as aQ, isTagVersionCompatibleWithCurrent as aR, formatPackagesForSlack as aa, formatSlackMessage as ab, postReleaseToSlack as ac, extractChangelogSummary as ad, getReleaseUrl as ae, getIndependentTag as af, getLastStableTag as ag, getLastTag as ah, getLastRepoTag as ai, getLastPackageTag as aj, NEW_PACKAGE_MARKER as ak, resolveTags as al, getTwitterCredentials as am, formatTweetMessage as an, postReleaseToTwitter as ao, executeHook as ap, isInCI as aq, getCIName as ar, executeFormatCmd as as, executeBuildCmd as at, isBumpedPackage as au, filterOutPrivatePackages as av, getPackagesOrBumpedPackages as aw, isGraduatingToStableBetweenVersion as ax, capReleaseTypeForZeroMajor as ay, determineSemverChange as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };
6368
+ export { getAuthCommand as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, isAncestor as I, getCommitSubject as J, findReachableCommitBySubject as K, tagExists as L, retagAnnotatedLocal as M, pushTagForce as N, github as O, createGitlabRelease as P, gitlab as Q, buildCompareLink as R, buildChangelogBody as S, collectContributorNames as T, buildContributors as U, generateMarkDown as V, parseChangelogMarkdown as W, detectPackageManager as X, determinePublishTag as Y, getPackagesToPublishInSelectiveMode as Z, getPackagesToPublishInIndependentMode as _, buildCommentBody as a, publishPackage as a0, collectPackageBumps as a1, findGitHubPR as a2, findGitLabMR as a3, detectPullRequest as a4, PR_COMMENT_MARKER as a5, postPrComment as a6, readPackageJson as a7, getRootPackage as a8, readPackages as a9, executeFormatCmd as aA, executeBuildCmd as aB, isBumpedPackage as aC, filterOutPrivatePackages as aD, getPackagesOrBumpedPackages as aE, isGraduatingToStableBetweenVersion as aF, capReleaseTypeForZeroMajor as aG, determineSemverChange as aH, determineReleaseType as aI, writeVersion as aJ, getPackageNewVersion as aK, updateLernaVersion as aL, extractVersionFromPackageTag as aM, isPrerelease as aN, isStableReleaseType as aO, isPrereleaseReleaseType as aP, isGraduating as aQ, getPreid as aR, isChangedPreid as aS, getBumpedPackageIndependently as aT, confirmBump as aU, getBumpedIndependentPackages as aV, shouldFilterPrereleaseTags as aW, extractVersionFromTag as aX, getCanaryVersion as aY, isTagVersionCompatibleWithCurrent as aZ, getPackages as aa, getPackageCommits as ab, hasLernaJson as ac, resetRewrittenTagCache as ad, reconcileFromTag as ae, getSlackToken as af, getSlackWebhookUrl as ag, formatChangelogForSlack as ah, formatPackagesForSlack as ai, formatSlackMessage as aj, postReleaseToSlack as ak, extractChangelogSummary as al, getReleaseUrl as am, getIndependentTag as an, getLastStableTag as ao, getLastTag as ap, getLastRepoTag as aq, getLastPackageTag as ar, NEW_PACKAGE_MARKER as as, resolveTags as at, getTwitterCredentials as au, formatTweetMessage as av, postReleaseToTwitter as aw, executeHook as ax, isInCI as ay, getCIName as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };