versionary 0.10.0 → 0.11.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
CHANGED
|
@@ -49,7 +49,7 @@ release/tag.
|
|
|
49
49
|
|
|
50
50
|
Current implementation focuses on:
|
|
51
51
|
|
|
52
|
-
- strategy-based version updates (`simple`, `node`)
|
|
52
|
+
- strategy-based version updates (`simple`, `node`, `rust`, `r`)
|
|
53
53
|
- release planning and changelog generation
|
|
54
54
|
- review-mode vs direct-mode release flow
|
|
55
55
|
- built-in GitHub SCM plugin capabilities
|
|
@@ -57,6 +57,40 @@ Current implementation focuses on:
|
|
|
57
57
|
Planned/harder areas include deeper monorepo ergonomics, broader SCM coverage,
|
|
58
58
|
and stronger failure recovery around release steps.
|
|
59
59
|
|
|
60
|
+
## Adding a new release strategy
|
|
61
|
+
|
|
62
|
+
Versionary is set up so new language strategies can be added internally without
|
|
63
|
+
changing release orchestration. A new strategy should implement the
|
|
64
|
+
`VersionStrategy` contract in `src/domain/strategy/types.ts` and be wired in
|
|
65
|
+
`src/domain/strategy/resolve.ts`.
|
|
66
|
+
|
|
67
|
+
Checklist for new strategies (for example `python`):
|
|
68
|
+
|
|
69
|
+
- define strategy `name`
|
|
70
|
+
- define `getVersionFile(config)` defaults and config override behavior
|
|
71
|
+
- implement `readVersion(cwd, config)` with explicit malformed-file errors
|
|
72
|
+
- implement `writeVersion(cwd, config, version)` returning deterministic updated
|
|
73
|
+
file paths
|
|
74
|
+
- add release-name extraction support if package tags should derive from
|
|
75
|
+
language metadata (similar to Node/Rust/R)
|
|
76
|
+
- add focused strategy tests for ecosystem-specific behavior and edge cases
|
|
77
|
+
- add/extend strategy contract tests in `tests/strategy-contract.test.ts`
|
|
78
|
+
- update schema/docs for new `release-type` behavior and defaults
|
|
79
|
+
|
|
80
|
+
Current ecosystem policy defaults:
|
|
81
|
+
|
|
82
|
+
- changelog source for publish:
|
|
83
|
+
- root target uses root `changelog-file`
|
|
84
|
+
- package target uses `packages.<path>.changelog-file` when configured, else
|
|
85
|
+
root `changelog-file`
|
|
86
|
+
- lockfiles:
|
|
87
|
+
- Node strategy updates root `package-lock.json`/`npm-shrinkwrap.json` when
|
|
88
|
+
present
|
|
89
|
+
- Rust release PR prep refreshes all discovered `Cargo.lock` files
|
|
90
|
+
- workspace/inheritance:
|
|
91
|
+
- Rust supports `version.workspace = true` via `[workspace.package].version`
|
|
92
|
+
- other strategies should document equivalent inheritance behavior explicitly
|
|
93
|
+
|
|
60
94
|
## Architecture layout (current migration)
|
|
61
95
|
|
|
62
96
|
The repository is moving to explicit layered modules:
|
|
@@ -177,7 +211,8 @@ Release planning is based on Conventional Commit parsing semantics:
|
|
|
177
211
|
- recognizes breaking changes from `!` and `BREAKING CHANGE` / `BREAKING-CHANGE`
|
|
178
212
|
footers
|
|
179
213
|
- maps release impact as `feat => minor`, `fix|perf => patch`, breaking => major
|
|
180
|
-
- treats `revert:` as
|
|
214
|
+
- treats `revert:` commits as patch-releasable by default (and major if marked
|
|
215
|
+
breaking, e.g. `revert!:` or `BREAKING CHANGE`)
|
|
181
216
|
- suppresses commits that are reverted within the analyzed release window so
|
|
182
217
|
they do not affect bump/changelog output
|
|
183
218
|
- emits parser diagnostics for malformed headers/footers/references and
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { VersionaryConfig } from "../../types/config.js";
|
|
1
2
|
import type { VersionaryPluginContext } from "../../types/plugins.js";
|
|
3
|
+
export declare function resolveTargetChangelogFile(config: VersionaryConfig, rootChangelogFile: string, targetPath: string): string;
|
|
2
4
|
export declare function runSimpleRelease(cwd?: string): Promise<string>;
|
|
3
5
|
export type SimpleRunReleaseResult = {
|
|
4
6
|
action: "release-skipped";
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveTargetChangelogFile = resolveTargetChangelogFile;
|
|
6
7
|
exports.runSimpleRelease = runSimpleRelease;
|
|
7
8
|
exports.runSimpleReleaseDetailed = runSimpleReleaseDetailed;
|
|
8
9
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -46,6 +47,16 @@ function readReleaseNotes(cwd, version, changelogFile) {
|
|
|
46
47
|
.trim();
|
|
47
48
|
return notes.length > 0 ? notes : `Automated release for v${version}`;
|
|
48
49
|
}
|
|
50
|
+
function resolveTargetChangelogFile(config, rootChangelogFile, targetPath) {
|
|
51
|
+
if (targetPath === ".") {
|
|
52
|
+
return rootChangelogFile;
|
|
53
|
+
}
|
|
54
|
+
const packageChangelogFile = config.packages?.[targetPath]?.["changelog-file"];
|
|
55
|
+
if (!packageChangelogFile) {
|
|
56
|
+
return rootChangelogFile;
|
|
57
|
+
}
|
|
58
|
+
return node_path_1.default.posix.join(targetPath, packageChangelogFile);
|
|
59
|
+
}
|
|
49
60
|
async function runSimpleRelease(cwd = process.cwd()) {
|
|
50
61
|
const result = await runSimpleReleaseDetailed(cwd, { logger: console });
|
|
51
62
|
if (result.action === "release-skipped") {
|
|
@@ -99,10 +110,11 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
99
110
|
const createReleaseMetadata = plugin.createReleaseMetadata;
|
|
100
111
|
const releases = [];
|
|
101
112
|
for (const target of targets) {
|
|
113
|
+
const targetChangelogFile = resolveTargetChangelogFile(loaded.config, changelogFile, target.path);
|
|
102
114
|
const outcome = await (0, recovery_js_1.executeIdempotentReleaseTarget)(cwd, {
|
|
103
115
|
tag: target.tag,
|
|
104
116
|
version: target.version,
|
|
105
|
-
notes: readReleaseNotes(cwd, target.version,
|
|
117
|
+
notes: readReleaseNotes(cwd, target.version, targetChangelogFile),
|
|
106
118
|
}, {
|
|
107
119
|
createReleaseMetadata: (input) => createReleaseMetadata(input, {
|
|
108
120
|
cwd,
|
|
@@ -48,6 +48,7 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
48
48
|
const breaking = [];
|
|
49
49
|
const features = [];
|
|
50
50
|
const fixes = [];
|
|
51
|
+
const reverts = [];
|
|
51
52
|
for (const commit of commits) {
|
|
52
53
|
const type = (0, commits_js_1.inferReleaseTypeFromParsedCommit)(commit);
|
|
53
54
|
if (!type) {
|
|
@@ -63,6 +64,10 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
63
64
|
const line = `- ${label}${message} (${hashLabel})${referencesSuffix}`;
|
|
64
65
|
const commitType = (commit.type ?? "").toLowerCase();
|
|
65
66
|
const isBreaking = type === "major";
|
|
67
|
+
if (commit.isRevert) {
|
|
68
|
+
reverts.push(line);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
66
71
|
if (isBreaking) {
|
|
67
72
|
breaking.push(line);
|
|
68
73
|
}
|
|
@@ -76,7 +81,7 @@ function groupCommitLines(commits, repoUrl) {
|
|
|
76
81
|
fixes.push(line);
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
|
-
return { breaking, features, fixes };
|
|
84
|
+
return { breaking, features, fixes, reverts };
|
|
80
85
|
}
|
|
81
86
|
function renderSimpleReleaseNotes(input, options = {}) {
|
|
82
87
|
const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(input.cwd ?? process.cwd());
|
|
@@ -94,6 +99,9 @@ function renderSimpleReleaseNotes(input, options = {}) {
|
|
|
94
99
|
if (grouped.fixes.length > 0) {
|
|
95
100
|
sections.push("### Bug Fixes", ...grouped.fixes, "");
|
|
96
101
|
}
|
|
102
|
+
if (grouped.reverts.length > 0) {
|
|
103
|
+
sections.push("### Reverts", ...grouped.reverts, "");
|
|
104
|
+
}
|
|
97
105
|
const lines = [header, "", ...sections];
|
|
98
106
|
if (options.includeFooter) {
|
|
99
107
|
lines.push("\n---\n\nThis PR was generated by [Versionary](https://github.com/jolars/versionary).");
|
|
@@ -127,6 +135,9 @@ function renderPackageChangelogSection(input) {
|
|
|
127
135
|
if (grouped.fixes.length > 0) {
|
|
128
136
|
sections.push("### Bug Fixes", ...grouped.fixes, "");
|
|
129
137
|
}
|
|
138
|
+
if (grouped.reverts.length > 0) {
|
|
139
|
+
sections.push("### Reverts", ...grouped.reverts, "");
|
|
140
|
+
}
|
|
130
141
|
return [header, "", ...sections].join("\n");
|
|
131
142
|
}
|
|
132
143
|
function prependChangelog(cwd, changelogFile, section) {
|
|
@@ -23,6 +23,7 @@ function createSimplePlan(cwd = process.cwd()) {
|
|
|
23
23
|
const changelogFile = loaded.config["changelog-file"] ?? "CHANGELOG.md";
|
|
24
24
|
const releaseBranchPrefix = loaded.config["release-branch"] ?? "versionary/release";
|
|
25
25
|
const baselineSha = (0, state_js_1.readBaselineSha)(cwd) ?? loaded.config["bootstrap-sha"] ?? null;
|
|
26
|
+
const releaseTargetByPath = new Map((0, state_js_1.readReleaseTargets)(cwd).map((target) => [target.path, target]));
|
|
26
27
|
const allowStableMajor = loaded.config["allow-stable-major"] ?? false;
|
|
27
28
|
const configuredPackages = Object.entries(loaded.config.packages ?? {}).map(([pkgPath, cfg]) => ({
|
|
28
29
|
path: pkgPath,
|
|
@@ -59,7 +60,7 @@ function createSimplePlan(cwd = process.cwd()) {
|
|
|
59
60
|
.map((pkg) => {
|
|
60
61
|
const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loaded.config, pkg.path, pkg);
|
|
61
62
|
const packageCurrentVersion = packageContext.strategy.readVersion(cwd, packageContext.config);
|
|
62
|
-
const parsedCommits = (0, commits_js_1.getParsedCommitsForPath)(cwd, baselineSha, pkg.path, pkg["exclude-paths"] ?? []);
|
|
63
|
+
const parsedCommits = (0, commits_js_1.getParsedCommitsForPath)(cwd, releaseTargetByPath.get(pkg.path)?.tag ?? baselineSha, pkg.path, pkg["exclude-paths"] ?? []);
|
|
63
64
|
const effectiveCommits = (0, commits_js_1.applyRevertSuppression)(parsedCommits);
|
|
64
65
|
const commits = effectiveCommits;
|
|
65
66
|
const releaseType = (0, commits_js_1.analyzeParsedCommits)(parsedCommits);
|
|
@@ -351,12 +351,12 @@ function getParsedCommitsForPath(cwd = process.cwd(), baselineSha, packagePath =
|
|
|
351
351
|
return readGitLogFull(cwd, range, [normalizedPackagePath, ...excludes]);
|
|
352
352
|
}
|
|
353
353
|
function inferReleaseTypeFromParsedCommit(commit) {
|
|
354
|
-
if (commit.isRevert) {
|
|
355
|
-
return null;
|
|
356
|
-
}
|
|
357
354
|
if (commit.isBreaking) {
|
|
358
355
|
return "major";
|
|
359
356
|
}
|
|
357
|
+
if (commit.isRevert) {
|
|
358
|
+
return "patch";
|
|
359
|
+
}
|
|
360
360
|
const type = commit.type?.toLowerCase() ?? "";
|
|
361
361
|
if (type === "feat") {
|
|
362
362
|
return "minor";
|