@modulify/conventional-release 0.1.0 → 0.1.2
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 +44 -1
- package/bin/cli.cjs +29 -305
- package/bin/cli.mjs +27 -288
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/cli/args.cjs +67 -0
- package/dist/cli/args.mjs +65 -0
- package/dist/cli/output.cjs +51 -0
- package/dist/cli/output.mjs +46 -0
- package/dist/cli/reporter.cjs +127 -0
- package/dist/cli/reporter.mjs +127 -0
- package/dist/config.cjs +54 -0
- package/dist/config.mjs +51 -0
- package/dist/constants.cjs +16 -0
- package/dist/constants.mjs +12 -0
- package/dist/execute.cjs +192 -0
- package/dist/execute.mjs +190 -0
- package/dist/index.cjs +51 -707
- package/dist/index.mjs +51 -710
- package/dist/plan.cjs +260 -0
- package/dist/plan.mjs +253 -0
- package/dist/reporter.cjs +33 -0
- package/dist/reporter.mjs +27 -0
- package/dist/runtime.cjs +68 -0
- package/dist/runtime.mjs +67 -0
- package/package.json +16 -11
- package/types/release.d.ts +2 -0
package/dist/plan.cjs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
require("./_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
require("./constants.cjs");
|
|
3
|
+
let node_path = require("node:path");
|
|
4
|
+
let _modulify_conventional_git = require("@modulify/conventional-git");
|
|
5
|
+
let _modulify_pkg = require("@modulify/pkg");
|
|
6
|
+
//#region src/plan.ts
|
|
7
|
+
function toScope(scope, cwd) {
|
|
8
|
+
return {
|
|
9
|
+
mode: scope.mode,
|
|
10
|
+
packages: scope.packages.map((pkg) => toScopePackage(pkg, cwd)),
|
|
11
|
+
affected: scope.affected.map((pkg) => toScopePackage(pkg, cwd)),
|
|
12
|
+
slices: scope.slices.map((slice) => toSlice(slice, cwd))
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Discovers packages, affected scope, and ordered release slices without side effects. */
|
|
16
|
+
async function discover(runtime, options) {
|
|
17
|
+
const root = (0, _modulify_pkg.read)(runtime.cwd);
|
|
18
|
+
const packages = [];
|
|
19
|
+
await (0, _modulify_pkg.walk)([root], async (pkg) => {
|
|
20
|
+
packages.push(pkg);
|
|
21
|
+
});
|
|
22
|
+
const discovered = sortPackages(uniquePackages(applyWorkspaceFilters(packages, runtime.cwd, options.workspaces)), runtime.cwd);
|
|
23
|
+
const mode = options.mode ?? "sync";
|
|
24
|
+
const affectedPaths = mode === "hybrid" ? null : await detectAffectedPackages({
|
|
25
|
+
cwd: runtime.cwd,
|
|
26
|
+
root,
|
|
27
|
+
packages: discovered,
|
|
28
|
+
history: runtime.history,
|
|
29
|
+
range: {
|
|
30
|
+
fromTag: options.fromTag,
|
|
31
|
+
tagPrefix: options.tagPrefix
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const affected = affectedPaths ? sortPackages(uniquePackages(discovered.filter((pkg) => affectedPaths.has(pkg.path))), runtime.cwd) : [];
|
|
35
|
+
const slices = mode === "hybrid" ? await createHybridSlices({
|
|
36
|
+
root,
|
|
37
|
+
packages: discovered,
|
|
38
|
+
cwd: runtime.cwd,
|
|
39
|
+
history: runtime.history,
|
|
40
|
+
fromTag: options.fromTag,
|
|
41
|
+
tagPrefix: options.tagPrefix,
|
|
42
|
+
partitions: options.partitions
|
|
43
|
+
}) : createSlices({
|
|
44
|
+
mode,
|
|
45
|
+
packages: discovered,
|
|
46
|
+
affected,
|
|
47
|
+
cwd: runtime.cwd,
|
|
48
|
+
fromTag: options.fromTag,
|
|
49
|
+
tagPrefix: options.tagPrefix
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
mode,
|
|
53
|
+
packages: discovered,
|
|
54
|
+
affected: mode === "hybrid" ? sortPackages(uniquePackages(slices.flatMap((slice) => slice.packages)), runtime.cwd) : affected,
|
|
55
|
+
slices
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function toScopePackage(pkg, cwd) {
|
|
59
|
+
return {
|
|
60
|
+
name: pkg.manifest.name ?? pkg.name,
|
|
61
|
+
version: pkg.manifest.version,
|
|
62
|
+
path: toPublicPath(pkg, cwd)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function toSlice(slice, cwd) {
|
|
66
|
+
return {
|
|
67
|
+
id: slice.id,
|
|
68
|
+
kind: slice.kind,
|
|
69
|
+
mode: slice.mode,
|
|
70
|
+
partition: slice.partition,
|
|
71
|
+
packages: slice.packages.map((pkg) => toScopePackage(pkg, cwd)),
|
|
72
|
+
range: slice.range
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function uniquePackages(packages) {
|
|
76
|
+
const seen = /* @__PURE__ */ new Set();
|
|
77
|
+
return packages.filter((pkg) => {
|
|
78
|
+
if (seen.has(pkg.path)) return false;
|
|
79
|
+
seen.add(pkg.path);
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function uniqueStrings(values) {
|
|
84
|
+
return [...new Set(values)];
|
|
85
|
+
}
|
|
86
|
+
function packageIdentity(pkg, cwd) {
|
|
87
|
+
const name = pkg.manifest.name ?? pkg.name;
|
|
88
|
+
if (name) return name;
|
|
89
|
+
const path = packagePath(pkg, cwd);
|
|
90
|
+
return path === "" || path === "." ? "root" : path;
|
|
91
|
+
}
|
|
92
|
+
function createSlices({ mode, packages, affected, cwd, fromTag, tagPrefix }) {
|
|
93
|
+
if (mode === "sync") return affected.length ? [{
|
|
94
|
+
id: "sync:default",
|
|
95
|
+
kind: "sync",
|
|
96
|
+
mode: "sync",
|
|
97
|
+
packages,
|
|
98
|
+
range: {
|
|
99
|
+
fromTag,
|
|
100
|
+
tagPrefix
|
|
101
|
+
}
|
|
102
|
+
}] : [];
|
|
103
|
+
return affected.map((pkg) => ({
|
|
104
|
+
id: `async:${packageIdentity(pkg, cwd)}`,
|
|
105
|
+
kind: "async",
|
|
106
|
+
mode: "async",
|
|
107
|
+
packages: [pkg],
|
|
108
|
+
range: {
|
|
109
|
+
fromTag,
|
|
110
|
+
tagPrefix
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
async function createHybridSlices({ root, packages, cwd, history, fromTag, tagPrefix, partitions }) {
|
|
115
|
+
const partitionEntries = Object.entries(partitions ?? {}).sort(([a], [b]) => a.localeCompare(b));
|
|
116
|
+
const partitioned = [];
|
|
117
|
+
const usedPaths = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const [partition, definition] of partitionEntries) {
|
|
119
|
+
const matched = sortPackages(packages.filter((pkg) => {
|
|
120
|
+
if (usedPaths.has(pkg.path)) return false;
|
|
121
|
+
return definition.workspaces.some((selector) => matchesPackageSelector(pkg, cwd, selector));
|
|
122
|
+
}), cwd);
|
|
123
|
+
for (const pkg of matched) usedPaths.add(pkg.path);
|
|
124
|
+
const affectedPaths = await detectAffectedPackages({
|
|
125
|
+
cwd,
|
|
126
|
+
root,
|
|
127
|
+
packages: matched,
|
|
128
|
+
history,
|
|
129
|
+
range: resolvePartitionRange({
|
|
130
|
+
fromTag,
|
|
131
|
+
tagPrefix,
|
|
132
|
+
partition: definition
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
const scoped = matched.filter((pkg) => affectedPaths.has(pkg.path));
|
|
136
|
+
if (!scoped.length) continue;
|
|
137
|
+
const resolvedRange = resolvePartitionRange({
|
|
138
|
+
fromTag,
|
|
139
|
+
tagPrefix,
|
|
140
|
+
partition: definition
|
|
141
|
+
});
|
|
142
|
+
if (definition.mode === "sync") {
|
|
143
|
+
partitioned.push({
|
|
144
|
+
id: `partition:${partition}`,
|
|
145
|
+
kind: "partition",
|
|
146
|
+
mode: "sync",
|
|
147
|
+
partition,
|
|
148
|
+
packages: scoped,
|
|
149
|
+
range: resolvedRange
|
|
150
|
+
});
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
partitioned.push(...scoped.map((pkg) => ({
|
|
154
|
+
id: `partition:${partition}:${packageIdentity(pkg, cwd)}`,
|
|
155
|
+
kind: "partition",
|
|
156
|
+
mode: "async",
|
|
157
|
+
partition,
|
|
158
|
+
packages: [pkg],
|
|
159
|
+
range: resolvedRange
|
|
160
|
+
})));
|
|
161
|
+
}
|
|
162
|
+
const fallbackCandidates = sortPackages(packages.filter((pkg) => !usedPaths.has(pkg.path)), cwd);
|
|
163
|
+
const fallbackPaths = await detectAffectedPackages({
|
|
164
|
+
cwd,
|
|
165
|
+
root,
|
|
166
|
+
packages: fallbackCandidates,
|
|
167
|
+
history,
|
|
168
|
+
range: {
|
|
169
|
+
fromTag,
|
|
170
|
+
tagPrefix
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const fallback = fallbackCandidates.filter((pkg) => fallbackPaths.has(pkg.path)).map((pkg) => ({
|
|
174
|
+
id: `hybrid:${packageIdentity(pkg, cwd)}`,
|
|
175
|
+
kind: "async",
|
|
176
|
+
mode: "async",
|
|
177
|
+
packages: [pkg],
|
|
178
|
+
range: {
|
|
179
|
+
fromTag,
|
|
180
|
+
tagPrefix
|
|
181
|
+
}
|
|
182
|
+
}));
|
|
183
|
+
return [...partitioned, ...fallback];
|
|
184
|
+
}
|
|
185
|
+
function resolvePartitionRange({ fromTag, tagPrefix, partition }) {
|
|
186
|
+
return {
|
|
187
|
+
fromTag: partition.fromTag ?? fromTag,
|
|
188
|
+
tagPrefix: partition.tagPrefix ?? tagPrefix
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async function detectAffectedPackages({ cwd, root, packages, history, range }) {
|
|
192
|
+
const touched = await readCommitRangePaths(history, range);
|
|
193
|
+
if (touched === null) return new Set(packages.map((pkg) => pkg.path));
|
|
194
|
+
if (!touched.length) return /* @__PURE__ */ new Set();
|
|
195
|
+
const normalizedRoot = normalizePath((0, node_path.relative)(cwd, root.path));
|
|
196
|
+
const children = packages.filter((pkg) => pkg.path !== root.path).map((pkg) => ({
|
|
197
|
+
packagePath: pkg.path,
|
|
198
|
+
relativePath: normalizePath((0, node_path.relative)(cwd, pkg.path))
|
|
199
|
+
})).sort((a, b) => b.relativePath.length - a.relativePath.length);
|
|
200
|
+
const affected = /* @__PURE__ */ new Set();
|
|
201
|
+
for (const path of touched.map(normalizePath)) {
|
|
202
|
+
if (!isPathInside(path, normalizedRoot)) continue;
|
|
203
|
+
const child = children.find((entry) => isPathInside(path, entry.relativePath));
|
|
204
|
+
affected.add(child?.packagePath ?? root.path);
|
|
205
|
+
}
|
|
206
|
+
return affected;
|
|
207
|
+
}
|
|
208
|
+
function applyWorkspaceFilters(packages, cwd, selector) {
|
|
209
|
+
if (!selector?.include?.length && !selector?.exclude?.length) return packages;
|
|
210
|
+
return packages.filter((pkg) => {
|
|
211
|
+
if (!(selector.include?.length ? selector.include.some((entry) => matchesPackageSelector(pkg, cwd, entry)) : true)) return false;
|
|
212
|
+
return !(selector.exclude?.some((entry) => matchesPackageSelector(pkg, cwd, entry)) ?? false);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
function sortPackages(packages, cwd) {
|
|
216
|
+
return [...packages].sort((a, b) => packagePath(a, cwd).localeCompare(packagePath(b, cwd)));
|
|
217
|
+
}
|
|
218
|
+
function packagePath(pkg, cwd) {
|
|
219
|
+
return normalizePath((0, node_path.relative)(cwd, pkg.path));
|
|
220
|
+
}
|
|
221
|
+
function toPublicPath(pkg, cwd) {
|
|
222
|
+
return packagePath(pkg, cwd) || ".";
|
|
223
|
+
}
|
|
224
|
+
function matchesPackageSelector(pkg, cwd, selector) {
|
|
225
|
+
const name = pkg.manifest.name ?? pkg.name ?? "";
|
|
226
|
+
const path = packagePath(pkg, cwd);
|
|
227
|
+
return matchesGlob(name, selector) || matchesGlob(path, selector);
|
|
228
|
+
}
|
|
229
|
+
function matchesGlob(input, pattern) {
|
|
230
|
+
if (!pattern) return false;
|
|
231
|
+
if (pattern === "*") return true;
|
|
232
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "__DOUBLE_STAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLE_STAR__/g, ".*");
|
|
233
|
+
return new RegExp(`^${escaped}$`).test(input);
|
|
234
|
+
}
|
|
235
|
+
async function readCommitRangePaths(history, range) {
|
|
236
|
+
try {
|
|
237
|
+
return (await history.traverse({
|
|
238
|
+
fromTag: range.fromTag,
|
|
239
|
+
tagPrefix: range.tagPrefix,
|
|
240
|
+
changeset: true,
|
|
241
|
+
traversers: [(0, _modulify_conventional_git.createChangesetTraverser)()]
|
|
242
|
+
})).results.get("changeset").paths;
|
|
243
|
+
} catch {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function normalizePath(path) {
|
|
248
|
+
return path.replace(/\\/g, "/");
|
|
249
|
+
}
|
|
250
|
+
function isPathInside(path, root) {
|
|
251
|
+
return !root || root === "." || root === path || path.startsWith(`${root}/`);
|
|
252
|
+
}
|
|
253
|
+
//#endregion
|
|
254
|
+
exports.discover = discover;
|
|
255
|
+
exports.packageIdentity = packageIdentity;
|
|
256
|
+
exports.toScope = toScope;
|
|
257
|
+
exports.toScopePackage = toScopePackage;
|
|
258
|
+
exports.toSlice = toSlice;
|
|
259
|
+
exports.uniquePackages = uniquePackages;
|
|
260
|
+
exports.uniqueStrings = uniqueStrings;
|
package/dist/plan.mjs
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import "./constants.mjs";
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { createChangesetTraverser } from "@modulify/conventional-git";
|
|
4
|
+
import { read, walk } from "@modulify/pkg";
|
|
5
|
+
//#region src/plan.ts
|
|
6
|
+
function toScope(scope, cwd) {
|
|
7
|
+
return {
|
|
8
|
+
mode: scope.mode,
|
|
9
|
+
packages: scope.packages.map((pkg) => toScopePackage(pkg, cwd)),
|
|
10
|
+
affected: scope.affected.map((pkg) => toScopePackage(pkg, cwd)),
|
|
11
|
+
slices: scope.slices.map((slice) => toSlice(slice, cwd))
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Discovers packages, affected scope, and ordered release slices without side effects. */
|
|
15
|
+
async function discover(runtime, options) {
|
|
16
|
+
const root = read(runtime.cwd);
|
|
17
|
+
const packages = [];
|
|
18
|
+
await walk([root], async (pkg) => {
|
|
19
|
+
packages.push(pkg);
|
|
20
|
+
});
|
|
21
|
+
const discovered = sortPackages(uniquePackages(applyWorkspaceFilters(packages, runtime.cwd, options.workspaces)), runtime.cwd);
|
|
22
|
+
const mode = options.mode ?? "sync";
|
|
23
|
+
const affectedPaths = mode === "hybrid" ? null : await detectAffectedPackages({
|
|
24
|
+
cwd: runtime.cwd,
|
|
25
|
+
root,
|
|
26
|
+
packages: discovered,
|
|
27
|
+
history: runtime.history,
|
|
28
|
+
range: {
|
|
29
|
+
fromTag: options.fromTag,
|
|
30
|
+
tagPrefix: options.tagPrefix
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const affected = affectedPaths ? sortPackages(uniquePackages(discovered.filter((pkg) => affectedPaths.has(pkg.path))), runtime.cwd) : [];
|
|
34
|
+
const slices = mode === "hybrid" ? await createHybridSlices({
|
|
35
|
+
root,
|
|
36
|
+
packages: discovered,
|
|
37
|
+
cwd: runtime.cwd,
|
|
38
|
+
history: runtime.history,
|
|
39
|
+
fromTag: options.fromTag,
|
|
40
|
+
tagPrefix: options.tagPrefix,
|
|
41
|
+
partitions: options.partitions
|
|
42
|
+
}) : createSlices({
|
|
43
|
+
mode,
|
|
44
|
+
packages: discovered,
|
|
45
|
+
affected,
|
|
46
|
+
cwd: runtime.cwd,
|
|
47
|
+
fromTag: options.fromTag,
|
|
48
|
+
tagPrefix: options.tagPrefix
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
mode,
|
|
52
|
+
packages: discovered,
|
|
53
|
+
affected: mode === "hybrid" ? sortPackages(uniquePackages(slices.flatMap((slice) => slice.packages)), runtime.cwd) : affected,
|
|
54
|
+
slices
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function toScopePackage(pkg, cwd) {
|
|
58
|
+
return {
|
|
59
|
+
name: pkg.manifest.name ?? pkg.name,
|
|
60
|
+
version: pkg.manifest.version,
|
|
61
|
+
path: toPublicPath(pkg, cwd)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function toSlice(slice, cwd) {
|
|
65
|
+
return {
|
|
66
|
+
id: slice.id,
|
|
67
|
+
kind: slice.kind,
|
|
68
|
+
mode: slice.mode,
|
|
69
|
+
partition: slice.partition,
|
|
70
|
+
packages: slice.packages.map((pkg) => toScopePackage(pkg, cwd)),
|
|
71
|
+
range: slice.range
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function uniquePackages(packages) {
|
|
75
|
+
const seen = /* @__PURE__ */ new Set();
|
|
76
|
+
return packages.filter((pkg) => {
|
|
77
|
+
if (seen.has(pkg.path)) return false;
|
|
78
|
+
seen.add(pkg.path);
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function uniqueStrings(values) {
|
|
83
|
+
return [...new Set(values)];
|
|
84
|
+
}
|
|
85
|
+
function packageIdentity(pkg, cwd) {
|
|
86
|
+
const name = pkg.manifest.name ?? pkg.name;
|
|
87
|
+
if (name) return name;
|
|
88
|
+
const path = packagePath(pkg, cwd);
|
|
89
|
+
return path === "" || path === "." ? "root" : path;
|
|
90
|
+
}
|
|
91
|
+
function createSlices({ mode, packages, affected, cwd, fromTag, tagPrefix }) {
|
|
92
|
+
if (mode === "sync") return affected.length ? [{
|
|
93
|
+
id: "sync:default",
|
|
94
|
+
kind: "sync",
|
|
95
|
+
mode: "sync",
|
|
96
|
+
packages,
|
|
97
|
+
range: {
|
|
98
|
+
fromTag,
|
|
99
|
+
tagPrefix
|
|
100
|
+
}
|
|
101
|
+
}] : [];
|
|
102
|
+
return affected.map((pkg) => ({
|
|
103
|
+
id: `async:${packageIdentity(pkg, cwd)}`,
|
|
104
|
+
kind: "async",
|
|
105
|
+
mode: "async",
|
|
106
|
+
packages: [pkg],
|
|
107
|
+
range: {
|
|
108
|
+
fromTag,
|
|
109
|
+
tagPrefix
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
async function createHybridSlices({ root, packages, cwd, history, fromTag, tagPrefix, partitions }) {
|
|
114
|
+
const partitionEntries = Object.entries(partitions ?? {}).sort(([a], [b]) => a.localeCompare(b));
|
|
115
|
+
const partitioned = [];
|
|
116
|
+
const usedPaths = /* @__PURE__ */ new Set();
|
|
117
|
+
for (const [partition, definition] of partitionEntries) {
|
|
118
|
+
const matched = sortPackages(packages.filter((pkg) => {
|
|
119
|
+
if (usedPaths.has(pkg.path)) return false;
|
|
120
|
+
return definition.workspaces.some((selector) => matchesPackageSelector(pkg, cwd, selector));
|
|
121
|
+
}), cwd);
|
|
122
|
+
for (const pkg of matched) usedPaths.add(pkg.path);
|
|
123
|
+
const affectedPaths = await detectAffectedPackages({
|
|
124
|
+
cwd,
|
|
125
|
+
root,
|
|
126
|
+
packages: matched,
|
|
127
|
+
history,
|
|
128
|
+
range: resolvePartitionRange({
|
|
129
|
+
fromTag,
|
|
130
|
+
tagPrefix,
|
|
131
|
+
partition: definition
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
const scoped = matched.filter((pkg) => affectedPaths.has(pkg.path));
|
|
135
|
+
if (!scoped.length) continue;
|
|
136
|
+
const resolvedRange = resolvePartitionRange({
|
|
137
|
+
fromTag,
|
|
138
|
+
tagPrefix,
|
|
139
|
+
partition: definition
|
|
140
|
+
});
|
|
141
|
+
if (definition.mode === "sync") {
|
|
142
|
+
partitioned.push({
|
|
143
|
+
id: `partition:${partition}`,
|
|
144
|
+
kind: "partition",
|
|
145
|
+
mode: "sync",
|
|
146
|
+
partition,
|
|
147
|
+
packages: scoped,
|
|
148
|
+
range: resolvedRange
|
|
149
|
+
});
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
partitioned.push(...scoped.map((pkg) => ({
|
|
153
|
+
id: `partition:${partition}:${packageIdentity(pkg, cwd)}`,
|
|
154
|
+
kind: "partition",
|
|
155
|
+
mode: "async",
|
|
156
|
+
partition,
|
|
157
|
+
packages: [pkg],
|
|
158
|
+
range: resolvedRange
|
|
159
|
+
})));
|
|
160
|
+
}
|
|
161
|
+
const fallbackCandidates = sortPackages(packages.filter((pkg) => !usedPaths.has(pkg.path)), cwd);
|
|
162
|
+
const fallbackPaths = await detectAffectedPackages({
|
|
163
|
+
cwd,
|
|
164
|
+
root,
|
|
165
|
+
packages: fallbackCandidates,
|
|
166
|
+
history,
|
|
167
|
+
range: {
|
|
168
|
+
fromTag,
|
|
169
|
+
tagPrefix
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const fallback = fallbackCandidates.filter((pkg) => fallbackPaths.has(pkg.path)).map((pkg) => ({
|
|
173
|
+
id: `hybrid:${packageIdentity(pkg, cwd)}`,
|
|
174
|
+
kind: "async",
|
|
175
|
+
mode: "async",
|
|
176
|
+
packages: [pkg],
|
|
177
|
+
range: {
|
|
178
|
+
fromTag,
|
|
179
|
+
tagPrefix
|
|
180
|
+
}
|
|
181
|
+
}));
|
|
182
|
+
return [...partitioned, ...fallback];
|
|
183
|
+
}
|
|
184
|
+
function resolvePartitionRange({ fromTag, tagPrefix, partition }) {
|
|
185
|
+
return {
|
|
186
|
+
fromTag: partition.fromTag ?? fromTag,
|
|
187
|
+
tagPrefix: partition.tagPrefix ?? tagPrefix
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async function detectAffectedPackages({ cwd, root, packages, history, range }) {
|
|
191
|
+
const touched = await readCommitRangePaths(history, range);
|
|
192
|
+
if (touched === null) return new Set(packages.map((pkg) => pkg.path));
|
|
193
|
+
if (!touched.length) return /* @__PURE__ */ new Set();
|
|
194
|
+
const normalizedRoot = normalizePath(relative(cwd, root.path));
|
|
195
|
+
const children = packages.filter((pkg) => pkg.path !== root.path).map((pkg) => ({
|
|
196
|
+
packagePath: pkg.path,
|
|
197
|
+
relativePath: normalizePath(relative(cwd, pkg.path))
|
|
198
|
+
})).sort((a, b) => b.relativePath.length - a.relativePath.length);
|
|
199
|
+
const affected = /* @__PURE__ */ new Set();
|
|
200
|
+
for (const path of touched.map(normalizePath)) {
|
|
201
|
+
if (!isPathInside(path, normalizedRoot)) continue;
|
|
202
|
+
const child = children.find((entry) => isPathInside(path, entry.relativePath));
|
|
203
|
+
affected.add(child?.packagePath ?? root.path);
|
|
204
|
+
}
|
|
205
|
+
return affected;
|
|
206
|
+
}
|
|
207
|
+
function applyWorkspaceFilters(packages, cwd, selector) {
|
|
208
|
+
if (!selector?.include?.length && !selector?.exclude?.length) return packages;
|
|
209
|
+
return packages.filter((pkg) => {
|
|
210
|
+
if (!(selector.include?.length ? selector.include.some((entry) => matchesPackageSelector(pkg, cwd, entry)) : true)) return false;
|
|
211
|
+
return !(selector.exclude?.some((entry) => matchesPackageSelector(pkg, cwd, entry)) ?? false);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function sortPackages(packages, cwd) {
|
|
215
|
+
return [...packages].sort((a, b) => packagePath(a, cwd).localeCompare(packagePath(b, cwd)));
|
|
216
|
+
}
|
|
217
|
+
function packagePath(pkg, cwd) {
|
|
218
|
+
return normalizePath(relative(cwd, pkg.path));
|
|
219
|
+
}
|
|
220
|
+
function toPublicPath(pkg, cwd) {
|
|
221
|
+
return packagePath(pkg, cwd) || ".";
|
|
222
|
+
}
|
|
223
|
+
function matchesPackageSelector(pkg, cwd, selector) {
|
|
224
|
+
const name = pkg.manifest.name ?? pkg.name ?? "";
|
|
225
|
+
const path = packagePath(pkg, cwd);
|
|
226
|
+
return matchesGlob(name, selector) || matchesGlob(path, selector);
|
|
227
|
+
}
|
|
228
|
+
function matchesGlob(input, pattern) {
|
|
229
|
+
if (!pattern) return false;
|
|
230
|
+
if (pattern === "*") return true;
|
|
231
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "__DOUBLE_STAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLE_STAR__/g, ".*");
|
|
232
|
+
return new RegExp(`^${escaped}$`).test(input);
|
|
233
|
+
}
|
|
234
|
+
async function readCommitRangePaths(history, range) {
|
|
235
|
+
try {
|
|
236
|
+
return (await history.traverse({
|
|
237
|
+
fromTag: range.fromTag,
|
|
238
|
+
tagPrefix: range.tagPrefix,
|
|
239
|
+
changeset: true,
|
|
240
|
+
traversers: [createChangesetTraverser()]
|
|
241
|
+
})).results.get("changeset").paths;
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function normalizePath(path) {
|
|
247
|
+
return path.replace(/\\/g, "/");
|
|
248
|
+
}
|
|
249
|
+
function isPathInside(path, root) {
|
|
250
|
+
return !root || root === "." || root === path || path.startsWith(`${root}/`);
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
export { discover, packageIdentity, toScope, toScopePackage, toSlice, uniquePackages, uniqueStrings };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/reporter.ts
|
|
2
|
+
function createRunContext({ cwd, dry }) {
|
|
3
|
+
return {
|
|
4
|
+
cwd,
|
|
5
|
+
dry
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
async function reportStart(reporter, context) {
|
|
9
|
+
await reporter?.onStart?.(context);
|
|
10
|
+
}
|
|
11
|
+
async function reportScope(reporter, scope, context) {
|
|
12
|
+
await reporter?.onScope?.(scope, context);
|
|
13
|
+
}
|
|
14
|
+
async function reportSliceStart(reporter, slice, context) {
|
|
15
|
+
await reporter?.onSliceStart?.(slice, context);
|
|
16
|
+
}
|
|
17
|
+
async function reportSliceSuccess(reporter, slice, context) {
|
|
18
|
+
await reporter?.onSliceSuccess?.(slice, context);
|
|
19
|
+
}
|
|
20
|
+
async function reportSuccess(reporter, result, context) {
|
|
21
|
+
await reporter?.onSuccess?.(result, context);
|
|
22
|
+
}
|
|
23
|
+
async function reportError(reporter, error, context) {
|
|
24
|
+
await reporter?.onError?.(error, context);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.createRunContext = createRunContext;
|
|
28
|
+
exports.reportError = reportError;
|
|
29
|
+
exports.reportScope = reportScope;
|
|
30
|
+
exports.reportSliceStart = reportSliceStart;
|
|
31
|
+
exports.reportSliceSuccess = reportSliceSuccess;
|
|
32
|
+
exports.reportStart = reportStart;
|
|
33
|
+
exports.reportSuccess = reportSuccess;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/reporter.ts
|
|
2
|
+
function createRunContext({ cwd, dry }) {
|
|
3
|
+
return {
|
|
4
|
+
cwd,
|
|
5
|
+
dry
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
async function reportStart(reporter, context) {
|
|
9
|
+
await reporter?.onStart?.(context);
|
|
10
|
+
}
|
|
11
|
+
async function reportScope(reporter, scope, context) {
|
|
12
|
+
await reporter?.onScope?.(scope, context);
|
|
13
|
+
}
|
|
14
|
+
async function reportSliceStart(reporter, slice, context) {
|
|
15
|
+
await reporter?.onSliceStart?.(slice, context);
|
|
16
|
+
}
|
|
17
|
+
async function reportSliceSuccess(reporter, slice, context) {
|
|
18
|
+
await reporter?.onSliceSuccess?.(slice, context);
|
|
19
|
+
}
|
|
20
|
+
async function reportSuccess(reporter, result, context) {
|
|
21
|
+
await reporter?.onSuccess?.(result, context);
|
|
22
|
+
}
|
|
23
|
+
async function reportError(reporter, error, context) {
|
|
24
|
+
await reporter?.onError?.(error, context);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { createRunContext, reportError, reportScope, reportSliceStart, reportSliceSuccess, reportStart, reportSuccess };
|
package/dist/runtime.cjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require("./_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_constants = require("./constants.cjs");
|
|
3
|
+
let _modulify_git_toolkit = require("@modulify/git-toolkit");
|
|
4
|
+
let _modulify_git_toolkit_shell = require("@modulify/git-toolkit/shell");
|
|
5
|
+
let node_fs = require("node:fs");
|
|
6
|
+
let node_path = require("node:path");
|
|
7
|
+
let _modulify_conventional_git = require("@modulify/conventional-git");
|
|
8
|
+
let _modulify_conventional_changelog = require("@modulify/conventional-changelog");
|
|
9
|
+
//#region src/runtime.ts
|
|
10
|
+
/** Creates the default runtime used by the public planning and release APIs. */
|
|
11
|
+
function createRuntime({ cwd = process.cwd(), dry = false, changelogFile = require_constants.DEFAULT_CHANGELOG_FILE } = {}) {
|
|
12
|
+
const sh = new _modulify_git_toolkit_shell.Runner(cwd);
|
|
13
|
+
return {
|
|
14
|
+
cwd,
|
|
15
|
+
dry,
|
|
16
|
+
changelogFile,
|
|
17
|
+
packageManager: resolvePackageManager(cwd),
|
|
18
|
+
history: new _modulify_conventional_git.Client({ cwd }),
|
|
19
|
+
writeChangelog: (changes) => (0, _modulify_conventional_changelog.writeChangelog)(changes, { file: dry ? void 0 : (0, node_path.join)(cwd, changelogFile) }),
|
|
20
|
+
sh,
|
|
21
|
+
git: createGit(sh)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createGit(sh) {
|
|
25
|
+
const git = new _modulify_git_toolkit.GitCommander({ sh });
|
|
26
|
+
return {
|
|
27
|
+
add: (files) => git.add(files),
|
|
28
|
+
commit: (options) => git.commit(options),
|
|
29
|
+
tag: (options) => git.tag(options)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function resolvePackageManager(cwd) {
|
|
33
|
+
const command = readPackageManager(cwd) ?? inferPackageManagerFromLockfile(cwd) ?? "npm";
|
|
34
|
+
return {
|
|
35
|
+
command,
|
|
36
|
+
lockfile: resolveLockfile(cwd, command)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function readPackageManager(cwd) {
|
|
40
|
+
const file = (0, node_path.join)(cwd, "package.json");
|
|
41
|
+
if (!(0, node_fs.existsSync)(file)) return null;
|
|
42
|
+
const content = JSON.parse((0, node_fs.readFileSync)(file, "utf-8"));
|
|
43
|
+
if (typeof content.packageManager !== "string" || content.packageManager === "") return null;
|
|
44
|
+
const [name] = content.packageManager.split("@");
|
|
45
|
+
return isPackageManagerName(name) ? name : null;
|
|
46
|
+
}
|
|
47
|
+
function inferPackageManagerFromLockfile(cwd) {
|
|
48
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(cwd, "yarn.lock"))) return "yarn";
|
|
49
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
50
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(cwd, "package-lock.json"))) return "npm";
|
|
51
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(cwd, "bun.lock"))) return "bun";
|
|
52
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(cwd, "bun.lockb"))) return "bun";
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function resolveLockfile(cwd, command) {
|
|
56
|
+
if (command === "bun" && (0, node_fs.existsSync)((0, node_path.join)(cwd, "bun.lockb"))) return "bun.lockb";
|
|
57
|
+
return {
|
|
58
|
+
yarn: "yarn.lock",
|
|
59
|
+
pnpm: "pnpm-lock.yaml",
|
|
60
|
+
npm: "package-lock.json",
|
|
61
|
+
bun: "bun.lock"
|
|
62
|
+
}[command];
|
|
63
|
+
}
|
|
64
|
+
function isPackageManagerName(value) {
|
|
65
|
+
return value === "yarn" || value === "pnpm" || value === "npm" || value === "bun";
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
exports.createRuntime = createRuntime;
|