ts-repo-utils 7.8.1 → 7.9.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 +10 -0
- package/dist/cmd/assert-repo-is-clean.mjs +2 -1
- package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
- package/dist/cmd/check-should-run-type-checks.mjs +2 -1
- package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
- package/dist/cmd/format-diff-from.mjs +2 -1
- package/dist/cmd/format-diff-from.mjs.map +1 -1
- package/dist/cmd/format-uncommitted.mjs +2 -1
- package/dist/cmd/format-uncommitted.mjs.map +1 -1
- package/dist/cmd/gen-index-ts.mjs +2 -1
- package/dist/cmd/gen-index-ts.mjs.map +1 -1
- package/dist/entry-point.d.mts.map +1 -1
- package/dist/functions/assert-ext.d.mts +0 -1
- package/dist/functions/assert-ext.d.mts.map +1 -1
- package/dist/functions/assert-ext.mjs.map +1 -1
- package/dist/functions/assert-path-exists.d.mts.map +1 -1
- package/dist/functions/assert-path-exists.mjs.map +1 -1
- package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
- package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
- package/dist/functions/create-result-assert.d.mts +0 -1
- package/dist/functions/create-result-assert.d.mts.map +1 -1
- package/dist/functions/create-result-assert.mjs.map +1 -1
- package/dist/functions/diff.d.mts +0 -1
- package/dist/functions/diff.d.mts.map +1 -1
- package/dist/functions/exec-async.d.mts +0 -1
- package/dist/functions/exec-async.d.mts.map +1 -1
- package/dist/functions/exec-async.mjs.map +1 -1
- package/dist/functions/format.d.mts +4 -5
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +3 -3
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/gen-index.d.mts +0 -1
- package/dist/functions/gen-index.d.mts.map +1 -1
- package/dist/functions/gen-index.mjs.map +1 -1
- package/dist/functions/should-run.d.mts.map +1 -1
- package/dist/functions/should-run.mjs.map +1 -1
- package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
- package/dist/functions/workspace-utils/execute-parallel.mjs +4 -5
- package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
- package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs +2 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.mjs +2 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
- package/dist/node-global.d.mts +0 -1
- package/dist/node-global.d.mts.map +1 -1
- package/package.json +25 -26
- package/src/cmd/assert-repo-is-clean.mts +2 -1
- package/src/cmd/check-should-run-type-checks.mts +2 -1
- package/src/cmd/format-diff-from.mts +2 -1
- package/src/cmd/format-uncommitted.mts +3 -1
- package/src/cmd/gen-index-ts.mts +8 -2
- package/src/entry-point.mts +1 -0
- package/src/functions/assert-ext.mts +4 -0
- package/src/functions/assert-path-exists.mts +2 -0
- package/src/functions/assert-repo-is-clean.mts +9 -0
- package/src/functions/create-result-assert.mts +1 -0
- package/src/functions/diff.test.mts +136 -8
- package/src/functions/exec-async.mts +4 -0
- package/src/functions/exec-async.test.mts +59 -2
- package/src/functions/format.mts +26 -7
- package/src/functions/format.test.mts +166 -9
- package/src/functions/gen-index.mts +16 -0
- package/src/functions/should-run.mts +2 -0
- package/src/functions/workspace-utils/execute-parallel.mts +27 -5
- package/src/functions/workspace-utils/get-workspace-packages.mts +5 -0
- package/src/functions/workspace-utils/run-cmd-in-parallel.mts +7 -1
- package/src/functions/workspace-utils/run-cmd-in-stages.mts +7 -1
- package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +17 -3
- package/src/node-global.mts +7 -1
|
@@ -91,28 +91,35 @@ export const genIndex = async (
|
|
|
91
91
|
// Step 1: Verify target directories exist
|
|
92
92
|
for (const dir of targetDirs) {
|
|
93
93
|
const resolvedDir = path.resolve(dir);
|
|
94
|
+
|
|
94
95
|
// eslint-disable-next-line no-await-in-loop
|
|
95
96
|
await assertPathExists(resolvedDir, `Target directory: ${dir}`);
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// Step 2: Generate index files
|
|
99
100
|
conditionalEcho('Generating index files...');
|
|
101
|
+
|
|
100
102
|
for (const dir of targetDirs) {
|
|
101
103
|
const resolvedDir = path.resolve(dir);
|
|
104
|
+
|
|
102
105
|
// eslint-disable-next-line no-await-in-loop
|
|
103
106
|
await generateIndexFileForDir(resolvedDir, filledConfig);
|
|
104
107
|
}
|
|
108
|
+
|
|
105
109
|
conditionalEcho('✓ Index files generated\n');
|
|
106
110
|
|
|
107
111
|
// Step 3: Format generated files
|
|
108
112
|
if (filledConfig.formatCommand !== undefined) {
|
|
109
113
|
conditionalEcho('Formatting generated files...');
|
|
114
|
+
|
|
110
115
|
const fmtResult = await $(filledConfig.formatCommand, {
|
|
111
116
|
silent: filledConfig.silent,
|
|
112
117
|
});
|
|
118
|
+
|
|
113
119
|
if (Result.isErr(fmtResult)) {
|
|
114
120
|
throw new Error(`Formatting failed: ${fmtResult.value.message}`);
|
|
115
121
|
}
|
|
122
|
+
|
|
116
123
|
conditionalEcho('✓ Formatting completed\n');
|
|
117
124
|
}
|
|
118
125
|
|
|
@@ -121,6 +128,7 @@ export const genIndex = async (
|
|
|
121
128
|
return Result.ok(undefined);
|
|
122
129
|
} catch (error) {
|
|
123
130
|
conditionalEcho(`❌ Index generation failed: ${String(error)}\n`);
|
|
131
|
+
|
|
124
132
|
return Result.err(error);
|
|
125
133
|
}
|
|
126
134
|
};
|
|
@@ -148,6 +156,7 @@ const fillConfig = (config: GenIndexConfig): GenIndexConfigInternal => {
|
|
|
148
156
|
if (exclude !== undefined && Array.isArray(exclude)) {
|
|
149
157
|
yield* exclude;
|
|
150
158
|
}
|
|
159
|
+
|
|
151
160
|
yield* defaultConfig.exclude;
|
|
152
161
|
}),
|
|
153
162
|
),
|
|
@@ -169,6 +178,7 @@ const fillConfig = (config: GenIndexConfig): GenIndexConfigInternal => {
|
|
|
169
178
|
return true;
|
|
170
179
|
}
|
|
171
180
|
}
|
|
181
|
+
|
|
172
182
|
return false;
|
|
173
183
|
},
|
|
174
184
|
).value,
|
|
@@ -198,14 +208,18 @@ const generateIndexFileForDir = async (
|
|
|
198
208
|
): Promise<void> => {
|
|
199
209
|
try {
|
|
200
210
|
const actualBaseDir = baseDir ?? dirPath;
|
|
211
|
+
|
|
201
212
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
202
213
|
|
|
203
214
|
const mut_subDirectories: string[] = [];
|
|
215
|
+
|
|
204
216
|
const mut_filesToExport: string[] = [];
|
|
205
217
|
|
|
206
218
|
for (const entry of entries) {
|
|
207
219
|
const entryName = entry.name;
|
|
220
|
+
|
|
208
221
|
const entryPath = path.join(dirPath, entryName);
|
|
222
|
+
|
|
209
223
|
const relativePath = path.relative(actualBaseDir, entryPath);
|
|
210
224
|
|
|
211
225
|
if (
|
|
@@ -220,6 +234,7 @@ const generateIndexFileForDir = async (
|
|
|
220
234
|
|
|
221
235
|
if (entry.isDirectory()) {
|
|
222
236
|
mut_subDirectories.push(entryName);
|
|
237
|
+
|
|
223
238
|
// Recursively call for subdirectories first
|
|
224
239
|
// eslint-disable-next-line no-await-in-loop
|
|
225
240
|
await generateIndexFileForDir(entryPath, config, actualBaseDir);
|
|
@@ -244,6 +259,7 @@ const generateIndexFileForDir = async (
|
|
|
244
259
|
const indexPath = path.join(dirPath, `index${config.indexFileExtension}`);
|
|
245
260
|
|
|
246
261
|
await fs.writeFile(indexPath, indexContent);
|
|
262
|
+
|
|
247
263
|
echo(`Generated: ${path.relative(process.cwd(), indexPath)}`);
|
|
248
264
|
} catch (error) {
|
|
249
265
|
throw new Error(
|
|
@@ -84,6 +84,7 @@ export const checkShouldRunTypeChecks = async (
|
|
|
84
84
|
|
|
85
85
|
if (Result.isErr(files)) {
|
|
86
86
|
console.error('Error getting diff:', files.value);
|
|
87
|
+
|
|
87
88
|
process.exit(1);
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -102,6 +103,7 @@ export const checkShouldRunTypeChecks = async (
|
|
|
102
103
|
// File extension pattern match (pattern starts with '**.')
|
|
103
104
|
if (pattern.startsWith('**.')) {
|
|
104
105
|
const extension = pattern.slice(2); // Remove '**'
|
|
106
|
+
|
|
105
107
|
return path.basename(file).endsWith(extension);
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable require-atomic-updates */
|
|
2
|
+
import { isError } from '@sindresorhus/is';
|
|
2
3
|
import { spawn } from 'node:child_process';
|
|
3
4
|
import {
|
|
4
5
|
createPromise,
|
|
@@ -35,6 +36,7 @@ export const executeParallel = async (
|
|
|
35
36
|
>[] = [];
|
|
36
37
|
|
|
37
38
|
const mut_executing = new Set<Promise<unknown>>();
|
|
39
|
+
|
|
38
40
|
let mut_failed = false as boolean;
|
|
39
41
|
|
|
40
42
|
for (const pkg of packages) {
|
|
@@ -48,8 +50,10 @@ export const executeParallel = async (
|
|
|
48
50
|
// Check for failure immediately
|
|
49
51
|
if (Result.isErr(result)) {
|
|
50
52
|
mut_failed = true;
|
|
53
|
+
|
|
51
54
|
throw result.value; // Throw the error to trigger fail-fast
|
|
52
55
|
}
|
|
56
|
+
|
|
53
57
|
return result.value; // Return the unwrapped value for success
|
|
54
58
|
});
|
|
55
59
|
|
|
@@ -59,10 +63,12 @@ export const executeParallel = async (
|
|
|
59
63
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
60
64
|
.catch((error: unknown) => {
|
|
61
65
|
mut_failed = true;
|
|
66
|
+
|
|
62
67
|
throw error; // Re-throw to ensure fail-fast propagation
|
|
63
68
|
})
|
|
64
69
|
.finally(() => {
|
|
65
70
|
mut_executing.delete(wrappedPromise);
|
|
71
|
+
|
|
66
72
|
if (DEBUG) {
|
|
67
73
|
console.debug('executing size', mut_executing.size);
|
|
68
74
|
}
|
|
@@ -83,6 +89,7 @@ export const executeParallel = async (
|
|
|
83
89
|
// If any process fails, cancel remaining processes and throw immediately
|
|
84
90
|
// eslint-disable-next-line no-useless-assignment
|
|
85
91
|
mut_failed = true;
|
|
92
|
+
|
|
86
93
|
throw error;
|
|
87
94
|
}
|
|
88
95
|
}
|
|
@@ -116,6 +123,7 @@ export const executeStages = async (
|
|
|
116
123
|
const sorted = topologicalSortPackages(packages, dependencyGraph);
|
|
117
124
|
|
|
118
125
|
const mut_stages: (readonly Package[])[] = [];
|
|
126
|
+
|
|
119
127
|
const mut_completed = new Set<string>();
|
|
120
128
|
|
|
121
129
|
while (mut_completed.size < sorted.length) {
|
|
@@ -125,6 +133,7 @@ export const executeStages = async (
|
|
|
125
133
|
if (mut_completed.has(pkg.name)) continue;
|
|
126
134
|
|
|
127
135
|
const deps = dependencyGraph.get(pkg.name) ?? [];
|
|
136
|
+
|
|
128
137
|
const depsCompleted = deps.every((dep) => mut_completed.has(dep));
|
|
129
138
|
|
|
130
139
|
if (depsCompleted) {
|
|
@@ -137,6 +146,7 @@ export const executeStages = async (
|
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
mut_stages.push(mut_stage);
|
|
149
|
+
|
|
140
150
|
for (const pkg of mut_stage) {
|
|
141
151
|
mut_completed.add(pkg.name);
|
|
142
152
|
}
|
|
@@ -149,6 +159,7 @@ export const executeStages = async (
|
|
|
149
159
|
for (const [i, stage] of mut_stages.entries()) {
|
|
150
160
|
if (stage.length > 0) {
|
|
151
161
|
console.log(`Stage ${i + 1}: ${stage.map((p) => p.name).join(', ')}`);
|
|
162
|
+
|
|
152
163
|
try {
|
|
153
164
|
// eslint-disable-next-line no-await-in-loop
|
|
154
165
|
const results = await executeParallel(stage, scriptName, concurrency);
|
|
@@ -160,11 +171,12 @@ export const executeStages = async (
|
|
|
160
171
|
);
|
|
161
172
|
} catch (error) {
|
|
162
173
|
// executeParallel will throw immediately on any failure (fail-fast)
|
|
163
|
-
const errorMessage =
|
|
164
|
-
|
|
165
|
-
: String(error);
|
|
174
|
+
const errorMessage = isError(error) ? error.message : String(error);
|
|
175
|
+
|
|
166
176
|
console.error(`\n❌ Stage ${i + 1} failed (fail-fast):`);
|
|
177
|
+
|
|
167
178
|
console.error(errorMessage);
|
|
179
|
+
|
|
168
180
|
throw new Error(`Stage ${i + 1} failed: ${errorMessage}`, {
|
|
169
181
|
cause: error,
|
|
170
182
|
});
|
|
@@ -203,12 +215,15 @@ const executeScript = (
|
|
|
203
215
|
: {};
|
|
204
216
|
|
|
205
217
|
const hasScript = hasKey(packageJsonScripts, scriptName);
|
|
218
|
+
|
|
206
219
|
if (!hasScript) {
|
|
207
220
|
resolve({ skipped: true });
|
|
221
|
+
|
|
208
222
|
return;
|
|
209
223
|
}
|
|
210
224
|
|
|
211
225
|
const prefixStr = prefix ? `[${pkg.name}] ` : '';
|
|
226
|
+
|
|
212
227
|
const proc = spawn('npm', ['run', scriptName], {
|
|
213
228
|
cwd: pkg.path,
|
|
214
229
|
shell: true,
|
|
@@ -227,6 +242,7 @@ const executeScript = (
|
|
|
227
242
|
if (DEBUG) {
|
|
228
243
|
console.debug(`${pkg.name} process closed with code: ${code}`);
|
|
229
244
|
}
|
|
245
|
+
|
|
230
246
|
if (code === 0 || code === null) {
|
|
231
247
|
resolve({ code: code ?? 0 });
|
|
232
248
|
} else {
|
|
@@ -240,14 +256,15 @@ const executeScript = (
|
|
|
240
256
|
).map((result) =>
|
|
241
257
|
result.then(
|
|
242
258
|
Result.mapErr((err) => {
|
|
243
|
-
const errorMessage: string =
|
|
259
|
+
const errorMessage: string = isError(err)
|
|
244
260
|
? err.message
|
|
245
261
|
: isRecord(err) && hasKey(err, 'message')
|
|
246
262
|
? (err.message?.toString() ?? 'Unknown error message')
|
|
247
263
|
: 'Unknown error';
|
|
248
264
|
|
|
249
265
|
console.error(`\nError in ${pkg.name}:`, errorMessage);
|
|
250
|
-
|
|
266
|
+
|
|
267
|
+
return isError(err) ? err : new Error(errorMessage);
|
|
251
268
|
}),
|
|
252
269
|
),
|
|
253
270
|
).value;
|
|
@@ -264,15 +281,18 @@ const topologicalSortPackages = (
|
|
|
264
281
|
dependencyGraph: ReadonlyMap<string, readonly string[]>,
|
|
265
282
|
): readonly Package[] => {
|
|
266
283
|
const mut_visited = new Set<string>();
|
|
284
|
+
|
|
267
285
|
const mut_result: string[] = [];
|
|
268
286
|
|
|
269
287
|
const packageMap = new Map(packages.map((p) => [p.name, p]));
|
|
270
288
|
|
|
271
289
|
const visit = (pkgName: string): void => {
|
|
272
290
|
if (mut_visited.has(pkgName)) return;
|
|
291
|
+
|
|
273
292
|
mut_visited.add(pkgName);
|
|
274
293
|
|
|
275
294
|
const deps = dependencyGraph.get(pkgName) ?? [];
|
|
295
|
+
|
|
276
296
|
for (const dep of deps) {
|
|
277
297
|
visit(dep);
|
|
278
298
|
}
|
|
@@ -301,12 +321,14 @@ const buildDependencyGraph = (
|
|
|
301
321
|
packages: readonly Package[],
|
|
302
322
|
): ReadonlyMap<string, readonly string[]> => {
|
|
303
323
|
const packageMap = new Map(packages.map((p) => [p.name, p]));
|
|
324
|
+
|
|
304
325
|
const mut_graph = new Map<string, readonly string[]>();
|
|
305
326
|
|
|
306
327
|
for (const pkg of packages) {
|
|
307
328
|
const deps = Object.keys(pkg.dependencies).filter((depName) =>
|
|
308
329
|
packageMap.has(depName),
|
|
309
330
|
);
|
|
331
|
+
|
|
310
332
|
mut_graph.set(pkg.name, deps);
|
|
311
333
|
}
|
|
312
334
|
|
|
@@ -80,6 +80,7 @@ export const getWorkspacePackages = async (
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
const allPackageArrays = await Promise.all(packagePromises);
|
|
83
|
+
|
|
83
84
|
const finalPackages = allPackageArrays.flat();
|
|
84
85
|
|
|
85
86
|
return finalPackages;
|
|
@@ -108,12 +109,16 @@ const getKeyValueRecordFromJsonValue = (
|
|
|
108
109
|
if (!isRecord(value) || !hasKey(value, key)) {
|
|
109
110
|
return {};
|
|
110
111
|
}
|
|
112
|
+
|
|
111
113
|
const obj = value[key];
|
|
114
|
+
|
|
112
115
|
if (!isRecord(obj)) {
|
|
113
116
|
return {};
|
|
114
117
|
}
|
|
118
|
+
|
|
115
119
|
const entries = Object.entries(obj).filter(
|
|
116
120
|
(entry): entry is [string, string] => isString(entry[1]),
|
|
117
121
|
);
|
|
122
|
+
|
|
118
123
|
return Object.fromEntries(entries);
|
|
119
124
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
|
+
import { isError } from '@sindresorhus/is';
|
|
3
4
|
import { executeParallel } from './execute-parallel.mjs';
|
|
4
5
|
import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
5
6
|
|
|
@@ -40,14 +41,19 @@ export const runCmdInParallelAcrossWorkspaces = async ({
|
|
|
40
41
|
console.log(
|
|
41
42
|
`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast parallel mode)...`,
|
|
42
43
|
);
|
|
44
|
+
|
|
43
45
|
await executeParallel(filteredPackages, cmd, concurrency);
|
|
46
|
+
|
|
44
47
|
console.log(`\n✅ ${cmd} completed successfully (all packages)`);
|
|
45
48
|
} catch (error) {
|
|
46
|
-
const errorMessage =
|
|
49
|
+
const errorMessage = isError(error)
|
|
47
50
|
? error.message
|
|
48
51
|
: (error?.toString() ?? '');
|
|
52
|
+
|
|
49
53
|
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
54
|
+
|
|
50
55
|
console.error(errorMessage);
|
|
56
|
+
|
|
51
57
|
process.exit(1);
|
|
52
58
|
}
|
|
53
59
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
|
+
import { isError } from '@sindresorhus/is';
|
|
3
4
|
import { executeStages } from './execute-parallel.mjs';
|
|
4
5
|
import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
5
6
|
|
|
@@ -42,14 +43,19 @@ export const runCmdInStagesAcrossWorkspaces = async ({
|
|
|
42
43
|
console.log(
|
|
43
44
|
`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast mode)...`,
|
|
44
45
|
);
|
|
46
|
+
|
|
45
47
|
await executeStages(filteredPackages, cmd, concurrency);
|
|
48
|
+
|
|
46
49
|
console.log(`\n✅ ${cmd} completed successfully (all stages)`);
|
|
47
50
|
} catch (error) {
|
|
48
|
-
const errorMessage =
|
|
51
|
+
const errorMessage = isError(error)
|
|
49
52
|
? error.message
|
|
50
53
|
: (error?.toString() ?? '');
|
|
54
|
+
|
|
51
55
|
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
56
|
+
|
|
52
57
|
console.error(errorMessage);
|
|
58
|
+
|
|
53
59
|
process.exit(1);
|
|
54
60
|
}
|
|
55
61
|
};
|
|
@@ -7,15 +7,15 @@ import { runCmdInStagesAcrossWorkspaces } from './run-cmd-in-stages.mjs';
|
|
|
7
7
|
import { type Package } from './types.mjs';
|
|
8
8
|
|
|
9
9
|
// Mock the dependencies
|
|
10
|
-
vi.mock('./execute-parallel.mjs', () => ({
|
|
10
|
+
vi.mock(import('./execute-parallel.mjs'), () => ({
|
|
11
11
|
executeStages: vi.fn(),
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
vi.mock('./get-workspace-packages.mjs', () => ({
|
|
14
|
+
vi.mock(import('./get-workspace-packages.mjs'), () => ({
|
|
15
15
|
getWorkspacePackages: vi.fn(),
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
|
-
describe(
|
|
18
|
+
describe(runCmdInStagesAcrossWorkspaces, () => {
|
|
19
19
|
type MockedSpies = Readonly<{
|
|
20
20
|
consoleLogSpy: MockInstance<typeof console.log>;
|
|
21
21
|
consoleErrorSpy: MockInstance<typeof console.error>;
|
|
@@ -24,9 +24,11 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
24
24
|
|
|
25
25
|
const setupSpies = (): MockedSpies => {
|
|
26
26
|
vi.clearAllMocks();
|
|
27
|
+
|
|
27
28
|
const consoleLogSpy = vi
|
|
28
29
|
.spyOn(console, 'log')
|
|
29
30
|
.mockImplementation((): void => {});
|
|
31
|
+
|
|
30
32
|
const consoleErrorSpy = vi
|
|
31
33
|
.spyOn(console, 'error')
|
|
32
34
|
.mockImplementation((): void => {});
|
|
@@ -42,7 +44,9 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
42
44
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
43
45
|
const cleanupSpies = (spies: MockedSpies): void => {
|
|
44
46
|
spies.consoleLogSpy.mockRestore();
|
|
47
|
+
|
|
45
48
|
spies.consoleErrorSpy.mockRestore();
|
|
49
|
+
|
|
46
50
|
spies.processExitSpy.mockRestore();
|
|
47
51
|
};
|
|
48
52
|
|
|
@@ -76,6 +80,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
76
80
|
|
|
77
81
|
// Mock executeStages to throw an error (simulating a failed command)
|
|
78
82
|
const mockError = new Error('package-a exited with code 1');
|
|
83
|
+
|
|
79
84
|
vi.mocked(executeStages).mockRejectedValue(mockError);
|
|
80
85
|
|
|
81
86
|
// Record start time
|
|
@@ -90,6 +95,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
90
95
|
|
|
91
96
|
// Record end time
|
|
92
97
|
const endTime = Date.now();
|
|
98
|
+
|
|
93
99
|
const executionTime = endTime - startTime;
|
|
94
100
|
|
|
95
101
|
// Verify that execution was fast (fail-fast behavior)
|
|
@@ -103,6 +109,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
103
109
|
expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
|
|
104
110
|
'\n❌ test failed (fail-fast mode stopped execution):',
|
|
105
111
|
);
|
|
112
|
+
|
|
106
113
|
expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
|
|
107
114
|
'package-a exited with code 1',
|
|
108
115
|
);
|
|
@@ -140,6 +147,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
140
147
|
];
|
|
141
148
|
|
|
142
149
|
vi.mocked(getWorkspacePackages).mockResolvedValue(mockPackages);
|
|
150
|
+
|
|
143
151
|
vi.mocked(executeStages).mockResolvedValue(undefined);
|
|
144
152
|
|
|
145
153
|
// Execute the function
|
|
@@ -156,6 +164,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
156
164
|
expect(spies.consoleLogSpy).toHaveBeenCalledWith(
|
|
157
165
|
'\nStarting test across 2 packages (fail-fast mode)...',
|
|
158
166
|
);
|
|
167
|
+
|
|
159
168
|
expect(spies.consoleLogSpy).toHaveBeenCalledWith(
|
|
160
169
|
'\n✅ test completed successfully (all stages)',
|
|
161
170
|
);
|
|
@@ -200,6 +209,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
200
209
|
];
|
|
201
210
|
|
|
202
211
|
vi.mocked(getWorkspacePackages).mockResolvedValue(mockPackages);
|
|
212
|
+
|
|
203
213
|
vi.mocked(executeStages).mockResolvedValue(undefined);
|
|
204
214
|
|
|
205
215
|
// Filter to only packages starting with 'package-'
|
|
@@ -217,6 +227,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
217
227
|
const expectedFilteredPackages = mockPackages.filter((pkg) =>
|
|
218
228
|
pkg.name.startsWith('package-'),
|
|
219
229
|
);
|
|
230
|
+
|
|
220
231
|
expect(executeStages).toHaveBeenCalledWith(
|
|
221
232
|
expectedFilteredPackages,
|
|
222
233
|
'test',
|
|
@@ -238,6 +249,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
238
249
|
try {
|
|
239
250
|
// Mock getWorkspacePackages to throw an error
|
|
240
251
|
const mockError = new Error('Failed to load workspace packages');
|
|
252
|
+
|
|
241
253
|
vi.mocked(getWorkspacePackages).mockRejectedValue(mockError);
|
|
242
254
|
|
|
243
255
|
// Execute the function
|
|
@@ -254,9 +266,11 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
|
|
|
254
266
|
expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
|
|
255
267
|
'\n❌ test failed (fail-fast mode stopped execution):',
|
|
256
268
|
);
|
|
269
|
+
|
|
257
270
|
expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
|
|
258
271
|
'Failed to load workspace packages',
|
|
259
272
|
);
|
|
273
|
+
|
|
260
274
|
expect(spies.processExitSpy).toHaveBeenCalledWith(1);
|
|
261
275
|
} finally {
|
|
262
276
|
cleanupSpies(spies);
|
package/src/node-global.mts
CHANGED
|
@@ -29,14 +29,20 @@ Object.assign(globalThis, globalsDef);
|
|
|
29
29
|
|
|
30
30
|
declare global {
|
|
31
31
|
const path: typeof path_;
|
|
32
|
+
|
|
32
33
|
const fs: typeof fs_;
|
|
34
|
+
|
|
33
35
|
const os: typeof os_;
|
|
36
|
+
|
|
34
37
|
const glob: typeof glob_;
|
|
35
38
|
|
|
36
39
|
const $: typeof $_;
|
|
40
|
+
|
|
37
41
|
const Result: typeof Result_;
|
|
38
|
-
|
|
42
|
+
|
|
39
43
|
const echo: typeof console.log;
|
|
44
|
+
|
|
40
45
|
const cd: typeof chdir_;
|
|
46
|
+
|
|
41
47
|
const isDirectlyExecuted: typeof isDirectlyExecuted_;
|
|
42
48
|
}
|