versionary 0.12.0 → 0.14.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/README.md CHANGED
@@ -86,8 +86,10 @@ Current ecosystem policy defaults:
86
86
 
87
87
  - changelog source for publish:
88
88
  - root target uses root `changelog-file`
89
- - package target uses `packages.<path>.changelog-file` when configured, else
90
- root `changelog-file`
89
+ - package target uses package changelog defaults:
90
+ - `packages.<path>.changelog-file` when configured
91
+ - otherwise `NEWS.md` for R targets or `CHANGELOG.md` for other targets at
92
+ `<package-path>/<default-file>`
91
93
  - lockfiles:
92
94
  - Node strategy updates root `package-lock.json`/`npm-shrinkwrap.json` when
93
95
  present
@@ -142,6 +144,10 @@ For a quick trial, use:
142
144
  request)
143
145
  - `release-draft` (default `false`) publishes GitHub releases as drafts when
144
146
  enabled
147
+ - `release-reference-comments` controls release comments on linked issues/PRs:
148
+ - `off` (default): do not post comments
149
+ - `best-effort`: post comments and continue on API/permission failures
150
+ - `strict`: fail release if comment posting fails
145
151
  - optional monorepo planning with `monorepo-mode` and `packages`:
146
152
  - `independent` computes package bumps per path
147
153
  - `fixed` computes one shared bump across configured package paths
package/dist/cli/index.js CHANGED
@@ -52,7 +52,7 @@ async function main() {
52
52
  }).trim();
53
53
  if ((0, pr_js_1.isReleaseCommitMessage)(commitMessage)) {
54
54
  if (flags["dry-run"] && !flags.json) {
55
- const release = await (0, release_js_1.runSimpleReleaseDetailed)(process.cwd(), {
55
+ const release = await (0, release_js_1.runReleaseDetailed)(process.cwd(), {
56
56
  logger,
57
57
  "dry-run": true,
58
58
  });
@@ -62,7 +62,7 @@ async function main() {
62
62
  }
63
63
  }
64
64
  if (flags.json) {
65
- const release = await (0, release_js_1.runSimpleReleaseDetailed)(process.cwd(), {
65
+ const release = await (0, release_js_1.runReleaseDetailed)(process.cwd(), {
66
66
  logger,
67
67
  "dry-run": flags["dry-run"],
68
68
  });
@@ -93,11 +93,11 @@ async function main() {
93
93
  });
94
94
  return 0;
95
95
  }
96
- const message = await (0, release_js_1.runSimpleRelease)(process.cwd());
96
+ const message = await (0, release_js_1.runRelease)(process.cwd());
97
97
  console.log(message);
98
98
  return 0;
99
99
  }
100
- const plan = (0, plan_js_1.createSimplePlan)();
100
+ const plan = (0, plan_js_1.createReleasePlan)();
101
101
  if (!plan.nextVersion) {
102
102
  const message = "No releasable commits found. Nothing to do.";
103
103
  if (flags.json) {
@@ -140,9 +140,9 @@ async function main() {
140
140
  console.log(dryRunMessage);
141
141
  return 0;
142
142
  }
143
- const pr = (0, pr_js_1.prepareSimpleReleasePr)(process.cwd(), { logger });
143
+ const pr = (0, pr_js_1.prepareReleasePr)(process.cwd(), { logger });
144
144
  (0, pr_js_1.pushReleaseBranch)(process.cwd(), pr.branch);
145
- const reviewResult = await (0, pr_js_1.openOrUpdateSimpleReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan, { logger });
145
+ const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan, { logger });
146
146
  const message = `Prepared release PR branch ${pr.branch}`;
147
147
  if (flags.json) {
148
148
  emitJson({
@@ -165,18 +165,18 @@ async function main() {
165
165
  return printVerifyResult();
166
166
  }
167
167
  if (command === "plan") {
168
- const plan = (0, plan_js_1.createSimplePlan)();
168
+ const plan = (0, plan_js_1.createReleasePlan)();
169
169
  console.log(JSON.stringify(plan, null, 2));
170
170
  return 0;
171
171
  }
172
172
  if (command === "changelog") {
173
173
  const write = args.includes("--write");
174
- const plan = (0, plan_js_1.createSimplePlan)();
174
+ const plan = (0, plan_js_1.createReleasePlan)();
175
175
  if (!plan.nextVersion) {
176
176
  console.log("No releasable commits found.");
177
177
  return 0;
178
178
  }
179
- const section = (0, changelog_js_1.renderSimpleChangelog)(plan);
179
+ const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
180
180
  if (!write) {
181
181
  console.log(section);
182
182
  return 0;
@@ -187,7 +187,7 @@ async function main() {
187
187
  }
188
188
  if (command === "pr") {
189
189
  if (flags["dry-run"]) {
190
- const plan = (0, plan_js_1.createSimplePlan)();
190
+ const plan = (0, plan_js_1.createReleasePlan)();
191
191
  if (!plan.nextVersion) {
192
192
  console.log("No releasable commits found. Nothing to do.");
193
193
  return 0;
@@ -195,9 +195,9 @@ async function main() {
195
195
  console.log(`Dry run: would prepare release PR branch ${plan.releaseBranchPrefix} for ${plan.nextVersion}`);
196
196
  return 0;
197
197
  }
198
- const pr = (0, pr_js_1.prepareSimpleReleasePr)(process.cwd(), { logger: console });
198
+ const pr = (0, pr_js_1.prepareReleasePr)(process.cwd(), { logger: console });
199
199
  (0, pr_js_1.pushReleaseBranch)(process.cwd(), pr.branch);
200
- const reviewResult = await (0, pr_js_1.openOrUpdateSimpleReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan);
200
+ const reviewResult = await (0, pr_js_1.openOrUpdateReviewRequest)(process.cwd(), pr.branch, pr.title, pr.version, pr.previousVersion, pr.commits, pr.plan);
201
201
  console.log(`Prepared release PR branch ${pr.branch}`);
202
202
  console.log(`Title: ${pr.title}`);
203
203
  console.log(reviewResult);
@@ -205,7 +205,7 @@ async function main() {
205
205
  }
206
206
  if (command === "release") {
207
207
  if (flags["dry-run"]) {
208
- const result = await (0, release_js_1.runSimpleReleaseDetailed)(process.cwd(), {
208
+ const result = await (0, release_js_1.runReleaseDetailed)(process.cwd(), {
209
209
  logger,
210
210
  "dry-run": true,
211
211
  });
@@ -220,7 +220,7 @@ async function main() {
220
220
  }
221
221
  return 0;
222
222
  }
223
- const message = await (0, release_js_1.runSimpleRelease)(process.cwd());
223
+ const message = await (0, release_js_1.runRelease)(process.cwd());
224
224
  console.log(message);
225
225
  return 0;
226
226
  }
@@ -228,7 +228,7 @@ async function main() {
228
228
  console.log("Commands:");
229
229
  console.log(" run [--json] [--dry-run] Auto-dispatch release PR/update or release publish by context");
230
230
  console.log(" verify Validate config and basic repository shape");
231
- console.log(" plan Print release plan (simple mode)");
231
+ console.log(" plan Print release plan");
232
232
  console.log(" changelog [--write] Print or write changelog section");
233
233
  console.log(" pr [--dry-run] Prepare release PR commit and branch");
234
234
  console.log(" release [--dry-run] Publish release metadata for release commit context");
@@ -14,6 +14,11 @@ export declare const configSchema: z.ZodObject<{
14
14
  "r-news": "r-news";
15
15
  }>>;
16
16
  "release-draft": z.ZodOptional<z.ZodBoolean>;
17
+ "release-reference-comments": z.ZodOptional<z.ZodEnum<{
18
+ off: "off";
19
+ "best-effort": "best-effort";
20
+ strict: "strict";
21
+ }>>;
17
22
  "release-branch": z.ZodOptional<z.ZodString>;
18
23
  "baseline-file": z.ZodOptional<z.ZodString>;
19
24
  "bootstrap-sha": z.ZodOptional<z.ZodString>;
@@ -68,6 +68,9 @@ exports.configSchema = zod_1.z
68
68
  "changelog-file": zod_1.z.string().optional(),
69
69
  "changelog-format": zod_1.z.enum(["markdown-changelog", "r-news"]).optional(),
70
70
  "release-draft": zod_1.z.boolean().optional(),
71
+ "release-reference-comments": zod_1.z
72
+ .enum(["off", "best-effort", "strict"])
73
+ .optional(),
71
74
  "release-branch": zod_1.z.string().optional(),
72
75
  "baseline-file": zod_1.z.string().optional(),
73
76
  "bootstrap-sha": zod_1.z.string().optional(),
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { verifyProject } from "./release/verify-project.js";
3
3
  export { findPluginsByCapability, pluginHasCapability, } from "./scm/capabilities.js";
4
4
  export { getScmClient } from "./scm/client.js";
5
5
  export { createGitHubPlugin } from "./scm/github-plugin.js";
6
- export type { ScmClient, ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReviewRequestInput, ScmReviewRequestResult, } from "./scm/types.js";
6
+ export type { ScmClient, ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReleaseReferenceCommentsInput, ScmReleaseReferenceCommentsResult, ScmReviewRequestInput, ScmReviewRequestResult, } from "./scm/types.js";
7
7
  export { resolveVersionStrategy } from "./strategy/resolve.js";
8
8
  export type { VersionaryArtifactRule, VersionaryConfig, VersionaryPackage, } from "./types/config.js";
9
- export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, } from "./types/plugins.js";
9
+ export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, VersionaryScmReleaseReferenceCommentsInput, VersionaryScmReleaseReferenceCommentsResult, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, } from "./types/plugins.js";
@@ -1,6 +1,6 @@
1
1
  import { type ParsedCommit } from "../git/commits.js";
2
2
  import type { VersionaryChangelogFormat } from "../types/config.js";
3
- import type { SimplePlan } from "./plan.js";
3
+ import type { ReleasePlan, SimplePlan } from "./plan.js";
4
4
  export declare function renderSimpleReleaseNotes(input: {
5
5
  currentVersion: string;
6
6
  nextVersion: string;
@@ -13,6 +13,8 @@ export declare function renderSimpleReleaseNotes(input: {
13
13
  }, options?: {
14
14
  includeFooter?: boolean;
15
15
  }): string;
16
+ export declare function renderReleasePlanChangelog(plan: ReleasePlan): string;
17
+ /** @deprecated Use renderReleasePlanChangelog. */
16
18
  export declare function renderSimpleChangelog(plan: SimplePlan): string;
17
19
  export declare function renderPackageChangelogSection(input: {
18
20
  currentVersion: string;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.renderSimpleReleaseNotes = renderSimpleReleaseNotes;
7
+ exports.renderReleasePlanChangelog = renderReleasePlanChangelog;
7
8
  exports.renderSimpleChangelog = renderSimpleChangelog;
8
9
  exports.renderPackageChangelogSection = renderPackageChangelogSection;
9
10
  exports.prependChangelog = prependChangelog;
@@ -112,7 +113,7 @@ function renderSimpleReleaseNotes(input, options = {}) {
112
113
  }
113
114
  return lines.join("\n");
114
115
  }
115
- function renderSimpleChangelog(plan) {
116
+ function renderReleasePlanChangelog(plan) {
116
117
  if (!plan.nextVersion) {
117
118
  return "";
118
119
  }
@@ -129,22 +130,29 @@ function renderSimpleChangelog(plan) {
129
130
  version: pkg.nextVersion,
130
131
  }))
131
132
  : [];
133
+ const dedupedCommits = [
134
+ ...new Map(plan.commits.map((commit) => [commit.hash, commit])).values(),
135
+ ];
132
136
  if (plan.changelogFormat === "r-news") {
133
137
  return renderRNewsReleaseNotes({
134
138
  packageName: plan.packageName,
135
139
  nextVersion: plan.nextVersion,
136
- commits: plan.commits,
140
+ commits: dedupedCommits,
137
141
  cwd: process.cwd(),
138
142
  });
139
143
  }
140
144
  return renderSimpleReleaseNotes({
141
145
  currentVersion: plan.currentVersion,
142
146
  nextVersion: plan.nextVersion,
143
- commits: plan.commits,
147
+ commits: dedupedCommits,
144
148
  cwd: process.cwd(),
145
149
  dependencies,
146
150
  });
147
151
  }
152
+ /** @deprecated Use renderReleasePlanChangelog. */
153
+ function renderSimpleChangelog(plan) {
154
+ return renderReleasePlanChangelog(plan);
155
+ }
148
156
  function renderPackageChangelogSection(input) {
149
157
  const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(input.cwd ?? process.cwd());
150
158
  const header = repoUrl
@@ -172,15 +180,16 @@ function prependChangelog(cwd, changelogFile, section, format = "markdown-change
172
180
  ? node_fs_1.default.readFileSync(changelogPath, "utf8")
173
181
  : "";
174
182
  if (format === "r-news") {
175
- const separator = existing.length > 0 ? "\n\n" : "";
176
- const next = `${section}${separator}${existing}`.trimEnd() + "\n";
183
+ const bodyWithoutDevHeader = existing.replace(/^#\s+.+\s+\(development version\)\s*(?:\r?\n)*/u, "");
184
+ const separator = bodyWithoutDevHeader.length > 0 ? "\n\n" : "";
185
+ const next = `${`${section}${separator}${bodyWithoutDevHeader}`.trimEnd()}\n`;
177
186
  node_fs_1.default.writeFileSync(changelogPath, next, "utf8");
178
187
  return;
179
188
  }
180
189
  const heading = "# Changelog\n\n";
181
190
  const bodyWithoutHeading = existing.replace(/^# Changelog\s*/u, "");
182
191
  const separator = existing.length > 0 ? "\n" : "";
183
- const next = `${heading}${section}${separator}${bodyWithoutHeading}`.trimEnd() + "\n";
192
+ const next = `${`${heading}${section}${separator}${bodyWithoutHeading}`.trimEnd()}\n`;
184
193
  node_fs_1.default.writeFileSync(changelogPath, next, "utf8");
185
194
  }
186
195
  function renderRNewsReleaseNotes(input) {
@@ -1,7 +1,7 @@
1
1
  import { type ParsedCommit } from "../git/commits.js";
2
2
  import type { VersionaryChangelogFormat, VersionaryConfig } from "../types/config.js";
3
3
  import { type ReleaseType } from "./semver.js";
4
- export interface SimplePlan {
4
+ export interface ReleasePlan {
5
5
  mode: "simple";
6
6
  releaseType: ReleaseType;
7
7
  currentVersion: string;
@@ -22,6 +22,8 @@ export interface SimplePlan {
22
22
  commits: ParsedCommit[];
23
23
  }>;
24
24
  }
25
+ /** @deprecated Use ReleasePlan. */
26
+ export type SimplePlan = ReleasePlan;
25
27
  export declare function getChangelogDefaults(config: {
26
28
  "release-type"?: VersionaryConfig["release-type"];
27
29
  "changelog-file"?: VersionaryConfig["changelog-file"];
@@ -30,4 +32,6 @@ export declare function getChangelogDefaults(config: {
30
32
  changelogFile: string;
31
33
  changelogFormat: VersionaryChangelogFormat;
32
34
  };
33
- export declare function createSimplePlan(cwd?: string): SimplePlan;
35
+ export declare function createReleasePlan(cwd?: string): ReleasePlan;
36
+ /** @deprecated Use createReleasePlan. */
37
+ export declare function createSimplePlan(cwd?: string): ReleasePlan;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getChangelogDefaults = getChangelogDefaults;
7
+ exports.createReleasePlan = createReleasePlan;
7
8
  exports.createSimplePlan = createSimplePlan;
8
9
  const node_fs_1 = __importDefault(require("node:fs"));
9
10
  const node_path_1 = __importDefault(require("node:path"));
@@ -23,7 +24,7 @@ function getChangelogDefaults(config) {
23
24
  (changelogFormat === "r-news" ? "NEWS.md" : "CHANGELOG.md");
24
25
  return { changelogFile, changelogFormat };
25
26
  }
26
- function createSimplePlan(cwd = process.cwd()) {
27
+ function createReleasePlan(cwd = process.cwd()) {
27
28
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
28
29
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
29
30
  const versionFile = strategy.getVersionFile(loaded.config);
@@ -189,3 +190,7 @@ function createSimplePlan(cwd = process.cwd()) {
189
190
  packages: adjustedPackages,
190
191
  };
191
192
  }
193
+ /** @deprecated Use createReleasePlan. */
194
+ function createSimplePlan(cwd = process.cwd()) {
195
+ return createReleasePlan(cwd);
196
+ }
@@ -1,11 +1,11 @@
1
1
  import type { ParsedCommit } from "../git/commits.js";
2
2
  import type { VersionaryPluginContext } from "../types/plugins.js";
3
- import { type SimplePlan } from "./plan.js";
3
+ import { type ReleasePlan, type SimplePlan } from "./plan.js";
4
4
  export declare function splitSafeDirtyFiles(files: string[]): {
5
5
  ignored: string[];
6
6
  blocking: string[];
7
7
  };
8
- export declare function prepareSimpleReleasePr(cwd?: string, options?: {
8
+ export declare function prepareReleasePr(cwd?: string, options?: {
9
9
  logger?: VersionaryPluginContext["logger"];
10
10
  }): {
11
11
  branch: string;
@@ -13,9 +13,17 @@ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
13
13
  version: string;
14
14
  previousVersion: string;
15
15
  commits: ParsedCommit[];
16
- plan: SimplePlan;
16
+ plan: ReleasePlan;
17
17
  };
18
18
  export declare function renderSimpleReviewRequestBody(version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, cwd?: string): string;
19
+ export declare function openOrUpdateReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
20
+ logger?: VersionaryPluginContext["logger"];
21
+ }): Promise<string>;
22
+ /** @deprecated Use prepareReleasePr. */
23
+ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
24
+ logger?: VersionaryPluginContext["logger"];
25
+ }): ReturnType<typeof prepareReleasePr>;
26
+ /** @deprecated Use openOrUpdateReviewRequest. */
19
27
  export declare function openOrUpdateSimpleReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
20
28
  logger?: VersionaryPluginContext["logger"];
21
29
  }): Promise<string>;
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.splitSafeDirtyFiles = splitSafeDirtyFiles;
7
- exports.prepareSimpleReleasePr = prepareSimpleReleasePr;
7
+ exports.prepareReleasePr = prepareReleasePr;
8
8
  exports.renderSimpleReviewRequestBody = renderSimpleReviewRequestBody;
9
+ exports.openOrUpdateReviewRequest = openOrUpdateReviewRequest;
10
+ exports.prepareSimpleReleasePr = prepareSimpleReleasePr;
9
11
  exports.openOrUpdateSimpleReviewRequest = openOrUpdateSimpleReviewRequest;
10
12
  exports.pushReleaseBranch = pushReleaseBranch;
11
13
  exports.isReleaseCommitMessage = isReleaseCommitMessage;
@@ -202,8 +204,8 @@ function formatReleaseCommitTitle(releaseTargets) {
202
204
  }
203
205
  return `chore(release): ${tags[0]} (+${tags.length - 1} more)`;
204
206
  }
205
- function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
206
- const plan = (0, plan_js_1.createSimplePlan)(cwd);
207
+ function prepareReleasePr(cwd = process.cwd(), options = {}) {
208
+ const plan = (0, plan_js_1.createReleasePlan)(cwd);
207
209
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
208
210
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
209
211
  if (!plan.nextVersion) {
@@ -253,7 +255,7 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
253
255
  const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
254
256
  const updatedRustLockFiles = ensureCargoLockUpToDate(cwd);
255
257
  const packageReleaseMetadata = buildPackageReleaseMetadata(cwd, plan, loaded.config);
256
- const section = (0, changelog_js_1.renderSimpleChangelog)(plan);
258
+ const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
257
259
  (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section, plan.changelogFormat);
258
260
  const updatedChangelogFiles = [plan.changelogFile];
259
261
  for (const packagePlan of plan.packages ?? []) {
@@ -261,10 +263,11 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
261
263
  continue;
262
264
  }
263
265
  const packageConfig = loaded.config.packages?.[packagePlan.path] ?? {};
264
- const packageChangelogFile = packageConfig["changelog-file"];
265
- if (!packageChangelogFile) {
266
- continue;
267
- }
266
+ const { changelogFile: packageChangelogFile } = (0, plan_js_1.getChangelogDefaults)({
267
+ "release-type": packageConfig["release-type"] ?? loaded.config["release-type"],
268
+ "changelog-file": packageConfig["changelog-file"] ?? loaded.config["changelog-file"],
269
+ "changelog-format": packageConfig["changelog-format"] ?? loaded.config["changelog-format"],
270
+ });
268
271
  const packageMetadata = packageReleaseMetadata[packagePlan.path];
269
272
  if (!packageMetadata) {
270
273
  continue;
@@ -342,9 +345,28 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
342
345
  .sort((a, b) => a.name.localeCompare(b.name));
343
346
  return directSources;
344
347
  };
348
+ const relabelSectionHeader = (notes, packageLabel, nextVersion) => {
349
+ const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
350
+ if (linkedHeader) {
351
+ const [, , compareUrl, date] = linkedHeader;
352
+ return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${nextVersion}](${compareUrl}) (${date})`);
353
+ }
354
+ const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
355
+ if (plainHeader) {
356
+ const [, , date] = plainHeader;
357
+ return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${nextVersion} (${date})`);
358
+ }
359
+ return notes;
360
+ };
345
361
  if (plan?.packages && plan.packages.length > 1) {
346
- const sections = plan.packages
347
- .filter((pkg) => pkg.nextVersion)
362
+ const sections = [];
363
+ const rootPackage = plan.packages.find((pkg) => pkg.path === "." && pkg.nextVersion);
364
+ if (rootPackage?.nextVersion) {
365
+ const rootNotes = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
366
+ sections.push(relabelSectionHeader(rootNotes, formatPackageLabel("."), rootPackage.nextVersion));
367
+ }
368
+ const packageSections = plan.packages
369
+ .filter((pkg) => pkg.path !== "." && pkg.nextVersion)
348
370
  .map((pkg) => {
349
371
  const packageLabel = formatPackageLabel(pkg.path);
350
372
  const propagatedDependencies = findPropagatedDependencies(pkg.path, plan.packages ?? []);
@@ -355,20 +377,14 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
355
377
  cwd,
356
378
  dependencies: propagatedDependencies,
357
379
  }, { includeFooter: false });
358
- const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
359
- if (linkedHeader) {
360
- const [, , compareUrl, date] = linkedHeader;
361
- return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${pkg.nextVersion ?? ""}](${compareUrl}) (${date})`);
362
- }
363
- const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
364
- if (plainHeader) {
365
- const [, , date] = plainHeader;
366
- return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${pkg.nextVersion ?? ""} (${date})`);
367
- }
368
- return notes;
369
- })
370
- .join("\n\n");
371
- return `${sections}\n\nThis PR was generated by Versionary.`;
380
+ return relabelSectionHeader(notes, packageLabel, pkg.nextVersion ?? "");
381
+ });
382
+ sections.push(...packageSections);
383
+ const bodySections = sections.join("\n\n");
384
+ if (bodySections.length === 0) {
385
+ return "This PR was generated by Versionary.";
386
+ }
387
+ return `${bodySections}\n\nThis PR was generated by Versionary.`;
372
388
  }
373
389
  return (0, changelog_js_1.renderSimpleReleaseNotes)({
374
390
  currentVersion: previousVersion,
@@ -377,7 +393,7 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
377
393
  cwd,
378
394
  }, { includeFooter: true });
379
395
  }
380
- async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
396
+ async function openOrUpdateReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
381
397
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
382
398
  const releaseFlow = loaded.config["review-mode"] ?? "pr";
383
399
  if (releaseFlow === "direct") {
@@ -396,6 +412,14 @@ async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, prev
396
412
  });
397
413
  return result.url;
398
414
  }
415
+ /** @deprecated Use prepareReleasePr. */
416
+ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
417
+ return prepareReleasePr(cwd, options);
418
+ }
419
+ /** @deprecated Use openOrUpdateReviewRequest. */
420
+ async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
421
+ return openOrUpdateReviewRequest(cwd, branch, title, version, previousVersion, commits, plan, options);
422
+ }
399
423
  function pushReleaseBranch(cwd, branch) {
400
424
  (0, node_child_process_1.execFileSync)("git", ["push", "--force-with-lease", "origin", branch], {
401
425
  cwd,
@@ -1,8 +1,10 @@
1
1
  import type { VersionaryConfig } from "../types/config.js";
2
2
  import type { VersionaryPluginContext } from "../types/plugins.js";
3
+ export declare function extractReleaseNotes(content: string, version: string, changelogFormat: "markdown-changelog" | "r-news"): string;
4
+ export declare function extractClosingReferencesFromNotes(notes: string): number[];
3
5
  export declare function resolveTargetChangelogFile(config: VersionaryConfig, rootChangelogFile: string, targetPath: string): string;
4
- export declare function runSimpleRelease(cwd?: string): Promise<string>;
5
- export type SimpleRunReleaseResult = {
6
+ export declare function runRelease(cwd?: string): Promise<string>;
7
+ export type RunReleaseResult = {
6
8
  action: "release-skipped";
7
9
  reason: string;
8
10
  } | {
@@ -22,8 +24,16 @@ export type SimpleRunReleaseResult = {
22
24
  metadataStatus: "created" | "exists";
23
25
  }[];
24
26
  };
25
- export interface RunSimpleReleaseOptions {
27
+ export interface RunReleaseOptions {
26
28
  logger?: VersionaryPluginContext["logger"];
27
29
  "dry-run"?: boolean;
28
30
  }
31
+ export declare function runReleaseDetailed(cwd?: string, options?: RunReleaseOptions): Promise<RunReleaseResult>;
32
+ /** @deprecated Use RunReleaseResult. */
33
+ export type SimpleRunReleaseResult = RunReleaseResult;
34
+ /** @deprecated Use RunReleaseOptions. */
35
+ export type RunSimpleReleaseOptions = RunReleaseOptions;
36
+ /** @deprecated Use runRelease. */
37
+ export declare function runSimpleRelease(cwd?: string): Promise<string>;
38
+ /** @deprecated Use runReleaseDetailed. */
29
39
  export declare function runSimpleReleaseDetailed(cwd?: string, options?: RunSimpleReleaseOptions): Promise<SimpleRunReleaseResult>;
@@ -3,7 +3,11 @@ 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.extractReleaseNotes = extractReleaseNotes;
7
+ exports.extractClosingReferencesFromNotes = extractClosingReferencesFromNotes;
6
8
  exports.resolveTargetChangelogFile = resolveTargetChangelogFile;
9
+ exports.runRelease = runRelease;
10
+ exports.runReleaseDetailed = runReleaseDetailed;
7
11
  exports.runSimpleRelease = runSimpleRelease;
8
12
  exports.runSimpleReleaseDetailed = runSimpleReleaseDetailed;
9
13
  const node_child_process_1 = require("node:child_process");
@@ -16,60 +20,109 @@ const plan_js_1 = require("./plan.js");
16
20
  const pr_js_1 = require("./pr.js");
17
21
  const recovery_js_1 = require("./recovery.js");
18
22
  const state_js_1 = require("./state.js");
19
- function getHeadCommitMessage(cwd) {
20
- return (0, node_child_process_1.execFileSync)("git", ["log", "-1", "--pretty=%B"], {
21
- cwd,
22
- encoding: "utf8",
23
- stdio: ["ignore", "pipe", "ignore"],
24
- }).trim();
23
+ function escapeRegExp(input) {
24
+ return input.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
25
25
  }
26
- function readReleaseNotes(cwd, version, changelogFile) {
27
- const changelogPath = node_path_1.default.join(cwd, changelogFile);
28
- if (!node_fs_1.default.existsSync(changelogPath)) {
29
- return `Automated release for v${version}`;
30
- }
31
- const content = node_fs_1.default.readFileSync(changelogPath, "utf8");
26
+ function extractReleaseNotes(content, version, changelogFormat) {
32
27
  const lines = content.split("\n");
33
28
  const shortVersion = version.replace(/\.\d+$/u, "");
34
- const start = lines.findIndex((line) => line.startsWith(`## ${version} -`) ||
35
- line.startsWith(`## [${version}](`) ||
36
- line.startsWith(`# ${shortVersion} -`) ||
37
- line.startsWith(`# [${shortVersion}](`) ||
38
- new RegExp(`^#\\s+.+\\s+${shortVersion}\\s*$`, "u").test(line));
29
+ const start = changelogFormat === "r-news"
30
+ ? lines.findIndex((line) => {
31
+ const fullMatch = new RegExp(`^#\\s+.+\\s+${escapeRegExp(version)}\\s*$`, "u");
32
+ const shortMatch = new RegExp(`^#\\s+.+\\s+${escapeRegExp(shortVersion)}\\s*$`, "u");
33
+ return fullMatch.test(line) || shortMatch.test(line);
34
+ })
35
+ : lines.findIndex((line) => line.startsWith(`## ${version} -`) ||
36
+ line.startsWith(`## [${version}](`) ||
37
+ line.startsWith(`# ${shortVersion} -`) ||
38
+ line.startsWith(`# [${shortVersion}](`) ||
39
+ new RegExp(`^#\\s+.+\\s+${shortVersion}\\s*$`, "u").test(line));
39
40
  if (start < 0) {
40
- return `Automated release for v${version}`;
41
+ return "";
41
42
  }
42
43
  let end = lines.length;
43
44
  for (let idx = start + 1; idx < lines.length; idx += 1) {
44
- if (lines[idx]?.startsWith("## ")) {
45
+ const line = lines[idx] ?? "";
46
+ if (changelogFormat === "r-news") {
47
+ if (/^#(?!#)\s+/u.test(line)) {
48
+ end = idx;
49
+ break;
50
+ }
51
+ continue;
52
+ }
53
+ if (line.startsWith("## ")) {
45
54
  end = idx;
46
55
  break;
47
56
  }
48
57
  }
49
- const notes = lines
58
+ return lines
50
59
  .slice(start + 1, end)
51
60
  .join("\n")
52
61
  .trim();
62
+ }
63
+ function getHeadCommitMessage(cwd) {
64
+ return (0, node_child_process_1.execFileSync)("git", ["log", "-1", "--pretty=%B"], {
65
+ cwd,
66
+ encoding: "utf8",
67
+ stdio: ["ignore", "pipe", "ignore"],
68
+ }).trim();
69
+ }
70
+ function readReleaseNotes(cwd, version, changelogFile, changelogFormat) {
71
+ const changelogPath = node_path_1.default.join(cwd, changelogFile);
72
+ if (!node_fs_1.default.existsSync(changelogPath)) {
73
+ return `Automated release for v${version}`;
74
+ }
75
+ const content = node_fs_1.default.readFileSync(changelogPath, "utf8");
76
+ const notes = extractReleaseNotes(content, version, changelogFormat);
53
77
  return notes.length > 0 ? notes : `Automated release for v${version}`;
54
78
  }
79
+ function extractClosingReferencesFromNotes(notes) {
80
+ const refs = new Set();
81
+ const linkedPattern = /\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\b\s+\[#(\d+)\]\([^)]+\)/giu;
82
+ for (const match of notes.matchAll(linkedPattern)) {
83
+ const issue = Number(match[2] ?? "");
84
+ if (Number.isInteger(issue) && issue > 0) {
85
+ refs.add(issue);
86
+ }
87
+ }
88
+ const plainPattern = /\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\b\s+#(\d+)/giu;
89
+ for (const match of notes.matchAll(plainPattern)) {
90
+ const issue = Number(match[2] ?? "");
91
+ if (Number.isInteger(issue) && issue > 0) {
92
+ refs.add(issue);
93
+ }
94
+ }
95
+ return [...refs].sort((a, b) => a - b);
96
+ }
55
97
  function resolveTargetChangelogFile(config, rootChangelogFile, targetPath) {
56
98
  if (targetPath === ".") {
57
99
  return rootChangelogFile;
58
100
  }
59
- const packageChangelogFile = config.packages?.[targetPath]?.["changelog-file"];
60
- if (!packageChangelogFile) {
61
- return rootChangelogFile;
62
- }
101
+ const packageConfig = config.packages?.[targetPath];
102
+ const { changelogFile: packageChangelogFile } = (0, plan_js_1.getChangelogDefaults)({
103
+ "release-type": packageConfig?.["release-type"] ?? config["release-type"],
104
+ "changelog-file": packageConfig?.["changelog-file"] ?? config["changelog-file"],
105
+ "changelog-format": packageConfig?.["changelog-format"] ?? config["changelog-format"],
106
+ });
63
107
  return node_path_1.default.posix.join(targetPath, packageChangelogFile);
64
108
  }
65
- async function runSimpleRelease(cwd = process.cwd()) {
66
- const result = await runSimpleReleaseDetailed(cwd, { logger: console });
109
+ function resolveTargetChangelogFormat(config, targetPath) {
110
+ const packageConfig = targetPath === "." ? undefined : config.packages?.[targetPath];
111
+ const { changelogFormat } = (0, plan_js_1.getChangelogDefaults)({
112
+ "release-type": packageConfig?.["release-type"] ?? config["release-type"],
113
+ "changelog-file": packageConfig?.["changelog-file"] ?? config["changelog-file"],
114
+ "changelog-format": packageConfig?.["changelog-format"] ?? config["changelog-format"],
115
+ });
116
+ return changelogFormat;
117
+ }
118
+ async function runRelease(cwd = process.cwd()) {
119
+ const result = await runReleaseDetailed(cwd, { logger: console });
67
120
  if (result.action === "release-skipped") {
68
121
  return result.reason;
69
122
  }
70
123
  return result.message;
71
124
  }
72
- async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
125
+ async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
73
126
  const commitMessage = getHeadCommitMessage(cwd);
74
127
  if (!(0, pr_js_1.isReleaseCommitMessage)(commitMessage)) {
75
128
  return {
@@ -80,6 +133,7 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
80
133
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
81
134
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
82
135
  const { changelogFile } = (0, plan_js_1.getChangelogDefaults)(loaded.config);
136
+ const referenceCommentMode = loaded.config["release-reference-comments"] ?? "off";
83
137
  const version = strategy.readVersion(cwd, loaded.config);
84
138
  const defaultTag = `v${version}`;
85
139
  const releaseTargets = (0, state_js_1.readReleaseTargets)(cwd);
@@ -105,12 +159,16 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
105
159
  }
106
160
  const scmClient = (0, client_js_1.getScmClient)();
107
161
  const releases = [];
162
+ const referencesByTag = new Map();
108
163
  for (const target of targets) {
109
164
  const targetChangelogFile = resolveTargetChangelogFile(loaded.config, changelogFile, target.path);
165
+ const targetChangelogFormat = resolveTargetChangelogFormat(loaded.config, target.path);
166
+ const releaseNotes = readReleaseNotes(cwd, target.version, targetChangelogFile, targetChangelogFormat);
167
+ referencesByTag.set(target.tag, extractClosingReferencesFromNotes(releaseNotes));
110
168
  const outcome = await (0, recovery_js_1.executeIdempotentReleaseTarget)(cwd, {
111
169
  tag: target.tag,
112
170
  version: target.version,
113
- notes: readReleaseNotes(cwd, target.version, targetChangelogFile),
171
+ notes: releaseNotes,
114
172
  draft: loaded.config["release-draft"] ?? false,
115
173
  }, {
116
174
  createReleaseMetadata: (input) => scmClient.createReleaseMetadata(input, {
@@ -125,6 +183,20 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
125
183
  tagStatus: outcome.tagStatus,
126
184
  metadataStatus: outcome.metadataStatus,
127
185
  });
186
+ const references = referencesByTag.get(outcome.tag) ?? [];
187
+ if (references.length > 0 &&
188
+ referenceCommentMode !== "off" &&
189
+ scmClient.createReleaseReferenceComments) {
190
+ await scmClient.createReleaseReferenceComments({
191
+ version: target.version,
192
+ releaseUrl: outcome.url,
193
+ references,
194
+ mode: referenceCommentMode,
195
+ }, {
196
+ cwd,
197
+ logger: options.logger,
198
+ });
199
+ }
128
200
  }
129
201
  const published = releases.map((outcome) => `${outcome.tag}: ${outcome.url} (tag=${outcome.tagStatus}, metadata=${outcome.metadataStatus})`);
130
202
  return {
@@ -133,3 +205,11 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
133
205
  message: `Published releases ${published.join(", ")}`,
134
206
  };
135
207
  }
208
+ /** @deprecated Use runRelease. */
209
+ async function runSimpleRelease(cwd = process.cwd()) {
210
+ return runRelease(cwd);
211
+ }
212
+ /** @deprecated Use runReleaseDetailed. */
213
+ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
214
+ return runReleaseDetailed(cwd, options);
215
+ }
@@ -5,10 +5,21 @@ exports.isValidVersion = isValidVersion;
5
5
  exports.compareVersions = compareVersions;
6
6
  exports.bumpVersion = bumpVersion;
7
7
  const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
8
+ const COMPAT_DOTTED_PRERELEASE_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u;
9
+ function normalizeVersionInput(version) {
10
+ const trimmed = version.trim();
11
+ const compatMatch = trimmed.match(COMPAT_DOTTED_PRERELEASE_PATTERN);
12
+ if (!compatMatch) {
13
+ return trimmed;
14
+ }
15
+ const [, major, minor, patch, prerelease] = compatMatch;
16
+ return `${major}.${minor}.${patch}-${prerelease}`;
17
+ }
8
18
  function parseVersion(version) {
9
- const match = version.trim().match(SEMVER_PATTERN);
19
+ const normalized = normalizeVersionInput(version);
20
+ const match = normalized.match(SEMVER_PATTERN);
10
21
  if (!match) {
11
- throw new Error(`Invalid version in version file: "${version}". Expected SemVer 2.0.0 format.`);
22
+ throw new Error(`Invalid version in version file: "${version}". Expected SemVer 2.0.0 format (or compatibility form X.Y.Z.W).`);
12
23
  }
13
24
  return {
14
25
  major: Number(match[1]),
@@ -19,7 +30,7 @@ function parseVersion(version) {
19
30
  };
20
31
  }
21
32
  function isValidVersion(version) {
22
- return SEMVER_PATTERN.test(version.trim());
33
+ return SEMVER_PATTERN.test(normalizeVersionInput(version));
23
34
  }
24
35
  function isNumericIdentifier(identifier) {
25
36
  return /^(0|[1-9]\d*)$/u.test(identifier);
@@ -89,7 +89,11 @@ async function ensureLabels(octokit, repo, pullNumber, labels, branchContext) {
89
89
  function createGitHubPlugin() {
90
90
  return {
91
91
  name: "github",
92
- capabilities: ["scm.reviewRequest", "scm.releaseMetadata"],
92
+ capabilities: [
93
+ "scm.reviewRequest",
94
+ "scm.releaseMetadata",
95
+ "scm.releaseReferenceComments",
96
+ ],
93
97
  provider: "github",
94
98
  async createOrUpdateReviewRequest(input, _context) {
95
99
  const repo = getRepoFromEnv();
@@ -205,5 +209,38 @@ function createGitHubPlugin() {
205
209
  }
206
210
  return { url: data.html_url, status: "created" };
207
211
  },
212
+ async createReleaseReferenceComments(input, context) {
213
+ const repo = getRepoFromEnv();
214
+ const octokit = new rest_1.Octokit({ auth: getGitHubToken() });
215
+ const uniqueReferences = [...new Set(input.references)].sort((a, b) => a - b);
216
+ const commented = [];
217
+ const mode = input.mode ?? "best-effort";
218
+ for (const reference of uniqueReferences) {
219
+ const body = reference >= 1_000_000_000
220
+ ? `This pull request is included in [version ${input.version}](${input.releaseUrl}).`
221
+ : `This issue has been resolved in [version ${input.version}](${input.releaseUrl}).`;
222
+ try {
223
+ await octokit.issues.createComment({
224
+ owner: repo.owner,
225
+ repo: repo.repo,
226
+ issue_number: reference,
227
+ body,
228
+ });
229
+ commented.push(reference);
230
+ }
231
+ catch (error) {
232
+ const { status, message } = parseGitHubError(error);
233
+ if (mode === "strict") {
234
+ throw new Error(`Failed creating release reference comment on #${reference}: [${repoRef(repo)}] ${message}`);
235
+ }
236
+ if (status === 404 || status === 410 || status === 403) {
237
+ context.logger?.warn(`Skipping release reference comment on #${reference}: [${repoRef(repo)}] ${message}`);
238
+ continue;
239
+ }
240
+ context.logger?.warn(`Skipping release reference comment on #${reference}: [${repoRef(repo)}] ${message}`);
241
+ }
242
+ }
243
+ return { commented };
244
+ },
208
245
  };
209
246
  }
@@ -30,8 +30,18 @@ export interface ScmReleaseMetadataResult {
30
30
  url: string;
31
31
  status?: "created" | "exists";
32
32
  }
33
+ export interface ScmReleaseReferenceCommentsInput {
34
+ version: string;
35
+ releaseUrl: string;
36
+ references: number[];
37
+ mode?: "best-effort" | "strict";
38
+ }
39
+ export interface ScmReleaseReferenceCommentsResult {
40
+ commented: number[];
41
+ }
33
42
  export interface ScmClient {
34
43
  provider: ScmProvider;
35
44
  createOrUpdateReviewRequest: (input: ScmReviewRequestInput, context: ScmClientContext) => Promise<ScmReviewRequestResult>;
36
45
  createReleaseMetadata: (input: ScmReleaseMetadataInput, context: ScmClientContext) => Promise<ScmReleaseMetadataResult>;
46
+ createReleaseReferenceComments?: (input: ScmReleaseReferenceCommentsInput, context: ScmClientContext) => Promise<ScmReleaseReferenceCommentsResult>;
37
47
  }
@@ -1,5 +1,6 @@
1
1
  export type ConfigFileFormat = "jsonc" | "json" | "toml" | "js";
2
2
  export type VersionaryChangelogFormat = "markdown-changelog" | "r-news";
3
+ export type ReleaseReferenceCommentsMode = "off" | "best-effort" | "strict";
3
4
  export interface VersionaryArtifactRule {
4
5
  type: "json" | "toml" | "yaml" | "regex";
5
6
  path: string;
@@ -22,6 +23,7 @@ export interface VersionaryConfig {
22
23
  "changelog-file"?: string;
23
24
  "changelog-format"?: VersionaryChangelogFormat;
24
25
  "release-draft"?: boolean;
26
+ "release-reference-comments"?: ReleaseReferenceCommentsMode;
25
27
  "release-branch"?: string;
26
28
  "baseline-file"?: string;
27
29
  "bootstrap-sha"?: string;
@@ -1,9 +1,11 @@
1
- import type { ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReviewRequestInput, ScmReviewRequestResult } from "../scm/types.js";
2
- export type VersionaryPluginCapability = "scm.reviewRequest" | "scm.releaseMetadata";
1
+ import type { ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReleaseReferenceCommentsInput, ScmReleaseReferenceCommentsResult, ScmReviewRequestInput, ScmReviewRequestResult } from "../scm/types.js";
2
+ export type VersionaryPluginCapability = "scm.reviewRequest" | "scm.releaseMetadata" | "scm.releaseReferenceComments";
3
3
  export type VersionaryScmReviewRequestInput = ScmReviewRequestInput;
4
4
  export type VersionaryScmReviewRequestResult = ScmReviewRequestResult;
5
5
  export type VersionaryScmReleaseMetadataInput = ScmReleaseMetadataInput;
6
6
  export type VersionaryScmReleaseMetadataResult = ScmReleaseMetadataResult;
7
+ export type VersionaryScmReleaseReferenceCommentsInput = ScmReleaseReferenceCommentsInput;
8
+ export type VersionaryScmReleaseReferenceCommentsResult = ScmReleaseReferenceCommentsResult;
7
9
  export type VersionaryPluginContext = ScmClientContext;
8
10
  export interface VersionaryPluginRuntime {
9
11
  name: string;
@@ -11,4 +13,5 @@ export interface VersionaryPluginRuntime {
11
13
  provider?: ScmProvider;
12
14
  createOrUpdateReviewRequest?: (input: VersionaryScmReviewRequestInput, context: VersionaryPluginContext) => Promise<VersionaryScmReviewRequestResult>;
13
15
  createReleaseMetadata?: (input: VersionaryScmReleaseMetadataInput, context: VersionaryPluginContext) => Promise<VersionaryScmReleaseMetadataResult>;
16
+ createReleaseReferenceComments?: (input: VersionaryScmReleaseReferenceCommentsInput, context: VersionaryPluginContext) => Promise<VersionaryScmReleaseReferenceCommentsResult>;
14
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",