versionary 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const node_child_process_1 = require("node:child_process");
5
+ const load_config_js_1 = require("../config/load-config.js");
5
6
  const changelog_js_1 = require("../release/changelog.js");
6
7
  const plan_js_1 = require("../release/plan.js");
7
8
  const pr_js_1 = require("../release/pr.js");
@@ -162,7 +163,7 @@ async function main() {
162
163
  return 0;
163
164
  }
164
165
  (0, pr_js_1.pushReleaseBranch)(process.cwd(), pr.branch);
165
- const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan, { logger });
166
+ const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan, { logger, highlights: pr.highlights });
166
167
  const message = `Prepared release PR branch ${pr.branch}`;
167
168
  if (flags.json) {
168
169
  emitJson({
@@ -196,12 +197,18 @@ async function main() {
196
197
  console.log("No releasable commits found.");
197
198
  return 0;
198
199
  }
199
- const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
200
+ const loaded = (0, load_config_js_1.loadConfig)();
201
+ const highlightsRead = (0, pr_js_1.readNextReleaseHighlights)(process.cwd(), loaded.config);
202
+ const highlights = highlightsRead?.content ?? "";
203
+ const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan, { highlights });
200
204
  if (!write) {
201
205
  console.log(section);
202
206
  return 0;
203
207
  }
204
208
  (0, changelog_js_1.prependChangelog)(process.cwd(), plan.changelogFile, section, plan.changelogFormat);
209
+ if (highlightsRead) {
210
+ (0, pr_js_1.consumeNextReleaseFile)(process.cwd(), highlightsRead.filePath);
211
+ }
205
212
  console.log(`Updated ${plan.changelogFile}`);
206
213
  return 0;
207
214
  }
@@ -227,7 +234,7 @@ async function main() {
227
234
  return 0;
228
235
  }
229
236
  (0, pr_js_1.pushReleaseBranch)(process.cwd(), pr.branch);
230
- const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan);
237
+ const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan, { highlights: pr.highlights });
231
238
  console.log(`Prepared release PR branch ${pr.branch}`);
232
239
  console.log(`Title: ${pr.title}`);
233
240
  console.log(reviewResult);
@@ -21,6 +21,7 @@ export declare const configSchema: z.ZodObject<{
21
21
  }>>;
22
22
  "release-branch": z.ZodOptional<z.ZodString>;
23
23
  "baseline-file": z.ZodOptional<z.ZodString>;
24
+ "next-release-file": z.ZodOptional<z.ZodString>;
24
25
  "bootstrap-sha": z.ZodOptional<z.ZodString>;
25
26
  "monorepo-mode": z.ZodOptional<z.ZodEnum<{
26
27
  independent: "independent";
@@ -76,6 +76,7 @@ exports.configSchema = zod_1.z
76
76
  .optional(),
77
77
  "release-branch": zod_1.z.string().optional(),
78
78
  "baseline-file": zod_1.z.string().optional(),
79
+ "next-release-file": zod_1.z.string().optional(),
79
80
  "bootstrap-sha": zod_1.z.string().optional(),
80
81
  "monorepo-mode": zod_1.z.enum(["independent", "fixed"]).optional(),
81
82
  "bump-minor-pre-major": zod_1.z.boolean().optional(),
@@ -26,7 +26,7 @@ function parseFieldPath(fieldPath) {
26
26
  index += 2;
27
27
  continue;
28
28
  }
29
- const keyMatch = fieldPath.slice(index + 1).match(/^[A-Za-z0-9_-]+/u);
29
+ const keyMatch = fieldPath.slice(index + 1).match(/^[A-Za-z0-9_@/-]+/u);
30
30
  if (!keyMatch) {
31
31
  throw new Error(`Invalid field-path "${fieldPath}" near index ${index}.`);
32
32
  }
@@ -10,6 +10,7 @@ export declare function renderSimpleReleaseNotes(input: {
10
10
  name: string;
11
11
  version: string;
12
12
  }>;
13
+ highlights?: string;
13
14
  }, options?: {
14
15
  includeFooter?: boolean;
15
16
  headerLabel?: string;
@@ -19,6 +20,7 @@ export declare function renderReleasePlanChangelog(plan: ReleasePlan, options?:
19
20
  headerLabel?: string;
20
21
  includeFooter?: boolean;
21
22
  cwd?: string;
23
+ highlights?: string;
22
24
  }): string;
23
25
  /** @deprecated Use renderReleasePlanChangelog. */
24
26
  export declare function renderSimpleChangelog(plan: SimplePlan): string;
@@ -35,4 +37,5 @@ export declare function renderRNewsReleaseNotes(input: {
35
37
  nextVersion: string;
36
38
  commits: ParsedCommit[];
37
39
  cwd?: string;
40
+ highlights?: string;
38
41
  }): string;
@@ -148,6 +148,10 @@ function renderSimpleReleaseNotes(input, options = {}) {
148
148
  : `## ${headerLabel} (${formatDate()})`;
149
149
  const grouped = groupCommitLines(input.commits, repoUrl);
150
150
  const sections = [];
151
+ const trimmedHighlights = input.highlights?.trim() ?? "";
152
+ if (trimmedHighlights.length > 0) {
153
+ sections.push(trimmedHighlights, "");
154
+ }
151
155
  if (grouped.breaking.length > 0) {
152
156
  sections.push("### Breaking changes", ...grouped.breaking, "");
153
157
  }
@@ -212,6 +216,7 @@ function renderReleasePlanChangelog(plan, options = {}) {
212
216
  nextVersion: plan.nextVersion,
213
217
  commits: dedupedCommits,
214
218
  cwd: process.cwd(),
219
+ highlights: options.highlights,
215
220
  });
216
221
  }
217
222
  return renderSimpleReleaseNotes({
@@ -220,6 +225,7 @@ function renderReleasePlanChangelog(plan, options = {}) {
220
225
  commits: dedupedCommits,
221
226
  cwd: options.cwd ?? process.cwd(),
222
227
  dependencies,
228
+ highlights: options.highlights,
223
229
  }, {
224
230
  includeFooter: options.includeFooter,
225
231
  headerLabel: options.headerLabel,
@@ -276,6 +282,10 @@ function renderRNewsReleaseNotes(input) {
276
282
  const grouped = groupCommitLines(input.commits, repoUrl);
277
283
  const normalizedVersion = input.nextVersion.replace(/\.\d+$/u, "");
278
284
  const sections = [];
285
+ const trimmedHighlights = input.highlights?.trim() ?? "";
286
+ if (trimmedHighlights.length > 0) {
287
+ sections.push(trimmedHighlights, "");
288
+ }
279
289
  if (grouped.breaking.length > 0) {
280
290
  sections.push("## Breaking changes", "", ...grouped.breaking, "");
281
291
  }
@@ -1,6 +1,15 @@
1
1
  import type { ParsedCommit } from "../git/commits.js";
2
+ import type { VersionaryConfig } from "../types/config.js";
2
3
  import type { VersionaryPluginContext } from "../types/plugins.js";
3
4
  import { type ReleasePlan, type SimplePlan } from "./plan.js";
5
+ export declare function getNextReleaseFile(config: VersionaryConfig): string;
6
+ export declare function readNextReleaseHighlights(cwd: string, config: VersionaryConfig): {
7
+ content: string;
8
+ filePath: string;
9
+ } | null;
10
+ export declare function consumeNextReleaseFile(cwd: string, filePath: string): {
11
+ tracked: boolean;
12
+ };
4
13
  export declare function splitSafeDirtyFiles(files: string[]): {
5
14
  ignored: string[];
6
15
  blocking: string[];
@@ -15,10 +24,12 @@ export declare function prepareReleasePr(cwd?: string, options?: {
15
24
  commits: ParsedCommit[];
16
25
  plan: ReleasePlan;
17
26
  updated: boolean;
27
+ highlights: string;
18
28
  };
19
- export declare function renderSimpleReviewRequestBody(version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, cwd?: string): string;
29
+ export declare function renderSimpleReviewRequestBody(version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, cwd?: string, highlights?: string): string;
20
30
  export declare function openOrUpdateReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
21
31
  logger?: VersionaryPluginContext["logger"];
32
+ highlights?: string;
22
33
  }): Promise<string>;
23
34
  export declare function closeStaleReviewRequestIfExists(cwd?: string, options?: {
24
35
  logger?: VersionaryPluginContext["logger"];
@@ -34,6 +45,7 @@ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
34
45
  /** @deprecated Use openOrUpdateReviewRequest. */
35
46
  export declare function openOrUpdateSimpleReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
36
47
  logger?: VersionaryPluginContext["logger"];
48
+ highlights?: string;
37
49
  }): Promise<string>;
38
50
  export declare function pushReleaseBranch(cwd: string, branch: string): void;
39
51
  export declare function isReleaseCommitMessage(commitMessage: string): boolean;
@@ -3,6 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getNextReleaseFile = getNextReleaseFile;
7
+ exports.readNextReleaseHighlights = readNextReleaseHighlights;
8
+ exports.consumeNextReleaseFile = consumeNextReleaseFile;
6
9
  exports.splitSafeDirtyFiles = splitSafeDirtyFiles;
7
10
  exports.prepareReleasePr = prepareReleasePr;
8
11
  exports.renderSimpleReviewRequestBody = renderSimpleReviewRequestBody;
@@ -13,6 +16,7 @@ exports.openOrUpdateSimpleReviewRequest = openOrUpdateSimpleReviewRequest;
13
16
  exports.pushReleaseBranch = pushReleaseBranch;
14
17
  exports.isReleaseCommitMessage = isReleaseCommitMessage;
15
18
  const node_child_process_1 = require("node:child_process");
19
+ const node_fs_1 = __importDefault(require("node:fs"));
16
20
  const node_path_1 = __importDefault(require("node:path"));
17
21
  const load_config_js_1 = require("../config/load-config.js");
18
22
  const client_js_1 = require("../scm/client.js");
@@ -29,6 +33,38 @@ const SAFE_DIRTY_FILES = new Set([
29
33
  "npm-shrinkwrap.json",
30
34
  ]);
31
35
  const VERSIONARY_RELEASE_TRAILER = "Versionary-Release: true";
36
+ function getNextReleaseFile(config) {
37
+ return config["next-release-file"] ?? "NEXT_RELEASE.md";
38
+ }
39
+ function readNextReleaseHighlights(cwd, config) {
40
+ const filePath = getNextReleaseFile(config);
41
+ const fullPath = node_path_1.default.join(cwd, filePath);
42
+ if (!node_fs_1.default.existsSync(fullPath)) {
43
+ return null;
44
+ }
45
+ const content = node_fs_1.default.readFileSync(fullPath, "utf8").trim();
46
+ return { content, filePath };
47
+ }
48
+ function isTrackedFile(cwd, filePath) {
49
+ try {
50
+ (0, node_child_process_1.execFileSync)("git", ["ls-files", "--error-unmatch", "--", filePath], {
51
+ cwd,
52
+ stdio: ["ignore", "pipe", "ignore"],
53
+ });
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ function consumeNextReleaseFile(cwd, filePath) {
61
+ const tracked = isTrackedFile(cwd, filePath);
62
+ const fullPath = node_path_1.default.join(cwd, filePath);
63
+ if (node_fs_1.default.existsSync(fullPath)) {
64
+ node_fs_1.default.rmSync(fullPath);
65
+ }
66
+ return { tracked };
67
+ }
32
68
  function listTrackedDirtyFiles(cwd) {
33
69
  const status = (0, node_child_process_1.execFileSync)("git", ["status", "--porcelain", "--untracked-files=no"], {
34
70
  cwd,
@@ -251,9 +287,18 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
251
287
  }
252
288
  const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
253
289
  const packageReleaseMetadata = buildPackageReleaseMetadata(cwd, plan, loaded.config);
254
- const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
290
+ const nextReleaseRead = readNextReleaseHighlights(cwd, loaded.config);
291
+ const highlights = nextReleaseRead?.content ?? "";
292
+ const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan, { highlights, cwd });
255
293
  (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section, plan.changelogFormat);
256
294
  const updatedChangelogFiles = [plan.changelogFile];
295
+ let consumedHighlightsPath = null;
296
+ if (nextReleaseRead) {
297
+ const { tracked } = consumeNextReleaseFile(cwd, nextReleaseRead.filePath);
298
+ if (tracked) {
299
+ consumedHighlightsPath = nextReleaseRead.filePath;
300
+ }
301
+ }
257
302
  for (const packagePlan of plan.packages ?? []) {
258
303
  if (!packagePlan.nextVersion || packagePlan.path === ".") {
259
304
  continue;
@@ -296,6 +341,7 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
296
341
  ...updatedVersionFiles,
297
342
  ...updatedArtifactFiles,
298
343
  ...updatedChangelogFiles,
344
+ ...(consumedHighlightsPath ? [consumedHighlightsPath] : []),
299
345
  ]),
300
346
  ];
301
347
  (0, node_child_process_1.execFileSync)("git", ["add", ...filesToAdd], {
@@ -325,9 +371,10 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
325
371
  commits: plan.commits,
326
372
  plan,
327
373
  updated,
374
+ highlights,
328
375
  };
329
376
  }
330
- function renderSimpleReviewRequestBody(version, previousVersion, commits, plan = null, cwd = process.cwd()) {
377
+ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan = null, cwd = process.cwd(), highlights = "") {
331
378
  const rootPackageLabel = node_path_1.default.basename(cwd);
332
379
  const formatPackageLabel = (packagePath) => packagePath === "." ? rootPackageLabel : packagePath;
333
380
  const isDirectBump = (pkg) => pkg.bumpReason === "direct" ||
@@ -361,6 +408,7 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
361
408
  const rootNotes = (0, changelog_js_1.renderReleasePlanChangelog)(plan, {
362
409
  headerLabel: `${formatPackageLabel(".")}: ${rootPackage.nextVersion}`,
363
410
  cwd,
411
+ highlights,
364
412
  });
365
413
  sections.push(rootNotes);
366
414
  }
@@ -393,6 +441,7 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
393
441
  nextVersion: version,
394
442
  commits,
395
443
  cwd,
444
+ highlights,
396
445
  }, { includeFooter: true });
397
446
  }
398
447
  async function openOrUpdateReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
@@ -406,7 +455,7 @@ async function openOrUpdateReviewRequest(cwd, branch, title, version, previousVe
406
455
  baseBranch: process.env.VERSIONARY_BASE_BRANCH ?? "main",
407
456
  headBranch: branch,
408
457
  title,
409
- body: renderSimpleReviewRequestBody(version, previousVersion, commits, plan, cwd),
458
+ body: renderSimpleReviewRequestBody(version, previousVersion, commits, plan, cwd, options.highlights ?? ""),
410
459
  labels: ["release"],
411
460
  }, {
412
461
  cwd,
@@ -26,6 +26,7 @@ export interface VersionaryConfig {
26
26
  "release-reference-comments"?: ReleaseReferenceCommentsMode;
27
27
  "release-branch"?: string;
28
28
  "baseline-file"?: string;
29
+ "next-release-file"?: string;
29
30
  "bootstrap-sha"?: string;
30
31
  "monorepo-mode"?: "independent" | "fixed";
31
32
  "bump-minor-pre-major"?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",