versionary 0.13.0 → 0.14.1
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 +4 -0
- package/dist/config/schema.d.ts +5 -0
- package/dist/config/schema.js +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/release/changelog.js +30 -2
- package/dist/release/release.d.ts +1 -0
- package/dist/release/release.js +38 -1
- package/dist/scm/github-plugin.js +38 -1
- package/dist/scm/types.d.ts +10 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/plugins.d.ts +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,10 @@ For a quick trial, use:
|
|
|
144
144
|
request)
|
|
145
145
|
- `release-draft` (default `false`) publishes GitHub releases as drafts when
|
|
146
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
|
|
147
151
|
- optional monorepo planning with `monorepo-mode` and `packages`:
|
|
148
152
|
- `independent` computes package bumps per path
|
|
149
153
|
- `fixed` computes one shared bump across configured package paths
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -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>;
|
package/dist/config/schema.js
CHANGED
|
@@ -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";
|
|
@@ -51,6 +51,28 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
51
51
|
const features = [];
|
|
52
52
|
const fixes = [];
|
|
53
53
|
const reverts = [];
|
|
54
|
+
const getRevertedSubject = (commit) => {
|
|
55
|
+
const normalizedDescription = (commit.description ?? "")
|
|
56
|
+
.trim()
|
|
57
|
+
.replace(/^"(.*)"$/u, "$1");
|
|
58
|
+
if (normalizedDescription.length > 0) {
|
|
59
|
+
return normalizedDescription;
|
|
60
|
+
}
|
|
61
|
+
const quoted = commit.subject.match(/^revert:\s+"(.+)"$/iu);
|
|
62
|
+
if (quoted) {
|
|
63
|
+
return quoted[1].trim();
|
|
64
|
+
}
|
|
65
|
+
const plain = commit.subject.match(/^revert:\s+(.+)$/iu);
|
|
66
|
+
return plain ? plain[1].trim() : "";
|
|
67
|
+
};
|
|
68
|
+
const shouldIncludeRevert = (commit) => {
|
|
69
|
+
const revertedSubject = getRevertedSubject(commit);
|
|
70
|
+
if (revertedSubject.length === 0) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const revertedCommit = (0, commits_js_1.parseConventionalCommitMessage)(revertedSubject);
|
|
74
|
+
return (0, commits_js_1.inferReleaseTypeFromParsedCommit)(revertedCommit) !== null;
|
|
75
|
+
};
|
|
54
76
|
for (const commit of commits) {
|
|
55
77
|
const type = (0, commits_js_1.inferReleaseTypeFromParsedCommit)(commit);
|
|
56
78
|
if (!type) {
|
|
@@ -67,6 +89,9 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
67
89
|
const commitType = (commit.type ?? "").toLowerCase();
|
|
68
90
|
const isBreaking = type === "major";
|
|
69
91
|
if (commit.isRevert) {
|
|
92
|
+
if (!shouldIncludeRevert(commit)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
70
95
|
reverts.push(line);
|
|
71
96
|
continue;
|
|
72
97
|
}
|
|
@@ -130,18 +155,21 @@ function renderReleasePlanChangelog(plan) {
|
|
|
130
155
|
version: pkg.nextVersion,
|
|
131
156
|
}))
|
|
132
157
|
: [];
|
|
158
|
+
const dedupedCommits = [
|
|
159
|
+
...new Map(plan.commits.map((commit) => [commit.hash, commit])).values(),
|
|
160
|
+
];
|
|
133
161
|
if (plan.changelogFormat === "r-news") {
|
|
134
162
|
return renderRNewsReleaseNotes({
|
|
135
163
|
packageName: plan.packageName,
|
|
136
164
|
nextVersion: plan.nextVersion,
|
|
137
|
-
commits:
|
|
165
|
+
commits: dedupedCommits,
|
|
138
166
|
cwd: process.cwd(),
|
|
139
167
|
});
|
|
140
168
|
}
|
|
141
169
|
return renderSimpleReleaseNotes({
|
|
142
170
|
currentVersion: plan.currentVersion,
|
|
143
171
|
nextVersion: plan.nextVersion,
|
|
144
|
-
commits:
|
|
172
|
+
commits: dedupedCommits,
|
|
145
173
|
cwd: process.cwd(),
|
|
146
174
|
dependencies,
|
|
147
175
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { VersionaryConfig } from "../types/config.js";
|
|
2
2
|
import type { VersionaryPluginContext } from "../types/plugins.js";
|
|
3
3
|
export declare function extractReleaseNotes(content: string, version: string, changelogFormat: "markdown-changelog" | "r-news"): string;
|
|
4
|
+
export declare function extractClosingReferencesFromNotes(notes: string): number[];
|
|
4
5
|
export declare function resolveTargetChangelogFile(config: VersionaryConfig, rootChangelogFile: string, targetPath: string): string;
|
|
5
6
|
export declare function runRelease(cwd?: string): Promise<string>;
|
|
6
7
|
export type RunReleaseResult = {
|
package/dist/release/release.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.extractReleaseNotes = extractReleaseNotes;
|
|
7
|
+
exports.extractClosingReferencesFromNotes = extractClosingReferencesFromNotes;
|
|
7
8
|
exports.resolveTargetChangelogFile = resolveTargetChangelogFile;
|
|
8
9
|
exports.runRelease = runRelease;
|
|
9
10
|
exports.runReleaseDetailed = runReleaseDetailed;
|
|
@@ -75,6 +76,24 @@ function readReleaseNotes(cwd, version, changelogFile, changelogFormat) {
|
|
|
75
76
|
const notes = extractReleaseNotes(content, version, changelogFormat);
|
|
76
77
|
return notes.length > 0 ? notes : `Automated release for v${version}`;
|
|
77
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
|
+
}
|
|
78
97
|
function resolveTargetChangelogFile(config, rootChangelogFile, targetPath) {
|
|
79
98
|
if (targetPath === ".") {
|
|
80
99
|
return rootChangelogFile;
|
|
@@ -114,6 +133,7 @@ async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
114
133
|
const loaded = (0, load_config_js_1.loadConfig)(cwd);
|
|
115
134
|
const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
|
|
116
135
|
const { changelogFile } = (0, plan_js_1.getChangelogDefaults)(loaded.config);
|
|
136
|
+
const referenceCommentMode = loaded.config["release-reference-comments"] ?? "off";
|
|
117
137
|
const version = strategy.readVersion(cwd, loaded.config);
|
|
118
138
|
const defaultTag = `v${version}`;
|
|
119
139
|
const releaseTargets = (0, state_js_1.readReleaseTargets)(cwd);
|
|
@@ -139,13 +159,16 @@ async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
139
159
|
}
|
|
140
160
|
const scmClient = (0, client_js_1.getScmClient)();
|
|
141
161
|
const releases = [];
|
|
162
|
+
const referencesByTag = new Map();
|
|
142
163
|
for (const target of targets) {
|
|
143
164
|
const targetChangelogFile = resolveTargetChangelogFile(loaded.config, changelogFile, target.path);
|
|
144
165
|
const targetChangelogFormat = resolveTargetChangelogFormat(loaded.config, target.path);
|
|
166
|
+
const releaseNotes = readReleaseNotes(cwd, target.version, targetChangelogFile, targetChangelogFormat);
|
|
167
|
+
referencesByTag.set(target.tag, extractClosingReferencesFromNotes(releaseNotes));
|
|
145
168
|
const outcome = await (0, recovery_js_1.executeIdempotentReleaseTarget)(cwd, {
|
|
146
169
|
tag: target.tag,
|
|
147
170
|
version: target.version,
|
|
148
|
-
notes:
|
|
171
|
+
notes: releaseNotes,
|
|
149
172
|
draft: loaded.config["release-draft"] ?? false,
|
|
150
173
|
}, {
|
|
151
174
|
createReleaseMetadata: (input) => scmClient.createReleaseMetadata(input, {
|
|
@@ -160,6 +183,20 @@ async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
160
183
|
tagStatus: outcome.tagStatus,
|
|
161
184
|
metadataStatus: outcome.metadataStatus,
|
|
162
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
|
+
}
|
|
163
200
|
}
|
|
164
201
|
const published = releases.map((outcome) => `${outcome.tag}: ${outcome.url} (tag=${outcome.tagStatus}, metadata=${outcome.metadataStatus})`);
|
|
165
202
|
return {
|
|
@@ -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: [
|
|
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
|
}
|
package/dist/scm/types.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -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;
|
package/dist/types/plugins.d.ts
CHANGED
|
@@ -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
|
}
|