relacher 0.0.4-rc.2 → 0.0.4-rc.4
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/lib-types/builder/cargo.d.ts +5 -0
- package/lib-types/prepare.d.ts +1 -0
- package/package.json +3 -2
- package/src/builder/cargo.ts +30 -5
- package/src/prepare.ts +37 -1
- package/src/updater/toml.ts +6 -2
package/lib-types/prepare.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare function matchBumpSize(message: string, sizes: SizePatterns): Bum
|
|
|
9
9
|
export declare function evaluateCommitsBump(commits: Commit[], sizes: SizePatterns): BumpSize;
|
|
10
10
|
export declare function topologicalSort(items: IntermediateReport[]): IntermediateReport[];
|
|
11
11
|
export declare function propagateBumps(sorted: IntermediateReport[], rules?: CascadeRules): void;
|
|
12
|
+
export declare function propagateCoupledBumps(sorted: IntermediateReport[]): void;
|
|
12
13
|
export declare function initReportItems(cargoDeps: DependencyConfig[], vcs: VcsProvider, sizes: SizePatterns, cwd: string): Promise<IntermediateReport[]>;
|
|
13
14
|
export declare function prepare(cargoDeps: DependencyConfig[], vcs: VcsProvider, options?: PrepareOptions): Promise<DependencyUpdateReport[]>;
|
|
14
15
|
export declare function finalizeReports(sorted: IntermediateReport[]): DependencyUpdateReport[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "relacher",
|
|
3
|
-
"version": "0.0.4-rc.
|
|
3
|
+
"version": "0.0.4-rc.4",
|
|
4
4
|
"description": "Scriptable release orchestration library for monorepos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -57,8 +57,9 @@
|
|
|
57
57
|
"oxlint": "^1.64.0",
|
|
58
58
|
"prettier": "^3.8.3",
|
|
59
59
|
"typescript": "^6.0.3"
|
|
60
|
-
},
|
|
60
|
+
},
|
|
61
61
|
"dependencies": {
|
|
62
|
+
"@decimalturn/toml-patch": "^2.0.0",
|
|
62
63
|
"smol-toml": "^1.6.1"
|
|
63
64
|
}
|
|
64
65
|
}
|
package/src/builder/cargo.ts
CHANGED
|
@@ -8,6 +8,12 @@ import { tomlUpdate, tomlFallback } from '../updater';
|
|
|
8
8
|
|
|
9
9
|
import { decorateList, type DependencyList } from './shared';
|
|
10
10
|
|
|
11
|
+
declare module './shared' {
|
|
12
|
+
interface DependencyList {
|
|
13
|
+
couple(a: string, b: string): this;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export interface CargoBuilderOptions {
|
|
12
18
|
syncWorkspaceDeps?: boolean;
|
|
13
19
|
}
|
|
@@ -237,22 +243,41 @@ function buildCrateConfig(
|
|
|
237
243
|
};
|
|
238
244
|
}
|
|
239
245
|
|
|
246
|
+
function coupleConfigs(configs: any[], a: string, b: string): boolean {
|
|
247
|
+
const itemA = configs.find((d) => d.name === a);
|
|
248
|
+
const itemB = configs.find((d) => d.name === b);
|
|
249
|
+
if (itemA && itemB) {
|
|
250
|
+
itemA.coupled = itemA.coupled || [];
|
|
251
|
+
itemB.coupled = itemB.coupled || [];
|
|
252
|
+
if (!itemA.coupled.includes(b)) itemA.coupled.push(b);
|
|
253
|
+
if (!itemB.coupled.includes(a)) itemB.coupled.push(a);
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function scanWorkspace(workspaceRoot: string, rootDoc: any): CrateScanner {
|
|
259
|
+
const scanner = new CrateScanner(workspaceRoot, rootDoc.workspace?.dependencies || {});
|
|
260
|
+
if (rootDoc.workspace) registerWorkspaceMembers(scanner, rootDoc);
|
|
261
|
+
else if (rootDoc.package?.name) scanner.registerCrate(workspaceRoot);
|
|
262
|
+
runRecursiveDiscovery(scanner);
|
|
263
|
+
return scanner;
|
|
264
|
+
}
|
|
265
|
+
|
|
240
266
|
export function cargoDeps(cwd: string, options?: CargoBuilderOptions): DependencyList {
|
|
241
267
|
const workspaceRoot = findCargoWorkspaceRoot(cwd);
|
|
242
268
|
const rootCargo = path.join(workspaceRoot, 'Cargo.toml');
|
|
243
269
|
if (!fs.existsSync(rootCargo)) return decorateList([]);
|
|
244
270
|
try {
|
|
245
271
|
const rootDoc = parse(fs.readFileSync(rootCargo, 'utf8')) as any;
|
|
246
|
-
const scanner =
|
|
247
|
-
if (rootDoc.workspace) registerWorkspaceMembers(scanner, rootDoc);
|
|
248
|
-
else if (rootDoc.package?.name) scanner.registerCrate(workspaceRoot);
|
|
249
|
-
runRecursiveDiscovery(scanner);
|
|
272
|
+
const scanner = scanWorkspace(workspaceRoot, rootDoc);
|
|
250
273
|
const hasLock = fs.existsSync(path.join(workspaceRoot, 'Cargo.lock'));
|
|
251
274
|
const localNames = new Set(scanner.crateInfos.map((c) => c.name));
|
|
252
275
|
const configs = scanner.crateInfos.map((info) =>
|
|
253
276
|
buildCrateConfig(info, workspaceRoot, localNames, hasLock, scanner.workspaceDeps, options),
|
|
254
277
|
);
|
|
255
|
-
|
|
278
|
+
const list = decorateList(configs) as any;
|
|
279
|
+
list.couple = (a: string, b: string) => (coupleConfigs(configs, a, b) ? list : list);
|
|
280
|
+
return list;
|
|
256
281
|
} catch {
|
|
257
282
|
return decorateList([]);
|
|
258
283
|
}
|
package/src/prepare.ts
CHANGED
|
@@ -125,6 +125,39 @@ export function propagateBumps(sorted: IntermediateReport[], rules?: CascadeRule
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
export function propagateCoupledBumps(sorted: IntermediateReport[]): void {
|
|
129
|
+
const priority: Record<BumpSize, number> = { skip: 0, patch: 1, minor: 2, major: 3 };
|
|
130
|
+
const bumps: BumpSize[] = ['skip', 'patch', 'minor', 'major'];
|
|
131
|
+
|
|
132
|
+
let changed = true;
|
|
133
|
+
while (changed) {
|
|
134
|
+
changed = false;
|
|
135
|
+
for (const item of sorted) {
|
|
136
|
+
const coupledNames = (item as any).coupled || [];
|
|
137
|
+
for (const name of coupledNames) {
|
|
138
|
+
const other = sorted.find((r) => r.name === name);
|
|
139
|
+
if (other) {
|
|
140
|
+
const maxPriority = Math.max(priority[item.bump], priority[other.bump]);
|
|
141
|
+
const targetBump = bumps[maxPriority]!;
|
|
142
|
+
if (item.bump !== targetBump) {
|
|
143
|
+
item.bump = targetBump;
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
if (other.bump !== targetBump) {
|
|
147
|
+
other.bump = targetBump;
|
|
148
|
+
changed = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const item of sorted) {
|
|
156
|
+
item.newVersion =
|
|
157
|
+
item.bump !== 'skip' ? bumpVersion(item.currentVersion, item.bump) : item.currentVersion;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
128
161
|
export async function initReportItems(
|
|
129
162
|
cargoDeps: DependencyConfig[],
|
|
130
163
|
vcs: VcsProvider,
|
|
@@ -165,7 +198,8 @@ export async function initReportItems(
|
|
|
165
198
|
depends: dep.depends || [],
|
|
166
199
|
isErroneous,
|
|
167
200
|
isFirstRelease: isFallback,
|
|
168
|
-
|
|
201
|
+
coupled: (dep as any).coupled || [],
|
|
202
|
+
} as any);
|
|
169
203
|
}
|
|
170
204
|
return reports;
|
|
171
205
|
}
|
|
@@ -180,6 +214,7 @@ export async function prepare(
|
|
|
180
214
|
const items = await initReportItems(cargoDeps, vcs, sizes, cwd);
|
|
181
215
|
const sorted = topologicalSort(items);
|
|
182
216
|
propagateBumps(sorted, options.cascade);
|
|
217
|
+
propagateCoupledBumps(sorted);
|
|
183
218
|
return finalizeReports(sorted);
|
|
184
219
|
}
|
|
185
220
|
|
|
@@ -203,6 +238,7 @@ export function finalizeReports(sorted: IntermediateReport[]): DependencyUpdateR
|
|
|
203
238
|
depends: item.depends,
|
|
204
239
|
isErroneous: item.isErroneous,
|
|
205
240
|
isFirstRelease: item.isFirstRelease,
|
|
241
|
+
coupled: (item as any).coupled || [],
|
|
206
242
|
}));
|
|
207
243
|
}
|
|
208
244
|
|
package/src/updater/toml.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { patch } from '@decimalturn/toml-patch';
|
|
5
|
+
import { parse } from 'smol-toml';
|
|
5
6
|
|
|
6
7
|
import type { DependencyUpdateReport } from '../types';
|
|
7
8
|
|
|
@@ -44,6 +45,9 @@ export const tomlUpdate = updateBuilder<TomlUpdateParams>({
|
|
|
44
45
|
// Safely mutate the object using the user provided callback
|
|
45
46
|
params(parsed, report, reports);
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
// Patch the original document string using the mutated JS object
|
|
49
|
+
const updatedContent = patch(content, parsed);
|
|
50
|
+
|
|
51
|
+
fs.writeFileSync(filePath, updatedContent);
|
|
48
52
|
},
|
|
49
53
|
});
|