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
@@ -1,2 +1 @@
1
- import type { VersionaryPluginRuntime } from "../types/plugins.js";
2
- export declare function loadRuntimePlugins(cwd?: string): VersionaryPluginRuntime[];
1
+ export { loadRuntimePlugins } from "../infra/scm/runtime.js";
@@ -1,24 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadRuntimePlugins = loadRuntimePlugins;
4
- const load_config_js_1 = require("../config/load-config.js");
5
- const github_plugin_js_1 = require("../scm/github-plugin.js");
6
- const BUILTIN_PLUGIN_FACTORIES = {
7
- github: 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, github_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
- }
3
+ exports.loadRuntimePlugins = void 0;
4
+ var runtime_js_1 = require("../infra/scm/runtime.js");
5
+ Object.defineProperty(exports, "loadRuntimePlugins", { enumerable: true, get: function () { return runtime_js_1.loadRuntimePlugins; } });
@@ -17,13 +17,56 @@ function getRepoFromEnv() {
17
17
  return parseRepoSlug(slug);
18
18
  }
19
19
  function getGitHubToken() {
20
- const token = process.env.VERSIONARY_PR_TOKEN ?? process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN;
20
+ const token = process.env.VERSIONARY_PR_TOKEN ??
21
+ process.env.GH_TOKEN ??
22
+ process.env.GITHUB_TOKEN;
21
23
  if (!token) {
22
24
  throw new Error("Missing GitHub token. Set VERSIONARY_PR_TOKEN, GH_TOKEN, or GITHUB_TOKEN.");
23
25
  }
24
26
  return token;
25
27
  }
26
- async function ensureLabels(octokit, repo, pullNumber, labels) {
28
+ function parseGitHubError(error) {
29
+ const status = typeof error === "object" && error !== null && "status" in error
30
+ ? Number(error.status)
31
+ : undefined;
32
+ const message = error instanceof Error ? error.message : "Unknown GitHub API error";
33
+ return { status, message };
34
+ }
35
+ function repoRef(repo) {
36
+ return `${repo.owner}/${repo.repo}`;
37
+ }
38
+ function resolveHeadForList(repo, headBranch) {
39
+ const separator = headBranch.indexOf(":");
40
+ if (separator === -1) {
41
+ return `${repo.owner}:${headBranch}`;
42
+ }
43
+ const owner = headBranch.slice(0, separator);
44
+ const branch = headBranch.slice(separator + 1);
45
+ if (!owner || !branch || branch.includes(":")) {
46
+ throw new Error(`Invalid head branch "${headBranch}". Expected "branch" or "owner:branch".`);
47
+ }
48
+ return `${owner}:${branch}`;
49
+ }
50
+ function toReviewRequestState(pull, context) {
51
+ if (pull.state === "open") {
52
+ return "open";
53
+ }
54
+ if (pull.merged_at) {
55
+ return "merged";
56
+ }
57
+ if (pull.state === "closed") {
58
+ return "closed";
59
+ }
60
+ throw new Error(`Unexpected pull request state "${String(pull.state)}" for ${context}.`);
61
+ }
62
+ /**
63
+ * GitHub hardening contract (see tests/github-plugin-hardening-matrix.test.ts):
64
+ * - GITHUB_REPOSITORY must exist and use owner/repo format.
65
+ * - Token precedence: VERSIONARY_PR_TOKEN -> GH_TOKEN -> GITHUB_TOKEN.
66
+ * - Label application is best-effort for 404/422, but fails for other statuses.
67
+ * - Release metadata lookup treats 404 as "missing, create release"; non-404 fails.
68
+ */
69
+ async function ensureLabels(octokit, repo, pullNumber, labels, branchContext) {
27
70
  if (labels.length === 0) {
28
71
  return;
29
72
  }
@@ -35,8 +78,12 @@ async function ensureLabels(octokit, repo, pullNumber, labels) {
35
78
  labels,
36
79
  });
37
80
  }
38
- catch {
39
- // Best effort: label may not exist or permissions may be restricted.
81
+ catch (error) {
82
+ const { status, message } = parseGitHubError(error);
83
+ if (status === 404 || status === 422) {
84
+ return;
85
+ }
86
+ throw new Error(`Failed applying labels to pull request #${pullNumber}: [${repoRef(repo)} base=${branchContext.baseBranch} head=${branchContext.headBranch}] ${message}`);
40
87
  }
41
88
  }
42
89
  function createGitHubPlugin() {
@@ -46,45 +93,80 @@ function createGitHubPlugin() {
46
93
  async createOrUpdateReviewRequest(input, _context) {
47
94
  const repo = getRepoFromEnv();
48
95
  const octokit = new rest_1.Octokit({ auth: getGitHubToken() });
49
- const { data: existing } = await octokit.pulls.list({
50
- owner: repo.owner,
51
- repo: repo.repo,
52
- state: "open",
53
- head: `${repo.owner}:${input.headBranch}`,
54
- base: input.baseBranch,
55
- per_page: 1,
56
- });
57
- if (existing.length > 0) {
58
- const pr = existing[0];
59
- const { data: updated } = await octokit.pulls.update({
96
+ const listHead = resolveHeadForList(repo, input.headBranch);
97
+ let existing;
98
+ try {
99
+ const response = await octokit.pulls.list({
60
100
  owner: repo.owner,
61
101
  repo: repo.repo,
62
- pull_number: pr.number,
63
- title: input.title,
64
- body: input.body,
102
+ state: "open",
103
+ head: listHead,
104
+ base: input.baseBranch,
105
+ per_page: 100,
106
+ });
107
+ existing = response.data;
108
+ }
109
+ catch (error) {
110
+ const { message } = parseGitHubError(error);
111
+ throw new Error(`Failed listing open pull requests for branch "${input.headBranch}" into "${input.baseBranch}": [${repoRef(repo)}] ${message}`);
112
+ }
113
+ if (existing.length > 1) {
114
+ const matches = existing.map((item) => `#${item.number}`).join(", ");
115
+ throw new Error(`Ambiguous open pull request matches for "${input.headBranch}" into "${input.baseBranch}": [${repoRef(repo)}] ${matches}`);
116
+ }
117
+ if (existing.length > 0) {
118
+ const pr = existing[0];
119
+ let updated;
120
+ try {
121
+ const response = await octokit.pulls.update({
122
+ owner: repo.owner,
123
+ repo: repo.repo,
124
+ pull_number: pr.number,
125
+ title: input.title,
126
+ body: input.body,
127
+ });
128
+ updated = response.data;
129
+ }
130
+ catch (error) {
131
+ const { message } = parseGitHubError(error);
132
+ throw new Error(`Failed updating pull request #${pr.number}: [${repoRef(repo)} base=${input.baseBranch} head=${input.headBranch}] ${message}`);
133
+ }
134
+ await ensureLabels(octokit, repo, updated.number, input.labels ?? [], {
135
+ baseBranch: input.baseBranch,
136
+ headBranch: input.headBranch,
65
137
  });
66
- await ensureLabels(octokit, repo, updated.number, input.labels ?? []);
67
138
  return {
68
139
  id: String(updated.id),
69
140
  number: updated.number,
70
141
  url: updated.html_url,
71
- state: updated.state === "open" ? "open" : "closed",
142
+ state: toReviewRequestState(updated, `pull request #${updated.number} in ${repoRef(repo)}`),
72
143
  };
73
144
  }
74
- const { data: created } = await octokit.pulls.create({
75
- owner: repo.owner,
76
- repo: repo.repo,
77
- title: input.title,
78
- head: input.headBranch,
79
- base: input.baseBranch,
80
- body: input.body,
145
+ let created;
146
+ try {
147
+ const response = await octokit.pulls.create({
148
+ owner: repo.owner,
149
+ repo: repo.repo,
150
+ title: input.title,
151
+ head: input.headBranch,
152
+ base: input.baseBranch,
153
+ body: input.body,
154
+ });
155
+ created = response.data;
156
+ }
157
+ catch (error) {
158
+ const { message } = parseGitHubError(error);
159
+ throw new Error(`Failed creating pull request from "${input.headBranch}" into "${input.baseBranch}": [${repoRef(repo)}] ${message}`);
160
+ }
161
+ await ensureLabels(octokit, repo, created.number, input.labels ?? [], {
162
+ baseBranch: input.baseBranch,
163
+ headBranch: input.headBranch,
81
164
  });
82
- await ensureLabels(octokit, repo, created.number, input.labels ?? []);
83
165
  return {
84
166
  id: String(created.id),
85
167
  number: created.number,
86
168
  url: created.html_url,
87
- state: created.state === "open" ? "open" : "closed",
169
+ state: toReviewRequestState(created, `pull request #${created.number} in ${repoRef(repo)}`),
88
170
  };
89
171
  },
90
172
  async createReleaseMetadata(input, _context) {
@@ -96,19 +178,30 @@ function createGitHubPlugin() {
96
178
  repo: repo.repo,
97
179
  tag: input.tag,
98
180
  });
99
- return { url: existing.data.html_url };
181
+ return { url: existing.data.html_url, status: "exists" };
100
182
  }
101
- catch {
102
- // Continue with create flow when release does not exist.
183
+ catch (error) {
184
+ const { status, message } = parseGitHubError(error);
185
+ if (status !== 404) {
186
+ throw new Error(`Failed checking existing GitHub release for tag "${input.tag}": [${repoRef(repo)}] ${message}`);
187
+ }
103
188
  }
104
- const { data } = await octokit.repos.createRelease({
105
- owner: repo.owner,
106
- repo: repo.repo,
107
- tag_name: input.tag,
108
- name: input.tag,
109
- body: input.notes,
110
- });
111
- return { url: data.html_url };
189
+ let data;
190
+ try {
191
+ const response = await octokit.repos.createRelease({
192
+ owner: repo.owner,
193
+ repo: repo.repo,
194
+ tag_name: input.tag,
195
+ name: input.tag,
196
+ body: input.notes,
197
+ });
198
+ data = response.data;
199
+ }
200
+ catch (error) {
201
+ const { message } = parseGitHubError(error);
202
+ throw new Error(`Failed creating GitHub release for tag "${input.tag}": [${repoRef(repo)}] ${message}`);
203
+ }
204
+ return { url: data.html_url, status: "created" };
112
205
  },
113
206
  };
114
207
  }
@@ -0,0 +1 @@
1
+ export { nodeVersionStrategy } from "../domain/strategy/node.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nodeVersionStrategy = void 0;
4
+ var node_js_1 = require("../domain/strategy/node.js");
5
+ Object.defineProperty(exports, "nodeVersionStrategy", { enumerable: true, get: function () { return node_js_1.nodeVersionStrategy; } });
@@ -0,0 +1 @@
1
+ export { resolveVersionStrategy } from "../domain/strategy/resolve.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveVersionStrategy = void 0;
4
+ var resolve_js_1 = require("../domain/strategy/resolve.js");
5
+ Object.defineProperty(exports, "resolveVersionStrategy", { enumerable: true, get: function () { return resolve_js_1.resolveVersionStrategy; } });
@@ -0,0 +1 @@
1
+ export { simpleVersionStrategy } from "../domain/strategy/simple.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.simpleVersionStrategy = void 0;
4
+ var simple_js_1 = require("../domain/strategy/simple.js");
5
+ Object.defineProperty(exports, "simpleVersionStrategy", { enumerable: true, get: function () { return simple_js_1.simpleVersionStrategy; } });
@@ -0,0 +1 @@
1
+ export type { VersionStrategy } from "../domain/strategy/types.js";
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -21,6 +21,7 @@ export interface VersionaryConfig {
21
21
  "bootstrap-sha"?: string;
22
22
  "monorepo-mode"?: "independent" | "fixed";
23
23
  "bump-minor-pre-major"?: boolean;
24
+ "allow-stable-major"?: boolean;
24
25
  "include-commit-authors"?: boolean;
25
26
  "release-type"?: string;
26
27
  packages?: Record<string, VersionaryPackage>;
@@ -19,6 +19,7 @@ export interface VersionaryScmReleaseMetadataInput {
19
19
  }
20
20
  export interface VersionaryScmReleaseMetadataResult {
21
21
  url: string;
22
+ status?: "created" | "exists";
22
23
  }
23
24
  export interface VersionaryPluginContext {
24
25
  cwd: string;
@@ -7,6 +7,7 @@ exports.verifyProject = verifyProject;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const load_config_js_1 = require("../config/load-config.js");
10
+ const resolve_js_1 = require("../domain/strategy/resolve.js");
10
11
  function verifyProject(cwd = process.cwd()) {
11
12
  const checks = [];
12
13
  const config = (0, load_config_js_1.loadConfig)(cwd);
@@ -15,7 +16,8 @@ function verifyProject(cwd = process.cwd()) {
15
16
  ok: true,
16
17
  details: `Loaded ${node_path_1.default.basename(config.path)} (${config.format})`,
17
18
  });
18
- const versionFile = config.config["version-file"] ?? "version.txt";
19
+ const strategy = (0, resolve_js_1.resolveVersionStrategy)(config.config);
20
+ const versionFile = strategy.getVersionFile(config.config);
19
21
  const exists = node_fs_1.default.existsSync(node_path_1.default.join(cwd, versionFile));
20
22
  checks.push({
21
23
  name: `version-file:${versionFile}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",
@@ -1,3 +0,0 @@
1
- import type { SimplePlan } from "./plan.js";
2
- export declare function renderSimpleChangelog(plan: SimplePlan): string;
3
- export declare function prependChangelog(cwd: string, changelogFile: string, section: string): void;
@@ -1,46 +0,0 @@
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.renderSimpleChangelog = renderSimpleChangelog;
7
- exports.prependChangelog = prependChangelog;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const git_js_1 = require("./git.js");
11
- const repo_url_js_1 = require("./repo-url.js");
12
- function formatDate() {
13
- return new Date().toISOString().slice(0, 10);
14
- }
15
- function renderSimpleChangelog(plan) {
16
- if (!plan.nextVersion) {
17
- return "";
18
- }
19
- const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(process.cwd());
20
- const versionHeading = repoUrl
21
- ? `## [${plan.nextVersion}](${repoUrl}/compare/v${plan.currentVersion}...v${plan.nextVersion}) (${formatDate()})`
22
- : `## ${plan.nextVersion} - ${formatDate()}`;
23
- const lines = [
24
- versionHeading,
25
- "",
26
- ...plan.commits
27
- .filter((commit) => (0, git_js_1.isReleasableCommit)(commit.subject))
28
- .map((commit) => {
29
- const short = commit.hash.slice(0, 7);
30
- if (!repoUrl) {
31
- return `- ${commit.subject} (\`${short}\`)`;
32
- }
33
- return `- ${commit.subject} ([\`${short}\`](${repoUrl}/commit/${commit.hash}))`;
34
- }),
35
- "",
36
- ];
37
- return lines.join("\n");
38
- }
39
- function prependChangelog(cwd, changelogFile, section) {
40
- const changelogPath = node_path_1.default.join(cwd, changelogFile);
41
- const existing = node_fs_1.default.existsSync(changelogPath) ? node_fs_1.default.readFileSync(changelogPath, "utf8") : "";
42
- const heading = existing.startsWith("# Changelog") ? "" : "# Changelog\n\n";
43
- const separator = existing.length > 0 ? "\n" : "";
44
- const next = `${heading}${section}${separator}${existing.replace(/^# Changelog\s*/u, "")}`.trimEnd() + "\n";
45
- node_fs_1.default.writeFileSync(changelogPath, next, "utf8");
46
- }
@@ -1,10 +0,0 @@
1
- import type { ReleaseType } from "./semver.js";
2
- export interface CommitInfo {
3
- hash: string;
4
- subject: string;
5
- }
6
- export declare function getCommitsSinceLastTag(cwd?: string, baselineSha?: string | null): CommitInfo[];
7
- export declare function getCommitsForPath(cwd?: string, baselineSha?: string | null, packagePath?: string, excludePaths?: string[]): CommitInfo[];
8
- export declare function inferReleaseTypeFromSubject(subject: string): ReleaseType;
9
- export declare function isReleasableCommit(subject: string): boolean;
10
- export declare function analyzeCommits(commits: CommitInfo[]): ReleaseType;
@@ -1,114 +0,0 @@
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.getCommitsSinceLastTag = getCommitsSinceLastTag;
7
- exports.getCommitsForPath = getCommitsForPath;
8
- exports.inferReleaseTypeFromSubject = inferReleaseTypeFromSubject;
9
- exports.isReleasableCommit = isReleasableCommit;
10
- exports.analyzeCommits = analyzeCommits;
11
- const node_path_1 = __importDefault(require("node:path"));
12
- const node_child_process_1 = require("node:child_process");
13
- function getReleaseBranchExcludeArgs(cwd) {
14
- const releaseBranchesRaw = (0, node_child_process_1.execFileSync)("git", ["branch", "--list", "--format", "%(refname:short)"], {
15
- cwd,
16
- encoding: "utf8",
17
- stdio: ["ignore", "pipe", "ignore"],
18
- });
19
- const releaseBranches = releaseBranchesRaw
20
- .split("\n")
21
- .map((line) => line.trim())
22
- .filter((line) => line.startsWith("versionary/release"));
23
- return releaseBranches.flatMap((branch) => ["--exclude", branch]);
24
- }
25
- function resolveBaseRef(cwd, baselineSha) {
26
- const excludeArgs = getReleaseBranchExcludeArgs(cwd);
27
- let baseRef = baselineSha ?? "";
28
- if (!baseRef) {
29
- try {
30
- const cmd = ["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*", ...excludeArgs];
31
- baseRef = (0, node_child_process_1.execFileSync)("git", cmd, {
32
- cwd,
33
- encoding: "utf8",
34
- stdio: ["ignore", "pipe", "ignore"],
35
- }).trim();
36
- }
37
- catch {
38
- baseRef = "";
39
- }
40
- }
41
- return baseRef;
42
- }
43
- function readGitLog(cwd, range, pathspecs = []) {
44
- const output = (0, node_child_process_1.execFileSync)("git", ["log", range, "--pretty=format:%H%x09%s", "--", ...pathspecs], {
45
- cwd,
46
- encoding: "utf8",
47
- stdio: ["ignore", "pipe", "ignore"],
48
- });
49
- if (!output.trim()) {
50
- return [];
51
- }
52
- return output
53
- .trim()
54
- .split("\n")
55
- .map((line) => {
56
- const [hash, subject] = line.split("\t");
57
- return { hash, subject };
58
- });
59
- }
60
- function getCommitsSinceLastTag(cwd = process.cwd(), baselineSha) {
61
- const baseRef = resolveBaseRef(cwd, baselineSha);
62
- const range = baseRef ? `${baseRef}..HEAD` : "HEAD";
63
- return readGitLog(cwd, range);
64
- }
65
- function getCommitsForPath(cwd = process.cwd(), baselineSha, packagePath = ".", excludePaths = []) {
66
- const baseRef = resolveBaseRef(cwd, baselineSha);
67
- const range = baseRef ? `${baseRef}..HEAD` : "HEAD";
68
- const normalizedPackagePath = packagePath === "." ? "." : packagePath;
69
- const excludes = excludePaths.map((excludePath) => {
70
- const combined = normalizedPackagePath === "."
71
- ? excludePath
72
- : node_path_1.default.posix.join(normalizedPackagePath, excludePath);
73
- return `:(exclude)${combined}`;
74
- });
75
- return readGitLog(cwd, range, [normalizedPackagePath, ...excludes]);
76
- }
77
- function inferReleaseTypeFromSubject(subject) {
78
- if (/^revert:\s/i.test(subject)) {
79
- return null;
80
- }
81
- if (/^chore(\(.+\))?:\s/i.test(subject)) {
82
- return null;
83
- }
84
- if (/!:/u.test(subject) || /BREAKING CHANGE/u.test(subject)) {
85
- return "major";
86
- }
87
- if (/^feat(\(.+\))?:\s/i.test(subject)) {
88
- return "minor";
89
- }
90
- if (/^(fix|perf)(\(.+\))?:\s/i.test(subject)) {
91
- return "patch";
92
- }
93
- return null;
94
- }
95
- function isReleasableCommit(subject) {
96
- return inferReleaseTypeFromSubject(subject) !== null;
97
- }
98
- function analyzeCommits(commits) {
99
- let result = null;
100
- for (const commit of commits) {
101
- const type = inferReleaseTypeFromSubject(commit.subject);
102
- if (type === "major") {
103
- return "major";
104
- }
105
- if (type === "minor") {
106
- result = "minor";
107
- continue;
108
- }
109
- if (type === "patch" && result === null) {
110
- result = "patch";
111
- }
112
- }
113
- return result;
114
- }
@@ -1,8 +0,0 @@
1
- export type ReleaseType = "major" | "minor" | "patch" | null;
2
- export interface ParsedVersion {
3
- major: number;
4
- minor: number;
5
- patch: number;
6
- }
7
- export declare function parseVersion(version: string): ParsedVersion;
8
- export declare function bumpVersion(current: string, releaseType: Exclude<ReleaseType, null>): string;
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseVersion = parseVersion;
4
- exports.bumpVersion = bumpVersion;
5
- function parseVersion(version) {
6
- const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)$/);
7
- if (!match) {
8
- throw new Error(`Invalid version in version file: "${version}". Expected x.y.z`);
9
- }
10
- return {
11
- major: Number(match[1]),
12
- minor: Number(match[2]),
13
- patch: Number(match[3]),
14
- };
15
- }
16
- function bumpVersion(current, releaseType) {
17
- const parsed = parseVersion(current);
18
- if (releaseType === "major") {
19
- return `${parsed.major + 1}.0.0`;
20
- }
21
- if (releaseType === "minor") {
22
- return `${parsed.major}.${parsed.minor + 1}.0`;
23
- }
24
- return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
25
- }
@@ -1,3 +0,0 @@
1
- export declare function getBaselineStatePath(cwd: string): string;
2
- export declare function readBaselineSha(cwd?: string): string | null;
3
- export declare function writeBaselineSha(cwd?: string, sha?: string): void;
File without changes
File without changes
File without changes