versionary 0.2.0 → 0.3.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.
Files changed (63) hide show
  1. package/README.md +187 -11
  2. package/dist/{simple → app/release}/pr.d.ts +7 -4
  3. package/dist/{simple → app/release}/pr.js +89 -74
  4. package/dist/app/release/recovery.d.ts +17 -0
  5. package/dist/app/release/recovery.js +101 -0
  6. package/dist/{simple → app/release}/release.js +37 -24
  7. package/dist/app/release/state.d.ts +10 -0
  8. package/dist/{simple → app/release}/state.js +16 -4
  9. package/dist/app/release/verify.d.ts +2 -0
  10. package/dist/app/release/verify.js +5 -0
  11. package/dist/cli/index.js +12 -10
  12. package/dist/config/load-config.js +2 -12
  13. package/dist/config/schema.d.ts +1 -0
  14. package/dist/config/schema.js +1 -0
  15. package/dist/domain/release/changelog.d.ts +12 -0
  16. package/dist/domain/release/changelog.js +123 -0
  17. package/dist/{simple → domain/release}/plan.d.ts +4 -3
  18. package/dist/{simple → domain/release}/plan.js +32 -15
  19. package/dist/domain/release/semver.d.ts +15 -0
  20. package/dist/domain/release/semver.js +111 -0
  21. package/dist/domain/strategy/node.d.ts +2 -0
  22. package/dist/domain/strategy/node.js +37 -0
  23. package/dist/domain/strategy/resolve.d.ts +3 -0
  24. package/dist/domain/strategy/resolve.js +11 -0
  25. package/dist/domain/strategy/simple.d.ts +2 -0
  26. package/dist/domain/strategy/simple.js +28 -0
  27. package/dist/domain/strategy/types.d.ts +7 -0
  28. package/dist/domain/strategy/types.js +2 -0
  29. package/dist/index.d.ts +5 -3
  30. package/dist/index.js +5 -1
  31. package/dist/infra/git/commits.d.ts +65 -0
  32. package/dist/infra/git/commits.js +436 -0
  33. package/dist/infra/scm/github/plugin.d.ts +1 -0
  34. package/dist/infra/scm/github/plugin.js +5 -0
  35. package/dist/infra/scm/runtime.d.ts +2 -0
  36. package/dist/infra/scm/runtime.js +24 -0
  37. package/dist/infra/scm/types.d.ts +1 -0
  38. package/dist/infra/scm/types.js +2 -0
  39. package/dist/plugins/runtime.d.ts +1 -2
  40. package/dist/plugins/runtime.js +3 -22
  41. package/dist/scm/github-plugin.js +133 -40
  42. package/dist/strategies/node.d.ts +1 -0
  43. package/dist/strategies/node.js +5 -0
  44. package/dist/strategies/resolve.d.ts +1 -0
  45. package/dist/strategies/resolve.js +5 -0
  46. package/dist/strategies/simple.d.ts +1 -0
  47. package/dist/strategies/simple.js +5 -0
  48. package/dist/strategies/types.d.ts +1 -0
  49. package/dist/strategies/types.js +2 -0
  50. package/dist/types/config.d.ts +1 -0
  51. package/dist/types/plugins.d.ts +1 -0
  52. package/dist/verify/verify-project.js +3 -1
  53. package/package.json +1 -1
  54. package/dist/simple/changelog.d.ts +0 -3
  55. package/dist/simple/changelog.js +0 -46
  56. package/dist/simple/git.d.ts +0 -10
  57. package/dist/simple/git.js +0 -114
  58. package/dist/simple/semver.d.ts +0 -8
  59. package/dist/simple/semver.js +0 -25
  60. package/dist/simple/state.d.ts +0 -3
  61. /package/dist/{simple → app/release}/release.d.ts +0 -0
  62. /package/dist/{simple → infra/git}/repo-url.d.ts +0 -0
  63. /package/dist/{simple → infra/git}/repo-url.js +0 -0
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.nodeVersionStrategy = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ exports.nodeVersionStrategy = {
10
+ name: "node",
11
+ getVersionFile(config) {
12
+ return config["version-file"] ?? "version.txt";
13
+ },
14
+ readVersion(cwd, config) {
15
+ const versionFile = this.getVersionFile(config);
16
+ const versionPath = node_path_1.default.join(cwd, versionFile);
17
+ if (!node_fs_1.default.existsSync(versionPath)) {
18
+ throw new Error(`Versionary requires ${versionFile} to exist.`);
19
+ }
20
+ return node_fs_1.default.readFileSync(versionPath, "utf8").trim();
21
+ },
22
+ writeVersion(cwd, config, version) {
23
+ const versionFile = this.getVersionFile(config);
24
+ const versionPath = node_path_1.default.join(cwd, versionFile);
25
+ node_fs_1.default.writeFileSync(versionPath, `${version}\n`, "utf8");
26
+ const updatedFiles = [versionFile];
27
+ const packageJsonPath = node_path_1.default.join(cwd, "package.json");
28
+ if (node_fs_1.default.existsSync(packageJsonPath)) {
29
+ const packageJsonRaw = node_fs_1.default.readFileSync(packageJsonPath, "utf8");
30
+ const packageJson = JSON.parse(packageJsonRaw);
31
+ packageJson.version = version;
32
+ node_fs_1.default.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
33
+ updatedFiles.push("package.json");
34
+ }
35
+ return updatedFiles;
36
+ },
37
+ };
@@ -0,0 +1,3 @@
1
+ import type { VersionaryConfig } from "../../types/config.js";
2
+ import type { VersionStrategy } from "./types.js";
3
+ export declare function resolveVersionStrategy(config: VersionaryConfig): VersionStrategy;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveVersionStrategy = resolveVersionStrategy;
4
+ const node_js_1 = require("./node.js");
5
+ const simple_js_1 = require("./simple.js");
6
+ function resolveVersionStrategy(config) {
7
+ if (config["release-type"] === "node") {
8
+ return node_js_1.nodeVersionStrategy;
9
+ }
10
+ return simple_js_1.simpleVersionStrategy;
11
+ }
@@ -0,0 +1,2 @@
1
+ import type { VersionStrategy } from "./types.js";
2
+ export declare const simpleVersionStrategy: VersionStrategy;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.simpleVersionStrategy = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ exports.simpleVersionStrategy = {
10
+ name: "simple",
11
+ getVersionFile(config) {
12
+ return config["version-file"] ?? "version.txt";
13
+ },
14
+ readVersion(cwd, config) {
15
+ const versionFile = this.getVersionFile(config);
16
+ const versionPath = node_path_1.default.join(cwd, versionFile);
17
+ if (!node_fs_1.default.existsSync(versionPath)) {
18
+ throw new Error(`Versionary requires ${versionFile} to exist.`);
19
+ }
20
+ return node_fs_1.default.readFileSync(versionPath, "utf8").trim();
21
+ },
22
+ writeVersion(cwd, config, version) {
23
+ const versionFile = this.getVersionFile(config);
24
+ const versionPath = node_path_1.default.join(cwd, versionFile);
25
+ node_fs_1.default.writeFileSync(versionPath, `${version}\n`, "utf8");
26
+ return [versionFile];
27
+ },
28
+ };
@@ -0,0 +1,7 @@
1
+ import type { VersionaryConfig } from "../../types/config.js";
2
+ export interface VersionStrategy {
3
+ name: string;
4
+ getVersionFile(config: VersionaryConfig): string;
5
+ readVersion(cwd: string, config: VersionaryConfig): string;
6
+ writeVersion(cwd: string, config: VersionaryConfig, version: string): string[];
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- export type { VersionaryConfig, VersionaryPackage, VersionaryArtifactRule, } from "./types/config.js";
2
- export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, } from "./types/plugins.js";
3
1
  export { loadConfig } from "./config/load-config.js";
4
- export { findPluginsByCapability, pluginHasCapability } from "./plugins/capabilities.js";
2
+ export { resolveVersionStrategy } from "./domain/strategy/resolve.js";
3
+ export { createGitHubPlugin } from "./infra/scm/github/plugin.js";
4
+ export { findPluginsByCapability, pluginHasCapability, } from "./plugins/capabilities.js";
5
5
  export { loadRuntimePlugins } from "./plugins/runtime.js";
6
+ export type { VersionaryArtifactRule, VersionaryConfig, VersionaryPackage, } from "./types/config.js";
7
+ export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, } from "./types/plugins.js";
6
8
  export { verifyProject } from "./verify/verify-project.js";
package/dist/index.js CHANGED
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyProject = exports.loadRuntimePlugins = exports.pluginHasCapability = exports.findPluginsByCapability = exports.loadConfig = void 0;
3
+ exports.verifyProject = exports.loadRuntimePlugins = exports.pluginHasCapability = exports.findPluginsByCapability = exports.createGitHubPlugin = exports.resolveVersionStrategy = exports.loadConfig = void 0;
4
4
  var load_config_js_1 = require("./config/load-config.js");
5
5
  Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return load_config_js_1.loadConfig; } });
6
+ var resolve_js_1 = require("./domain/strategy/resolve.js");
7
+ Object.defineProperty(exports, "resolveVersionStrategy", { enumerable: true, get: function () { return resolve_js_1.resolveVersionStrategy; } });
8
+ var plugin_js_1 = require("./infra/scm/github/plugin.js");
9
+ Object.defineProperty(exports, "createGitHubPlugin", { enumerable: true, get: function () { return plugin_js_1.createGitHubPlugin; } });
6
10
  var capabilities_js_1 = require("./plugins/capabilities.js");
7
11
  Object.defineProperty(exports, "findPluginsByCapability", { enumerable: true, get: function () { return capabilities_js_1.findPluginsByCapability; } });
8
12
  Object.defineProperty(exports, "pluginHasCapability", { enumerable: true, get: function () { return capabilities_js_1.pluginHasCapability; } });
@@ -0,0 +1,65 @@
1
+ import type { ReleaseType } from "../../domain/release/semver.js";
2
+ export interface CommitInfo {
3
+ hash: string;
4
+ subject: string;
5
+ }
6
+ export interface ParsedCommit {
7
+ hash: string;
8
+ subject: string;
9
+ body: string;
10
+ fullMessage: string;
11
+ type: string | null;
12
+ scope: string | null;
13
+ description: string;
14
+ isBreaking: boolean;
15
+ isRevert: boolean;
16
+ footers: Array<{
17
+ token: string;
18
+ value: string;
19
+ }>;
20
+ revertedShas: string[];
21
+ header?: string;
22
+ merge?: string | null;
23
+ footer?: string | null;
24
+ notes?: CommitNote[];
25
+ references?: CommitReference[];
26
+ mentions?: string[];
27
+ revert?: RevertInfo | null;
28
+ isConventional?: boolean;
29
+ diagnostics?: ParseDiagnostic[];
30
+ }
31
+ export type CommitParseDiagnosticCode = "invalid-header" | "malformed-breaking-footer" | "malformed-reference" | "ambiguous-revert";
32
+ export interface ParseDiagnostic {
33
+ code: CommitParseDiagnosticCode;
34
+ message: string;
35
+ }
36
+ export interface CommitNote {
37
+ title: string;
38
+ text: string;
39
+ }
40
+ export interface CommitReference {
41
+ action: string | null;
42
+ owner: string | null;
43
+ repository: string | null;
44
+ issue: string | null;
45
+ raw: string;
46
+ prefix: "#" | "GH-";
47
+ }
48
+ export interface RevertInfo {
49
+ header: string;
50
+ hashes: string[];
51
+ }
52
+ export declare function parseConventionalCommitMessage(subject: string, body?: string): ParsedCommit;
53
+ export declare function parseConventionalCommitMessageDetailed(header: string, body?: string): ParsedCommit;
54
+ export declare function getCommitsSinceLastTag(cwd?: string, baselineSha?: string | null): CommitInfo[];
55
+ export declare function getCommitsForPath(cwd?: string, baselineSha?: string | null, packagePath?: string, excludePaths?: string[]): CommitInfo[];
56
+ export declare function getParsedCommitsSinceLastTag(cwd?: string, baselineSha?: string | null): ParsedCommit[];
57
+ export declare function getParsedCommitsForPath(cwd?: string, baselineSha?: string | null, packagePath?: string, excludePaths?: string[]): ParsedCommit[];
58
+ export declare function inferReleaseTypeFromParsedCommit(commit: ParsedCommit): ReleaseType;
59
+ export declare function inferReleaseTypeFromSubject(subject: string): ReleaseType;
60
+ export declare function isReleasableCommit(subject: string): boolean;
61
+ export declare function getCommitParseDiagnostics(commit: ParsedCommit): ParseDiagnostic[];
62
+ export declare function analyzeCommits(commits: CommitInfo[]): ReleaseType;
63
+ export declare function applyRevertSuppression(commits: ParsedCommit[]): ParsedCommit[];
64
+ export declare function analyzeParsedCommits(commits: ParsedCommit[]): ReleaseType;
65
+ export declare function isReleasableParsedCommit(commit: ParsedCommit): boolean;
@@ -0,0 +1,436 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseConventionalCommitMessage = parseConventionalCommitMessage;
7
+ exports.parseConventionalCommitMessageDetailed = parseConventionalCommitMessageDetailed;
8
+ exports.getCommitsSinceLastTag = getCommitsSinceLastTag;
9
+ exports.getCommitsForPath = getCommitsForPath;
10
+ exports.getParsedCommitsSinceLastTag = getParsedCommitsSinceLastTag;
11
+ exports.getParsedCommitsForPath = getParsedCommitsForPath;
12
+ exports.inferReleaseTypeFromParsedCommit = inferReleaseTypeFromParsedCommit;
13
+ exports.inferReleaseTypeFromSubject = inferReleaseTypeFromSubject;
14
+ exports.isReleasableCommit = isReleasableCommit;
15
+ exports.getCommitParseDiagnostics = getCommitParseDiagnostics;
16
+ exports.analyzeCommits = analyzeCommits;
17
+ exports.applyRevertSuppression = applyRevertSuppression;
18
+ exports.analyzeParsedCommits = analyzeParsedCommits;
19
+ exports.isReleasableParsedCommit = isReleasableParsedCommit;
20
+ const node_child_process_1 = require("node:child_process");
21
+ const node_path_1 = __importDefault(require("node:path"));
22
+ function getReleaseBranchExcludeArgs(cwd) {
23
+ const releaseBranchesRaw = (0, node_child_process_1.execFileSync)("git", ["branch", "--list", "--format", "%(refname:short)"], {
24
+ cwd,
25
+ encoding: "utf8",
26
+ stdio: ["ignore", "pipe", "ignore"],
27
+ });
28
+ const releaseBranches = releaseBranchesRaw
29
+ .split("\n")
30
+ .map((line) => line.trim())
31
+ .filter((line) => line.startsWith("versionary/release"));
32
+ return releaseBranches.flatMap((branch) => ["--exclude", branch]);
33
+ }
34
+ function getLatestReleaseTag(cwd) {
35
+ const excludeArgs = getReleaseBranchExcludeArgs(cwd);
36
+ try {
37
+ const cmd = [
38
+ "describe",
39
+ "--tags",
40
+ "--abbrev=0",
41
+ "--match",
42
+ "v[0-9]*",
43
+ ...excludeArgs,
44
+ ];
45
+ return (0, node_child_process_1.execFileSync)("git", cmd, {
46
+ cwd,
47
+ encoding: "utf8",
48
+ stdio: ["ignore", "pipe", "ignore"],
49
+ }).trim();
50
+ }
51
+ catch {
52
+ return "";
53
+ }
54
+ }
55
+ function isValidCommitish(cwd, ref) {
56
+ try {
57
+ (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--verify", `${ref}^{commit}`], {
58
+ cwd,
59
+ stdio: ["ignore", "pipe", "ignore"],
60
+ });
61
+ return true;
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ function resolveRange(cwd, baselineSha) {
68
+ const baseRef = baselineSha ?? "";
69
+ if (!baseRef) {
70
+ const latestTag = getLatestReleaseTag(cwd);
71
+ return latestTag ? `${latestTag}..HEAD` : "HEAD";
72
+ }
73
+ if (isValidCommitish(cwd, baseRef)) {
74
+ return `${baseRef}..HEAD`;
75
+ }
76
+ const latestTag = getLatestReleaseTag(cwd);
77
+ return latestTag ? `${latestTag}..HEAD` : "HEAD";
78
+ }
79
+ function readGitLog(cwd, range, pathspecs = []) {
80
+ const output = (0, node_child_process_1.execFileSync)("git", ["log", range, "--pretty=format:%H%x09%s", "--", ...pathspecs], {
81
+ cwd,
82
+ encoding: "utf8",
83
+ stdio: ["ignore", "pipe", "ignore"],
84
+ });
85
+ if (!output.trim()) {
86
+ return [];
87
+ }
88
+ return output
89
+ .trim()
90
+ .split("\n")
91
+ .map((line) => {
92
+ const [hash, subject] = line.split("\t");
93
+ return { hash, subject };
94
+ });
95
+ }
96
+ function readGitLogFull(cwd, range, pathspecs = []) {
97
+ const recordSeparator = "\x1e";
98
+ const fieldSeparator = "\x1f";
99
+ const output = (0, node_child_process_1.execFileSync)("git", [
100
+ "log",
101
+ range,
102
+ `--pretty=format:%H${fieldSeparator}%s${fieldSeparator}%b${recordSeparator}`,
103
+ "--",
104
+ ...pathspecs,
105
+ ], {
106
+ cwd,
107
+ encoding: "utf8",
108
+ stdio: ["ignore", "pipe", "ignore"],
109
+ });
110
+ if (!output.trim()) {
111
+ return [];
112
+ }
113
+ return output
114
+ .split(recordSeparator)
115
+ .map((record) => record.trim())
116
+ .filter((record) => record.length > 0)
117
+ .map((record) => {
118
+ const [hash = "", subject = "", body = ""] = record.split(fieldSeparator);
119
+ return parseCommitMessage(hash, subject.trim(), body.trim());
120
+ });
121
+ }
122
+ function parseHeader(subject) {
123
+ const conventionalMatch = subject.match(/^([a-z][a-z0-9-]*)(?:\(([^)]+)\))?(!)?:\s+(.+)$/iu);
124
+ if (!conventionalMatch) {
125
+ return {
126
+ type: null,
127
+ scope: null,
128
+ description: subject,
129
+ isBreakingHeader: false,
130
+ isConventional: false,
131
+ diagnostics: [
132
+ {
133
+ code: "invalid-header",
134
+ message: "Header does not match Conventional Commits format: <type>(<scope>)?: <description>.",
135
+ },
136
+ ],
137
+ };
138
+ }
139
+ return {
140
+ type: conventionalMatch[1]?.toLowerCase() ?? null,
141
+ scope: conventionalMatch[2]?.trim() ?? null,
142
+ isBreakingHeader: conventionalMatch[3] === "!",
143
+ description: conventionalMatch[4]?.trim() ?? subject,
144
+ isConventional: true,
145
+ diagnostics: [],
146
+ };
147
+ }
148
+ function parseFooters(body) {
149
+ if (!body) {
150
+ return {
151
+ bodyText: "",
152
+ footerText: null,
153
+ footers: [],
154
+ diagnostics: [],
155
+ references: [],
156
+ notes: [],
157
+ };
158
+ }
159
+ const parseFooterLine = (line) => {
160
+ const colonMatch = line.match(/^(BREAKING CHANGE|BREAKING-CHANGE|[A-Za-z][A-Za-z0-9-]*):\s+(.+)$/u);
161
+ if (colonMatch) {
162
+ return {
163
+ token: colonMatch[1] ?? "",
164
+ value: colonMatch[2] ?? "",
165
+ };
166
+ }
167
+ const issueRefMatch = line.match(/^([A-Za-z][A-Za-z0-9-]*)\s+((?:GH-|#).+)$/u);
168
+ if (issueRefMatch) {
169
+ return {
170
+ token: issueRefMatch[1] ?? "",
171
+ value: issueRefMatch[2] ?? "",
172
+ };
173
+ }
174
+ return null;
175
+ };
176
+ const diagnostics = [];
177
+ const lines = body.split("\n");
178
+ for (const line of lines) {
179
+ if (/^\s*BREAKING(?:\s|-)?CHANGE\b/iu.test(line) &&
180
+ !/^\s*(BREAKING CHANGE|BREAKING-CHANGE):\s+/iu.test(line)) {
181
+ diagnostics.push({
182
+ code: "malformed-breaking-footer",
183
+ message: "Found BREAKING CHANGE-like footer without required ': ' separator.",
184
+ });
185
+ }
186
+ }
187
+ const footerStart = lines.findIndex((line) => parseFooterLine(line) !== null);
188
+ const bodyLines = footerStart < 0 ? lines : lines.slice(0, footerStart);
189
+ const footerLines = footerStart < 0 ? [] : lines.slice(footerStart);
190
+ const footers = [];
191
+ const references = [];
192
+ const notes = [];
193
+ let current = null;
194
+ const pushCurrent = () => {
195
+ if (!current) {
196
+ return;
197
+ }
198
+ footers.push({
199
+ token: current.token,
200
+ value: current.value.trim(),
201
+ });
202
+ current = null;
203
+ };
204
+ const extractReferences = (text, action) => {
205
+ const refs = text.match(/(?:GH-|#)[^\s,;:()]+/gu) ?? [];
206
+ for (const raw of refs) {
207
+ const issue = raw.replace(/^(GH-|#)/u, "");
208
+ if (!/^\d+$/u.test(issue)) {
209
+ diagnostics.push({
210
+ code: "malformed-reference",
211
+ message: `Malformed issue reference "${raw}" in footer.`,
212
+ });
213
+ continue;
214
+ }
215
+ references.push({
216
+ action,
217
+ owner: null,
218
+ repository: null,
219
+ issue,
220
+ raw,
221
+ prefix: raw.startsWith("GH-") ? "GH-" : "#",
222
+ });
223
+ }
224
+ };
225
+ for (const line of footerLines) {
226
+ const footerMatch = parseFooterLine(line);
227
+ if (footerMatch) {
228
+ pushCurrent();
229
+ current = {
230
+ token: footerMatch.token,
231
+ value: footerMatch.value,
232
+ };
233
+ continue;
234
+ }
235
+ if (current && line.trim().length > 0) {
236
+ current.value = `${current.value}\n${line}`;
237
+ continue;
238
+ }
239
+ pushCurrent();
240
+ }
241
+ pushCurrent();
242
+ for (const footer of footers) {
243
+ if (/^(BREAKING CHANGE|BREAKING-CHANGE)$/iu.test(footer.token)) {
244
+ notes.push({
245
+ title: "BREAKING CHANGE",
246
+ text: footer.value,
247
+ });
248
+ }
249
+ extractReferences(`${footer.token}: ${footer.value}`, footer.token);
250
+ }
251
+ return {
252
+ bodyText: bodyLines.join("\n").trim() || "",
253
+ footerText: footerLines.length > 0 ? footerLines.join("\n").trim() : null,
254
+ footers,
255
+ diagnostics,
256
+ references,
257
+ notes,
258
+ };
259
+ }
260
+ function extractRevertedShas(subject, body) {
261
+ const full = `${subject}\n${body}`;
262
+ const matches = full.match(/\b[0-9a-f]{7,40}\b/giu) ?? [];
263
+ return [...new Set(matches.map((sha) => sha.toLowerCase()))];
264
+ }
265
+ function extractMentions(text) {
266
+ const mentions = text.match(/(?:^|[^A-Za-z0-9_])@([A-Za-z0-9][A-Za-z0-9-]{0,38})/gu) ?? [];
267
+ return [
268
+ ...new Set(mentions
269
+ .map((mention) => mention.replace(/^.*@/u, ""))
270
+ .filter((mention) => mention.length > 0)),
271
+ ];
272
+ }
273
+ function parseCommitMessage(hash, subject, body) {
274
+ const header = parseHeader(subject);
275
+ const footerResult = parseFooters(body);
276
+ const bodyText = footerResult.bodyText;
277
+ const footers = footerResult.footers;
278
+ const hasBreakingFooter = footers.some((footer) => /^(BREAKING CHANGE|BREAKING-CHANGE)$/iu.test(footer.token));
279
+ const isRevert = (header.type?.toLowerCase() ?? "") === "revert" ||
280
+ /^revert:\s/i.test(subject);
281
+ const revertInfo = isRevert
282
+ ? {
283
+ header: subject,
284
+ hashes: extractRevertedShas(subject, body),
285
+ }
286
+ : null;
287
+ const diagnostics = [...header.diagnostics, ...footerResult.diagnostics];
288
+ if (isRevert && revertInfo && revertInfo.hashes.length === 0) {
289
+ diagnostics.push({
290
+ code: "ambiguous-revert",
291
+ message: "Revert commit detected but no reverted commit SHA reference was parsed.",
292
+ });
293
+ }
294
+ return {
295
+ hash,
296
+ subject,
297
+ body: bodyText,
298
+ fullMessage: body ? `${subject}\n\n${body}` : subject,
299
+ type: header.type,
300
+ scope: header.scope,
301
+ description: header.description,
302
+ isBreaking: header.isBreakingHeader || hasBreakingFooter,
303
+ isRevert,
304
+ footers,
305
+ revertedShas: isRevert ? extractRevertedShas(subject, body) : [],
306
+ header: subject,
307
+ merge: null,
308
+ footer: footerResult.footerText,
309
+ notes: footerResult.notes,
310
+ references: footerResult.references,
311
+ mentions: extractMentions(`${subject}\n${body}`),
312
+ revert: revertInfo,
313
+ isConventional: header.isConventional,
314
+ diagnostics,
315
+ };
316
+ }
317
+ function parseConventionalCommitMessage(subject, body = "") {
318
+ return parseCommitMessage("", subject.trim(), body.trim());
319
+ }
320
+ function parseConventionalCommitMessageDetailed(header, body = "") {
321
+ return parseCommitMessage("", header.trim(), body.trim());
322
+ }
323
+ function getCommitsSinceLastTag(cwd = process.cwd(), baselineSha) {
324
+ const range = resolveRange(cwd, baselineSha);
325
+ return readGitLog(cwd, range);
326
+ }
327
+ function getCommitsForPath(cwd = process.cwd(), baselineSha, packagePath = ".", excludePaths = []) {
328
+ const range = resolveRange(cwd, baselineSha);
329
+ const normalizedPackagePath = packagePath === "." ? "." : packagePath;
330
+ const excludes = excludePaths.map((excludePath) => {
331
+ const combined = normalizedPackagePath === "."
332
+ ? excludePath
333
+ : node_path_1.default.posix.join(normalizedPackagePath, excludePath);
334
+ return `:(exclude)${combined}`;
335
+ });
336
+ return readGitLog(cwd, range, [normalizedPackagePath, ...excludes]);
337
+ }
338
+ function getParsedCommitsSinceLastTag(cwd = process.cwd(), baselineSha) {
339
+ const range = resolveRange(cwd, baselineSha);
340
+ return readGitLogFull(cwd, range);
341
+ }
342
+ function getParsedCommitsForPath(cwd = process.cwd(), baselineSha, packagePath = ".", excludePaths = []) {
343
+ const range = resolveRange(cwd, baselineSha);
344
+ const normalizedPackagePath = packagePath === "." ? "." : packagePath;
345
+ const excludes = excludePaths.map((excludePath) => {
346
+ const combined = normalizedPackagePath === "."
347
+ ? excludePath
348
+ : node_path_1.default.posix.join(normalizedPackagePath, excludePath);
349
+ return `:(exclude)${combined}`;
350
+ });
351
+ return readGitLogFull(cwd, range, [normalizedPackagePath, ...excludes]);
352
+ }
353
+ function inferReleaseTypeFromParsedCommit(commit) {
354
+ if (commit.isRevert) {
355
+ return null;
356
+ }
357
+ if (commit.isBreaking) {
358
+ return "major";
359
+ }
360
+ const type = commit.type?.toLowerCase() ?? "";
361
+ if (type === "feat") {
362
+ return "minor";
363
+ }
364
+ if (type === "fix" || type === "perf") {
365
+ return "patch";
366
+ }
367
+ if (type === "chore") {
368
+ return null;
369
+ }
370
+ return null;
371
+ }
372
+ function inferReleaseTypeFromSubject(subject) {
373
+ return inferReleaseTypeFromParsedCommit(parseCommitMessage("", subject.trim(), ""));
374
+ }
375
+ function isReleasableCommit(subject) {
376
+ return inferReleaseTypeFromSubject(subject) !== null;
377
+ }
378
+ function getCommitParseDiagnostics(commit) {
379
+ return commit.diagnostics ?? [];
380
+ }
381
+ function analyzeCommits(commits) {
382
+ let result = null;
383
+ for (const commit of commits) {
384
+ const type = inferReleaseTypeFromSubject(commit.subject);
385
+ if (type === "major") {
386
+ return "major";
387
+ }
388
+ if (type === "minor") {
389
+ result = "minor";
390
+ continue;
391
+ }
392
+ if (type === "patch" && result === null) {
393
+ result = "patch";
394
+ }
395
+ }
396
+ return result;
397
+ }
398
+ function applyRevertSuppression(commits) {
399
+ if (commits.length === 0) {
400
+ return commits;
401
+ }
402
+ const presentShas = new Set(commits.map((commit) => commit.hash.toLowerCase()));
403
+ const reverted = new Set();
404
+ for (const commit of commits) {
405
+ if (!commit.isRevert) {
406
+ continue;
407
+ }
408
+ for (const sha of commit.revertedShas) {
409
+ if (presentShas.has(sha)) {
410
+ reverted.add(sha);
411
+ }
412
+ }
413
+ }
414
+ return commits.filter((commit) => !reverted.has(commit.hash.toLowerCase()));
415
+ }
416
+ function analyzeParsedCommits(commits) {
417
+ let result = null;
418
+ const effectiveCommits = applyRevertSuppression(commits);
419
+ for (const commit of effectiveCommits) {
420
+ const type = inferReleaseTypeFromParsedCommit(commit);
421
+ if (type === "major") {
422
+ return "major";
423
+ }
424
+ if (type === "minor") {
425
+ result = "minor";
426
+ continue;
427
+ }
428
+ if (type === "patch" && result === null) {
429
+ result = "patch";
430
+ }
431
+ }
432
+ return result;
433
+ }
434
+ function isReleasableParsedCommit(commit) {
435
+ return inferReleaseTypeFromParsedCommit(commit) !== null;
436
+ }
@@ -0,0 +1 @@
1
+ export { createGitHubPlugin } from "../../../scm/github-plugin.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGitHubPlugin = void 0;
4
+ var github_plugin_js_1 = require("../../../scm/github-plugin.js");
5
+ Object.defineProperty(exports, "createGitHubPlugin", { enumerable: true, get: function () { return github_plugin_js_1.createGitHubPlugin; } });
@@ -0,0 +1,2 @@
1
+ import type { VersionaryPluginRuntime } from "../../types/plugins.js";
2
+ export declare function loadRuntimePlugins(cwd?: string): VersionaryPluginRuntime[];
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadRuntimePlugins = loadRuntimePlugins;
4
+ const load_config_js_1 = require("../../config/load-config.js");
5
+ const plugin_js_1 = require("./github/plugin.js");
6
+ const BUILTIN_PLUGIN_FACTORIES = {
7
+ github: plugin_js_1.createGitHubPlugin,
8
+ };
9
+ function loadRuntimePlugins(cwd = process.cwd()) {
10
+ const loaded = (0, load_config_js_1.loadConfig)(cwd);
11
+ const configured = loaded.config.plugins ?? [];
12
+ const plugins = [(0, plugin_js_1.createGitHubPlugin)()];
13
+ const seen = new Set(plugins.map((plugin) => plugin.name));
14
+ for (const name of configured) {
15
+ const factory = BUILTIN_PLUGIN_FACTORIES[name];
16
+ if (!factory || seen.has(name)) {
17
+ continue;
18
+ }
19
+ const plugin = factory();
20
+ plugins.push(plugin);
21
+ seen.add(plugin.name);
22
+ }
23
+ return plugins;
24
+ }
@@ -0,0 +1 @@
1
+ export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, } from "../../types/plugins.js";
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });