@ucdjs/release-scripts 0.1.0-beta.3 → 0.1.0-beta.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/dist/index.d.mts +24 -10
- package/dist/index.mjs +397 -326
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//#region src/workspace.d.ts
|
|
2
|
+
interface WorkspacePackage {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
path: string;
|
|
6
|
+
packageJson: PackageJson;
|
|
7
|
+
workspaceDependencies: string[];
|
|
8
|
+
workspaceDevDependencies: string[];
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
1
11
|
//#region src/types.d.ts
|
|
2
12
|
type BumpKind = "none" | "patch" | "minor" | "major";
|
|
3
13
|
interface PackageJson {
|
|
@@ -6,16 +16,9 @@ interface PackageJson {
|
|
|
6
16
|
dependencies?: Record<string, string>;
|
|
7
17
|
devDependencies?: Record<string, string>;
|
|
8
18
|
peerDependencies?: Record<string, string>;
|
|
19
|
+
private?: boolean;
|
|
9
20
|
[key: string]: unknown;
|
|
10
21
|
}
|
|
11
|
-
interface WorkspacePackage {
|
|
12
|
-
name: string;
|
|
13
|
-
version: string;
|
|
14
|
-
path: string;
|
|
15
|
-
packageJson: PackageJson;
|
|
16
|
-
workspaceDependencies: string[];
|
|
17
|
-
workspaceDevDependencies: string[];
|
|
18
|
-
}
|
|
19
22
|
interface FindWorkspacePackagesOptions {
|
|
20
23
|
/**
|
|
21
24
|
* Package names to exclude
|
|
@@ -100,8 +103,19 @@ interface ReleaseOptions {
|
|
|
100
103
|
*/
|
|
101
104
|
githubToken: string;
|
|
102
105
|
pullRequest?: {
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Title for the release pull request
|
|
108
|
+
*/
|
|
109
|
+
title?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Body for the release pull request
|
|
112
|
+
*
|
|
113
|
+
* If not provided, a default body will be generated.
|
|
114
|
+
*
|
|
115
|
+
* NOTE:
|
|
116
|
+
* You can use custom template expressions, see [h3js/rendu](https://github.com/h3js/rendu)
|
|
117
|
+
*/
|
|
118
|
+
body?: string;
|
|
105
119
|
};
|
|
106
120
|
}
|
|
107
121
|
interface ReleaseResult {
|
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { getCommits } from "commit-parser";
|
|
3
|
-
import createDebug from "debug";
|
|
4
3
|
import farver from "farver";
|
|
5
4
|
import { exec } from "tinyexec";
|
|
5
|
+
import { dedent } from "@luxass/utils";
|
|
6
|
+
import { Eta } from "eta";
|
|
6
7
|
import { readFile, writeFile } from "node:fs/promises";
|
|
7
8
|
import { join } from "node:path";
|
|
8
9
|
import prompts from "prompts";
|
|
9
10
|
|
|
10
|
-
//#region src/logger.ts
|
|
11
|
-
function createDebugger(namespace) {
|
|
12
|
-
const debug$2 = createDebug(namespace);
|
|
13
|
-
if (debug$2.enabled) return debug$2;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
//#endregion
|
|
17
11
|
//#region src/utils.ts
|
|
18
12
|
const globalOptions = { dryRun: false };
|
|
13
|
+
const isCI = typeof process.env.CI === "string" && process.env.CI !== "" && process.env.CI.toLowerCase() !== "false";
|
|
19
14
|
async function run(bin, args, opts = {}) {
|
|
20
15
|
return exec(bin, args, {
|
|
21
16
|
throwOnError: true,
|
|
@@ -33,7 +28,6 @@ const runIfNotDry = globalOptions.dryRun ? dryRun : run;
|
|
|
33
28
|
|
|
34
29
|
//#endregion
|
|
35
30
|
//#region src/commits.ts
|
|
36
|
-
const debug$1 = createDebugger("ucdjs:release-scripts:commits");
|
|
37
31
|
async function getLastPackageTag(packageName, workspaceRoot) {
|
|
38
32
|
const { stdout } = await run("git", ["tag", "--list"], { nodeOptions: {
|
|
39
33
|
cwd: workspaceRoot,
|
|
@@ -58,16 +52,31 @@ async function getPackageCommits(pkg, workspaceRoot) {
|
|
|
58
52
|
from: lastTag,
|
|
59
53
|
to: "HEAD"
|
|
60
54
|
});
|
|
61
|
-
|
|
55
|
+
console.log(`Found ${allCommits.length} commits for ${pkg.name} since ${lastTag || "beginning"}`);
|
|
62
56
|
const touchedCommitHashes = await getCommitsTouchingPackage(lastTag || "HEAD", "HEAD", pkg.path, workspaceRoot);
|
|
63
57
|
const touchedSet = new Set(touchedCommitHashes);
|
|
64
58
|
const packageCommits = allCommits.filter((commit) => touchedSet.has(commit.shortHash));
|
|
65
|
-
|
|
59
|
+
console.log(`${packageCommits.length} commits affect ${pkg.name}`);
|
|
66
60
|
return packageCommits;
|
|
67
61
|
}
|
|
68
62
|
async function analyzePackageCommits(pkg, workspaceRoot) {
|
|
69
63
|
return determineHighestBump(await getPackageCommits(pkg, workspaceRoot));
|
|
70
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Analyze commits for multiple packages to determine version bumps
|
|
67
|
+
*
|
|
68
|
+
* @param packages - Packages to analyze
|
|
69
|
+
* @param workspaceRoot - Root directory of the workspace
|
|
70
|
+
* @returns Map of package names to their bump types
|
|
71
|
+
*/
|
|
72
|
+
async function analyzeCommits(packages, workspaceRoot) {
|
|
73
|
+
const changedPackages = /* @__PURE__ */ new Map();
|
|
74
|
+
for (const pkg of packages) {
|
|
75
|
+
const bump = await analyzePackageCommits(pkg, workspaceRoot);
|
|
76
|
+
if (bump !== "none") changedPackages.set(pkg.name, bump);
|
|
77
|
+
}
|
|
78
|
+
return changedPackages;
|
|
79
|
+
}
|
|
71
80
|
function determineBumpType(commit) {
|
|
72
81
|
if (commit.isBreaking) return "major";
|
|
73
82
|
if (!commit.isConventional || !commit.type) return "none";
|
|
@@ -100,135 +109,11 @@ async function getCommitsTouchingPackage(from, to, packagePath, workspaceRoot) {
|
|
|
100
109
|
} });
|
|
101
110
|
return stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
102
111
|
} catch (error) {
|
|
103
|
-
|
|
112
|
+
console.error(`Error getting commits touching package: ${error}`);
|
|
104
113
|
return [];
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
116
|
|
|
108
|
-
//#endregion
|
|
109
|
-
//#region src/validation.ts
|
|
110
|
-
/**
|
|
111
|
-
* Validation utilities for release scripts
|
|
112
|
-
*/
|
|
113
|
-
function isValidSemver(version) {
|
|
114
|
-
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(version);
|
|
115
|
-
}
|
|
116
|
-
function validateSemver(version) {
|
|
117
|
-
if (!isValidSemver(version)) throw new Error(`Invalid semver version: ${version}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/version.ts
|
|
122
|
-
/**
|
|
123
|
-
* Calculate the new version based on current version and bump type
|
|
124
|
-
* Pure function - no side effects, easily testable
|
|
125
|
-
*/
|
|
126
|
-
function calculateNewVersion(currentVersion, bump) {
|
|
127
|
-
if (bump === "none") return currentVersion;
|
|
128
|
-
validateSemver(currentVersion);
|
|
129
|
-
const match = currentVersion.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
|
|
130
|
-
if (!match) throw new Error(`Invalid semver version: ${currentVersion}`);
|
|
131
|
-
const [, major, minor, patch, suffix] = match;
|
|
132
|
-
let newMajor = Number.parseInt(major, 10);
|
|
133
|
-
let newMinor = Number.parseInt(minor, 10);
|
|
134
|
-
let newPatch = Number.parseInt(patch, 10);
|
|
135
|
-
switch (bump) {
|
|
136
|
-
case "major":
|
|
137
|
-
newMajor += 1;
|
|
138
|
-
newMinor = 0;
|
|
139
|
-
newPatch = 0;
|
|
140
|
-
break;
|
|
141
|
-
case "minor":
|
|
142
|
-
newMinor += 1;
|
|
143
|
-
newPatch = 0;
|
|
144
|
-
break;
|
|
145
|
-
case "patch":
|
|
146
|
-
newPatch += 1;
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
return `${newMajor}.${newMinor}.${newPatch}`;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Create a version update object
|
|
153
|
-
*/
|
|
154
|
-
function createVersionUpdate(pkg, bump, hasDirectChanges) {
|
|
155
|
-
const newVersion = calculateNewVersion(pkg.version, bump);
|
|
156
|
-
return {
|
|
157
|
-
package: pkg,
|
|
158
|
-
currentVersion: pkg.version,
|
|
159
|
-
newVersion,
|
|
160
|
-
bumpType: bump,
|
|
161
|
-
hasDirectChanges
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Update a package.json file with new version and dependency versions
|
|
166
|
-
*/
|
|
167
|
-
async function updatePackageJson(pkg, newVersion, dependencyUpdates) {
|
|
168
|
-
const packageJsonPath = join(pkg.path, "package.json");
|
|
169
|
-
const content = await readFile(packageJsonPath, "utf-8");
|
|
170
|
-
const packageJson = JSON.parse(content);
|
|
171
|
-
packageJson.version = newVersion;
|
|
172
|
-
for (const [depName, depVersion] of dependencyUpdates) {
|
|
173
|
-
if (packageJson.dependencies?.[depName]) {
|
|
174
|
-
if (packageJson.dependencies[depName] === "workspace:*") continue;
|
|
175
|
-
packageJson.dependencies[depName] = `^${depVersion}`;
|
|
176
|
-
}
|
|
177
|
-
if (packageJson.devDependencies?.[depName]) {
|
|
178
|
-
if (packageJson.devDependencies[depName] === "workspace:*") continue;
|
|
179
|
-
packageJson.devDependencies[depName] = `^${depVersion}`;
|
|
180
|
-
}
|
|
181
|
-
if (packageJson.peerDependencies?.[depName]) {
|
|
182
|
-
if (packageJson.peerDependencies[depName] === "workspace:*") continue;
|
|
183
|
-
packageJson.peerDependencies[depName] = `^${depVersion}`;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf-8");
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Get all dependency updates needed for a package
|
|
190
|
-
*/
|
|
191
|
-
function getDependencyUpdates(pkg, allUpdates) {
|
|
192
|
-
const updates = /* @__PURE__ */ new Map();
|
|
193
|
-
const allDeps = [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies];
|
|
194
|
-
for (const dep of allDeps) {
|
|
195
|
-
const update = allUpdates.find((u) => u.package.name === dep);
|
|
196
|
-
if (update) updates.set(dep, update.newVersion);
|
|
197
|
-
}
|
|
198
|
-
return updates;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
//#endregion
|
|
202
|
-
//#region src/dependencies.ts
|
|
203
|
-
/**
|
|
204
|
-
* Pure function: Determine which packages need updates due to dependency changes
|
|
205
|
-
*
|
|
206
|
-
* When a package is updated, all packages that depend on it should also be updated.
|
|
207
|
-
* This function calculates which additional packages need patch bumps.
|
|
208
|
-
*
|
|
209
|
-
* @param updateOrder - Packages in topological order with their dependency levels
|
|
210
|
-
* @param directUpdates - Packages with direct code changes
|
|
211
|
-
* @returns All updates including dependent packages
|
|
212
|
-
*/
|
|
213
|
-
function createDependentUpdates(updateOrder, directUpdates) {
|
|
214
|
-
const allUpdates = [...directUpdates];
|
|
215
|
-
const updatedPackages = new Set(directUpdates.map((u) => u.package.name));
|
|
216
|
-
for (const { package: pkg } of updateOrder) {
|
|
217
|
-
if (updatedPackages.has(pkg.name)) continue;
|
|
218
|
-
if (hasUpdatedDependencies(pkg, updatedPackages)) {
|
|
219
|
-
allUpdates.push(createVersionUpdate(pkg, "patch", false));
|
|
220
|
-
updatedPackages.add(pkg.name);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return allUpdates;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Pure function: Check if a package has any updated dependencies
|
|
227
|
-
*/
|
|
228
|
-
function hasUpdatedDependencies(pkg, updatedPackages) {
|
|
229
|
-
return [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies].some((dep) => updatedPackages.has(dep));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
117
|
//#endregion
|
|
233
118
|
//#region src/git.ts
|
|
234
119
|
/**
|
|
@@ -474,49 +359,311 @@ async function upsertPullRequest({ owner, repo, title, body, head, base, pullNum
|
|
|
474
359
|
throw err;
|
|
475
360
|
}
|
|
476
361
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
lines.
|
|
496
|
-
lines.
|
|
497
|
-
|
|
498
|
-
|
|
362
|
+
const defaultTemplate = dedent`
|
|
363
|
+
This PR was automatically generated by the release script.
|
|
364
|
+
|
|
365
|
+
The following packages have been prepared for release:
|
|
366
|
+
|
|
367
|
+
<% it.packages.forEach((pkg) => { %>
|
|
368
|
+
- **<%= pkg.name %>**: <%= pkg.currentVersion %> → <%= pkg.newVersion %> (<%= pkg.bumpType %>)
|
|
369
|
+
<% }) %>
|
|
370
|
+
|
|
371
|
+
Please review the changes and merge when ready.
|
|
372
|
+
|
|
373
|
+
For a more in-depth look at the changes, please refer to the individual package changelogs.
|
|
374
|
+
|
|
375
|
+
> [!NOTE]
|
|
376
|
+
> When this PR is merged, the release process will be triggered automatically, publishing the new package versions to the registry.
|
|
377
|
+
`;
|
|
378
|
+
function dedentString(str) {
|
|
379
|
+
const lines = str.split("\n");
|
|
380
|
+
const minIndent = lines.filter((line) => line.trim().length > 0).reduce((min, line) => Math.min(min, line.search(/\S/)), Infinity);
|
|
381
|
+
return lines.map((line) => minIndent === Infinity ? line : line.slice(minIndent)).join("\n").trim();
|
|
382
|
+
}
|
|
383
|
+
function generatePullRequestBody(updates, body) {
|
|
384
|
+
const eta = new Eta();
|
|
385
|
+
const bodyTemplate = body ? dedentString(body) : defaultTemplate;
|
|
386
|
+
return eta.renderString(bodyTemplate, { packages: updates.map((u) => ({
|
|
387
|
+
name: u.package.name,
|
|
388
|
+
currentVersion: u.currentVersion,
|
|
389
|
+
newVersion: u.newVersion,
|
|
390
|
+
bumpType: u.bumpType,
|
|
391
|
+
hasDirectChanges: u.hasDirectChanges
|
|
392
|
+
})) });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/version.ts
|
|
397
|
+
function isValidSemver(version) {
|
|
398
|
+
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(version);
|
|
399
|
+
}
|
|
400
|
+
function validateSemver(version) {
|
|
401
|
+
if (!isValidSemver(version)) throw new Error(`Invalid semver version: ${version}`);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Calculate the new version based on current version and bump type
|
|
405
|
+
* Pure function - no side effects, easily testable
|
|
406
|
+
*/
|
|
407
|
+
function calculateNewVersion(currentVersion, bump) {
|
|
408
|
+
if (bump === "none") return currentVersion;
|
|
409
|
+
validateSemver(currentVersion);
|
|
410
|
+
const match = currentVersion.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
|
|
411
|
+
if (!match) throw new Error(`Invalid semver version: ${currentVersion}`);
|
|
412
|
+
const [, major, minor, patch] = match;
|
|
413
|
+
let newMajor = Number.parseInt(major, 10);
|
|
414
|
+
let newMinor = Number.parseInt(minor, 10);
|
|
415
|
+
let newPatch = Number.parseInt(patch, 10);
|
|
416
|
+
switch (bump) {
|
|
417
|
+
case "major":
|
|
418
|
+
newMajor += 1;
|
|
419
|
+
newMinor = 0;
|
|
420
|
+
newPatch = 0;
|
|
421
|
+
break;
|
|
422
|
+
case "minor":
|
|
423
|
+
newMinor += 1;
|
|
424
|
+
newPatch = 0;
|
|
425
|
+
break;
|
|
426
|
+
case "patch":
|
|
427
|
+
newPatch += 1;
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
return `${newMajor}.${newMinor}.${newPatch}`;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Create a version update object
|
|
434
|
+
*/
|
|
435
|
+
function createVersionUpdate(pkg, bump, hasDirectChanges) {
|
|
436
|
+
const newVersion = calculateNewVersion(pkg.version, bump);
|
|
437
|
+
return {
|
|
438
|
+
package: pkg,
|
|
439
|
+
currentVersion: pkg.version,
|
|
440
|
+
newVersion,
|
|
441
|
+
bumpType: bump,
|
|
442
|
+
hasDirectChanges
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Update a package.json file with new version and dependency versions
|
|
447
|
+
*/
|
|
448
|
+
async function updatePackageJson(pkg, newVersion, dependencyUpdates) {
|
|
449
|
+
const packageJsonPath = join(pkg.path, "package.json");
|
|
450
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
451
|
+
const packageJson = JSON.parse(content);
|
|
452
|
+
packageJson.version = newVersion;
|
|
453
|
+
for (const [depName, depVersion] of dependencyUpdates) {
|
|
454
|
+
if (packageJson.dependencies?.[depName]) {
|
|
455
|
+
if (packageJson.dependencies[depName] === "workspace:*") continue;
|
|
456
|
+
packageJson.dependencies[depName] = `^${depVersion}`;
|
|
457
|
+
}
|
|
458
|
+
if (packageJson.devDependencies?.[depName]) {
|
|
459
|
+
if (packageJson.devDependencies[depName] === "workspace:*") continue;
|
|
460
|
+
packageJson.devDependencies[depName] = `^${depVersion}`;
|
|
461
|
+
}
|
|
462
|
+
if (packageJson.peerDependencies?.[depName]) {
|
|
463
|
+
if (packageJson.peerDependencies[depName] === "workspace:*") continue;
|
|
464
|
+
packageJson.peerDependencies[depName] = `^${depVersion}`;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf-8");
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Get all dependency updates needed for a package
|
|
471
|
+
*/
|
|
472
|
+
function getDependencyUpdates(pkg, allUpdates) {
|
|
473
|
+
const updates = /* @__PURE__ */ new Map();
|
|
474
|
+
const allDeps = [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies];
|
|
475
|
+
for (const dep of allDeps) {
|
|
476
|
+
const update = allUpdates.find((u) => u.package.name === dep);
|
|
477
|
+
if (update) updates.set(dep, update.newVersion);
|
|
478
|
+
}
|
|
479
|
+
return updates;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/package.ts
|
|
484
|
+
/**
|
|
485
|
+
* Build a dependency graph from workspace packages
|
|
486
|
+
*
|
|
487
|
+
* Creates a bidirectional graph that maps:
|
|
488
|
+
* - packages: Map of package name → WorkspacePackage
|
|
489
|
+
* - dependents: Map of package name → Set of packages that depend on it
|
|
490
|
+
*
|
|
491
|
+
* @param packages - All workspace packages
|
|
492
|
+
* @returns Dependency graph with packages and dependents maps
|
|
493
|
+
*/
|
|
494
|
+
function buildPackageDependencyGraph(packages) {
|
|
495
|
+
const packagesMap = /* @__PURE__ */ new Map();
|
|
496
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
497
|
+
for (const pkg of packages) {
|
|
498
|
+
packagesMap.set(pkg.name, pkg);
|
|
499
|
+
dependents.set(pkg.name, /* @__PURE__ */ new Set());
|
|
500
|
+
}
|
|
501
|
+
for (const pkg of packages) {
|
|
502
|
+
const allDeps = [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies];
|
|
503
|
+
for (const dep of allDeps) {
|
|
504
|
+
const depSet = dependents.get(dep);
|
|
505
|
+
if (depSet) depSet.add(pkg.name);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
packages: packagesMap,
|
|
510
|
+
dependents
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Get all packages affected by changes (including transitive dependents)
|
|
515
|
+
*
|
|
516
|
+
* Uses graph traversal to find all packages that need updates:
|
|
517
|
+
* - Packages with direct changes
|
|
518
|
+
* - All packages that depend on changed packages (transitively)
|
|
519
|
+
*
|
|
520
|
+
* @param graph - Dependency graph
|
|
521
|
+
* @param changedPackages - Set of package names with direct changes
|
|
522
|
+
* @returns Set of all package names that need updates
|
|
523
|
+
*/
|
|
524
|
+
function getAllAffectedPackages(graph, changedPackages) {
|
|
525
|
+
const affected = /* @__PURE__ */ new Set();
|
|
526
|
+
function visitDependents(pkgName) {
|
|
527
|
+
if (affected.has(pkgName)) return;
|
|
528
|
+
affected.add(pkgName);
|
|
529
|
+
const dependents = graph.dependents.get(pkgName);
|
|
530
|
+
if (dependents) for (const dependent of dependents) visitDependents(dependent);
|
|
531
|
+
}
|
|
532
|
+
for (const pkg of changedPackages) visitDependents(pkg);
|
|
533
|
+
return affected;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Create version updates for all packages affected by dependency changes
|
|
537
|
+
*
|
|
538
|
+
* When a package is updated, all packages that depend on it should also be updated.
|
|
539
|
+
* This function calculates which additional packages need patch bumps due to dependency changes.
|
|
540
|
+
*
|
|
541
|
+
* @param graph - Dependency graph
|
|
542
|
+
* @param workspacePackages - All workspace packages
|
|
543
|
+
* @param directUpdates - Packages with direct code changes
|
|
544
|
+
* @returns All updates including dependent packages that need patch bumps
|
|
545
|
+
*/
|
|
546
|
+
function createDependentUpdates(graph, workspacePackages, directUpdates) {
|
|
547
|
+
const allUpdates = [...directUpdates];
|
|
548
|
+
const directUpdateMap = new Map(directUpdates.map((u) => [u.package.name, u]));
|
|
549
|
+
const affectedPackages = getAllAffectedPackages(graph, new Set(directUpdates.map((u) => u.package.name)));
|
|
550
|
+
for (const pkgName of affectedPackages) {
|
|
551
|
+
if (directUpdateMap.has(pkgName)) continue;
|
|
552
|
+
const pkg = workspacePackages.find((p) => p.name === pkgName);
|
|
553
|
+
if (!pkg) continue;
|
|
554
|
+
allUpdates.push(createVersionUpdate(pkg, "patch", false));
|
|
555
|
+
}
|
|
556
|
+
return allUpdates;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Update all package.json files with new versions and dependency updates
|
|
560
|
+
*
|
|
561
|
+
* Updates are performed in parallel for better performance.
|
|
562
|
+
*
|
|
563
|
+
* @param updates - Version updates to apply
|
|
564
|
+
*/
|
|
565
|
+
async function updateAllPackageJsonFiles(updates) {
|
|
566
|
+
await Promise.all(updates.map(async (update) => {
|
|
567
|
+
const depUpdates = getDependencyUpdates(update.package, updates);
|
|
568
|
+
await updatePackageJson(update.package, update.newVersion, depUpdates);
|
|
569
|
+
}));
|
|
499
570
|
}
|
|
500
571
|
|
|
501
572
|
//#endregion
|
|
502
573
|
//#region src/prompts.ts
|
|
503
|
-
|
|
574
|
+
/**
|
|
575
|
+
* Get commits for a package grouped by conventional commit type
|
|
576
|
+
*
|
|
577
|
+
* @param pkg - The workspace package
|
|
578
|
+
* @param workspaceRoot - Root directory of the workspace
|
|
579
|
+
* @param limit - Maximum number of commits to return (default: 10)
|
|
580
|
+
* @returns Commits grouped by type
|
|
581
|
+
*/
|
|
582
|
+
async function getCommitsForPackage(pkg, workspaceRoot, limit = 10) {
|
|
583
|
+
const limitedCommits = (await getPackageCommits(pkg, workspaceRoot)).slice(0, limit);
|
|
584
|
+
const grouped = {
|
|
585
|
+
feat: [],
|
|
586
|
+
fix: [],
|
|
587
|
+
perf: [],
|
|
588
|
+
chore: [],
|
|
589
|
+
docs: [],
|
|
590
|
+
style: [],
|
|
591
|
+
refactor: [],
|
|
592
|
+
test: [],
|
|
593
|
+
build: [],
|
|
594
|
+
ci: [],
|
|
595
|
+
revert: [],
|
|
596
|
+
other: []
|
|
597
|
+
};
|
|
598
|
+
for (const commit of limitedCommits) if (commit.type && commit.type in grouped) grouped[commit.type].push(commit);
|
|
599
|
+
else grouped.other.push(commit);
|
|
600
|
+
return grouped;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Format grouped commits into a readable string
|
|
604
|
+
*/
|
|
605
|
+
function formatCommitGroups(grouped) {
|
|
606
|
+
const lines = [];
|
|
607
|
+
const typeLabels = {
|
|
608
|
+
feat: "Features",
|
|
609
|
+
fix: "Bug Fixes",
|
|
610
|
+
perf: "Performance",
|
|
611
|
+
chore: "Chores",
|
|
612
|
+
docs: "Documentation",
|
|
613
|
+
style: "Styling",
|
|
614
|
+
refactor: "Refactoring",
|
|
615
|
+
test: "Tests",
|
|
616
|
+
build: "Build",
|
|
617
|
+
ci: "CI",
|
|
618
|
+
revert: "Reverts",
|
|
619
|
+
other: "Other"
|
|
620
|
+
};
|
|
621
|
+
for (const type of [
|
|
622
|
+
"feat",
|
|
623
|
+
"fix",
|
|
624
|
+
"perf",
|
|
625
|
+
"refactor",
|
|
626
|
+
"test",
|
|
627
|
+
"docs",
|
|
628
|
+
"style",
|
|
629
|
+
"build",
|
|
630
|
+
"ci",
|
|
631
|
+
"chore",
|
|
632
|
+
"revert",
|
|
633
|
+
"other"
|
|
634
|
+
]) {
|
|
635
|
+
const commits = grouped[type];
|
|
636
|
+
if (commits.length > 0) {
|
|
637
|
+
lines.push(`\n${typeLabels[type]}:`);
|
|
638
|
+
for (const commit of commits) {
|
|
639
|
+
const scope = commit.scope ? `(${commit.scope})` : "";
|
|
640
|
+
const breaking = commit.isBreaking ? " ⚠️ BREAKING" : "";
|
|
641
|
+
lines.push(` • ${commit.type}${scope}: ${commit.message}${breaking}`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return lines.join("\n");
|
|
646
|
+
}
|
|
647
|
+
async function selectPackagePrompt(packages) {
|
|
504
648
|
const response = await prompts({
|
|
505
649
|
type: "multiselect",
|
|
506
650
|
name: "selectedPackages",
|
|
507
651
|
message: "Select packages to release",
|
|
508
652
|
choices: packages.map((pkg) => ({
|
|
509
|
-
title: `${pkg.name} (${pkg.version})`,
|
|
653
|
+
title: `${pkg.name} (${farver.bold(pkg.version)})`,
|
|
510
654
|
value: pkg.name,
|
|
511
655
|
selected: true
|
|
512
656
|
})),
|
|
513
657
|
min: 1,
|
|
514
|
-
hint: "Space to select/deselect. Return to submit."
|
|
658
|
+
hint: "Space to select/deselect. Return to submit.",
|
|
659
|
+
instructions: false
|
|
515
660
|
});
|
|
516
|
-
if (!response.selectedPackages || response.selectedPackages.length === 0)
|
|
661
|
+
if (!response.selectedPackages || response.selectedPackages.length === 0) return [];
|
|
517
662
|
return response.selectedPackages;
|
|
518
663
|
}
|
|
519
|
-
async function promptVersionOverride(
|
|
664
|
+
async function promptVersionOverride(pkg, workspaceRoot, currentVersion, suggestedVersion, suggestedBumpType) {
|
|
665
|
+
const commitSummary = formatCommitGroups(await getCommitsForPackage(pkg, workspaceRoot));
|
|
666
|
+
if (commitSummary.trim()) console.log(`\nRecent changes in ${pkg.name}:${commitSummary}\n`);
|
|
520
667
|
const choices = [{
|
|
521
668
|
title: `Use suggested: ${suggestedVersion} (${suggestedBumpType})`,
|
|
522
669
|
value: "suggested"
|
|
@@ -539,7 +686,7 @@ async function promptVersionOverride(packageName, currentVersion, suggestedVersi
|
|
|
539
686
|
const response = await prompts([{
|
|
540
687
|
type: "select",
|
|
541
688
|
name: "choice",
|
|
542
|
-
message: `${
|
|
689
|
+
message: `${pkg.name} (${currentVersion}):`,
|
|
543
690
|
choices,
|
|
544
691
|
initial: 0
|
|
545
692
|
}, {
|
|
@@ -555,18 +702,85 @@ async function promptVersionOverride(packageName, currentVersion, suggestedVersi
|
|
|
555
702
|
else if (response.choice === "custom") return response.customVersion;
|
|
556
703
|
else return calculateNewVersion(currentVersion, response.choice);
|
|
557
704
|
}
|
|
558
|
-
async function promptVersionOverrides(packages) {
|
|
705
|
+
async function promptVersionOverrides(packages, workspaceRoot) {
|
|
559
706
|
const overrides = /* @__PURE__ */ new Map();
|
|
560
|
-
for (const
|
|
561
|
-
const newVersion = await promptVersionOverride(
|
|
562
|
-
overrides.set(
|
|
707
|
+
for (const item of packages) {
|
|
708
|
+
const newVersion = await promptVersionOverride(item.package, workspaceRoot, item.currentVersion, item.suggestedVersion, item.bumpType);
|
|
709
|
+
overrides.set(item.package.name, newVersion);
|
|
563
710
|
}
|
|
564
711
|
return overrides;
|
|
565
712
|
}
|
|
566
713
|
|
|
567
714
|
//#endregion
|
|
568
715
|
//#region src/workspace.ts
|
|
569
|
-
|
|
716
|
+
async function discoverWorkspacePackages(workspaceRoot, options) {
|
|
717
|
+
let workspaceOptions;
|
|
718
|
+
let explicitPackages;
|
|
719
|
+
if (options.packages == null || options.packages === true) workspaceOptions = { excludePrivate: false };
|
|
720
|
+
else if (Array.isArray(options.packages)) {
|
|
721
|
+
workspaceOptions = {
|
|
722
|
+
excludePrivate: false,
|
|
723
|
+
included: options.packages
|
|
724
|
+
};
|
|
725
|
+
explicitPackages = options.packages;
|
|
726
|
+
} else {
|
|
727
|
+
workspaceOptions = options.packages;
|
|
728
|
+
if (options.packages.included) explicitPackages = options.packages.included;
|
|
729
|
+
}
|
|
730
|
+
const workspacePackages = await findWorkspacePackages(workspaceRoot, workspaceOptions);
|
|
731
|
+
if (explicitPackages) {
|
|
732
|
+
const foundNames = new Set(workspacePackages.map((p) => p.name));
|
|
733
|
+
const missing = explicitPackages.filter((p) => !foundNames.has(p));
|
|
734
|
+
if (missing.length > 0) throw new Error(`Packages not found in workspace: ${missing.join(", ")}`);
|
|
735
|
+
}
|
|
736
|
+
let packagesToAnalyze = workspacePackages;
|
|
737
|
+
const isPackagePromptEnabled = options.prompts?.packages !== false;
|
|
738
|
+
if (!isCI && isPackagePromptEnabled && !explicitPackages) {
|
|
739
|
+
const selectedNames = await selectPackagePrompt(workspacePackages);
|
|
740
|
+
packagesToAnalyze = workspacePackages.filter((pkg) => selectedNames.includes(pkg.name));
|
|
741
|
+
}
|
|
742
|
+
return {
|
|
743
|
+
workspacePackages,
|
|
744
|
+
packagesToAnalyze
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
async function findWorkspacePackages(workspaceRoot, options) {
|
|
748
|
+
try {
|
|
749
|
+
const result = await run("pnpm", [
|
|
750
|
+
"-r",
|
|
751
|
+
"ls",
|
|
752
|
+
"--json"
|
|
753
|
+
], { nodeOptions: {
|
|
754
|
+
cwd: workspaceRoot,
|
|
755
|
+
stdio: "pipe"
|
|
756
|
+
} });
|
|
757
|
+
const rawProjects = JSON.parse(result.stdout);
|
|
758
|
+
const allPackageNames = new Set(rawProjects.map((p) => p.name));
|
|
759
|
+
const excludedPackages = /* @__PURE__ */ new Set();
|
|
760
|
+
const promises = rawProjects.map(async (rawProject) => {
|
|
761
|
+
const content = await readFile(join(rawProject.path, "package.json"), "utf-8");
|
|
762
|
+
const packageJson = JSON.parse(content);
|
|
763
|
+
if (!shouldIncludePackage(packageJson, options)) {
|
|
764
|
+
excludedPackages.add(rawProject.name);
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
return {
|
|
768
|
+
name: rawProject.name,
|
|
769
|
+
version: rawProject.version,
|
|
770
|
+
path: rawProject.path,
|
|
771
|
+
packageJson,
|
|
772
|
+
workspaceDependencies: extractWorkspaceDependencies(rawProject.dependencies, allPackageNames),
|
|
773
|
+
workspaceDevDependencies: extractWorkspaceDependencies(rawProject.devDependencies, allPackageNames)
|
|
774
|
+
};
|
|
775
|
+
});
|
|
776
|
+
const packages = await Promise.all(promises);
|
|
777
|
+
if (excludedPackages.size > 0) console.info(`${farver.cyan("[info]:")} Excluded packages: ${farver.green(Array.from(excludedPackages).join(", "))}`);
|
|
778
|
+
return packages.filter((pkg) => pkg !== null);
|
|
779
|
+
} catch (err) {
|
|
780
|
+
console.error("Error discovering workspace packages:", err);
|
|
781
|
+
throw err;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
570
784
|
function shouldIncludePackage(pkg, options) {
|
|
571
785
|
if (!options) return true;
|
|
572
786
|
if (options.excludePrivate && pkg.private) return false;
|
|
@@ -576,130 +790,45 @@ function shouldIncludePackage(pkg, options) {
|
|
|
576
790
|
if (options.excluded?.includes(pkg.name)) return false;
|
|
577
791
|
return true;
|
|
578
792
|
}
|
|
579
|
-
async function findWorkspacePackages(workspaceRoot, options) {
|
|
580
|
-
const result = await run("pnpm", [
|
|
581
|
-
"-r",
|
|
582
|
-
"ls",
|
|
583
|
-
"--json"
|
|
584
|
-
], { nodeOptions: {
|
|
585
|
-
cwd: workspaceRoot,
|
|
586
|
-
stdio: "pipe"
|
|
587
|
-
} });
|
|
588
|
-
const rawProjects = JSON.parse(result.stdout);
|
|
589
|
-
const packages = [];
|
|
590
|
-
const allPackageNames = new Set(rawProjects.map((p) => p.name));
|
|
591
|
-
for (const rawProject of rawProjects) {
|
|
592
|
-
const content = await readFile(join(rawProject.path, "package.json"), "utf-8");
|
|
593
|
-
const packageJson = JSON.parse(content);
|
|
594
|
-
if (!shouldIncludePackage(packageJson, options)) {
|
|
595
|
-
debug?.(`Excluding package ${rawProject.name}`);
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
const workspaceDeps = extractWorkspaceDependencies(rawProject.dependencies, allPackageNames);
|
|
599
|
-
const workspaceDevDeps = extractWorkspaceDependencies(rawProject.devDependencies, allPackageNames);
|
|
600
|
-
packages.push({
|
|
601
|
-
name: rawProject.name,
|
|
602
|
-
version: rawProject.version,
|
|
603
|
-
path: rawProject.path,
|
|
604
|
-
packageJson,
|
|
605
|
-
workspaceDependencies: workspaceDeps,
|
|
606
|
-
workspaceDevDependencies: workspaceDevDeps
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
return packages;
|
|
610
|
-
}
|
|
611
793
|
function extractWorkspaceDependencies(dependencies, workspacePackages) {
|
|
612
794
|
if (!dependencies) return [];
|
|
613
795
|
return Object.keys(dependencies).filter((dep) => {
|
|
614
796
|
return workspacePackages.has(dep);
|
|
615
797
|
});
|
|
616
798
|
}
|
|
617
|
-
function buildDependencyGraph(packages) {
|
|
618
|
-
const packagesMap = /* @__PURE__ */ new Map();
|
|
619
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
620
|
-
for (const pkg of packages) {
|
|
621
|
-
packagesMap.set(pkg.name, pkg);
|
|
622
|
-
dependents.set(pkg.name, /* @__PURE__ */ new Set());
|
|
623
|
-
}
|
|
624
|
-
for (const pkg of packages) {
|
|
625
|
-
const allDeps = [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies];
|
|
626
|
-
for (const dep of allDeps) {
|
|
627
|
-
const depSet = dependents.get(dep);
|
|
628
|
-
if (depSet) depSet.add(pkg.name);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return {
|
|
632
|
-
packages: packagesMap,
|
|
633
|
-
dependents
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function getPackageUpdateOrder(graph, changedPackages) {
|
|
637
|
-
const result = [];
|
|
638
|
-
const visited = /* @__PURE__ */ new Set();
|
|
639
|
-
const toUpdate = new Set(changedPackages);
|
|
640
|
-
const packagesToProcess = new Set(changedPackages);
|
|
641
|
-
for (const pkg of changedPackages) {
|
|
642
|
-
const deps = graph.dependents.get(pkg);
|
|
643
|
-
if (deps) for (const dep of deps) {
|
|
644
|
-
packagesToProcess.add(dep);
|
|
645
|
-
toUpdate.add(dep);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
function visit(pkgName, level) {
|
|
649
|
-
if (visited.has(pkgName)) return;
|
|
650
|
-
visited.add(pkgName);
|
|
651
|
-
const pkg = graph.packages.get(pkgName);
|
|
652
|
-
if (!pkg) return;
|
|
653
|
-
const allDeps = [...pkg.workspaceDependencies, ...pkg.workspaceDevDependencies];
|
|
654
|
-
let maxDepLevel = level;
|
|
655
|
-
for (const dep of allDeps) if (toUpdate.has(dep)) {
|
|
656
|
-
visit(dep, level);
|
|
657
|
-
const depResult = result.find((r) => r.package.name === dep);
|
|
658
|
-
if (depResult && depResult.level >= maxDepLevel) maxDepLevel = depResult.level + 1;
|
|
659
|
-
}
|
|
660
|
-
result.push({
|
|
661
|
-
package: pkg,
|
|
662
|
-
level: maxDepLevel
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
for (const pkg of toUpdate) visit(pkg, 0);
|
|
666
|
-
result.sort((a, b) => a.level - b.level);
|
|
667
|
-
return result;
|
|
668
|
-
}
|
|
669
799
|
|
|
670
800
|
//#endregion
|
|
671
801
|
//#region src/release.ts
|
|
672
|
-
const isCI = process.env.CI === "true";
|
|
673
802
|
async function release(options) {
|
|
674
803
|
const { dryRun: dryRun$1 = false, safeguards = true, workspaceRoot = process.cwd(), releaseBranch = "release/next", githubToken } = options;
|
|
675
804
|
globalOptions.dryRun = dryRun$1;
|
|
676
805
|
if (githubToken.trim() === "" || githubToken == null) throw new Error("GitHub token is required");
|
|
677
806
|
const [owner, repo] = options.repo.split("/");
|
|
678
807
|
if (!owner || !repo) throw new Error(`Invalid repo format: ${options.repo}. Expected "owner/repo".`);
|
|
679
|
-
if (safeguards && !isWorkingDirectoryClean(workspaceRoot)) {
|
|
808
|
+
if (safeguards && !await isWorkingDirectoryClean(workspaceRoot)) {
|
|
680
809
|
console.error("Working directory is not clean. Please commit or stash your changes before proceeding.");
|
|
681
810
|
return null;
|
|
682
811
|
}
|
|
683
|
-
const { workspacePackages, packagesToAnalyze
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
let packagesToAnalyze = initialPackages;
|
|
688
|
-
if (!isCI && isPackagePromptEnabled && !isPackagesPreConfigured) {
|
|
689
|
-
const selectedNames = await promptPackageSelection(initialPackages);
|
|
690
|
-
packagesToAnalyze = initialPackages.filter((pkg) => selectedNames.includes(pkg.name));
|
|
812
|
+
const { workspacePackages, packagesToAnalyze } = await discoverWorkspacePackages(workspaceRoot, options);
|
|
813
|
+
if (packagesToAnalyze.length === 0) {
|
|
814
|
+
console.log("No packages found to analyze for release.");
|
|
815
|
+
return null;
|
|
691
816
|
}
|
|
692
817
|
const changedPackages = await analyzeCommits(packagesToAnalyze, workspaceRoot);
|
|
693
818
|
if (changedPackages.size === 0) throw new Error("No packages have changes requiring a release");
|
|
694
|
-
let versionUpdates =
|
|
819
|
+
let versionUpdates = [];
|
|
820
|
+
for (const [pkgName, bump] of changedPackages) {
|
|
821
|
+
const pkg = workspacePackages.find((p) => p.name === pkgName);
|
|
822
|
+
if (pkg) versionUpdates.push(createVersionUpdate(pkg, bump, true));
|
|
823
|
+
}
|
|
695
824
|
const isVersionPromptEnabled = options.prompts?.versions !== false;
|
|
696
825
|
if (!isCI && isVersionPromptEnabled) {
|
|
697
826
|
const versionOverrides = await promptVersionOverrides(versionUpdates.map((u) => ({
|
|
698
|
-
|
|
827
|
+
package: u.package,
|
|
699
828
|
currentVersion: u.currentVersion,
|
|
700
829
|
suggestedVersion: u.newVersion,
|
|
701
830
|
bumpType: u.bumpType
|
|
702
|
-
})));
|
|
831
|
+
})), workspaceRoot);
|
|
703
832
|
versionUpdates = versionUpdates.map((update) => {
|
|
704
833
|
const overriddenVersion = versionOverrides.get(update.package.name);
|
|
705
834
|
if (overriddenVersion && overriddenVersion !== update.newVersion) return {
|
|
@@ -709,7 +838,7 @@ async function release(options) {
|
|
|
709
838
|
return update;
|
|
710
839
|
});
|
|
711
840
|
}
|
|
712
|
-
const allUpdates = createDependentUpdates(
|
|
841
|
+
const allUpdates = createDependentUpdates(buildPackageDependencyGraph(workspacePackages), workspacePackages, versionUpdates);
|
|
713
842
|
const currentBranch = await getCurrentBranch(workspaceRoot);
|
|
714
843
|
const existingPullRequest = await getExistingPullRequest({
|
|
715
844
|
owner,
|
|
@@ -732,7 +861,7 @@ async function release(options) {
|
|
|
732
861
|
}
|
|
733
862
|
console.log("Rebasing release branch onto", currentBranch);
|
|
734
863
|
await rebaseBranch(currentBranch, workspaceRoot);
|
|
735
|
-
await
|
|
864
|
+
await updateAllPackageJsonFiles(allUpdates);
|
|
736
865
|
const hasCommitted = await commitChanges("chore: update release versions", workspaceRoot);
|
|
737
866
|
const isBranchAhead = await isBranchAheadOfRemote(releaseBranch, workspaceRoot);
|
|
738
867
|
if (!hasCommitted && !isBranchAhead) {
|
|
@@ -772,64 +901,6 @@ async function release(options) {
|
|
|
772
901
|
created: !prExists
|
|
773
902
|
};
|
|
774
903
|
}
|
|
775
|
-
async function discoverPackages(workspaceRoot, options) {
|
|
776
|
-
let workspacePackages;
|
|
777
|
-
let packagesToAnalyze;
|
|
778
|
-
if (typeof options.packages === "boolean" && options.packages === true) {
|
|
779
|
-
workspacePackages = await findWorkspacePackages(workspaceRoot, { excludePrivate: false });
|
|
780
|
-
packagesToAnalyze = workspacePackages;
|
|
781
|
-
return {
|
|
782
|
-
workspacePackages,
|
|
783
|
-
packagesToAnalyze
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
if (Array.isArray(options.packages)) {
|
|
787
|
-
const packageNames = options.packages;
|
|
788
|
-
workspacePackages = await findWorkspacePackages(workspaceRoot, {
|
|
789
|
-
excludePrivate: false,
|
|
790
|
-
included: packageNames
|
|
791
|
-
});
|
|
792
|
-
packagesToAnalyze = workspacePackages.filter((pkg) => packageNames.includes(pkg.name));
|
|
793
|
-
if (packagesToAnalyze.length !== packageNames.length) {
|
|
794
|
-
const found = new Set(packagesToAnalyze.map((p) => p.name));
|
|
795
|
-
const missing = packageNames.filter((p) => !found.has(p));
|
|
796
|
-
throw new Error(`Packages not found in workspace: ${missing.join(", ")}`);
|
|
797
|
-
}
|
|
798
|
-
return {
|
|
799
|
-
workspacePackages,
|
|
800
|
-
packagesToAnalyze
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
workspacePackages = await findWorkspacePackages(workspaceRoot, options.packages);
|
|
804
|
-
packagesToAnalyze = workspacePackages;
|
|
805
|
-
return {
|
|
806
|
-
workspacePackages,
|
|
807
|
-
packagesToAnalyze
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
async function analyzeCommits(packages, workspaceRoot) {
|
|
811
|
-
const changedPackages = /* @__PURE__ */ new Map();
|
|
812
|
-
for (const pkg of packages) {
|
|
813
|
-
const bump = await analyzePackageCommits(pkg, workspaceRoot);
|
|
814
|
-
if (bump !== "none") changedPackages.set(pkg.name, bump);
|
|
815
|
-
}
|
|
816
|
-
return changedPackages;
|
|
817
|
-
}
|
|
818
|
-
function calculateVersions(allPackages, changedPackages) {
|
|
819
|
-
const updates = [];
|
|
820
|
-
for (const [pkgName, bump] of changedPackages) {
|
|
821
|
-
const pkg = allPackages.find((p) => p.name === pkgName);
|
|
822
|
-
if (!pkg) continue;
|
|
823
|
-
updates.push(createVersionUpdate(pkg, bump, true));
|
|
824
|
-
}
|
|
825
|
-
return updates;
|
|
826
|
-
}
|
|
827
|
-
async function updatePackageJsonFiles(updates) {
|
|
828
|
-
await Promise.all(updates.map(async (update) => {
|
|
829
|
-
const depUpdates = getDependencyUpdates(update.package, updates);
|
|
830
|
-
await updatePackageJson(update.package, update.newVersion, depUpdates);
|
|
831
|
-
}));
|
|
832
|
-
}
|
|
833
904
|
|
|
834
905
|
//#endregion
|
|
835
906
|
export { release };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ucdjs/release-scripts",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.4",
|
|
4
4
|
"description": "@ucdjs release scripts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@luxass/utils": "2.7.2",
|
|
22
23
|
"commit-parser": "0.4.5",
|
|
23
|
-
"
|
|
24
|
+
"eta": "4.0.1",
|
|
24
25
|
"farver": "1.0.0-beta.1",
|
|
25
26
|
"prompts": "2.4.2",
|
|
26
27
|
"tinyexec": "1.0.2"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@luxass/eslint-config": "6.0.1",
|
|
30
|
-
"@types/debug": "4.1.12",
|
|
31
31
|
"@types/node": "22.18.12",
|
|
32
32
|
"@types/prompts": "2.4.9",
|
|
33
33
|
"eslint": "9.39.1",
|