ts-repo-utils 6.0.3 → 6.0.5
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/cmd/assert-repo-is-clean.mjs +21 -21
- package/dist/cmd/check-should-run-type-checks.mjs +28 -30
- package/dist/cmd/format-diff-from.mjs +33 -34
- package/dist/cmd/format-untracked.mjs +23 -23
- package/dist/cmd/gen-index-ts.mjs +86 -102
- package/dist/functions/workspace-utils/execute-parallel.d.mts +10 -7
- package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
- package/dist/functions/workspace-utils/execute-parallel.mjs +60 -14
- package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts +3 -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 +8 -3
- package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
- package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts +3 -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 +8 -3
- package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
- package/package.json +10 -6
- package/src/cmd/assert-repo-is-clean.mts +1 -1
- package/src/cmd/check-should-run-type-checks.mts +1 -1
- package/src/cmd/format-diff-from.mts +1 -1
- package/src/cmd/format-untracked.mts +1 -1
- package/src/cmd/gen-index-ts.mts +1 -1
- package/src/functions/diff.test.mts +5 -1
- package/src/functions/workspace-utils/execute-parallel.mts +74 -22
- package/src/functions/workspace-utils/run-cmd-in-parallel.mts +11 -6
- package/src/functions/workspace-utils/run-cmd-in-stages.mts +11 -6
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
import 'child_process';
|
|
3
2
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import 'micromatch';
|
|
5
|
-
import 'node:child_process';
|
|
6
|
-
import 'prettier';
|
|
7
3
|
import 'ts-data-forge';
|
|
8
|
-
import { assertRepoIsClean } from '../functions/assert-repo-is-clean.mjs';
|
|
9
4
|
import '../node-global.mjs';
|
|
5
|
+
import { assertRepoIsClean } from '../functions/assert-repo-is-clean.mjs';
|
|
6
|
+
import 'node:child_process';
|
|
7
|
+
import 'prettier';
|
|
8
|
+
import 'micromatch';
|
|
9
|
+
import 'child_process';
|
|
10
10
|
|
|
11
11
|
const cmdDef = cmd.command({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
name: 'assert-repo-is-clean-cli',
|
|
13
|
+
version: '6.0.5',
|
|
14
|
+
args: {
|
|
15
|
+
silent: cmd.flag({
|
|
16
|
+
long: 'silent',
|
|
17
|
+
type: cmd.optional(cmd.boolean),
|
|
18
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
handler: (args) => {
|
|
22
|
+
main(args).catch((error) => {
|
|
23
|
+
console.error('An error occurred:', error);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
27
|
});
|
|
28
28
|
const main = async (args) => {
|
|
29
|
-
|
|
29
|
+
await assertRepoIsClean({ silent: args.silent });
|
|
30
30
|
};
|
|
31
31
|
await cmd.run(cmdDef, process.argv.slice(2));
|
|
32
32
|
//# sourceMappingURL=assert-repo-is-clean.mjs.map
|
|
@@ -1,42 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
import 'child_process';
|
|
3
2
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import '
|
|
3
|
+
import 'ts-data-forge';
|
|
4
|
+
import '../node-global.mjs';
|
|
5
5
|
import 'node:child_process';
|
|
6
6
|
import 'prettier';
|
|
7
|
-
import '
|
|
7
|
+
import 'micromatch';
|
|
8
8
|
import { checkShouldRunTypeChecks } from '../functions/should-run.mjs';
|
|
9
|
-
import '
|
|
9
|
+
import 'child_process';
|
|
10
10
|
|
|
11
11
|
const cmdDef = cmd.command({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
},
|
|
12
|
+
name: 'check-should-run-type-checks-cli',
|
|
13
|
+
version: '6.0.5',
|
|
14
|
+
args: {
|
|
15
|
+
pathsIgnore: cmd.multioption({
|
|
16
|
+
long: 'paths-ignore',
|
|
17
|
+
type: cmd.optional(cmd.array(cmd.string)),
|
|
18
|
+
description: 'Patterns to ignore when checking if type checks should run. Supports exact file matches, directory prefixes (ending with "/"), and file extensions (starting with "**.")',
|
|
19
|
+
}),
|
|
20
|
+
baseBranch: cmd.option({
|
|
21
|
+
long: 'base-branch',
|
|
22
|
+
type: cmd.optional(cmd.string),
|
|
23
|
+
description: 'Base branch to compare against for determining changed files. Defaults to "origin/main"',
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
handler: (args) => {
|
|
27
|
+
main(args).catch((error) => {
|
|
28
|
+
console.error('An error occurred:', error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
},
|
|
34
32
|
});
|
|
35
33
|
const main = async (args) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
await checkShouldRunTypeChecks({
|
|
35
|
+
pathsIgnore: args.pathsIgnore,
|
|
36
|
+
baseBranch: args.baseBranch,
|
|
37
|
+
});
|
|
40
38
|
};
|
|
41
39
|
await cmd.run(cmdDef, process.argv.slice(2));
|
|
42
40
|
//# sourceMappingURL=check-should-run-type-checks.mjs.map
|
|
@@ -1,45 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
import 'child_process';
|
|
3
2
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import 'micromatch';
|
|
5
|
-
import 'node:child_process';
|
|
6
3
|
import 'ts-data-forge';
|
|
7
|
-
import { formatDiffFrom } from '../functions/format.mjs';
|
|
8
4
|
import '../node-global.mjs';
|
|
5
|
+
import 'node:child_process';
|
|
6
|
+
import { formatDiffFrom } from '../functions/format.mjs';
|
|
7
|
+
import 'micromatch';
|
|
8
|
+
import 'child_process';
|
|
9
9
|
|
|
10
10
|
const cmdDef = cmd.command({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
},
|
|
11
|
+
name: 'format-diff-from-cli',
|
|
12
|
+
version: '6.0.5',
|
|
13
|
+
args: {
|
|
14
|
+
base: cmd.positional({
|
|
15
|
+
type: cmd.string,
|
|
16
|
+
displayName: 'base',
|
|
17
|
+
description: 'Base branch name or commit hash to compare against',
|
|
18
|
+
}),
|
|
19
|
+
includeUntracked: cmd.flag({
|
|
20
|
+
long: 'include-untracked',
|
|
21
|
+
type: cmd.optional(cmd.boolean),
|
|
22
|
+
description: 'Include untracked files in addition to diff files (default: true)',
|
|
23
|
+
}),
|
|
24
|
+
silent: cmd.flag({
|
|
25
|
+
long: 'silent',
|
|
26
|
+
type: cmd.optional(cmd.boolean),
|
|
27
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
handler: (args) => {
|
|
31
|
+
main(args).catch((error) => {
|
|
32
|
+
console.error('An error occurred:', error);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
},
|
|
37
36
|
});
|
|
38
37
|
const main = async (args) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
const result = await formatDiffFrom(args.base, args);
|
|
39
|
+
if (result === 'err') {
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
43
42
|
};
|
|
44
43
|
await cmd.run(cmdDef, process.argv.slice(2));
|
|
45
44
|
//# sourceMappingURL=format-diff-from.mjs.map
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
import 'child_process';
|
|
3
2
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import 'micromatch';
|
|
5
|
-
import 'node:child_process';
|
|
6
3
|
import 'ts-data-forge';
|
|
7
|
-
import { formatUntracked } from '../functions/format.mjs';
|
|
8
4
|
import '../node-global.mjs';
|
|
5
|
+
import 'node:child_process';
|
|
6
|
+
import { formatUntracked } from '../functions/format.mjs';
|
|
7
|
+
import 'micromatch';
|
|
8
|
+
import 'child_process';
|
|
9
9
|
|
|
10
10
|
const cmdDef = cmd.command({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
name: 'format-untracked-cli',
|
|
12
|
+
version: '6.0.5',
|
|
13
|
+
args: {
|
|
14
|
+
silent: cmd.flag({
|
|
15
|
+
long: 'silent',
|
|
16
|
+
type: cmd.optional(cmd.boolean),
|
|
17
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
20
|
+
handler: (args) => {
|
|
21
|
+
main(args).catch((error) => {
|
|
22
|
+
console.error('An error occurred:', error);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
26
|
});
|
|
27
27
|
const main = async (args) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const result = await formatUntracked({ silent: args.silent });
|
|
29
|
+
if (result === 'err') {
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
32
|
};
|
|
33
33
|
await cmd.run(cmdDef, process.argv.slice(2));
|
|
34
34
|
//# sourceMappingURL=format-untracked.mjs.map
|
|
@@ -1,119 +1,103 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
import 'child_process';
|
|
3
2
|
import * as cmd from 'cmd-ts';
|
|
3
|
+
import 'ts-data-forge';
|
|
4
|
+
import '../node-global.mjs';
|
|
4
5
|
import 'node:child_process';
|
|
5
6
|
import 'prettier';
|
|
6
|
-
import 'ts-data-forge';
|
|
7
7
|
import { genIndex } from '../functions/gen-index.mjs';
|
|
8
|
-
import '
|
|
8
|
+
import 'child_process';
|
|
9
9
|
|
|
10
10
|
const extensionType = cmd.extendType(cmd.string, {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
from: (s) => {
|
|
12
|
+
if (!s.startsWith('.')) {
|
|
13
|
+
throw new Error(`ext should start with '.'`);
|
|
14
|
+
}
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
16
|
+
return Promise.resolve(s);
|
|
17
|
+
},
|
|
18
18
|
});
|
|
19
19
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
-
const nonEmptyArray = (t, commandName) =>
|
|
21
|
-
cmd.extendType(cmd.array(t), {
|
|
20
|
+
const nonEmptyArray = (t, commandName) => cmd.extendType(cmd.array(t), {
|
|
22
21
|
from: (arr) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
29
|
-
return Promise.resolve(arr);
|
|
22
|
+
if (arr.length === 0) {
|
|
23
|
+
throw new Error(`No value provided for --${commandName}. At least one value is required.`);
|
|
24
|
+
}
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
26
|
+
return Promise.resolve(arr);
|
|
30
27
|
},
|
|
31
|
-
|
|
28
|
+
});
|
|
32
29
|
const cmdDef = cmd.command({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'Directory where the index file will be generated (Comma-separated list can be used)',
|
|
42
|
-
}),
|
|
43
|
-
targetExtensions: cmd.multioption({
|
|
44
|
-
long: 'target-ext',
|
|
45
|
-
type: nonEmptyArray(extensionType, 'target-ext'),
|
|
46
|
-
description: 'File extensions to include in the index file',
|
|
47
|
-
}),
|
|
48
|
-
indexFileExtension: cmd.option({
|
|
49
|
-
long: 'index-ext',
|
|
50
|
-
type: extensionType,
|
|
51
|
-
description: 'Extension of the index file to be generated',
|
|
52
|
-
}),
|
|
53
|
-
exportStatementExtension: cmd.option({
|
|
54
|
-
long: 'export-ext',
|
|
55
|
-
type: cmd.union([
|
|
56
|
-
extensionType,
|
|
57
|
-
cmd.extendType(cmd.string, {
|
|
58
|
-
from: (s) => {
|
|
59
|
-
if (s !== 'none') {
|
|
60
|
-
throw new Error(
|
|
61
|
-
`export-ext should be 'none' or a valid extension`,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
return Promise.resolve('none');
|
|
65
|
-
},
|
|
30
|
+
name: 'gen-index-ts-cli',
|
|
31
|
+
version: '6.0.5',
|
|
32
|
+
args: {
|
|
33
|
+
// required args
|
|
34
|
+
targetDirectory: cmd.positional({
|
|
35
|
+
type: cmd.string,
|
|
36
|
+
displayName: 'target-directory',
|
|
37
|
+
description: 'Directory where the index file will be generated (Comma-separated list can be used)',
|
|
66
38
|
}),
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
39
|
+
targetExtensions: cmd.multioption({
|
|
40
|
+
long: 'target-ext',
|
|
41
|
+
type: nonEmptyArray(extensionType, 'target-ext'),
|
|
42
|
+
description: 'File extensions to include in the index file',
|
|
43
|
+
}),
|
|
44
|
+
indexFileExtension: cmd.option({
|
|
45
|
+
long: 'index-ext',
|
|
46
|
+
type: extensionType,
|
|
47
|
+
description: 'Extension of the index file to be generated',
|
|
48
|
+
}),
|
|
49
|
+
exportStatementExtension: cmd.option({
|
|
50
|
+
long: 'export-ext',
|
|
51
|
+
type: cmd.union([
|
|
52
|
+
extensionType,
|
|
53
|
+
cmd.extendType(cmd.string, {
|
|
54
|
+
from: (s) => {
|
|
55
|
+
if (s !== 'none') {
|
|
56
|
+
throw new Error(`export-ext should be 'none' or a valid extension`);
|
|
57
|
+
}
|
|
58
|
+
return Promise.resolve('none');
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
]),
|
|
62
|
+
description: 'Extension of the export statements in the index file',
|
|
63
|
+
}),
|
|
64
|
+
// optional args
|
|
65
|
+
exclude: cmd.multioption({
|
|
66
|
+
long: 'exclude',
|
|
67
|
+
type: cmd.optional(cmd.array(cmd.string)),
|
|
68
|
+
description: 'Glob patterns of files to exclude from the index file (e.g., "*.d.mts", "*.test.mts")',
|
|
69
|
+
}),
|
|
70
|
+
formatCommand: cmd.option({
|
|
71
|
+
long: 'fmt',
|
|
72
|
+
type: cmd.optional(cmd.string),
|
|
73
|
+
description: 'Command to format after generating the index file (e.g., "npm run fmt")',
|
|
74
|
+
}),
|
|
75
|
+
silent: cmd.flag({
|
|
76
|
+
long: 'silent',
|
|
77
|
+
type: cmd.optional(cmd.boolean),
|
|
78
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
79
|
+
}),
|
|
80
|
+
},
|
|
81
|
+
handler: (args) => {
|
|
82
|
+
console.log(args);
|
|
83
|
+
main(args).catch((error) => {
|
|
84
|
+
console.error('An error occurred:', error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
87
|
+
},
|
|
96
88
|
});
|
|
97
|
-
const main = async ({
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
: targetDirectory,
|
|
110
|
-
exportStatementExtension,
|
|
111
|
-
targetExtensions,
|
|
112
|
-
exclude,
|
|
113
|
-
indexFileExtension,
|
|
114
|
-
formatCommand,
|
|
115
|
-
silent,
|
|
116
|
-
});
|
|
89
|
+
const main = async ({ targetDirectory, targetExtensions, exportStatementExtension, indexFileExtension, exclude, formatCommand, silent, }) => {
|
|
90
|
+
await genIndex({
|
|
91
|
+
targetDirectory: targetDirectory.includes(',')
|
|
92
|
+
? targetDirectory.split(',').map((dir) => dir.trim())
|
|
93
|
+
: targetDirectory,
|
|
94
|
+
exportStatementExtension,
|
|
95
|
+
targetExtensions,
|
|
96
|
+
exclude,
|
|
97
|
+
indexFileExtension,
|
|
98
|
+
formatCommand,
|
|
99
|
+
silent,
|
|
100
|
+
});
|
|
117
101
|
};
|
|
118
102
|
await cmd.run(cmdDef, process.argv.slice(2));
|
|
119
103
|
//# sourceMappingURL=gen-index-ts.mjs.map
|
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
import { Result } from 'ts-data-forge';
|
|
2
1
|
import '../../node-global.mjs';
|
|
3
2
|
import { type Package } from './types.mjs';
|
|
4
3
|
/**
|
|
5
4
|
* Executes a npm script across multiple packages in parallel with a concurrency
|
|
6
|
-
* limit.
|
|
5
|
+
* limit. Uses fail-fast behavior - stops execution immediately when any package
|
|
6
|
+
* fails.
|
|
7
7
|
*
|
|
8
8
|
* @param packages - Array of Package objects to execute the script in
|
|
9
9
|
* @param scriptName - The name of the npm script to execute
|
|
10
10
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
11
11
|
* (default: 3)
|
|
12
|
-
* @returns A promise that resolves to an array of execution results
|
|
12
|
+
* @returns A promise that resolves to an array of execution results, or rejects
|
|
13
|
+
* immediately on first failure
|
|
13
14
|
*/
|
|
14
|
-
export declare const executeParallel: (packages: readonly Package[], scriptName: string, concurrency?: number) => Promise<readonly
|
|
15
|
+
export declare const executeParallel: (packages: readonly Package[], scriptName: string, concurrency?: number) => Promise<readonly Readonly<{
|
|
15
16
|
code?: number;
|
|
16
17
|
skipped?: boolean;
|
|
17
|
-
}
|
|
18
|
+
}>[]>;
|
|
18
19
|
/**
|
|
19
20
|
* Executes a npm script across packages in dependency order stages. Packages
|
|
20
21
|
* are grouped into stages where each stage contains packages whose dependencies
|
|
21
|
-
* have been completed in previous stages.
|
|
22
|
+
* have been completed in previous stages. Uses fail-fast behavior - stops
|
|
23
|
+
* execution immediately when any package fails.
|
|
22
24
|
*
|
|
23
25
|
* @param packages - Array of Package objects to execute the script in
|
|
24
26
|
* @param scriptName - The name of the npm script to execute
|
|
25
27
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
26
28
|
* within each stage (default: 3)
|
|
27
|
-
* @returns A promise that resolves when all stages are complete
|
|
29
|
+
* @returns A promise that resolves when all stages are complete, or rejects
|
|
30
|
+
* immediately on first failure
|
|
28
31
|
*/
|
|
29
32
|
export declare const executeStages: (packages: readonly Package[], scriptName: string, concurrency?: number) => Promise<void>;
|
|
30
33
|
//# sourceMappingURL=execute-parallel.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute-parallel.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/execute-parallel.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"execute-parallel.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/execute-parallel.mts"],"names":[],"mappings":"AAUA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAC1B,UAAU,SAAS,OAAO,EAAE,EAC5B,YAAY,MAAM,EAClB,cAAa,MAAU,KACtB,OAAO,CAAC,SAAS,QAAQ,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EAAE,CA8DnE,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,SAAS,OAAO,EAAE,EAC5B,YAAY,MAAM,EAClB,cAAa,MAAU,KACtB,OAAO,CAAC,IAAI,CA0Dd,CAAC"}
|
|
@@ -1,45 +1,79 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
-
import { pipe, createPromise, isRecord, hasKey,
|
|
2
|
+
import { pipe, Result, createPromise, isRecord, hasKey, isNotUndefined } from 'ts-data-forge';
|
|
3
3
|
import '../../node-global.mjs';
|
|
4
4
|
|
|
5
|
+
/* eslint-disable require-atomic-updates */
|
|
5
6
|
/**
|
|
6
7
|
* Executes a npm script across multiple packages in parallel with a concurrency
|
|
7
|
-
* limit.
|
|
8
|
+
* limit. Uses fail-fast behavior - stops execution immediately when any package
|
|
9
|
+
* fails.
|
|
8
10
|
*
|
|
9
11
|
* @param packages - Array of Package objects to execute the script in
|
|
10
12
|
* @param scriptName - The name of the npm script to execute
|
|
11
13
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
12
14
|
* (default: 3)
|
|
13
|
-
* @returns A promise that resolves to an array of execution results
|
|
15
|
+
* @returns A promise that resolves to an array of execution results, or rejects
|
|
16
|
+
* immediately on first failure
|
|
14
17
|
*/
|
|
15
18
|
const executeParallel = async (packages, scriptName, concurrency = 3) => {
|
|
16
19
|
const mut_resultPromises = [];
|
|
17
20
|
const mut_executing = new Set();
|
|
21
|
+
let mut_failed = false;
|
|
18
22
|
for (const pkg of packages) {
|
|
19
|
-
|
|
23
|
+
// Stop starting new processes if any has failed
|
|
24
|
+
if (mut_failed) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
28
|
+
const promise = executeScript(pkg, scriptName).then((result) => {
|
|
29
|
+
// Check for failure immediately
|
|
30
|
+
if (Result.isErr(result)) {
|
|
31
|
+
mut_failed = true;
|
|
32
|
+
throw result.value; // Throw the error to trigger fail-fast
|
|
33
|
+
}
|
|
34
|
+
return result.value; // Return the unwrapped value for success
|
|
35
|
+
});
|
|
20
36
|
mut_resultPromises.push(promise);
|
|
21
|
-
const wrappedPromise = promise
|
|
37
|
+
const wrappedPromise = promise
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
39
|
+
.catch((error) => {
|
|
40
|
+
mut_failed = true;
|
|
41
|
+
throw error; // Re-throw to ensure fail-fast propagation
|
|
42
|
+
})
|
|
43
|
+
.finally(() => {
|
|
22
44
|
mut_executing.delete(wrappedPromise);
|
|
23
45
|
});
|
|
24
46
|
mut_executing.add(wrappedPromise);
|
|
25
47
|
// If we reach concurrency limit, wait for one to finish
|
|
26
48
|
if (mut_executing.size >= concurrency) {
|
|
27
|
-
|
|
28
|
-
|
|
49
|
+
try {
|
|
50
|
+
// eslint-disable-next-line no-await-in-loop
|
|
51
|
+
await Promise.race(mut_executing);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// If any process fails, cancel remaining processes and throw immediately
|
|
55
|
+
// eslint-disable-next-line no-useless-assignment
|
|
56
|
+
mut_failed = true;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
29
59
|
}
|
|
30
60
|
}
|
|
61
|
+
// Wait for all started processes to complete
|
|
62
|
+
// This will throw immediately if any process fails (fail-fast)
|
|
31
63
|
return Promise.all(mut_resultPromises);
|
|
32
64
|
};
|
|
33
65
|
/**
|
|
34
66
|
* Executes a npm script across packages in dependency order stages. Packages
|
|
35
67
|
* are grouped into stages where each stage contains packages whose dependencies
|
|
36
|
-
* have been completed in previous stages.
|
|
68
|
+
* have been completed in previous stages. Uses fail-fast behavior - stops
|
|
69
|
+
* execution immediately when any package fails.
|
|
37
70
|
*
|
|
38
71
|
* @param packages - Array of Package objects to execute the script in
|
|
39
72
|
* @param scriptName - The name of the npm script to execute
|
|
40
73
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
41
74
|
* within each stage (default: 3)
|
|
42
|
-
* @returns A promise that resolves when all stages are complete
|
|
75
|
+
* @returns A promise that resolves when all stages are complete, or rejects
|
|
76
|
+
* immediately on first failure
|
|
43
77
|
*/
|
|
44
78
|
const executeStages = async (packages, scriptName, concurrency = 3) => {
|
|
45
79
|
const dependencyGraph = buildDependencyGraph(packages);
|
|
@@ -65,12 +99,24 @@ const executeStages = async (packages, scriptName, concurrency = 3) => {
|
|
|
65
99
|
mut_completed.add(pkg.name);
|
|
66
100
|
}
|
|
67
101
|
}
|
|
68
|
-
console.log(`\nExecuting ${scriptName} in ${mut_stages.length} stages...\n`);
|
|
102
|
+
console.log(`\nExecuting ${scriptName} in ${mut_stages.length} stages (fail-fast mode)...\n`);
|
|
69
103
|
for (const [i, stage] of mut_stages.entries()) {
|
|
70
104
|
if (stage.length > 0) {
|
|
71
105
|
console.log(`Stage ${i + 1}: ${stage.map((p) => p.name).join(', ')}`);
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
try {
|
|
107
|
+
// eslint-disable-next-line no-await-in-loop
|
|
108
|
+
const results = await executeParallel(stage, scriptName, concurrency);
|
|
109
|
+
// Log successful completion of the stage
|
|
110
|
+
// All results are successful because executeParallel throws on any failure
|
|
111
|
+
console.log(`✅ Stage ${i + 1} completed successfully (${results.length}/${stage.length} packages)`);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
// executeParallel will throw immediately on any failure (fail-fast)
|
|
115
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
116
|
+
console.error(`\n❌ Stage ${i + 1} failed (fail-fast):`);
|
|
117
|
+
console.error(errorMessage);
|
|
118
|
+
throw new Error(`Stage ${i + 1} failed: ${errorMessage}`);
|
|
119
|
+
}
|
|
74
120
|
}
|
|
75
121
|
}
|
|
76
122
|
};
|
|
@@ -107,8 +153,8 @@ const executeScript = (pkg, scriptName, { prefix = true } = {}) => pipe(createPr
|
|
|
107
153
|
process.stderr.write(prefixStr + data.toString());
|
|
108
154
|
});
|
|
109
155
|
proc.on('close', (code) => {
|
|
110
|
-
if (code === 0) {
|
|
111
|
-
resolve({ code });
|
|
156
|
+
if (code === 0 || code === null) {
|
|
157
|
+
resolve({ code: code ?? 0 });
|
|
112
158
|
}
|
|
113
159
|
else {
|
|
114
160
|
reject(new Error(`${pkg.name} exited with code ${code}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute-parallel.mjs","sources":["../../../src/functions/workspace-utils/execute-parallel.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"execute-parallel.mjs","sources":["../../../src/functions/workspace-utils/execute-parallel.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
/**
|
|
3
|
-
* Executes a npm script command across all workspace packages in parallel.
|
|
3
|
+
* Executes a npm script command across all workspace packages in parallel. Uses
|
|
4
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
4
5
|
*
|
|
5
6
|
* @param options - Configuration options for the parallel execution
|
|
6
7
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -11,6 +12,7 @@
|
|
|
11
12
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
12
13
|
* by name
|
|
13
14
|
* @returns A promise that resolves when all packages have completed execution
|
|
15
|
+
* successfully, or rejects immediately on first failure
|
|
14
16
|
*/
|
|
15
17
|
export declare const runCmdInParallelAcrossWorkspaces: ({ rootPackageJsonDir, cmd, concurrency, filterWorkspacePattern, }: Readonly<{
|
|
16
18
|
rootPackageJsonDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cmd-in-parallel.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/run-cmd-in-parallel.mts"],"names":[],"mappings":";AAKA
|
|
1
|
+
{"version":3,"file":"run-cmd-in-parallel.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/run-cmd-in-parallel.mts"],"names":[],"mappings":";AAKA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gCAAgC,GAAU,mEAKpD,QAAQ,CAAC;IACV,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3D,CAAC,KAAG,OAAO,CAAC,IAAI,CAqBhB,CAAC"}
|
|
@@ -3,7 +3,8 @@ import { executeParallel } from './execute-parallel.mjs';
|
|
|
3
3
|
import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Executes a npm script command across all workspace packages in parallel.
|
|
6
|
+
* Executes a npm script command across all workspace packages in parallel. Uses
|
|
7
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
7
8
|
*
|
|
8
9
|
* @param options - Configuration options for the parallel execution
|
|
9
10
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -14,6 +15,7 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
14
15
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
15
16
|
* by name
|
|
16
17
|
* @returns A promise that resolves when all packages have completed execution
|
|
18
|
+
* successfully, or rejects immediately on first failure
|
|
17
19
|
*/
|
|
18
20
|
const runCmdInParallelAcrossWorkspaces = async ({ rootPackageJsonDir, cmd, concurrency = 3, filterWorkspacePattern, }) => {
|
|
19
21
|
try {
|
|
@@ -21,11 +23,14 @@ const runCmdInParallelAcrossWorkspaces = async ({ rootPackageJsonDir, cmd, concu
|
|
|
21
23
|
const filteredPackages = filterWorkspacePattern === undefined
|
|
22
24
|
? packages
|
|
23
25
|
: packages.filter((pkg) => filterWorkspacePattern(pkg.name));
|
|
26
|
+
console.log(`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast parallel mode)...`);
|
|
24
27
|
await executeParallel(filteredPackages, cmd, concurrency);
|
|
25
|
-
console.log(`\n✅ ${cmd} completed successfully`);
|
|
28
|
+
console.log(`\n✅ ${cmd} completed successfully (all packages)`);
|
|
26
29
|
}
|
|
27
30
|
catch (error) {
|
|
28
|
-
|
|
31
|
+
const errorMessage = error instanceof Error ? error.message : (error?.toString() ?? '');
|
|
32
|
+
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
33
|
+
console.error(errorMessage);
|
|
29
34
|
process.exit(1);
|
|
30
35
|
}
|
|
31
36
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cmd-in-parallel.mjs","sources":["../../../src/functions/workspace-utils/run-cmd-in-parallel.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKA
|
|
1
|
+
{"version":3,"file":"run-cmd-in-parallel.mjs","sources":["../../../src/functions/workspace-utils/run-cmd-in-parallel.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKA;;;;;;;;;;;;;;AAcG;AACI,MAAM,gCAAgC,GAAG,OAAO,EACrD,kBAAkB,EAClB,GAAG,EACH,WAAW,GAAG,CAAC,EACf,sBAAsB,GAMtB,KAAmB;AACnB,IAAA,IAAI;AACF,QAAA,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,kBAAkB,CAAC;AAE/D,QAAA,MAAM,gBAAgB,GACpB,sBAAsB,KAAK;AACzB,cAAE;AACF,cAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhE,OAAO,CAAC,GAAG,CACT,CAAA,WAAA,EAAc,GAAG,CAAA,QAAA,EAAW,gBAAgB,CAAC,MAAM,CAAA,sCAAA,CAAwC,CAC5F;QACD,MAAM,eAAe,CAAC,gBAAgB,EAAE,GAAG,EAAE,WAAW,CAAC;AACzD,QAAA,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAA,sCAAA,CAAwC,CAAC;IACjE;IAAE,OAAO,KAAK,EAAE;QACd,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACpE,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAA,2CAAA,CAA6C,CAAC;AACtE,QAAA,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;AAC3B,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjB;AACF;;;;"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Executes a npm script command across all workspace packages in dependency
|
|
4
4
|
* order stages. Packages are grouped into stages where each stage contains
|
|
5
|
-
* packages whose dependencies have been completed in previous stages.
|
|
5
|
+
* packages whose dependencies have been completed in previous stages. Uses
|
|
6
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
6
7
|
*
|
|
7
8
|
* @param options - Configuration options for the staged execution
|
|
8
9
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
14
15
|
* by name
|
|
15
16
|
* @returns A promise that resolves when all stages have completed execution
|
|
17
|
+
* successfully, or rejects immediately on first failure
|
|
16
18
|
*/
|
|
17
19
|
export declare const runCmdInStagesAcrossWorkspaces: ({ rootPackageJsonDir, cmd, concurrency, filterWorkspacePattern, }: Readonly<{
|
|
18
20
|
rootPackageJsonDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cmd-in-stages.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/run-cmd-in-stages.mts"],"names":[],"mappings":";AAKA
|
|
1
|
+
{"version":3,"file":"run-cmd-in-stages.d.mts","sourceRoot":"","sources":["../../../src/functions/workspace-utils/run-cmd-in-stages.mts"],"names":[],"mappings":";AAKA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,8BAA8B,GAAU,mEAKlD,QAAQ,CAAC;IACV,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3D,CAAC,KAAG,OAAO,CAAC,IAAI,CAqBhB,CAAC"}
|
|
@@ -5,7 +5,8 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
5
5
|
/**
|
|
6
6
|
* Executes a npm script command across all workspace packages in dependency
|
|
7
7
|
* order stages. Packages are grouped into stages where each stage contains
|
|
8
|
-
* packages whose dependencies have been completed in previous stages.
|
|
8
|
+
* packages whose dependencies have been completed in previous stages. Uses
|
|
9
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
9
10
|
*
|
|
10
11
|
* @param options - Configuration options for the staged execution
|
|
11
12
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -16,6 +17,7 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
16
17
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
17
18
|
* by name
|
|
18
19
|
* @returns A promise that resolves when all stages have completed execution
|
|
20
|
+
* successfully, or rejects immediately on first failure
|
|
19
21
|
*/
|
|
20
22
|
const runCmdInStagesAcrossWorkspaces = async ({ rootPackageJsonDir, cmd, concurrency = 3, filterWorkspacePattern, }) => {
|
|
21
23
|
try {
|
|
@@ -23,11 +25,14 @@ const runCmdInStagesAcrossWorkspaces = async ({ rootPackageJsonDir, cmd, concurr
|
|
|
23
25
|
const filteredPackages = filterWorkspacePattern === undefined
|
|
24
26
|
? packages
|
|
25
27
|
: packages.filter((pkg) => filterWorkspacePattern(pkg.name));
|
|
28
|
+
console.log(`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast mode)...`);
|
|
26
29
|
await executeStages(filteredPackages, cmd, concurrency);
|
|
27
|
-
console.log(`\n✅ ${cmd} completed successfully`);
|
|
30
|
+
console.log(`\n✅ ${cmd} completed successfully (all stages)`);
|
|
28
31
|
}
|
|
29
32
|
catch (error) {
|
|
30
|
-
|
|
33
|
+
const errorMessage = error instanceof Error ? error.message : (error?.toString() ?? '');
|
|
34
|
+
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
35
|
+
console.error(errorMessage);
|
|
31
36
|
process.exit(1);
|
|
32
37
|
}
|
|
33
38
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cmd-in-stages.mjs","sources":["../../../src/functions/workspace-utils/run-cmd-in-stages.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKA
|
|
1
|
+
{"version":3,"file":"run-cmd-in-stages.mjs","sources":["../../../src/functions/workspace-utils/run-cmd-in-stages.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKA;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,8BAA8B,GAAG,OAAO,EACnD,kBAAkB,EAClB,GAAG,EACH,WAAW,GAAG,CAAC,EACf,sBAAsB,GAMtB,KAAmB;AACnB,IAAA,IAAI;AACF,QAAA,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,kBAAkB,CAAC;AAE/D,QAAA,MAAM,gBAAgB,GACpB,sBAAsB,KAAK;AACzB,cAAE;AACF,cAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhE,OAAO,CAAC,GAAG,CACT,CAAA,WAAA,EAAc,GAAG,CAAA,QAAA,EAAW,gBAAgB,CAAC,MAAM,CAAA,6BAAA,CAA+B,CACnF;QACD,MAAM,aAAa,CAAC,gBAAgB,EAAE,GAAG,EAAE,WAAW,CAAC;AACvD,QAAA,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAA,oCAAA,CAAsC,CAAC;IAC/D;IAAE,OAAO,KAAK,EAAE;QACd,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACpE,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAA,2CAAA,CAA6C,CAAC;AACtE,QAAA,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;AAC3B,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjB;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-repo-utils",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"tsx": "^4.20.4"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@eslint/js": "^9.
|
|
74
|
+
"@eslint/js": "^9.34.0",
|
|
75
75
|
"@rollup/plugin-replace": "^6.0.2",
|
|
76
76
|
"@rollup/plugin-strip": "^3.0.4",
|
|
77
77
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
89
89
|
"cspell": "^9.2.0",
|
|
90
90
|
"dedent": "^1.6.0",
|
|
91
|
-
"eslint": "^9.
|
|
91
|
+
"eslint": "^9.34.0",
|
|
92
92
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
93
93
|
"eslint-plugin-array-func": "5.0.2",
|
|
94
94
|
"eslint-plugin-functional": "9.0.2",
|
|
@@ -100,19 +100,23 @@
|
|
|
100
100
|
"eslint-plugin-vitest": "0.5.4",
|
|
101
101
|
"markdownlint-cli2": "^0.18.1",
|
|
102
102
|
"npm-run-all2": "^8.0.4",
|
|
103
|
+
"prettier": "^3.6.2",
|
|
103
104
|
"prettier-plugin-jsdoc": "^1.3.3",
|
|
104
105
|
"prettier-plugin-organize-imports": "^4.2.0",
|
|
105
106
|
"prettier-plugin-packagejson": "^2.5.19",
|
|
106
|
-
"rollup": "^4.
|
|
107
|
+
"rollup": "^4.48.0",
|
|
107
108
|
"semantic-release": "^24.2.7",
|
|
108
109
|
"ts-type-forge": "^2.1.1",
|
|
109
110
|
"tslib": "^2.8.1",
|
|
110
111
|
"typedoc": "^0.28.10",
|
|
111
|
-
"typedoc-plugin-markdown": "^4.8.
|
|
112
|
+
"typedoc-plugin-markdown": "^4.8.1",
|
|
112
113
|
"typescript": "^5.9.2",
|
|
113
|
-
"typescript-eslint": "^8.
|
|
114
|
+
"typescript-eslint": "^8.40.0",
|
|
114
115
|
"vitest": "^3.2.4"
|
|
115
116
|
},
|
|
117
|
+
"peerDependencies": {
|
|
118
|
+
"prettier": "^3.6.2"
|
|
119
|
+
},
|
|
116
120
|
"engines": {
|
|
117
121
|
"node": ">=20.11.0"
|
|
118
122
|
}
|
package/src/cmd/gen-index-ts.mts
CHANGED
|
@@ -2,7 +2,11 @@ import { Result } from 'ts-data-forge';
|
|
|
2
2
|
import '../node-global.mjs';
|
|
3
3
|
import { getDiffFrom, getUntrackedFiles } from './diff.mjs';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Check if running in CI environment (GitHub Actions or other CI)
|
|
6
|
+
const isCI =
|
|
7
|
+
process.env['CI'] === 'true' || process.env['GITHUB_ACTIONS'] === 'true';
|
|
8
|
+
|
|
9
|
+
describe.skipIf(!isCI)('diff', () => {
|
|
6
10
|
// Helper function to clean up test files
|
|
7
11
|
const cleanupTestFiles = async (files: Set<string>): Promise<void> => {
|
|
8
12
|
for (const file of files) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable require-atomic-updates */
|
|
1
2
|
import { spawn } from 'child_process';
|
|
2
3
|
import {
|
|
3
4
|
createPromise,
|
|
@@ -14,39 +15,59 @@ const DEBUG = false as boolean;
|
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Executes a npm script across multiple packages in parallel with a concurrency
|
|
17
|
-
* limit.
|
|
18
|
+
* limit. Uses fail-fast behavior - stops execution immediately when any package
|
|
19
|
+
* fails.
|
|
18
20
|
*
|
|
19
21
|
* @param packages - Array of Package objects to execute the script in
|
|
20
22
|
* @param scriptName - The name of the npm script to execute
|
|
21
23
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
22
24
|
* (default: 3)
|
|
23
|
-
* @returns A promise that resolves to an array of execution results
|
|
25
|
+
* @returns A promise that resolves to an array of execution results, or rejects
|
|
26
|
+
* immediately on first failure
|
|
24
27
|
*/
|
|
25
28
|
export const executeParallel = async (
|
|
26
29
|
packages: readonly Package[],
|
|
27
30
|
scriptName: string,
|
|
28
31
|
concurrency: number = 3,
|
|
29
|
-
): Promise<
|
|
30
|
-
readonly Result<Readonly<{ code?: number; skipped?: boolean }>, Error>[]
|
|
31
|
-
> => {
|
|
32
|
+
): Promise<readonly Readonly<{ code?: number; skipped?: boolean }>[]> => {
|
|
32
33
|
const mut_resultPromises: Promise<
|
|
33
|
-
|
|
34
|
+
Readonly<{ code?: number; skipped?: boolean }>
|
|
34
35
|
>[] = [];
|
|
35
36
|
|
|
36
37
|
const mut_executing = new Set<Promise<unknown>>();
|
|
38
|
+
let mut_failed = false as boolean;
|
|
37
39
|
|
|
38
40
|
for (const pkg of packages) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
// Stop starting new processes if any has failed
|
|
42
|
+
if (mut_failed) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
47
|
+
const promise = executeScript(pkg, scriptName).then((result) => {
|
|
48
|
+
// Check for failure immediately
|
|
49
|
+
if (Result.isErr(result)) {
|
|
50
|
+
mut_failed = true;
|
|
51
|
+
throw result.value; // Throw the error to trigger fail-fast
|
|
47
52
|
}
|
|
53
|
+
return result.value; // Return the unwrapped value for success
|
|
48
54
|
});
|
|
49
55
|
|
|
56
|
+
mut_resultPromises.push(promise);
|
|
57
|
+
|
|
58
|
+
const wrappedPromise = promise
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
60
|
+
.catch((error) => {
|
|
61
|
+
mut_failed = true;
|
|
62
|
+
throw error; // Re-throw to ensure fail-fast propagation
|
|
63
|
+
})
|
|
64
|
+
.finally(() => {
|
|
65
|
+
mut_executing.delete(wrappedPromise);
|
|
66
|
+
if (DEBUG) {
|
|
67
|
+
console.debug('executing size', mut_executing.size);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
50
71
|
mut_executing.add(wrappedPromise);
|
|
51
72
|
|
|
52
73
|
if (DEBUG) {
|
|
@@ -55,24 +76,35 @@ export const executeParallel = async (
|
|
|
55
76
|
|
|
56
77
|
// If we reach concurrency limit, wait for one to finish
|
|
57
78
|
if (mut_executing.size >= concurrency) {
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
try {
|
|
80
|
+
// eslint-disable-next-line no-await-in-loop
|
|
81
|
+
await Promise.race(mut_executing);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
// If any process fails, cancel remaining processes and throw immediately
|
|
84
|
+
// eslint-disable-next-line no-useless-assignment
|
|
85
|
+
mut_failed = true;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
60
88
|
}
|
|
61
89
|
}
|
|
62
90
|
|
|
91
|
+
// Wait for all started processes to complete
|
|
92
|
+
// This will throw immediately if any process fails (fail-fast)
|
|
63
93
|
return Promise.all(mut_resultPromises);
|
|
64
94
|
};
|
|
65
95
|
|
|
66
96
|
/**
|
|
67
97
|
* Executes a npm script across packages in dependency order stages. Packages
|
|
68
98
|
* are grouped into stages where each stage contains packages whose dependencies
|
|
69
|
-
* have been completed in previous stages.
|
|
99
|
+
* have been completed in previous stages. Uses fail-fast behavior - stops
|
|
100
|
+
* execution immediately when any package fails.
|
|
70
101
|
*
|
|
71
102
|
* @param packages - Array of Package objects to execute the script in
|
|
72
103
|
* @param scriptName - The name of the npm script to execute
|
|
73
104
|
* @param concurrency - Maximum number of packages to process simultaneously
|
|
74
105
|
* within each stage (default: 3)
|
|
75
|
-
* @returns A promise that resolves when all stages are complete
|
|
106
|
+
* @returns A promise that resolves when all stages are complete, or rejects
|
|
107
|
+
* immediately on first failure
|
|
76
108
|
*/
|
|
77
109
|
export const executeStages = async (
|
|
78
110
|
packages: readonly Package[],
|
|
@@ -110,13 +142,30 @@ export const executeStages = async (
|
|
|
110
142
|
}
|
|
111
143
|
}
|
|
112
144
|
|
|
113
|
-
console.log(
|
|
145
|
+
console.log(
|
|
146
|
+
`\nExecuting ${scriptName} in ${mut_stages.length} stages (fail-fast mode)...\n`,
|
|
147
|
+
);
|
|
114
148
|
|
|
115
149
|
for (const [i, stage] of mut_stages.entries()) {
|
|
116
150
|
if (stage.length > 0) {
|
|
117
151
|
console.log(`Stage ${i + 1}: ${stage.map((p) => p.name).join(', ')}`);
|
|
118
|
-
|
|
119
|
-
|
|
152
|
+
try {
|
|
153
|
+
// eslint-disable-next-line no-await-in-loop
|
|
154
|
+
const results = await executeParallel(stage, scriptName, concurrency);
|
|
155
|
+
|
|
156
|
+
// Log successful completion of the stage
|
|
157
|
+
// All results are successful because executeParallel throws on any failure
|
|
158
|
+
console.log(
|
|
159
|
+
`✅ Stage ${i + 1} completed successfully (${results.length}/${stage.length} packages)`,
|
|
160
|
+
);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
// executeParallel will throw immediately on any failure (fail-fast)
|
|
163
|
+
const errorMessage =
|
|
164
|
+
error instanceof Error ? error.message : String(error);
|
|
165
|
+
console.error(`\n❌ Stage ${i + 1} failed (fail-fast):`);
|
|
166
|
+
console.error(errorMessage);
|
|
167
|
+
throw new Error(`Stage ${i + 1} failed: ${errorMessage}`);
|
|
168
|
+
}
|
|
120
169
|
}
|
|
121
170
|
}
|
|
122
171
|
};
|
|
@@ -172,8 +221,11 @@ const executeScript = (
|
|
|
172
221
|
});
|
|
173
222
|
|
|
174
223
|
proc.on('close', (code: number | null) => {
|
|
175
|
-
if (
|
|
176
|
-
|
|
224
|
+
if (DEBUG) {
|
|
225
|
+
console.debug(`${pkg.name} process closed with code: ${code}`);
|
|
226
|
+
}
|
|
227
|
+
if (code === 0 || code === null) {
|
|
228
|
+
resolve({ code: code ?? 0 });
|
|
177
229
|
} else {
|
|
178
230
|
reject(new Error(`${pkg.name} exited with code ${code}`));
|
|
179
231
|
}
|
|
@@ -4,7 +4,8 @@ import { executeParallel } from './execute-parallel.mjs';
|
|
|
4
4
|
import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Executes a npm script command across all workspace packages in parallel.
|
|
7
|
+
* Executes a npm script command across all workspace packages in parallel. Uses
|
|
8
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
8
9
|
*
|
|
9
10
|
* @param options - Configuration options for the parallel execution
|
|
10
11
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -15,6 +16,7 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
15
16
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
16
17
|
* by name
|
|
17
18
|
* @returns A promise that resolves when all packages have completed execution
|
|
19
|
+
* successfully, or rejects immediately on first failure
|
|
18
20
|
*/
|
|
19
21
|
export const runCmdInParallelAcrossWorkspaces = async ({
|
|
20
22
|
rootPackageJsonDir,
|
|
@@ -35,13 +37,16 @@ export const runCmdInParallelAcrossWorkspaces = async ({
|
|
|
35
37
|
? packages
|
|
36
38
|
: packages.filter((pkg) => filterWorkspacePattern(pkg.name));
|
|
37
39
|
|
|
40
|
+
console.log(
|
|
41
|
+
`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast parallel mode)...`,
|
|
42
|
+
);
|
|
38
43
|
await executeParallel(filteredPackages, cmd, concurrency);
|
|
39
|
-
console.log(`\n✅ ${cmd} completed successfully`);
|
|
44
|
+
console.log(`\n✅ ${cmd} completed successfully (all packages)`);
|
|
40
45
|
} catch (error) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
46
|
+
const errorMessage =
|
|
47
|
+
error instanceof Error ? error.message : (error?.toString() ?? '');
|
|
48
|
+
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
49
|
+
console.error(errorMessage);
|
|
45
50
|
process.exit(1);
|
|
46
51
|
}
|
|
47
52
|
};
|
|
@@ -6,7 +6,8 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
6
6
|
/**
|
|
7
7
|
* Executes a npm script command across all workspace packages in dependency
|
|
8
8
|
* order stages. Packages are grouped into stages where each stage contains
|
|
9
|
-
* packages whose dependencies have been completed in previous stages.
|
|
9
|
+
* packages whose dependencies have been completed in previous stages. Uses
|
|
10
|
+
* fail-fast behavior - stops execution immediately when any package fails.
|
|
10
11
|
*
|
|
11
12
|
* @param options - Configuration options for the staged execution
|
|
12
13
|
* @param options.rootPackageJsonDir - The directory containing the root
|
|
@@ -17,6 +18,7 @@ import { getWorkspacePackages } from './get-workspace-packages.mjs';
|
|
|
17
18
|
* @param options.filterWorkspacePattern - Optional function to filter packages
|
|
18
19
|
* by name
|
|
19
20
|
* @returns A promise that resolves when all stages have completed execution
|
|
21
|
+
* successfully, or rejects immediately on first failure
|
|
20
22
|
*/
|
|
21
23
|
export const runCmdInStagesAcrossWorkspaces = async ({
|
|
22
24
|
rootPackageJsonDir,
|
|
@@ -37,13 +39,16 @@ export const runCmdInStagesAcrossWorkspaces = async ({
|
|
|
37
39
|
? packages
|
|
38
40
|
: packages.filter((pkg) => filterWorkspacePattern(pkg.name));
|
|
39
41
|
|
|
42
|
+
console.log(
|
|
43
|
+
`\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast mode)...`,
|
|
44
|
+
);
|
|
40
45
|
await executeStages(filteredPackages, cmd, concurrency);
|
|
41
|
-
console.log(`\n✅ ${cmd} completed successfully`);
|
|
46
|
+
console.log(`\n✅ ${cmd} completed successfully (all stages)`);
|
|
42
47
|
} catch (error) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
48
|
+
const errorMessage =
|
|
49
|
+
error instanceof Error ? error.message : (error?.toString() ?? '');
|
|
50
|
+
console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
|
|
51
|
+
console.error(errorMessage);
|
|
47
52
|
process.exit(1);
|
|
48
53
|
}
|
|
49
54
|
};
|