versionary 0.15.1 → 0.17.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 +28 -4
- package/dist/config/load-config.js +30 -0
- package/dist/git/commits.js +8 -6
- package/dist/release/changelog.d.ts +7 -1
- package/dist/release/changelog.js +46 -13
- package/dist/release/pr.js +29 -25
- package/dist/release/recovery.d.ts +1 -0
- package/dist/release/release.js +1 -0
- package/dist/scm/github-plugin.js +1 -0
- package/dist/scm/types.d.ts +1 -0
- package/dist/strategy/latex.d.ts +2 -0
- package/dist/strategy/latex.js +96 -0
- package/dist/strategy/resolve.js +8 -1
- package/dist/strategy/rust.js +1 -1
- package/dist/strategy/types.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ release/tag.
|
|
|
49
49
|
|
|
50
50
|
Current implementation focuses on:
|
|
51
51
|
|
|
52
|
-
- strategy-based version updates (`simple`, `node`, `rust`, `r`)
|
|
52
|
+
- strategy-based version updates (`simple`, `node`, `rust`, `r`, `latex`)
|
|
53
53
|
- release planning and changelog generation
|
|
54
54
|
- review-mode vs direct-mode release flow
|
|
55
55
|
- a static internal SCM client (`github` provider today)
|
|
@@ -76,8 +76,8 @@ Checklist for new strategies (for example `python`):
|
|
|
76
76
|
- optionally implement `propagateDependentPatchImpacts(cwd, packages)` if
|
|
77
77
|
dependency updates in this ecosystem should trigger dependent package patch
|
|
78
78
|
bumps
|
|
79
|
-
- optionally implement `finalizeVersionWrites(cwd, writes)` for
|
|
80
|
-
post-processing after all target version files are written
|
|
79
|
+
- optionally implement `finalizeVersionWrites(cwd, writes, context)` for
|
|
80
|
+
ecosystem post-processing after all target version files are written
|
|
81
81
|
- add focused strategy tests for ecosystem-specific behavior and edge cases
|
|
82
82
|
- add/extend strategy contract tests in `tests/strategy-contract.test.ts`
|
|
83
83
|
- update schema/docs for new `release-type` behavior and defaults
|
|
@@ -105,7 +105,7 @@ Current runtime code uses a flat `src/` layout with clear module boundaries:
|
|
|
105
105
|
- `src/cli/`: command router (`run`, `verify`, `plan`, `changelog`, `pr`, `release`)
|
|
106
106
|
- `src/release/`: release orchestration (plan/changelog/PR/release/state/recovery)
|
|
107
107
|
- `src/strategy/`: strategy contracts, resolver, and built-in implementations
|
|
108
|
-
(`simple`, `node`, `rust`, `r`)
|
|
108
|
+
(`simple`, `node`, `rust`, `r`, `latex`)
|
|
109
109
|
- `src/scm/`: SCM client contracts and provider implementation(s)
|
|
110
110
|
- `src/config/`: config loading and schema validation
|
|
111
111
|
- `src/git/`: git commit/range and repository URL helpers
|
|
@@ -131,6 +131,9 @@ For a quick trial, use:
|
|
|
131
131
|
`Version:` field
|
|
132
132
|
- `release-type: "rust"` uses Cargo manifests (`Cargo.toml`) as version source;
|
|
133
133
|
`version-file` must point to a `Cargo.toml` (default: `Cargo.toml`)
|
|
134
|
+
- `release-type: "latex"` uses `build.lua` as version source and updates LaTeX
|
|
135
|
+
`\ProvidesPackage{...}[YYYY-MM-DD vX.Y.Z ...]` metadata in `src/**/*.dtx`
|
|
136
|
+
using the release commit date
|
|
134
137
|
- simple/default strategy keeps `version.txt` as source of truth and does not
|
|
135
138
|
update `package.json`
|
|
136
139
|
- stable release branch (`release-branch`, default: `versionary/release`) so
|
|
@@ -249,6 +252,27 @@ Commands:
|
|
|
249
252
|
through the SCM client. `pnpm run` is the recommended CI entrypoint and
|
|
250
253
|
auto-dispatches between PR/update and release publish.
|
|
251
254
|
|
|
255
|
+
### Moloch migration example (semantic-release -> versionary)
|
|
256
|
+
|
|
257
|
+
For LaTeX projects like `moloch`, use `release-type: "latex"` so Versionary:
|
|
258
|
+
|
|
259
|
+
- bumps `build.lua` version
|
|
260
|
+
- updates `src/**/*.dtx` `\ProvidesPackage{...}[YYYY-MM-DD vX.Y.Z ...]` entries
|
|
261
|
+
with the release commit date (`git show --format=%cs <sha>`)
|
|
262
|
+
|
|
263
|
+
Example `versionary.jsonc` for `moloch`:
|
|
264
|
+
|
|
265
|
+
```jsonc
|
|
266
|
+
{
|
|
267
|
+
"version": 1,
|
|
268
|
+
"review-mode": "pr",
|
|
269
|
+
"release-type": "latex",
|
|
270
|
+
"version-file": "build.lua",
|
|
271
|
+
"changelog-file": "CHANGELOG.md",
|
|
272
|
+
"release-branch": "versionary/release"
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
252
276
|
For first-run bootstrapping, set `bootstrap-sha` (similar to release-please).
|
|
253
277
|
Subsequent runs use the baseline state file.
|
|
254
278
|
|
|
@@ -8,6 +8,7 @@ exports.loadConfig = loadConfig;
|
|
|
8
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const jsonc_parser_1 = require("jsonc-parser");
|
|
11
|
+
const resolve_js_1 = require("../strategy/resolve.js");
|
|
11
12
|
const schema_js_1 = require("./schema.js");
|
|
12
13
|
const SUPPORTED_FILES = [
|
|
13
14
|
{ file: "versionary.jsonc", format: "jsonc" },
|
|
@@ -22,6 +23,34 @@ function parseConfig(raw, format) {
|
|
|
22
23
|
function isRecord(value) {
|
|
23
24
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
24
25
|
}
|
|
26
|
+
function validateReleaseTypes(config) {
|
|
27
|
+
try {
|
|
28
|
+
(0, resolve_js_1.resolveVersionStrategy)(config);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof Error) {
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
const known = (0, resolve_js_1.listKnownReleaseTypes)().join(", ");
|
|
35
|
+
throw new Error(`Unsupported release-type. Supported release types: ${known}.`);
|
|
36
|
+
}
|
|
37
|
+
for (const [packagePath, packageConfig] of Object.entries(config.packages ?? {})) {
|
|
38
|
+
const packageReleaseType = packageConfig["release-type"];
|
|
39
|
+
if (!packageReleaseType) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
(0, resolve_js_1.resolveVersionStrategy)({ ...config, "release-type": packageReleaseType });
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof Error) {
|
|
47
|
+
throw new Error(`${error.message} (in packages["${packagePath}"])`);
|
|
48
|
+
}
|
|
49
|
+
const known = (0, resolve_js_1.listKnownReleaseTypes)().join(", ");
|
|
50
|
+
throw new Error(`Unsupported release-type in packages["${packagePath}"]. Supported release types: ${known}.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
25
54
|
function findConfigFile(cwd) {
|
|
26
55
|
for (const candidate of SUPPORTED_FILES) {
|
|
27
56
|
const candidatePath = node_path_1.default.join(cwd, candidate.file);
|
|
@@ -45,6 +74,7 @@ function loadConfig(cwd = process.cwd()) {
|
|
|
45
74
|
throw new Error('The "plugins" config key is no longer supported. Versionary uses built-in integrations only.');
|
|
46
75
|
}
|
|
47
76
|
const validated = schema_js_1.configSchema.parse(parsed);
|
|
77
|
+
validateReleaseTypes(validated);
|
|
48
78
|
return {
|
|
49
79
|
path: found.path,
|
|
50
80
|
format: found.format,
|
package/dist/git/commits.js
CHANGED
|
@@ -270,12 +270,14 @@ function parseFooters(body) {
|
|
|
270
270
|
extractReferences(`${footer.token}: ${footer.value}`, footer.token);
|
|
271
271
|
}
|
|
272
272
|
extractInlineSentenceReferences(body);
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
const dedupedReferenceMap = new Map();
|
|
274
|
+
for (const reference of references) {
|
|
275
|
+
const key = `${reference.action?.trim().toLowerCase() ?? ""}:${reference.owner?.trim().toLowerCase() ?? ""}/${reference.repository?.trim().toLowerCase() ?? ""}:${reference.prefix}:${reference.issue ?? ""}`;
|
|
276
|
+
if (!dedupedReferenceMap.has(key)) {
|
|
277
|
+
dedupedReferenceMap.set(key, reference);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const dedupedReferences = [...dedupedReferenceMap.values()];
|
|
279
281
|
return {
|
|
280
282
|
bodyText: bodyLines.join("\n").trim() || "",
|
|
281
283
|
footerText: footerLines.length > 0 ? footerLines.join("\n").trim() : null,
|
|
@@ -12,8 +12,14 @@ export declare function renderSimpleReleaseNotes(input: {
|
|
|
12
12
|
}>;
|
|
13
13
|
}, options?: {
|
|
14
14
|
includeFooter?: boolean;
|
|
15
|
+
headerLabel?: string;
|
|
16
|
+
}): string;
|
|
17
|
+
export declare function renderReviewRequestFooter(): string;
|
|
18
|
+
export declare function renderReleasePlanChangelog(plan: ReleasePlan, options?: {
|
|
19
|
+
headerLabel?: string;
|
|
20
|
+
includeFooter?: boolean;
|
|
21
|
+
cwd?: string;
|
|
15
22
|
}): string;
|
|
16
|
-
export declare function renderReleasePlanChangelog(plan: ReleasePlan): string;
|
|
17
23
|
/** @deprecated Use renderReleasePlanChangelog. */
|
|
18
24
|
export declare function renderSimpleChangelog(plan: SimplePlan): string;
|
|
19
25
|
export declare function renderPackageChangelogSection(input: {
|
|
@@ -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.renderReviewRequestFooter = renderReviewRequestFooter;
|
|
7
8
|
exports.renderReleasePlanChangelog = renderReleasePlanChangelog;
|
|
8
9
|
exports.renderSimpleChangelog = renderSimpleChangelog;
|
|
9
10
|
exports.renderPackageChangelogSection = renderPackageChangelogSection;
|
|
@@ -13,6 +14,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
13
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
15
|
const commits_js_1 = require("../git/commits.js");
|
|
15
16
|
const repo_url_js_1 = require("../git/repo-url.js");
|
|
17
|
+
const REVIEW_REQUEST_FOOTER = "---\n\nThis PR was generated by [Versionary](https://github.com/jolars/versionary).";
|
|
16
18
|
function formatDate() {
|
|
17
19
|
return new Date().toISOString().slice(0, 10);
|
|
18
20
|
}
|
|
@@ -31,17 +33,41 @@ function formatCommitReferences(commit, repoBaseUrl) {
|
|
|
31
33
|
if (references.length === 0) {
|
|
32
34
|
return "";
|
|
33
35
|
}
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
+
const formatIssueList = (issues) => {
|
|
37
|
+
if (issues.length === 0) {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
if (issues.length === 1) {
|
|
41
|
+
return issues[0] ?? "";
|
|
42
|
+
}
|
|
43
|
+
if (issues.length === 2) {
|
|
44
|
+
return `${issues[0] ?? ""} and ${issues[1] ?? ""}`;
|
|
45
|
+
}
|
|
46
|
+
return `${issues.slice(0, -1).join(", ")}, and ${issues[issues.length - 1] ?? ""}`;
|
|
47
|
+
};
|
|
48
|
+
const referencesByAction = new Map();
|
|
49
|
+
for (const reference of references) {
|
|
36
50
|
const issue = reference.issue;
|
|
37
51
|
if (!issue) {
|
|
38
|
-
|
|
52
|
+
continue;
|
|
39
53
|
}
|
|
40
54
|
const action = (reference.action?.trim() || "refs").toLowerCase();
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
const formattedIssue = repoBaseUrl
|
|
56
|
+
? `[#${issue}](${repoBaseUrl}/issues/${issue})`
|
|
57
|
+
: `#${issue}`;
|
|
58
|
+
const existing = referencesByAction.get(action) ?? [];
|
|
59
|
+
if (!existing.includes(formattedIssue)) {
|
|
60
|
+
existing.push(formattedIssue);
|
|
61
|
+
referencesByAction.set(action, existing);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...referencesByAction.entries()]
|
|
65
|
+
.map(([action, issues]) => {
|
|
66
|
+
const list = formatIssueList(issues);
|
|
67
|
+
if (list.length === 0) {
|
|
68
|
+
return "";
|
|
43
69
|
}
|
|
44
|
-
return `${action}
|
|
70
|
+
return `${action} ${list}`;
|
|
45
71
|
})
|
|
46
72
|
.filter((entry) => entry.length > 0)
|
|
47
73
|
.join(", ");
|
|
@@ -112,9 +138,10 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
112
138
|
}
|
|
113
139
|
function renderSimpleReleaseNotes(input, options = {}) {
|
|
114
140
|
const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(input.cwd ?? process.cwd());
|
|
141
|
+
const headerLabel = options.headerLabel ?? input.nextVersion;
|
|
115
142
|
const header = repoUrl
|
|
116
|
-
? `## [${
|
|
117
|
-
: `## ${
|
|
143
|
+
? `## [${headerLabel}](${repoUrl}/compare/v${input.currentVersion}...v${input.nextVersion}) (${formatDate()})`
|
|
144
|
+
: `## ${headerLabel} (${formatDate()})`;
|
|
118
145
|
const grouped = groupCommitLines(input.commits, repoUrl);
|
|
119
146
|
const sections = [];
|
|
120
147
|
if (grouped.breaking.length > 0) {
|
|
@@ -132,13 +159,16 @@ function renderSimpleReleaseNotes(input, options = {}) {
|
|
|
132
159
|
if (input.dependencies && input.dependencies.length > 0) {
|
|
133
160
|
sections.push("### Dependencies", ...input.dependencies.map((dependency) => `- updated ${dependency.name} to v${dependency.version}`), "");
|
|
134
161
|
}
|
|
135
|
-
const
|
|
162
|
+
const body = [header, "", ...sections].join("\n").trimEnd();
|
|
136
163
|
if (options.includeFooter) {
|
|
137
|
-
|
|
164
|
+
return `${body}\n\n${renderReviewRequestFooter()}`;
|
|
138
165
|
}
|
|
139
|
-
return
|
|
166
|
+
return body;
|
|
167
|
+
}
|
|
168
|
+
function renderReviewRequestFooter() {
|
|
169
|
+
return REVIEW_REQUEST_FOOTER;
|
|
140
170
|
}
|
|
141
|
-
function renderReleasePlanChangelog(plan) {
|
|
171
|
+
function renderReleasePlanChangelog(plan, options = {}) {
|
|
142
172
|
if (!plan.nextVersion) {
|
|
143
173
|
return "";
|
|
144
174
|
}
|
|
@@ -170,8 +200,11 @@ function renderReleasePlanChangelog(plan) {
|
|
|
170
200
|
currentVersion: plan.currentVersion,
|
|
171
201
|
nextVersion: plan.nextVersion,
|
|
172
202
|
commits: dedupedCommits,
|
|
173
|
-
cwd: process.cwd(),
|
|
203
|
+
cwd: options.cwd ?? process.cwd(),
|
|
174
204
|
dependencies,
|
|
205
|
+
}, {
|
|
206
|
+
includeFooter: options.includeFooter,
|
|
207
|
+
headerLabel: options.headerLabel,
|
|
175
208
|
});
|
|
176
209
|
}
|
|
177
210
|
/** @deprecated Use renderReleasePlanChangelog. */
|
package/dist/release/pr.js
CHANGED
|
@@ -82,6 +82,13 @@ function getCommitTreeSha(cwd, revision) {
|
|
|
82
82
|
stdio: ["ignore", "pipe", "ignore"],
|
|
83
83
|
}).trim();
|
|
84
84
|
}
|
|
85
|
+
function resolveCommitDate(cwd, revision) {
|
|
86
|
+
return (0, node_child_process_1.execFileSync)("git", ["show", "-s", "--format=%cs", revision], {
|
|
87
|
+
cwd,
|
|
88
|
+
encoding: "utf8",
|
|
89
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
90
|
+
}).trim();
|
|
91
|
+
}
|
|
85
92
|
function hasOriginRemote(cwd) {
|
|
86
93
|
const remotes = (0, node_child_process_1.execFileSync)("git", ["remote"], {
|
|
87
94
|
cwd,
|
|
@@ -191,6 +198,15 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
|
|
|
191
198
|
throw new Error("No releasable commits found. Nothing to open a release PR for.");
|
|
192
199
|
}
|
|
193
200
|
ensureCleanWorktree(cwd, options.logger);
|
|
201
|
+
const releaseBaselineSha = (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
202
|
+
cwd,
|
|
203
|
+
encoding: "utf8",
|
|
204
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
205
|
+
}).trim();
|
|
206
|
+
const finalizeContext = {
|
|
207
|
+
releaseCommitSha: releaseBaselineSha,
|
|
208
|
+
releaseDate: resolveCommitDate(cwd, releaseBaselineSha),
|
|
209
|
+
};
|
|
194
210
|
const updatedVersionFiles = [];
|
|
195
211
|
const writesByStrategy = new Map();
|
|
196
212
|
const addStrategyWrite = (strategy, write) => {
|
|
@@ -230,7 +246,7 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
|
|
|
230
246
|
});
|
|
231
247
|
}
|
|
232
248
|
for (const strategyGroup of writesByStrategy.values()) {
|
|
233
|
-
updatedVersionFiles.push(...(strategyGroup.strategy.finalizeVersionWrites?.(cwd, strategyGroup.writes) ?? []));
|
|
249
|
+
updatedVersionFiles.push(...(strategyGroup.strategy.finalizeVersionWrites?.(cwd, strategyGroup.writes, finalizeContext) ?? []));
|
|
234
250
|
}
|
|
235
251
|
const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
|
|
236
252
|
const packageReleaseMetadata = buildPackageReleaseMetadata(cwd, plan, loaded.config);
|
|
@@ -266,11 +282,6 @@ function prepareReleasePr(cwd = process.cwd(), options = {}) {
|
|
|
266
282
|
const releaseTargets = buildReleaseTargets(cwd, plan, loaded.config);
|
|
267
283
|
const branch = plan.releaseBranchPrefix;
|
|
268
284
|
const title = formatReleaseCommitTitle(releaseTargets);
|
|
269
|
-
const releaseBaselineSha = (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
270
|
-
cwd,
|
|
271
|
-
encoding: "utf8",
|
|
272
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
273
|
-
}).trim();
|
|
274
285
|
const hasRemoteReleaseBranch = remoteReleaseBranchExists(cwd, branch);
|
|
275
286
|
const remoteReleaseRef = hasRemoteReleaseBranch
|
|
276
287
|
? fetchRemoteReleaseBranch(cwd, branch)
|
|
@@ -337,25 +348,15 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
|
|
|
337
348
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
338
349
|
return directSources;
|
|
339
350
|
};
|
|
340
|
-
const relabelSectionHeader = (notes, packageLabel, nextVersion) => {
|
|
341
|
-
const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
|
|
342
|
-
if (linkedHeader) {
|
|
343
|
-
const [, , compareUrl, date] = linkedHeader;
|
|
344
|
-
return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${nextVersion}](${compareUrl}) (${date})`);
|
|
345
|
-
}
|
|
346
|
-
const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
|
|
347
|
-
if (plainHeader) {
|
|
348
|
-
const [, , date] = plainHeader;
|
|
349
|
-
return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${nextVersion} (${date})`);
|
|
350
|
-
}
|
|
351
|
-
return notes;
|
|
352
|
-
};
|
|
353
351
|
if (plan?.packages && plan.packages.length > 1) {
|
|
354
352
|
const sections = [];
|
|
355
353
|
const rootPackage = plan.packages.find((pkg) => pkg.path === "." && pkg.nextVersion);
|
|
356
354
|
if (rootPackage?.nextVersion) {
|
|
357
|
-
const rootNotes = (0, changelog_js_1.renderReleasePlanChangelog)(plan
|
|
358
|
-
|
|
355
|
+
const rootNotes = (0, changelog_js_1.renderReleasePlanChangelog)(plan, {
|
|
356
|
+
headerLabel: `${formatPackageLabel(".")}: ${rootPackage.nextVersion}`,
|
|
357
|
+
cwd,
|
|
358
|
+
});
|
|
359
|
+
sections.push(rootNotes);
|
|
359
360
|
}
|
|
360
361
|
const packageSections = plan.packages
|
|
361
362
|
.filter((pkg) => pkg.path !== "." && pkg.nextVersion)
|
|
@@ -368,15 +369,18 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
|
|
|
368
369
|
commits: pkg.commits,
|
|
369
370
|
cwd,
|
|
370
371
|
dependencies: propagatedDependencies,
|
|
371
|
-
}, {
|
|
372
|
-
|
|
372
|
+
}, {
|
|
373
|
+
includeFooter: false,
|
|
374
|
+
headerLabel: `${packageLabel}: ${pkg.nextVersion ?? ""}`,
|
|
375
|
+
});
|
|
376
|
+
return notes;
|
|
373
377
|
});
|
|
374
378
|
sections.push(...packageSections);
|
|
375
379
|
const bodySections = sections.join("\n\n");
|
|
376
380
|
if (bodySections.length === 0) {
|
|
377
|
-
return
|
|
381
|
+
return (0, changelog_js_1.renderReviewRequestFooter)();
|
|
378
382
|
}
|
|
379
|
-
return `${bodySections}\n\
|
|
383
|
+
return `${bodySections}\n\n${(0, changelog_js_1.renderReviewRequestFooter)()}`;
|
|
380
384
|
}
|
|
381
385
|
return (0, changelog_js_1.renderSimpleReleaseNotes)({
|
|
382
386
|
currentVersion: previousVersion,
|
|
@@ -5,6 +5,7 @@ export interface ReleaseTargetInput {
|
|
|
5
5
|
version: string;
|
|
6
6
|
notes: string;
|
|
7
7
|
draft?: boolean;
|
|
8
|
+
makeLatest?: "true" | "false" | "legacy";
|
|
8
9
|
}
|
|
9
10
|
export interface ReleaseExecutionContext {
|
|
10
11
|
createReleaseMetadata: (input: ReleaseTargetInput) => Promise<VersionaryScmReleaseMetadataResult>;
|
package/dist/release/release.js
CHANGED
|
@@ -183,6 +183,7 @@ async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
183
183
|
version: target.version,
|
|
184
184
|
notes: releaseNotes,
|
|
185
185
|
draft: loaded.config["release-draft"] ?? false,
|
|
186
|
+
makeLatest: target.path === "." ? "true" : "false",
|
|
186
187
|
}, {
|
|
187
188
|
createReleaseMetadata: (input) => scmClient.createReleaseMetadata(input, {
|
|
188
189
|
cwd,
|
package/dist/scm/types.d.ts
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
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.latexVersionStrategy = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const BUILD_LUA_VERSION_PATTERN = /^(\s*version\s*=\s*")([^"]+)(")/mu;
|
|
10
|
+
const PROVIDES_PACKAGE_PATTERN = /\\ProvidesPackage\{([^}]+)\}\[\d{4}-\d{2}-\d{2} v([0-9]+\.[0-9]+\.[0-9]+) ([^\]]+)\]/gu;
|
|
11
|
+
function normalizeRelative(base, target) {
|
|
12
|
+
return node_path_1.default.relative(base, target).replaceAll("\\", "/");
|
|
13
|
+
}
|
|
14
|
+
function collectDtxFiles(dir) {
|
|
15
|
+
if (!node_fs_1.default.existsSync(dir)) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
19
|
+
const files = [];
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const target = node_path_1.default.join(dir, entry.name);
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
files.push(...collectDtxFiles(target));
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (entry.isFile() && target.endsWith(".dtx")) {
|
|
27
|
+
files.push(target);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return files.sort((a, b) => a.localeCompare(b));
|
|
31
|
+
}
|
|
32
|
+
function replaceBuildLuaVersion(content, version, versionFile) {
|
|
33
|
+
const match = content.match(BUILD_LUA_VERSION_PATTERN);
|
|
34
|
+
if (!match) {
|
|
35
|
+
throw new Error(`${versionFile} is missing a valid version field required by release-type "latex".`);
|
|
36
|
+
}
|
|
37
|
+
return content.replace(BUILD_LUA_VERSION_PATTERN, `$1${version}$3`);
|
|
38
|
+
}
|
|
39
|
+
function replaceProvidesPackageMetadata(content, version, releaseDate, relativePath) {
|
|
40
|
+
const matches = [...content.matchAll(PROVIDES_PACKAGE_PATTERN)];
|
|
41
|
+
if (matches.length !== 1) {
|
|
42
|
+
throw new Error(`${relativePath} must contain exactly one \\ProvidesPackage metadata entry; matched ${matches.length}.`);
|
|
43
|
+
}
|
|
44
|
+
return content.replace(PROVIDES_PACKAGE_PATTERN, (_full, pkg, _prevVersion, desc) => `\\ProvidesPackage{${pkg}}[${releaseDate} v${version} ${desc}]`);
|
|
45
|
+
}
|
|
46
|
+
exports.latexVersionStrategy = {
|
|
47
|
+
name: "latex",
|
|
48
|
+
getVersionFile(config) {
|
|
49
|
+
return config["version-file"] ?? "build.lua";
|
|
50
|
+
},
|
|
51
|
+
readVersion(cwd, config) {
|
|
52
|
+
const versionFile = this.getVersionFile(config);
|
|
53
|
+
const versionPath = node_path_1.default.join(cwd, versionFile);
|
|
54
|
+
if (!node_fs_1.default.existsSync(versionPath)) {
|
|
55
|
+
throw new Error(`Versionary requires ${versionFile} to exist.`);
|
|
56
|
+
}
|
|
57
|
+
const content = node_fs_1.default.readFileSync(versionPath, "utf8");
|
|
58
|
+
const match = content.match(BUILD_LUA_VERSION_PATTERN);
|
|
59
|
+
if (!match?.[2]) {
|
|
60
|
+
throw new Error(`${versionFile} is missing a valid version field required by release-type "latex".`);
|
|
61
|
+
}
|
|
62
|
+
return match[2].trim();
|
|
63
|
+
},
|
|
64
|
+
writeVersion(cwd, config, version) {
|
|
65
|
+
const versionFile = this.getVersionFile(config);
|
|
66
|
+
const versionPath = node_path_1.default.join(cwd, versionFile);
|
|
67
|
+
if (!node_fs_1.default.existsSync(versionPath)) {
|
|
68
|
+
throw new Error(`Versionary requires ${versionFile} to exist.`);
|
|
69
|
+
}
|
|
70
|
+
const next = replaceBuildLuaVersion(node_fs_1.default.readFileSync(versionPath, "utf8"), version, versionFile);
|
|
71
|
+
node_fs_1.default.writeFileSync(versionPath, next, "utf8");
|
|
72
|
+
return [versionFile];
|
|
73
|
+
},
|
|
74
|
+
finalizeVersionWrites(cwd, writes, context) {
|
|
75
|
+
const updated = new Set();
|
|
76
|
+
for (const write of writes) {
|
|
77
|
+
const packageRoot = write.packagePath === "." ? cwd : node_path_1.default.join(cwd, write.packagePath);
|
|
78
|
+
const srcDir = node_path_1.default.join(packageRoot, "src");
|
|
79
|
+
const dtxFiles = collectDtxFiles(srcDir);
|
|
80
|
+
if (dtxFiles.length === 0) {
|
|
81
|
+
throw new Error(`release-type "latex" requires at least one .dtx file under ${normalizeRelative(cwd, srcDir)}.`);
|
|
82
|
+
}
|
|
83
|
+
for (const dtxPath of dtxFiles) {
|
|
84
|
+
const relativePath = normalizeRelative(cwd, dtxPath);
|
|
85
|
+
const existing = node_fs_1.default.readFileSync(dtxPath, "utf8");
|
|
86
|
+
const next = replaceProvidesPackageMetadata(existing, write.version, context.releaseDate, relativePath);
|
|
87
|
+
if (next === existing) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
node_fs_1.default.writeFileSync(dtxPath, next, "utf8");
|
|
91
|
+
updated.add(relativePath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return [...updated].sort((a, b) => a.localeCompare(b));
|
|
95
|
+
},
|
|
96
|
+
};
|
package/dist/strategy/resolve.js
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listKnownReleaseTypes = listKnownReleaseTypes;
|
|
4
4
|
exports.resolveVersionStrategy = resolveVersionStrategy;
|
|
5
|
+
const latex_js_1 = require("./latex.js");
|
|
5
6
|
const node_js_1 = require("./node.js");
|
|
6
7
|
const r_js_1 = require("./r.js");
|
|
7
8
|
const rust_js_1 = require("./rust.js");
|
|
8
9
|
const simple_js_1 = require("./simple.js");
|
|
9
10
|
const strategyRegistry = {
|
|
11
|
+
latex: latex_js_1.latexVersionStrategy,
|
|
10
12
|
simple: simple_js_1.simpleVersionStrategy,
|
|
11
13
|
node: node_js_1.nodeVersionStrategy,
|
|
12
14
|
rust: rust_js_1.rustVersionStrategy,
|
|
@@ -17,5 +19,10 @@ function listKnownReleaseTypes() {
|
|
|
17
19
|
}
|
|
18
20
|
function resolveVersionStrategy(config) {
|
|
19
21
|
const releaseType = config["release-type"] ?? "simple";
|
|
20
|
-
|
|
22
|
+
const strategy = strategyRegistry[releaseType];
|
|
23
|
+
if (!strategy) {
|
|
24
|
+
const known = listKnownReleaseTypes().join(", ");
|
|
25
|
+
throw new Error(`Unsupported release-type "${releaseType}". Supported release types: ${known}.`);
|
|
26
|
+
}
|
|
27
|
+
return strategy;
|
|
21
28
|
}
|
package/dist/strategy/rust.js
CHANGED
|
@@ -721,7 +721,7 @@ exports.rustVersionStrategy = {
|
|
|
721
721
|
.filter((pkgPath) => Boolean(pkgPath))
|
|
722
722
|
.sort((a, b) => a.localeCompare(b));
|
|
723
723
|
},
|
|
724
|
-
finalizeVersionWrites(cwd, writes) {
|
|
724
|
+
finalizeVersionWrites(cwd, writes, _context) {
|
|
725
725
|
const manifestToVersion = {};
|
|
726
726
|
for (const write of writes) {
|
|
727
727
|
manifestToVersion[write.versionFile] = write.version;
|
package/dist/strategy/types.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ export interface StrategyVersionWriteContext {
|
|
|
10
10
|
versionFile: string;
|
|
11
11
|
version: string;
|
|
12
12
|
}
|
|
13
|
+
export interface StrategyFinalizeContext {
|
|
14
|
+
releaseCommitSha: string;
|
|
15
|
+
releaseDate: string;
|
|
16
|
+
}
|
|
13
17
|
export interface VersionStrategy {
|
|
14
18
|
name: string;
|
|
15
19
|
getVersionFile(config: VersionaryConfig): string;
|
|
@@ -19,5 +23,5 @@ export interface VersionStrategy {
|
|
|
19
23
|
validateProject?(cwd: string, config: VersionaryConfig): string | null;
|
|
20
24
|
readPackageName?(cwd: string, config: VersionaryConfig): string | null;
|
|
21
25
|
propagateDependentPatchImpacts?(cwd: string, packages: StrategyPackagePlanContext[]): string[];
|
|
22
|
-
finalizeVersionWrites?(cwd: string, writes: StrategyVersionWriteContext[]): string[];
|
|
26
|
+
finalizeVersionWrites?(cwd: string, writes: StrategyVersionWriteContext[], context: StrategyFinalizeContext): string[];
|
|
23
27
|
}
|