versionary 0.24.0 → 0.26.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 +11 -0
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +6 -2
- package/dist/strategy/composite.d.ts +2 -0
- package/dist/strategy/composite.js +100 -0
- package/dist/strategy/python.js +82 -5
- package/dist/strategy/resolve.js +23 -4
- package/dist/strategy/rust.js +7 -0
- package/dist/types/config.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,17 @@ For a quick trial, use:
|
|
|
144
144
|
Python source file (e.g. `src/<pkg>/__init__.py`) to update a `__version__`
|
|
145
145
|
assignment instead. Refreshes `poetry.lock`/`uv.lock`/`pdm.lock` at the
|
|
146
146
|
package root if present
|
|
147
|
+
- `release-type` can also be an array of strategy names to compose them across
|
|
148
|
+
manifests, e.g. `["python", "rust"]` for a PyO3/maturin project: the first
|
|
149
|
+
entry is the *primary* (drives `readVersion`, `readPackageName`, and consumes
|
|
150
|
+
any `version-file` override); each *secondary* writes its default manifest
|
|
151
|
+
with the same target version. Common combinations:
|
|
152
|
+
- `["python", "rust"]` — PyO3/maturin (`pyproject.toml` + `Cargo.toml` +
|
|
153
|
+
`Cargo.lock`)
|
|
154
|
+
- `["node", "rust"]` — napi-rs (`package.json` + `Cargo.toml` + `Cargo.lock`)
|
|
155
|
+
- `["r", "rust"]` — R packages with embedded Rust crates (note: nested
|
|
156
|
+
`src/rust/Cargo.toml` layouts are not supported by the array form yet —
|
|
157
|
+
use a single strategy until per-strategy `version-file` overrides land)
|
|
147
158
|
- simple/default strategy keeps `version.txt` as source of truth and does not
|
|
148
159
|
update `package.json`
|
|
149
160
|
- stable release branch (`release-branch`, default: `versionary/release`) so
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -30,9 +30,9 @@ export declare const configSchema: z.ZodObject<{
|
|
|
30
30
|
"bump-minor-pre-major": z.ZodOptional<z.ZodBoolean>;
|
|
31
31
|
"allow-stable-major": z.ZodOptional<z.ZodBoolean>;
|
|
32
32
|
"include-commit-authors": z.ZodOptional<z.ZodBoolean>;
|
|
33
|
-
"release-type": z.ZodOptional<z.ZodString
|
|
33
|
+
"release-type": z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
34
34
|
packages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
35
|
-
"release-type": z.ZodOptional<z.ZodString
|
|
35
|
+
"release-type": z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
36
36
|
"package-name": z.ZodOptional<z.ZodString>;
|
|
37
37
|
"changelog-file": z.ZodOptional<z.ZodString>;
|
|
38
38
|
"changelog-format": z.ZodOptional<z.ZodEnum<{
|
package/dist/config/schema.js
CHANGED
|
@@ -54,7 +54,9 @@ const artifactRuleSchema = zod_1.z
|
|
|
54
54
|
});
|
|
55
55
|
const packageSchema = zod_1.z
|
|
56
56
|
.object({
|
|
57
|
-
"release-type": zod_1.z
|
|
57
|
+
"release-type": zod_1.z
|
|
58
|
+
.union([zod_1.z.string().min(1), zod_1.z.array(zod_1.z.string().min(1)).min(1)])
|
|
59
|
+
.optional(),
|
|
58
60
|
"package-name": zod_1.z.string().optional(),
|
|
59
61
|
"changelog-file": zod_1.z.string().optional(),
|
|
60
62
|
"changelog-format": zod_1.z.enum(["markdown-changelog", "r-news"]).optional(),
|
|
@@ -83,7 +85,9 @@ exports.configSchema = zod_1.z
|
|
|
83
85
|
"bump-minor-pre-major": zod_1.z.boolean().optional(),
|
|
84
86
|
"allow-stable-major": zod_1.z.boolean().optional(),
|
|
85
87
|
"include-commit-authors": zod_1.z.boolean().optional(),
|
|
86
|
-
"release-type": zod_1.z
|
|
88
|
+
"release-type": zod_1.z
|
|
89
|
+
.union([zod_1.z.string().min(1), zod_1.z.array(zod_1.z.string().min(1)).min(1)])
|
|
90
|
+
.optional(),
|
|
87
91
|
packages: zod_1.z.record(zod_1.z.string().min(1), packageSchema).optional(),
|
|
88
92
|
})
|
|
89
93
|
.strict()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compositeVersionStrategy = compositeVersionStrategy;
|
|
4
|
+
function configForSecondary(config) {
|
|
5
|
+
if (config["version-file"] === undefined) {
|
|
6
|
+
return config;
|
|
7
|
+
}
|
|
8
|
+
const { "version-file": _omit, ...rest } = config;
|
|
9
|
+
return rest;
|
|
10
|
+
}
|
|
11
|
+
function dedupedSorted(values) {
|
|
12
|
+
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
13
|
+
}
|
|
14
|
+
function compositeVersionStrategy(strategies) {
|
|
15
|
+
if (strategies.length === 0) {
|
|
16
|
+
throw new Error("compositeVersionStrategy requires at least one strategy.");
|
|
17
|
+
}
|
|
18
|
+
if (strategies.length === 1) {
|
|
19
|
+
const only = strategies[0];
|
|
20
|
+
if (!only) {
|
|
21
|
+
throw new Error("compositeVersionStrategy requires at least one strategy.");
|
|
22
|
+
}
|
|
23
|
+
return only;
|
|
24
|
+
}
|
|
25
|
+
const primary = strategies[0];
|
|
26
|
+
const secondaries = strategies.slice(1);
|
|
27
|
+
if (!primary) {
|
|
28
|
+
throw new Error("compositeVersionStrategy requires at least one strategy.");
|
|
29
|
+
}
|
|
30
|
+
const composite = {
|
|
31
|
+
name: strategies.map((strategy) => strategy.name).join("+"),
|
|
32
|
+
getVersionFile(config) {
|
|
33
|
+
return primary.getVersionFile(config);
|
|
34
|
+
},
|
|
35
|
+
readVersion(cwd, config) {
|
|
36
|
+
return primary.readVersion(cwd, config);
|
|
37
|
+
},
|
|
38
|
+
writeVersion(cwd, config, version) {
|
|
39
|
+
const updated = [];
|
|
40
|
+
updated.push(...primary.writeVersion(cwd, config, version));
|
|
41
|
+
const secondaryConfig = configForSecondary(config);
|
|
42
|
+
for (const secondary of secondaries) {
|
|
43
|
+
updated.push(...secondary.writeVersion(cwd, secondaryConfig, version));
|
|
44
|
+
}
|
|
45
|
+
return dedupedSorted(updated);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
if (primary.getDefaultChangelogFormat ||
|
|
49
|
+
secondaries.some((strategy) => strategy.getDefaultChangelogFormat)) {
|
|
50
|
+
composite.getDefaultChangelogFormat = () => {
|
|
51
|
+
return primary.getDefaultChangelogFormat?.() ?? "markdown-changelog";
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (primary.validateProject ||
|
|
55
|
+
secondaries.some((strategy) => strategy.validateProject)) {
|
|
56
|
+
composite.validateProject = (cwd, config) => {
|
|
57
|
+
const messages = [];
|
|
58
|
+
const primaryError = primary.validateProject?.(cwd, config) ?? null;
|
|
59
|
+
if (primaryError) {
|
|
60
|
+
messages.push(primaryError);
|
|
61
|
+
}
|
|
62
|
+
const secondaryConfig = configForSecondary(config);
|
|
63
|
+
for (const secondary of secondaries) {
|
|
64
|
+
const error = secondary.validateProject?.(cwd, secondaryConfig) ?? null;
|
|
65
|
+
if (error) {
|
|
66
|
+
messages.push(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return messages.length === 0 ? null : messages.join("\n");
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (primary.readPackageName) {
|
|
73
|
+
composite.readPackageName = (cwd, config) => {
|
|
74
|
+
return primary.readPackageName?.(cwd, config) ?? null;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (primary.propagateDependentPatchImpacts ||
|
|
78
|
+
secondaries.some((strategy) => strategy.propagateDependentPatchImpacts)) {
|
|
79
|
+
composite.propagateDependentPatchImpacts = (cwd, packages) => {
|
|
80
|
+
const impacted = [];
|
|
81
|
+
impacted.push(...(primary.propagateDependentPatchImpacts?.(cwd, packages) ?? []));
|
|
82
|
+
for (const secondary of secondaries) {
|
|
83
|
+
impacted.push(...(secondary.propagateDependentPatchImpacts?.(cwd, packages) ?? []));
|
|
84
|
+
}
|
|
85
|
+
return dedupedSorted(impacted);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (primary.finalizeVersionWrites ||
|
|
89
|
+
secondaries.some((strategy) => strategy.finalizeVersionWrites)) {
|
|
90
|
+
composite.finalizeVersionWrites = (cwd, writes, context) => {
|
|
91
|
+
const updated = [];
|
|
92
|
+
updated.push(...(primary.finalizeVersionWrites?.(cwd, writes, context) ?? []));
|
|
93
|
+
for (const secondary of secondaries) {
|
|
94
|
+
updated.push(...(secondary.finalizeVersionWrites?.(cwd, writes, context) ?? []));
|
|
95
|
+
}
|
|
96
|
+
return dedupedSorted(updated);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return composite;
|
|
100
|
+
}
|
package/dist/strategy/python.js
CHANGED
|
@@ -166,6 +166,67 @@ function readPyProjectFromCwd(cwd) {
|
|
|
166
166
|
const content = node_fs_1.default.readFileSync(target, "utf8");
|
|
167
167
|
return { parsed: parsePyProject(content, "pyproject.toml"), rawPath: target };
|
|
168
168
|
}
|
|
169
|
+
function packageNameFromParsed(parsed) {
|
|
170
|
+
const projectName = parsed.project?.name;
|
|
171
|
+
if (typeof projectName === "string" && projectName.trim().length > 0) {
|
|
172
|
+
return projectName.trim();
|
|
173
|
+
}
|
|
174
|
+
const poetryName = parsed.toolPoetry?.name;
|
|
175
|
+
if (typeof poetryName === "string" && poetryName.trim().length > 0) {
|
|
176
|
+
return poetryName.trim();
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
function normalizeModuleName(name) {
|
|
181
|
+
return name.replace(/[-.]+/gu, "_");
|
|
182
|
+
}
|
|
183
|
+
function findAuxiliaryInitPy(cwd, parsed) {
|
|
184
|
+
const packageName = packageNameFromParsed(parsed);
|
|
185
|
+
if (!packageName) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const moduleName = normalizeModuleName(packageName);
|
|
189
|
+
const candidates = [
|
|
190
|
+
node_path_1.default.join("src", moduleName, "__init__.py"),
|
|
191
|
+
node_path_1.default.join(moduleName, "__init__.py"),
|
|
192
|
+
];
|
|
193
|
+
for (const candidate of candidates) {
|
|
194
|
+
const absolute = node_path_1.default.join(cwd, candidate);
|
|
195
|
+
if (!node_fs_1.default.existsSync(absolute)) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const content = node_fs_1.default.readFileSync(absolute, "utf8");
|
|
199
|
+
if (SOURCE_FILE_VERSION_PATTERN.test(content)) {
|
|
200
|
+
return candidate;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
function tryUpdateInitPyVersion(cwd, relativePath, version) {
|
|
206
|
+
const absolute = node_path_1.default.join(cwd, relativePath);
|
|
207
|
+
const existing = node_fs_1.default.readFileSync(absolute, "utf8");
|
|
208
|
+
if (!SOURCE_FILE_VERSION_PATTERN.test(existing)) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
const updated = writeSourceFileVersion(existing, relativePath, version);
|
|
212
|
+
node_fs_1.default.writeFileSync(absolute, updated, "utf8");
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
function tryUpdatePyProjectVersion(cwd, version) {
|
|
216
|
+
const target = node_path_1.default.join(cwd, "pyproject.toml");
|
|
217
|
+
if (!node_fs_1.default.existsSync(target)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const content = node_fs_1.default.readFileSync(target, "utf8");
|
|
221
|
+
const parsed = parsePyProject(content, "pyproject.toml");
|
|
222
|
+
const { projectVersion, poetryVersion } = lookupPyProjectVersions(parsed);
|
|
223
|
+
if (!projectVersion && !poetryVersion) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
const updated = writePyProjectVersion(content, "pyproject.toml", version);
|
|
227
|
+
node_fs_1.default.writeFileSync(target, updated, "utf8");
|
|
228
|
+
return "pyproject.toml";
|
|
229
|
+
}
|
|
169
230
|
exports.pythonVersionStrategy = {
|
|
170
231
|
name: "python",
|
|
171
232
|
getVersionFile(config) {
|
|
@@ -209,11 +270,27 @@ exports.pythonVersionStrategy = {
|
|
|
209
270
|
throw new Error(`Versionary requires ${versionFile} to exist.`);
|
|
210
271
|
}
|
|
211
272
|
const existing = node_fs_1.default.readFileSync(versionPath, "utf8");
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
273
|
+
const written = [];
|
|
274
|
+
if (isSourceFileMode(versionFile)) {
|
|
275
|
+
const updated = writeSourceFileVersion(existing, versionFile, version);
|
|
276
|
+
node_fs_1.default.writeFileSync(versionPath, updated, "utf8");
|
|
277
|
+
written.push(versionFile);
|
|
278
|
+
const auxiliary = tryUpdatePyProjectVersion(cwd, version);
|
|
279
|
+
if (auxiliary && auxiliary !== versionFile) {
|
|
280
|
+
written.push(auxiliary);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
const updated = writePyProjectVersion(existing, versionFile, version);
|
|
285
|
+
node_fs_1.default.writeFileSync(versionPath, updated, "utf8");
|
|
286
|
+
written.push(versionFile);
|
|
287
|
+
const parsed = parsePyProject(updated, versionFile);
|
|
288
|
+
const initPy = findAuxiliaryInitPy(cwd, parsed);
|
|
289
|
+
if (initPy && tryUpdateInitPyVersion(cwd, initPy, version)) {
|
|
290
|
+
written.push(initPy);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return written;
|
|
217
294
|
},
|
|
218
295
|
readPackageName(cwd, _config) {
|
|
219
296
|
const found = readPyProjectFromCwd(cwd);
|
package/dist/strategy/resolve.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listKnownReleaseTypes = listKnownReleaseTypes;
|
|
4
4
|
exports.resolveVersionStrategy = resolveVersionStrategy;
|
|
5
|
+
const composite_js_1 = require("./composite.js");
|
|
5
6
|
const latex_js_1 = require("./latex.js");
|
|
6
7
|
const node_js_1 = require("./node.js");
|
|
7
8
|
const python_js_1 = require("./python.js");
|
|
@@ -19,12 +20,30 @@ const strategyRegistry = {
|
|
|
19
20
|
function listKnownReleaseTypes() {
|
|
20
21
|
return Object.keys(strategyRegistry).sort((a, b) => a.localeCompare(b));
|
|
21
22
|
}
|
|
22
|
-
function
|
|
23
|
-
const
|
|
24
|
-
const strategy = strategyRegistry[releaseType];
|
|
23
|
+
function resolveSingle(name) {
|
|
24
|
+
const strategy = strategyRegistry[name];
|
|
25
25
|
if (!strategy) {
|
|
26
26
|
const known = listKnownReleaseTypes().join(", ");
|
|
27
|
-
throw new Error(`Unsupported release-type "${
|
|
27
|
+
throw new Error(`Unsupported release-type "${name}". Supported release types: ${known}.`);
|
|
28
28
|
}
|
|
29
29
|
return strategy;
|
|
30
30
|
}
|
|
31
|
+
function resolveVersionStrategy(config) {
|
|
32
|
+
const releaseType = config["release-type"] ?? "simple";
|
|
33
|
+
if (Array.isArray(releaseType)) {
|
|
34
|
+
if (releaseType.length === 0) {
|
|
35
|
+
throw new Error("release-type array must contain at least one strategy name.");
|
|
36
|
+
}
|
|
37
|
+
const seen = new Set();
|
|
38
|
+
const strategies = [];
|
|
39
|
+
for (const name of releaseType) {
|
|
40
|
+
if (seen.has(name)) {
|
|
41
|
+
throw new Error(`release-type array contains duplicate entry "${name}".`);
|
|
42
|
+
}
|
|
43
|
+
seen.add(name);
|
|
44
|
+
strategies.push(resolveSingle(name));
|
|
45
|
+
}
|
|
46
|
+
return (0, composite_js_1.compositeVersionStrategy)(strategies);
|
|
47
|
+
}
|
|
48
|
+
return resolveSingle(releaseType);
|
|
49
|
+
}
|
package/dist/strategy/rust.js
CHANGED
|
@@ -748,6 +748,9 @@ exports.rustVersionStrategy = {
|
|
|
748
748
|
const manifestToPath = new Map();
|
|
749
749
|
for (const pkg of packages) {
|
|
750
750
|
const manifest = pkg.versionFile;
|
|
751
|
+
if (node_path_1.default.posix.basename(normalizeSlashPath(manifest)) !== "Cargo.toml") {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
751
754
|
candidateManifests.push(manifest);
|
|
752
755
|
manifestToPath.set(manifest, pkg.packagePath);
|
|
753
756
|
if (pkg.nextVersion) {
|
|
@@ -763,6 +766,10 @@ exports.rustVersionStrategy = {
|
|
|
763
766
|
finalizeVersionWrites(cwd, writes, _context) {
|
|
764
767
|
const manifestToVersion = {};
|
|
765
768
|
for (const write of writes) {
|
|
769
|
+
if (node_path_1.default.posix.basename(normalizeSlashPath(write.versionFile)) !==
|
|
770
|
+
"Cargo.toml") {
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
766
773
|
manifestToVersion[write.versionFile] = write.version;
|
|
767
774
|
}
|
|
768
775
|
return [
|
package/dist/types/config.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface VersionaryArtifactRule {
|
|
|
9
9
|
pattern?: string;
|
|
10
10
|
}
|
|
11
11
|
export interface VersionaryPackage {
|
|
12
|
-
"release-type"?: string;
|
|
12
|
+
"release-type"?: string | string[];
|
|
13
13
|
"package-name"?: string;
|
|
14
14
|
"changelog-file"?: string;
|
|
15
15
|
"changelog-format"?: VersionaryChangelogFormat;
|
|
@@ -33,7 +33,7 @@ export interface VersionaryConfig {
|
|
|
33
33
|
"bump-minor-pre-major"?: boolean;
|
|
34
34
|
"allow-stable-major"?: boolean;
|
|
35
35
|
"include-commit-authors"?: boolean;
|
|
36
|
-
"release-type"?: string;
|
|
36
|
+
"release-type"?: string | string[];
|
|
37
37
|
packages?: Record<string, VersionaryPackage>;
|
|
38
38
|
}
|
|
39
39
|
export interface LoadedConfig {
|