@dotcom-tool-kit/parallel 1.0.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/.toolkitrc.yml ADDED
@@ -0,0 +1,4 @@
1
+ version: 2
2
+
3
+ tasks:
4
+ Parallel: './lib/tasks/parallel'
@@ -0,0 +1,22 @@
1
+ import { Task, TaskRunContext } from '@dotcom-tool-kit/base';
2
+ import { z } from 'zod';
3
+ declare const ParallelSchema: z.ZodObject<{
4
+ tasks: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, "many">;
5
+ onError: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"stop-all">, z.ZodLiteral<"wait-for-others">]>>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ tasks: Record<string, Record<string, unknown>>[];
8
+ onError: "stop-all" | "wait-for-others";
9
+ }, {
10
+ tasks: Record<string, Record<string, unknown>>[];
11
+ onError?: "stop-all" | "wait-for-others" | undefined;
12
+ }>;
13
+ export { ParallelSchema as schema };
14
+ export default class Parallel extends Task<{
15
+ task: typeof ParallelSchema;
16
+ }> {
17
+ taskInstances: Task<any>[];
18
+ run(context: TaskRunContext): Promise<void>;
19
+ stop(): Promise<void>;
20
+ assertUnreachable(label: string, value: never): asserts value is never;
21
+ }
22
+ //# sourceMappingURL=parallel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../../src/tasks/parallel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,QAAA,MAAM,cAAc;;;;;;;;;EAsClB,CAAA;AAEF,OAAO,EAAE,cAAc,IAAI,MAAM,EAAE,CAAA;AAEnC,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,IAAI,CAAC;IAAE,IAAI,EAAE,OAAO,cAAc,CAAA;CAAE,CAAC;IACzE,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAK;IAEzB,GAAG,CAAC,OAAO,EAAE,cAAc;IAsD3B,IAAI;IAWV,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK;CAKvE"}
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schema = void 0;
4
+ const base_1 = require("@dotcom-tool-kit/base");
5
+ const logger_1 = require("@dotcom-tool-kit/logger");
6
+ const zod_1 = require("zod");
7
+ const tasks_1 = require("dotcom-tool-kit/lib/tasks");
8
+ const error_1 = require("@dotcom-tool-kit/error");
9
+ const ParallelSchema = zod_1.z.object({
10
+ tasks: zod_1.z.array(zod_1.z.record(zod_1.z.record(zod_1.z.unknown()))),
11
+ onError: zod_1.z.union([zod_1.z.literal('stop-all'), zod_1.z.literal('wait-for-others')]).default('wait-for-others')
12
+ }).describe(`Run Tool Kit tasks in parallel
13
+
14
+ ### Task options
15
+
16
+ #### \`tasks\`
17
+
18
+ An array listing the tasks to run in parallel, and the options to run each task with. Each element in the array is an object with a single key and value; the key is the name of the task to run, and the value is the options object for that task. Other tasks' options are documented in their plugin's readme.
19
+
20
+ ##### Example
21
+
22
+ ~~~yaml
23
+ commands:
24
+ run:local:
25
+ - Parallel:
26
+ tasks:
27
+ - Node:
28
+ entry: server/index.js
29
+ - Webpack:
30
+ watch: true
31
+ ~~~
32
+
33
+ #### \`onError\`
34
+
35
+ _optional_
36
+
37
+ | Value | Description |
38
+ |-|-|
39
+ | \`'wait-for-others'\` (default) | If any task errors, wait for the other tasks to complete, and print all the errors at the end. |
40
+ | \`'stop-all'\` | If any task errors, immediately stop the other tasks, and print the error. |
41
+
42
+ For long-running tasks, e.g. a Node server and Webpack in \`watch\` mode, it's possible for one task to error, but its error logging to be buried by the other tasks' output, meaning you might have missed an error and aren't aware that not everything you expect to be running is still running. In these cases, set \`onError: stop-all\`; Tool Kit will exit every \`Parallel\` task if one of them errors, so you're always in a consistent state and don't miss any errors.
43
+
44
+ If you're using \`Parallel\` to run shorter tasks in parallel as an optimisation, keep this as the default \`wait-for-others\` so every task runs to completion and Tool Kit can show the final results of all the tasks.
45
+
46
+ <!-- hide autogenerated schema docs -->
47
+ `);
48
+ exports.schema = ParallelSchema;
49
+ class Parallel extends base_1.Task {
50
+ taskInstances = [];
51
+ async run(context) {
52
+ const tasks = this.options.tasks.flatMap((entry) => Object.entries(entry).map(([task, options]) => ({ task, options, plugin: this.plugin })));
53
+ this.logger.info(`running tasks in parallel:
54
+ ${tasks
55
+ .map((task) => ` - ${logger_1.styles.task(task.task)} ${logger_1.styles.dim(`(with options ${logger_1.styles.code(JSON.stringify(task.options))})`)}`)
56
+ .join('\n')}
57
+ `);
58
+ this.taskInstances = (await (0, tasks_1.loadTasks)(this.logger, tasks, context.config)).unwrap('tasks are invalid!');
59
+ switch (this.options.onError) {
60
+ case 'stop-all': {
61
+ try {
62
+ await Promise.all(this.taskInstances.map((task) => task.run(context)));
63
+ }
64
+ catch (error) {
65
+ this.stop();
66
+ throw error;
67
+ }
68
+ break;
69
+ }
70
+ case 'wait-for-others': {
71
+ const errors = [];
72
+ await Promise.all(this.taskInstances.map((task) => task.run(context).catch((error) => {
73
+ errors.push({
74
+ task: task.id,
75
+ error
76
+ });
77
+ })));
78
+ if (errors.length > 0) {
79
+ (0, tasks_1.handleTaskErrors)(errors, context.command);
80
+ }
81
+ break;
82
+ }
83
+ default: {
84
+ this.assertUnreachable('Parallel.options.onError', this.options.onError);
85
+ }
86
+ }
87
+ }
88
+ async stop() {
89
+ await Promise.all(this.taskInstances.map((task) => task.stop().catch((error) => {
90
+ this.logger.warn(`error stopping ${logger_1.styles.task(task.id)}:
91
+ ${error.message}`);
92
+ })));
93
+ }
94
+ assertUnreachable(label, value) {
95
+ const error = new error_1.ToolKitError(`Unexpected value for ${label}, received ${value}`);
96
+ error.details = 'This should never happen! Talk to #cp-platforms-team, something weird af is going on';
97
+ throw error;
98
+ }
99
+ }
100
+ exports.default = Parallel;
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@dotcom-tool-kit/parallel",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "lib",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "FT.com Platforms Team <platforms-team.customer-products@ft.com>",
11
+ "license": "ISC",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/financial-times/dotcom-tool-kit.git",
15
+ "directory": "plugins/parallel"
16
+ },
17
+ "bugs": "https://github.com/financial-times/dotcom-tool-kit/issues",
18
+ "homepage": "https://github.com/financial-times/dotcom-tool-kit/tree/main/plugins/parallel",
19
+ "files": [
20
+ "/lib",
21
+ ".toolkitrc.yml"
22
+ ],
23
+ "engines": {
24
+ "node": "20.x || 22.x"
25
+ },
26
+ "volta": {
27
+ "extends": "../../package.json"
28
+ },
29
+ "peerDependencies": {
30
+ "dotcom-tool-kit": "^4.8.1"
31
+ },
32
+ "dependencies": {
33
+ "@dotcom-tool-kit/base": "^1.3.0",
34
+ "zod": "^3.25.67"
35
+ }
36
+ }
package/readme.md ADDED
@@ -0,0 +1,65 @@
1
+ # @dotcom-tool-kit/parallel
2
+
3
+ This plugin allows you to run Tool Kit tasks in parallel. By default, Tool Kit tasks run sequentially in the order they are specified in a command.
4
+
5
+ ## Installation
6
+
7
+ Install `@dotcom-tool-kit/parallel` as a `devDependency` in your app:
8
+
9
+ ```sh
10
+ npm install --save-dev @dotcom-tool-kit/parallel
11
+ ```
12
+
13
+ Add the plugin to your [Tool Kit configuration](https://github.com/financial-times/dotcom-tool-kit/blob/main/readme.md#configuration):
14
+
15
+ ```yaml
16
+ plugins:
17
+ - '@dotcom-tool-kit/parallel'
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ To run tasks in parallel, pass them in as the `tasks` option to the [`Parallel` task](#parallel).
23
+
24
+ <!-- begin autogenerated docs -->
25
+ ## Tasks
26
+
27
+ ### `Parallel`
28
+
29
+ Run Tool Kit tasks in parallel
30
+
31
+ #### Task options
32
+
33
+ ##### `tasks`
34
+
35
+ An array listing the tasks to run in parallel, and the options to run each task with. Each element in the array is an object with a single key and value; the key is the name of the task to run, and the value is the options object for that task. Other tasks' options are documented in their plugin's readme.
36
+
37
+ ###### Example
38
+
39
+ ~~~yaml
40
+ commands:
41
+ run:local:
42
+ - Parallel:
43
+ tasks:
44
+ - Node:
45
+ entry: server/index.js
46
+ - Webpack:
47
+ watch: true
48
+ ~~~
49
+
50
+ ##### `onError`
51
+
52
+ _optional_
53
+
54
+ | Value | Description |
55
+ |-|-|
56
+ | `'wait-for-others'` (default) | If any task errors, wait for the other tasks to complete, and print all the errors at the end. |
57
+ | `'stop-all'` | If any task errors, immediately stop the other tasks, and print the error. |
58
+
59
+ For long-running tasks, e.g. a Node server and Webpack in `watch` mode, it's possible for one task to error, but its error logging to be buried by the other tasks' output, meaning you might have missed an error and aren't aware that not everything you expect to be running is still running. In these cases, set `onError: stop-all`; Tool Kit will exit every `Parallel` task if one of them errors, so you're always in a consistent state and don't miss any errors.
60
+
61
+ If you're using `Parallel` to run shorter tasks in parallel as an optimisation, keep this as the default `wait-for-others` so every task runs to completion and Tool Kit can show the final results of all the tasks.
62
+
63
+ <!-- hide autogenerated schema docs -->
64
+
65
+ <!-- end autogenerated docs -->