versionary 0.3.0 → 0.5.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 +71 -28
- package/dist/app/release/artifact-rules.d.ts +3 -0
- package/dist/app/release/artifact-rules.js +186 -0
- package/dist/app/release/pr.d.ts +7 -2
- package/dist/app/release/pr.js +38 -20
- package/dist/app/release/recovery.d.ts +3 -0
- package/dist/app/release/recovery.js +1 -1
- package/dist/app/release/release.d.ts +18 -0
- package/dist/app/release/release.js +28 -7
- package/dist/app/release/state.d.ts +0 -1
- package/dist/app/release/state.js +36 -2
- package/dist/cli/index.js +60 -6
- package/dist/config/schema.js +33 -1
- package/dist/domain/release/changelog.js +1 -1
- package/dist/domain/release/plan.js +62 -16
- package/dist/domain/strategy/node.js +41 -11
- package/dist/domain/strategy/package-context.d.ts +7 -0
- package/dist/domain/strategy/package-context.js +49 -0
- package/dist/domain/strategy/r.d.ts +2 -0
- package/dist/domain/strategy/r.js +46 -0
- package/dist/domain/strategy/resolve.js +8 -0
- package/dist/domain/strategy/rust.d.ts +5 -0
- package/dist/domain/strategy/rust.js +477 -0
- package/dist/verify/verify-project.js +14 -1
- package/package.json +3 -2
|
@@ -0,0 +1,477 @@
|
|
|
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.rustVersionStrategy = void 0;
|
|
7
|
+
exports.applyRustWorkspaceDependencyUpdates = applyRustWorkspaceDependencyUpdates;
|
|
8
|
+
exports.detectRustDependencyImpact = detectRustDependencyImpact;
|
|
9
|
+
exports.toCargoManifestPath = toCargoManifestPath;
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const toml_1 = __importDefault(require("@iarna/toml"));
|
|
13
|
+
const ROOT_DEPENDENCY_SECTIONS = new Set([
|
|
14
|
+
"dependencies",
|
|
15
|
+
"dev-dependencies",
|
|
16
|
+
"build-dependencies",
|
|
17
|
+
]);
|
|
18
|
+
function normalizeSlashPath(input) {
|
|
19
|
+
return input.replaceAll("\\", "/");
|
|
20
|
+
}
|
|
21
|
+
function hasGlobPattern(pattern) {
|
|
22
|
+
return /[*?]/u.test(pattern);
|
|
23
|
+
}
|
|
24
|
+
function escapeRegex(input) {
|
|
25
|
+
return input.replace(/[.+^${}()|\\]/gu, "\\$&");
|
|
26
|
+
}
|
|
27
|
+
function globToRegex(pattern) {
|
|
28
|
+
const normalized = normalizeSlashPath(pattern);
|
|
29
|
+
let source = "^";
|
|
30
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
31
|
+
const current = normalized[index] ?? "";
|
|
32
|
+
const next = normalized[index + 1] ?? "";
|
|
33
|
+
if (current === "*" && next === "*") {
|
|
34
|
+
source += ".*";
|
|
35
|
+
index += 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (current === "*") {
|
|
39
|
+
source += "[^/]*";
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (current === "?") {
|
|
43
|
+
source += "[^/]";
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
source += escapeRegex(current);
|
|
47
|
+
}
|
|
48
|
+
source += "$";
|
|
49
|
+
return new RegExp(source, "u");
|
|
50
|
+
}
|
|
51
|
+
function findCargoManifestDirectories(rootDir) {
|
|
52
|
+
const results = new Set();
|
|
53
|
+
const queue = [rootDir];
|
|
54
|
+
while (queue.length > 0) {
|
|
55
|
+
const currentDir = queue.shift();
|
|
56
|
+
if (!currentDir) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const entries = node_fs_1.default.readdirSync(currentDir, {
|
|
60
|
+
withFileTypes: true,
|
|
61
|
+
});
|
|
62
|
+
let hasCargoManifest = false;
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
const fullPath = node_path_1.default.join(currentDir, entry.name);
|
|
65
|
+
if (entry.isFile() && entry.name === "Cargo.toml") {
|
|
66
|
+
hasCargoManifest = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (entry.isDirectory()) {
|
|
70
|
+
queue.push(fullPath);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (hasCargoManifest) {
|
|
74
|
+
const rel = normalizeSlashPath(node_path_1.default.relative(rootDir, currentDir));
|
|
75
|
+
results.add(rel === "" ? "." : rel);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [...results].sort((a, b) => a.localeCompare(b));
|
|
79
|
+
}
|
|
80
|
+
function collectAllCrateManifests(cwd) {
|
|
81
|
+
const manifests = [];
|
|
82
|
+
const cargoDirs = findCargoManifestDirectories(cwd);
|
|
83
|
+
for (const dir of cargoDirs) {
|
|
84
|
+
const manifest = dir === "."
|
|
85
|
+
? "Cargo.toml"
|
|
86
|
+
: normalizeSlashPath(node_path_1.default.posix.join(dir, "Cargo.toml"));
|
|
87
|
+
const manifestPath = node_path_1.default.join(cwd, manifest);
|
|
88
|
+
if (!node_fs_1.default.existsSync(manifestPath)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(manifestPath, "utf8");
|
|
92
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
manifests.push(manifest);
|
|
96
|
+
}
|
|
97
|
+
return manifests.sort((a, b) => a.localeCompare(b));
|
|
98
|
+
}
|
|
99
|
+
function parseCargoManifest(versionFile, cargoTomlRaw) {
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = toml_1.default.parse(cargoTomlRaw);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
106
|
+
throw new Error(`Failed to parse ${versionFile}: ${message}`);
|
|
107
|
+
}
|
|
108
|
+
const parsedRecord = parsed;
|
|
109
|
+
const packageTable = parsedRecord.package && typeof parsedRecord.package === "object"
|
|
110
|
+
? parsedRecord.package
|
|
111
|
+
: null;
|
|
112
|
+
const workspaceTable = parsedRecord.workspace && typeof parsedRecord.workspace === "object"
|
|
113
|
+
? parsedRecord.workspace
|
|
114
|
+
: null;
|
|
115
|
+
return { packageTable, workspaceTable };
|
|
116
|
+
}
|
|
117
|
+
function isCrateManifest(versionFile, cargoTomlRaw) {
|
|
118
|
+
const parsed = parseCargoManifest(versionFile, cargoTomlRaw);
|
|
119
|
+
return parsed.packageTable !== null;
|
|
120
|
+
}
|
|
121
|
+
function readWorkspaceMemberPatterns(workspaceTable) {
|
|
122
|
+
if (!workspaceTable) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
const members = workspaceTable.members;
|
|
126
|
+
if (!Array.isArray(members)) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
return members
|
|
130
|
+
.filter((member) => typeof member === "string")
|
|
131
|
+
.map((member) => normalizeSlashPath(member.trim()))
|
|
132
|
+
.filter((member) => member.length > 0);
|
|
133
|
+
}
|
|
134
|
+
function readWorkspaceExcludes(workspaceTable) {
|
|
135
|
+
if (!workspaceTable) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const excludes = workspaceTable.exclude;
|
|
139
|
+
if (!Array.isArray(excludes)) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
return excludes
|
|
143
|
+
.filter((entry) => typeof entry === "string")
|
|
144
|
+
.map((entry) => normalizeSlashPath(entry.trim()))
|
|
145
|
+
.filter((entry) => entry.length > 0);
|
|
146
|
+
}
|
|
147
|
+
function resolveWorkspaceMemberManifests(rootDir, workspaceTable) {
|
|
148
|
+
const memberPatterns = readWorkspaceMemberPatterns(workspaceTable);
|
|
149
|
+
if (memberPatterns.length === 0) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
const excludes = readWorkspaceExcludes(workspaceTable);
|
|
153
|
+
const excludeRegexes = excludes.map((pattern) => globToRegex(pattern));
|
|
154
|
+
const cargoDirs = findCargoManifestDirectories(rootDir);
|
|
155
|
+
const manifests = new Set();
|
|
156
|
+
for (const pattern of memberPatterns) {
|
|
157
|
+
if (hasGlobPattern(pattern)) {
|
|
158
|
+
const regex = globToRegex(pattern);
|
|
159
|
+
for (const dir of cargoDirs) {
|
|
160
|
+
if (regex.test(dir)) {
|
|
161
|
+
manifests.add(normalizeSlashPath(node_path_1.default.posix.join(dir, "Cargo.toml")));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const candidateDir = normalizeSlashPath(pattern);
|
|
167
|
+
if (excludeRegexes.some((regex) => regex.test(candidateDir))) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const cargoPath = node_path_1.default.join(rootDir, candidateDir, "Cargo.toml");
|
|
171
|
+
if (node_fs_1.default.existsSync(cargoPath)) {
|
|
172
|
+
manifests.add(normalizeSlashPath(node_path_1.default.posix.join(candidateDir, "Cargo.toml")));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const filtered = [...manifests].filter((manifestPath) => {
|
|
176
|
+
const dir = normalizeSlashPath(node_path_1.default.posix.dirname(manifestPath));
|
|
177
|
+
return !excludeRegexes.some((regex) => regex.test(dir));
|
|
178
|
+
});
|
|
179
|
+
return filtered.sort((a, b) => a.localeCompare(b));
|
|
180
|
+
}
|
|
181
|
+
function collectRustTargetManifests(cwd, versionFile, includeWorkspaceMembers) {
|
|
182
|
+
if (node_path_1.default.basename(versionFile) !== "Cargo.toml") {
|
|
183
|
+
throw new Error(`Rust strategy requires "version-file" to point to a Cargo.toml manifest (received "${versionFile}").`);
|
|
184
|
+
}
|
|
185
|
+
const rootManifestPath = node_path_1.default.join(cwd, versionFile);
|
|
186
|
+
if (!node_fs_1.default.existsSync(rootManifestPath)) {
|
|
187
|
+
throw new Error(`Versionary requires ${versionFile} to exist.`);
|
|
188
|
+
}
|
|
189
|
+
const rootRaw = node_fs_1.default.readFileSync(rootManifestPath, "utf8");
|
|
190
|
+
const parsedRoot = parseCargoManifest(versionFile, rootRaw);
|
|
191
|
+
const rootIsCrate = parsedRoot.packageTable !== null;
|
|
192
|
+
const rootDir = node_path_1.default.dirname(rootManifestPath);
|
|
193
|
+
const workspaceMembers = includeWorkspaceMembers
|
|
194
|
+
? resolveWorkspaceMemberManifests(rootDir, parsedRoot.workspaceTable)
|
|
195
|
+
: [];
|
|
196
|
+
if (rootIsCrate) {
|
|
197
|
+
const relRoot = normalizeSlashPath(node_path_1.default.relative(cwd, rootManifestPath));
|
|
198
|
+
return [...new Set([relRoot, ...workspaceMembers])].sort((a, b) => a.localeCompare(b));
|
|
199
|
+
}
|
|
200
|
+
if (workspaceMembers.length > 0) {
|
|
201
|
+
return workspaceMembers;
|
|
202
|
+
}
|
|
203
|
+
throw new Error(`Configured rust target "${versionFile}" is not a Rust crate manifest. Expected [package].version or [workspace].members with crate Cargo.toml files.`);
|
|
204
|
+
}
|
|
205
|
+
function readCargoVersion(cargoTomlRaw, versionFile) {
|
|
206
|
+
const { packageTable } = parseCargoManifest(versionFile, cargoTomlRaw);
|
|
207
|
+
if (!packageTable || typeof packageTable !== "object") {
|
|
208
|
+
throw new Error(`${versionFile} is missing [package].version. Add [package] with a SemVer version.`);
|
|
209
|
+
}
|
|
210
|
+
const rawVersion = packageTable.version;
|
|
211
|
+
if (rawVersion === undefined) {
|
|
212
|
+
throw new Error(`${versionFile} is missing [package].version. Add [package] with a SemVer version.`);
|
|
213
|
+
}
|
|
214
|
+
if (typeof rawVersion !== "string" || rawVersion.trim().length === 0) {
|
|
215
|
+
throw new Error(`${versionFile} has invalid [package].version. Expected a non-empty SemVer string.`);
|
|
216
|
+
}
|
|
217
|
+
return rawVersion.trim();
|
|
218
|
+
}
|
|
219
|
+
function readCargoPackageName(cargoTomlRaw, versionFile) {
|
|
220
|
+
const { packageTable } = parseCargoManifest(versionFile, cargoTomlRaw);
|
|
221
|
+
if (!packageTable || typeof packageTable !== "object") {
|
|
222
|
+
throw new Error(`${versionFile} is missing [package].name. Add [package] with a crate name.`);
|
|
223
|
+
}
|
|
224
|
+
const rawName = packageTable.name;
|
|
225
|
+
if (typeof rawName !== "string" || rawName.trim().length === 0) {
|
|
226
|
+
throw new Error(`${versionFile} has invalid [package].name. Expected a non-empty crate name.`);
|
|
227
|
+
}
|
|
228
|
+
return rawName.trim();
|
|
229
|
+
}
|
|
230
|
+
function writeCargoVersion(cargoTomlRaw, versionFile, version) {
|
|
231
|
+
const lineEnding = cargoTomlRaw.includes("\r\n") ? "\r\n" : "\n";
|
|
232
|
+
const hasFinalLineEnding = cargoTomlRaw.endsWith("\n") || cargoTomlRaw.endsWith("\r\n");
|
|
233
|
+
const lines = cargoTomlRaw.split(/\r?\n/u);
|
|
234
|
+
let inPackageSection = false;
|
|
235
|
+
let foundPackageSection = false;
|
|
236
|
+
let replacedVersion = false;
|
|
237
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
238
|
+
const line = lines[index] ?? "";
|
|
239
|
+
const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/u);
|
|
240
|
+
if (sectionMatch) {
|
|
241
|
+
const section = sectionMatch[1]?.trim();
|
|
242
|
+
inPackageSection = section === "package";
|
|
243
|
+
if (inPackageSection) {
|
|
244
|
+
foundPackageSection = true;
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (!inPackageSection) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const versionMatch = line.match(/^(\s*version\s*=\s*)(["'])([^"']*)(\2)(\s*(?:#.*)?)?$/u);
|
|
252
|
+
if (!versionMatch) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const [, prefix = "", quote = '"', , , suffix = ""] = versionMatch;
|
|
256
|
+
lines[index] = `${prefix}${quote}${version}${quote}${suffix}`;
|
|
257
|
+
replacedVersion = true;
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
if (!foundPackageSection) {
|
|
261
|
+
throw new Error(`${versionFile} is missing [package].version. Add [package] with a SemVer version.`);
|
|
262
|
+
}
|
|
263
|
+
if (!replacedVersion) {
|
|
264
|
+
throw new Error(`${versionFile} is missing [package].version. Add [package] with a SemVer version.`);
|
|
265
|
+
}
|
|
266
|
+
let updated = lines.join(lineEnding);
|
|
267
|
+
if (hasFinalLineEnding && !updated.endsWith(lineEnding)) {
|
|
268
|
+
updated += lineEnding;
|
|
269
|
+
}
|
|
270
|
+
if (!hasFinalLineEnding && updated.endsWith(lineEnding)) {
|
|
271
|
+
updated = updated.slice(0, -lineEnding.length);
|
|
272
|
+
}
|
|
273
|
+
return updated;
|
|
274
|
+
}
|
|
275
|
+
function isDependencySection(section) {
|
|
276
|
+
if (ROOT_DEPENDENCY_SECTIONS.has(section)) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
if (!section.startsWith("target.")) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
return (section.endsWith(".dependencies") ||
|
|
283
|
+
section.endsWith(".dev-dependencies") ||
|
|
284
|
+
section.endsWith(".build-dependencies"));
|
|
285
|
+
}
|
|
286
|
+
function parseDependencyName(line) {
|
|
287
|
+
const match = line.match(/^\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_-]+))\s*=/u);
|
|
288
|
+
return match?.[1] ?? match?.[2] ?? match?.[3] ?? null;
|
|
289
|
+
}
|
|
290
|
+
function writeInternalDependencyVersionInLine(line, dependencyName, versionByDependency) {
|
|
291
|
+
const nextVersion = versionByDependency.get(dependencyName);
|
|
292
|
+
if (!nextVersion) {
|
|
293
|
+
return line;
|
|
294
|
+
}
|
|
295
|
+
const stringVersionMatch = line.match(/^(\s*(?:"[^"]+"|'[^']+'|[A-Za-z0-9_-]+)\s*=\s*)(["'])([^"']*)(\2)(\s*(?:#.*)?)?$/u);
|
|
296
|
+
if (stringVersionMatch) {
|
|
297
|
+
const [, prefix = "", quote = '"', , , suffix = ""] = stringVersionMatch;
|
|
298
|
+
return `${prefix}${quote}${nextVersion}${quote}${suffix}`;
|
|
299
|
+
}
|
|
300
|
+
const inlineTableMatch = line.match(/^(\s*(?:"[^"]+"|'[^']+'|[A-Za-z0-9_-]+)\s*=\s*\{)(.*)(\}\s*(?:#.*)?)$/u);
|
|
301
|
+
if (!inlineTableMatch) {
|
|
302
|
+
return line;
|
|
303
|
+
}
|
|
304
|
+
const [, prefix = "", tableBody = "", suffix = ""] = inlineTableMatch;
|
|
305
|
+
const updatedTableBody = tableBody.replace(/(\bversion\s*=\s*)(["'])([^"']*)(\2)/u, `$1$2${nextVersion}$4`);
|
|
306
|
+
if (updatedTableBody === tableBody) {
|
|
307
|
+
return line;
|
|
308
|
+
}
|
|
309
|
+
return `${prefix}${updatedTableBody}${suffix}`;
|
|
310
|
+
}
|
|
311
|
+
function writeInternalDependencyVersions(cargoTomlRaw, internalCrates, version) {
|
|
312
|
+
if (internalCrates.size === 0) {
|
|
313
|
+
return cargoTomlRaw;
|
|
314
|
+
}
|
|
315
|
+
const versionByDependency = new Map();
|
|
316
|
+
for (const crateName of internalCrates) {
|
|
317
|
+
versionByDependency.set(crateName, version);
|
|
318
|
+
}
|
|
319
|
+
return writeMappedDependencyVersions(cargoTomlRaw, versionByDependency);
|
|
320
|
+
}
|
|
321
|
+
function writeMappedDependencyVersions(cargoTomlRaw, versionByDependency) {
|
|
322
|
+
if (versionByDependency.size === 0) {
|
|
323
|
+
return cargoTomlRaw;
|
|
324
|
+
}
|
|
325
|
+
const lineEnding = cargoTomlRaw.includes("\r\n") ? "\r\n" : "\n";
|
|
326
|
+
const hasFinalLineEnding = cargoTomlRaw.endsWith("\n") || cargoTomlRaw.endsWith("\r\n");
|
|
327
|
+
const lines = cargoTomlRaw.split(/\r?\n/u);
|
|
328
|
+
let currentSection = null;
|
|
329
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
330
|
+
const line = lines[index] ?? "";
|
|
331
|
+
const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/u);
|
|
332
|
+
if (sectionMatch) {
|
|
333
|
+
currentSection = sectionMatch[1]?.trim() ?? null;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (!currentSection || !isDependencySection(currentSection)) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const dependencyName = parseDependencyName(line);
|
|
340
|
+
if (!dependencyName) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
lines[index] = writeInternalDependencyVersionInLine(line, dependencyName, versionByDependency);
|
|
344
|
+
}
|
|
345
|
+
let updated = lines.join(lineEnding);
|
|
346
|
+
if (hasFinalLineEnding && !updated.endsWith(lineEnding)) {
|
|
347
|
+
updated += lineEnding;
|
|
348
|
+
}
|
|
349
|
+
if (!hasFinalLineEnding && updated.endsWith(lineEnding)) {
|
|
350
|
+
updated = updated.slice(0, -lineEnding.length);
|
|
351
|
+
}
|
|
352
|
+
return updated;
|
|
353
|
+
}
|
|
354
|
+
function readPackageNameForManifest(cwd, manifest) {
|
|
355
|
+
const manifestPath = node_path_1.default.join(cwd, manifest);
|
|
356
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(manifestPath, "utf8");
|
|
357
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
358
|
+
throw new Error(`Configured rust target "${manifest}" is not a Rust crate manifest to update.`);
|
|
359
|
+
}
|
|
360
|
+
return readCargoPackageName(cargoTomlRaw, manifest);
|
|
361
|
+
}
|
|
362
|
+
function applyRustWorkspaceDependencyUpdates(cwd, manifestToVersion) {
|
|
363
|
+
const versionByDependency = new Map();
|
|
364
|
+
for (const [manifest, version] of Object.entries(manifestToVersion)) {
|
|
365
|
+
if (!version) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
const crateName = readPackageNameForManifest(cwd, manifest);
|
|
369
|
+
versionByDependency.set(crateName, version);
|
|
370
|
+
}
|
|
371
|
+
if (versionByDependency.size === 0) {
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
const updatedFiles = [];
|
|
375
|
+
const manifests = collectAllCrateManifests(cwd);
|
|
376
|
+
for (const manifest of manifests) {
|
|
377
|
+
const manifestPath = node_path_1.default.join(cwd, manifest);
|
|
378
|
+
if (!node_fs_1.default.existsSync(manifestPath)) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(manifestPath, "utf8");
|
|
382
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const next = writeMappedDependencyVersions(cargoTomlRaw, versionByDependency);
|
|
386
|
+
if (next !== cargoTomlRaw) {
|
|
387
|
+
node_fs_1.default.writeFileSync(manifestPath, next, "utf8");
|
|
388
|
+
updatedFiles.push(manifest);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return updatedFiles;
|
|
392
|
+
}
|
|
393
|
+
function detectRustDependencyImpact(cwd, manifestToVersion, candidateManifests) {
|
|
394
|
+
const versionByDependency = new Map();
|
|
395
|
+
for (const [manifest, version] of Object.entries(manifestToVersion)) {
|
|
396
|
+
if (!version) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const crateName = readPackageNameForManifest(cwd, manifest);
|
|
400
|
+
versionByDependency.set(crateName, version);
|
|
401
|
+
}
|
|
402
|
+
if (versionByDependency.size === 0) {
|
|
403
|
+
return [];
|
|
404
|
+
}
|
|
405
|
+
const impacted = [];
|
|
406
|
+
for (const manifest of [...new Set(candidateManifests)].sort((a, b) => a.localeCompare(b))) {
|
|
407
|
+
const manifestPath = node_path_1.default.join(cwd, manifest);
|
|
408
|
+
if (!node_fs_1.default.existsSync(manifestPath)) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(manifestPath, "utf8");
|
|
412
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const next = writeMappedDependencyVersions(cargoTomlRaw, versionByDependency);
|
|
416
|
+
if (next !== cargoTomlRaw) {
|
|
417
|
+
impacted.push(manifest);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return impacted;
|
|
421
|
+
}
|
|
422
|
+
function toCargoManifestPath(packagePath) {
|
|
423
|
+
return packagePath === "."
|
|
424
|
+
? "Cargo.toml"
|
|
425
|
+
: normalizeSlashPath(node_path_1.default.posix.join(packagePath, "Cargo.toml"));
|
|
426
|
+
}
|
|
427
|
+
exports.rustVersionStrategy = {
|
|
428
|
+
name: "rust",
|
|
429
|
+
getVersionFile(config) {
|
|
430
|
+
return config["version-file"] ?? "Cargo.toml";
|
|
431
|
+
},
|
|
432
|
+
readVersion(cwd, config) {
|
|
433
|
+
const versionFile = this.getVersionFile(config);
|
|
434
|
+
const manifests = collectRustTargetManifests(cwd, versionFile, !config.packages);
|
|
435
|
+
const selectedManifest = manifests[0];
|
|
436
|
+
if (!selectedManifest) {
|
|
437
|
+
throw new Error(`Configured rust target "${versionFile}" did not resolve to a Rust crate manifest.`);
|
|
438
|
+
}
|
|
439
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(node_path_1.default.join(cwd, selectedManifest), "utf8");
|
|
440
|
+
return readCargoVersion(cargoTomlRaw, selectedManifest);
|
|
441
|
+
},
|
|
442
|
+
writeVersion(cwd, config, version) {
|
|
443
|
+
const versionFile = this.getVersionFile(config);
|
|
444
|
+
const manifests = collectRustTargetManifests(cwd, versionFile, !config.packages);
|
|
445
|
+
const updatedFiles = [];
|
|
446
|
+
const internalCrates = new Set();
|
|
447
|
+
for (const manifest of manifests) {
|
|
448
|
+
const versionPath = node_path_1.default.join(cwd, manifest);
|
|
449
|
+
if (!node_fs_1.default.existsSync(versionPath)) {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(versionPath, "utf8");
|
|
453
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
internalCrates.add(readCargoPackageName(cargoTomlRaw, manifest));
|
|
457
|
+
}
|
|
458
|
+
for (const manifest of manifests) {
|
|
459
|
+
const versionPath = node_path_1.default.join(cwd, manifest);
|
|
460
|
+
if (!node_fs_1.default.existsSync(versionPath)) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
const cargoTomlRaw = node_fs_1.default.readFileSync(versionPath, "utf8");
|
|
464
|
+
if (!isCrateManifest(manifest, cargoTomlRaw)) {
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
readCargoVersion(cargoTomlRaw, manifest);
|
|
468
|
+
const updatedCargoToml = writeInternalDependencyVersions(writeCargoVersion(cargoTomlRaw, manifest, version), internalCrates, version);
|
|
469
|
+
node_fs_1.default.writeFileSync(versionPath, updatedCargoToml, "utf8");
|
|
470
|
+
updatedFiles.push(manifest);
|
|
471
|
+
}
|
|
472
|
+
if (updatedFiles.length === 0) {
|
|
473
|
+
throw new Error(`Configured rust target "${versionFile}" did not resolve to a Rust crate manifest to update.`);
|
|
474
|
+
}
|
|
475
|
+
return updatedFiles.sort((a, b) => a.localeCompare(b));
|
|
476
|
+
},
|
|
477
|
+
};
|
|
@@ -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 package_context_js_1 = require("../domain/strategy/package-context.js");
|
|
10
11
|
const resolve_js_1 = require("../domain/strategy/resolve.js");
|
|
11
12
|
function verifyProject(cwd = process.cwd()) {
|
|
12
13
|
const checks = [];
|
|
@@ -25,7 +26,7 @@ function verifyProject(cwd = process.cwd()) {
|
|
|
25
26
|
details: exists ? "Version file exists" : `Missing ${versionFile}`,
|
|
26
27
|
});
|
|
27
28
|
if (config.config.packages) {
|
|
28
|
-
for (const pkgPathRaw of Object.
|
|
29
|
+
for (const [pkgPathRaw, packageConfig] of Object.entries(config.config.packages)) {
|
|
29
30
|
const pkgPath = node_path_1.default.join(cwd, pkgPathRaw);
|
|
30
31
|
const exists = node_fs_1.default.existsSync(pkgPath);
|
|
31
32
|
checks.push({
|
|
@@ -33,6 +34,18 @@ function verifyProject(cwd = process.cwd()) {
|
|
|
33
34
|
ok: exists,
|
|
34
35
|
details: exists ? "Path exists" : `Missing path: ${pkgPathRaw}`,
|
|
35
36
|
});
|
|
37
|
+
if (exists) {
|
|
38
|
+
const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(config.config, pkgPathRaw, packageConfig);
|
|
39
|
+
const packageVersionFile = packageContext.versionFile;
|
|
40
|
+
const packageVersionExists = node_fs_1.default.existsSync(node_path_1.default.join(cwd, packageVersionFile));
|
|
41
|
+
checks.push({
|
|
42
|
+
name: `version-file:${packageVersionFile}`,
|
|
43
|
+
ok: packageVersionExists,
|
|
44
|
+
details: packageVersionExists
|
|
45
|
+
? "Version file exists"
|
|
46
|
+
: `Missing ${packageVersionFile}`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
36
49
|
}
|
|
37
50
|
}
|
|
38
51
|
const ok = checks.every((c) => c.ok);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versionary",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Automatic release framework based on conventional commits and semantic versioning",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"releasing",
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
"main": "dist/index.js",
|
|
28
28
|
"types": "dist/index.d.ts",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@octokit/rest": "^22.0.0",
|
|
31
30
|
"@iarna/toml": "^2.2.5",
|
|
31
|
+
"@octokit/rest": "^22.0.0",
|
|
32
32
|
"jsonc-parser": "^3.3.1",
|
|
33
|
+
"yaml": "^2.8.3",
|
|
33
34
|
"zod": "^4.1.12"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|