concurrently 9.1.1 → 9.2.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 +8 -7
- package/dist/bin/concurrently.js +10 -3
- package/dist/src/assert.d.ts +5 -0
- package/dist/src/assert.js +16 -0
- package/dist/src/command.d.ts +8 -0
- package/dist/src/command.js +14 -3
- package/dist/src/completion-listener.js +4 -1
- package/dist/src/concurrently.d.ts +0 -4
- package/dist/src/concurrently.js +5 -1
- package/dist/src/flow-control/input-handler.js +1 -1
- package/dist/src/flow-control/kill-others.d.ts +4 -1
- package/dist/src/flow-control/kill-others.js +17 -1
- package/dist/src/flow-control/output-error-handler.d.ts +20 -0
- package/dist/src/flow-control/output-error-handler.js +27 -0
- package/dist/src/flow-control/restart-process.js +1 -1
- package/dist/src/index.d.ts +14 -2
- package/dist/src/index.js +16 -9
- package/dist/src/logger.js +3 -3
- package/dist/src/observables.d.ts +9 -0
- package/dist/src/observables.js +24 -0
- package/dist/src/output-writer.d.ts +4 -0
- package/dist/src/output-writer.js +16 -1
- package/dist/src/prefix-color-selector.js +1 -1
- package/dist/src/spawn.js +1 -1
- package/docs/README.md +2 -0
- package/docs/cli/input-handling.md +5 -5
- package/docs/cli/output-control.md +3 -3
- package/docs/cli/prefixing.md +10 -10
- package/docs/cli/restarting.md +3 -3
- package/docs/cli/shortcuts.md +7 -7
- package/docs/cli/success.md +73 -0
- package/docs/cli/terminating.md +52 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ The tool is written in Node.js, but you can use it to run **any** commands.
|
|
|
61
61
|
Remember to surround separate commands with quotes:
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
concurrently
|
|
64
|
+
concurrently 'command1 arg' 'command2 arg'
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Otherwise **concurrently** would try to run 4 separate commands:
|
|
@@ -70,7 +70,7 @@ Otherwise **concurrently** would try to run 4 separate commands:
|
|
|
70
70
|
In package.json, escape quotes:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
"start": "concurrently
|
|
73
|
+
"start": "concurrently 'command1 arg' 'command2 arg'"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
You can always check concurrently's flag list by running `concurrently --help`.
|
|
@@ -88,7 +88,7 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
|
|
|
88
88
|
with the shape `{ command, name, prefixColor, env, cwd, ipc }`.
|
|
89
89
|
|
|
90
90
|
- `options` (optional): an object containing any of the below:
|
|
91
|
-
- `cwd`: the working directory to be used by all commands. Can be
|
|
91
|
+
- `cwd`: the working directory to be used by all commands. Can be overridden per command.
|
|
92
92
|
Default: `process.cwd()`.
|
|
93
93
|
- `defaultInputTarget`: the default input target when reading from `inputStream`.
|
|
94
94
|
Default: `0`.
|
|
@@ -96,8 +96,8 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
|
|
|
96
96
|
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
|
|
97
97
|
to read the input from. Should only be used in the rare instance you would like to stream anything other than `process.stdin`. Overrides `handleInput`.
|
|
98
98
|
- `pauseInputStreamOnFinish`: by default, pauses the input stream (`process.stdin` when `handleInput` is enabled, or `inputStream` if provided) when all of the processes have finished. If you need to read from the input stream after `concurrently` has finished, set this to `false`. ([#252](https://github.com/kimmobrunfeldt/concurrently/issues/252)).
|
|
99
|
-
- `
|
|
100
|
-
Can
|
|
99
|
+
- `killOthersOn`: once the first command exits with one of these statuses, kill other commands.
|
|
100
|
+
Can be an array containing the strings `success` (status code zero) and/or `failure` (non-zero exit status).
|
|
101
101
|
- `maxProcesses`: how many processes should run at once.
|
|
102
102
|
- `outputStream`: a [`Writable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_streams)
|
|
103
103
|
to write logs to. Default: `process.stdout`.
|
|
@@ -109,14 +109,14 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
|
|
|
109
109
|
Prefix colors specified per-command take precedence over this list.
|
|
110
110
|
- `prefixLength`: how many characters to show when prefixing with `command`. Default: `10`
|
|
111
111
|
- `raw`: whether raw mode should be used, meaning strictly process output will
|
|
112
|
-
be logged, without any prefixes, coloring or extra stuff. Can be
|
|
112
|
+
be logged, without any prefixes, coloring or extra stuff. Can be overridden per command.
|
|
113
113
|
- `successCondition`: the condition to consider the run was successful.
|
|
114
114
|
If `first`, only the first process to exit will make up the success of the run; if `last`, the last process that exits will determine whether the run succeeds.
|
|
115
115
|
Anything else means all processes should exit successfully.
|
|
116
116
|
- `restartTries`: how many attempts to restart a process that dies will be made. Default: `0`.
|
|
117
117
|
- `restartDelay`: how many milliseconds to wait between process restarts. Default: `0`.
|
|
118
118
|
- `timestampFormat`: a [Unicode format](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
|
|
119
|
-
to use when prefixing with `time`. Default: `yyyy-MM-dd HH:mm:ss.
|
|
119
|
+
to use when prefixing with `time`. Default: `yyyy-MM-dd HH:mm:ss.SSS`
|
|
120
120
|
- `additionalArguments`: list of additional arguments passed that will get replaced in each command. If not defined, no argument replacing will happen.
|
|
121
121
|
|
|
122
122
|
> **Returns:** an object in the shape `{ result, commands }`.
|
|
@@ -172,6 +172,7 @@ It has the following properties:
|
|
|
172
172
|
- `stderr`: an RxJS observable to the command's `stderr`.
|
|
173
173
|
- `error`: an RxJS observable to the command's error events (e.g. when it fails to spawn).
|
|
174
174
|
- `timer`: an RxJS observable to the command's timing events (e.g. starting, stopping).
|
|
175
|
+
- `stateChange`: an RxJS observable for changes to the command's `state` property.
|
|
175
176
|
- `messages`: an object with the following properties:
|
|
176
177
|
|
|
177
178
|
- `incoming`: an RxJS observable for the IPC messages received from the underlying process.
|
package/dist/bin/concurrently.js
CHANGED
|
@@ -30,6 +30,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
30
30
|
const lodash_1 = __importDefault(require("lodash"));
|
|
31
31
|
const yargs_1 = __importDefault(require("yargs"));
|
|
32
32
|
const helpers_1 = require("yargs/helpers");
|
|
33
|
+
const assert_1 = require("../src/assert");
|
|
33
34
|
const defaults = __importStar(require("../src/defaults"));
|
|
34
35
|
const index_1 = require("../src/index");
|
|
35
36
|
const read_package_1 = require("./read-package");
|
|
@@ -128,7 +129,7 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
|
128
129
|
// Kill others
|
|
129
130
|
'kill-others': {
|
|
130
131
|
alias: 'k',
|
|
131
|
-
describe: 'Kill other processes
|
|
132
|
+
describe: 'Kill other processes once the first exits.',
|
|
132
133
|
type: 'boolean',
|
|
133
134
|
},
|
|
134
135
|
'kill-others-on-fail': {
|
|
@@ -141,6 +142,10 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
|
141
142
|
type: 'string',
|
|
142
143
|
default: defaults.killSignal,
|
|
143
144
|
},
|
|
145
|
+
'kill-timeout': {
|
|
146
|
+
describe: 'How many milliseconds to wait before forcing process terminating.',
|
|
147
|
+
type: 'number',
|
|
148
|
+
},
|
|
144
149
|
// Prefix
|
|
145
150
|
prefix: {
|
|
146
151
|
alias: 'p',
|
|
@@ -209,10 +214,11 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
|
209
214
|
.group(['m', 'n', 'name-separator', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'P', 'teardown'], 'General')
|
|
210
215
|
.group(['p', 'c', 'l', 't', 'pad-prefix'], 'Prefix styling')
|
|
211
216
|
.group(['i', 'default-input-target'], 'Input handling')
|
|
212
|
-
.group(['k', 'kill-others-on-fail', 'kill-signal'], 'Killing other processes')
|
|
217
|
+
.group(['k', 'kill-others-on-fail', 'kill-signal', 'kill-timeout'], 'Killing other processes')
|
|
213
218
|
.group(['restart-tries', 'restart-after'], 'Restarting')
|
|
214
219
|
.epilogue(epilogue);
|
|
215
220
|
const args = program.parseSync();
|
|
221
|
+
(0, assert_1.assertDeprecated)(args.nameSeparator === defaults.nameSeparator, 'name-separator', 'Use commas as name separators instead.');
|
|
216
222
|
// Get names of commands by the specified separator
|
|
217
223
|
const names = (args.names || '').split(args.nameSeparator);
|
|
218
224
|
const additionalArguments = lodash_1.default.castArray(args['--'] ?? []).map(String);
|
|
@@ -227,12 +233,13 @@ if (!commands.length) {
|
|
|
227
233
|
})), {
|
|
228
234
|
handleInput: args.handleInput,
|
|
229
235
|
defaultInputTarget: args.defaultInputTarget,
|
|
230
|
-
|
|
236
|
+
killOthersOn: args.killOthers
|
|
231
237
|
? ['success', 'failure']
|
|
232
238
|
: args.killOthersOnFail
|
|
233
239
|
? ['failure']
|
|
234
240
|
: [],
|
|
235
241
|
killSignal: args.killSignal,
|
|
242
|
+
killTimeout: args.killTimeout,
|
|
236
243
|
maxProcesses: args.maxProcesses,
|
|
237
244
|
raw: args.raw,
|
|
238
245
|
hide: args.hide.split(','),
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertDeprecated = void 0;
|
|
4
|
+
const deprecations = new Set();
|
|
5
|
+
/**
|
|
6
|
+
* Asserts that some condition is true, and if not, prints a warning about it being deprecated.
|
|
7
|
+
* The message is printed only once.
|
|
8
|
+
*/
|
|
9
|
+
function assertDeprecated(check, name, message) {
|
|
10
|
+
if (!check) {
|
|
11
|
+
// eslint-disable-next-line no-console
|
|
12
|
+
console.warn(`[concurrently] ${name} is deprecated. ${message}`);
|
|
13
|
+
deprecations.add(name);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.assertDeprecated = assertDeprecated;
|
package/dist/src/command.d.ts
CHANGED
|
@@ -117,6 +117,13 @@ export declare class Command implements CommandInfo {
|
|
|
117
117
|
readonly stdout: Rx.Subject<Buffer>;
|
|
118
118
|
readonly stderr: Rx.Subject<Buffer>;
|
|
119
119
|
readonly timer: Rx.Subject<TimerEvent>;
|
|
120
|
+
/**
|
|
121
|
+
* A stream of changes to the `#state` property.
|
|
122
|
+
*
|
|
123
|
+
* Note that the command never goes back to the `stopped` state, therefore it's not a value
|
|
124
|
+
* that's emitted by this stream.
|
|
125
|
+
*/
|
|
126
|
+
readonly stateChange: Rx.Subject<"started" | "errored" | "exited">;
|
|
120
127
|
readonly messages: {
|
|
121
128
|
incoming: Rx.Subject<MessageEvent>;
|
|
122
129
|
outgoing: Rx.ReplaySubject<OutgoingMessageEvent>;
|
|
@@ -135,6 +142,7 @@ export declare class Command implements CommandInfo {
|
|
|
135
142
|
* Starts this command, piping output, error and close events onto the corresponding observables.
|
|
136
143
|
*/
|
|
137
144
|
start(): void;
|
|
145
|
+
private changeState;
|
|
138
146
|
private maybeSetupIPC;
|
|
139
147
|
/**
|
|
140
148
|
* Sends a message to the underlying process once it starts.
|
package/dist/src/command.js
CHANGED
|
@@ -47,6 +47,13 @@ class Command {
|
|
|
47
47
|
stdout = new Rx.Subject();
|
|
48
48
|
stderr = new Rx.Subject();
|
|
49
49
|
timer = new Rx.Subject();
|
|
50
|
+
/**
|
|
51
|
+
* A stream of changes to the `#state` property.
|
|
52
|
+
*
|
|
53
|
+
* Note that the command never goes back to the `stopped` state, therefore it's not a value
|
|
54
|
+
* that's emitted by this stream.
|
|
55
|
+
*/
|
|
56
|
+
stateChange = new Rx.Subject();
|
|
50
57
|
messages = {
|
|
51
58
|
incoming: new Rx.Subject(),
|
|
52
59
|
outgoing: new Rx.ReplaySubject(),
|
|
@@ -76,7 +83,7 @@ class Command {
|
|
|
76
83
|
*/
|
|
77
84
|
start() {
|
|
78
85
|
const child = this.spawn(this.command, this.spawnOpts);
|
|
79
|
-
this.
|
|
86
|
+
this.changeState('started');
|
|
80
87
|
this.process = child;
|
|
81
88
|
this.pid = child.pid;
|
|
82
89
|
const startDate = new Date(Date.now());
|
|
@@ -88,7 +95,7 @@ class Command {
|
|
|
88
95
|
const endDate = new Date(Date.now());
|
|
89
96
|
this.timer.next({ startDate, endDate });
|
|
90
97
|
this.error.next(event);
|
|
91
|
-
this.
|
|
98
|
+
this.changeState('errored');
|
|
92
99
|
});
|
|
93
100
|
Rx.fromEvent(child, 'close')
|
|
94
101
|
.pipe(Rx.map((event) => event))
|
|
@@ -96,7 +103,7 @@ class Command {
|
|
|
96
103
|
this.cleanUp();
|
|
97
104
|
// Don't override error event
|
|
98
105
|
if (this.state !== 'errored') {
|
|
99
|
-
this.
|
|
106
|
+
this.changeState('exited');
|
|
100
107
|
}
|
|
101
108
|
const endDate = new Date(Date.now());
|
|
102
109
|
this.timer.next({ startDate, endDate });
|
|
@@ -119,6 +126,10 @@ class Command {
|
|
|
119
126
|
pipeTo(Rx.fromEvent(child.stderr, 'data').pipe(Rx.map((event) => event)), this.stderr);
|
|
120
127
|
this.stdin = child.stdin || undefined;
|
|
121
128
|
}
|
|
129
|
+
changeState(state) {
|
|
130
|
+
this.state = state;
|
|
131
|
+
this.stateChange.next(state);
|
|
132
|
+
}
|
|
122
133
|
maybeSetupIPC(child) {
|
|
123
134
|
if (!this.ipc) {
|
|
124
135
|
return [];
|
|
@@ -61,7 +61,7 @@ class CompletionListener {
|
|
|
61
61
|
// All commands except the specified ones must exit successfully
|
|
62
62
|
return events.every((event) => targetCommandsEvents.includes(event) || event.exitCode === 0);
|
|
63
63
|
}
|
|
64
|
-
// Only the specified commands must exit
|
|
64
|
+
// Only the specified commands must exit successfully
|
|
65
65
|
return (targetCommandsEvents.length > 0 &&
|
|
66
66
|
targetCommandsEvents.every((event) => event.exitCode === 0));
|
|
67
67
|
}
|
|
@@ -73,6 +73,9 @@ class CompletionListener {
|
|
|
73
73
|
* Commands that didn't spawn are filtered out.
|
|
74
74
|
*/
|
|
75
75
|
listen(commands, abortSignal) {
|
|
76
|
+
if (!commands.length) {
|
|
77
|
+
return Promise.resolve([]);
|
|
78
|
+
}
|
|
76
79
|
const abort = abortSignal &&
|
|
77
80
|
Rx.fromEvent(abortSignal, 'abort', { once: true }).pipe(
|
|
78
81
|
// The abort signal must happen before commands are killed, otherwise new commands
|
|
@@ -101,10 +101,6 @@ export type ConcurrentlyOptions = {
|
|
|
101
101
|
* Defaults to the `tree-kill` module.
|
|
102
102
|
*/
|
|
103
103
|
kill: KillProcess;
|
|
104
|
-
/**
|
|
105
|
-
* Signal to send to killed processes.
|
|
106
|
-
*/
|
|
107
|
-
killSignal?: string;
|
|
108
104
|
/**
|
|
109
105
|
* List of additional arguments passed that will get replaced in each command.
|
|
110
106
|
* If not defined, no argument replacing will happen.
|
package/dist/src/concurrently.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.concurrently = void 0;
|
|
|
7
7
|
const assert_1 = __importDefault(require("assert"));
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
9
|
const os_1 = require("os");
|
|
10
|
+
const rxjs_1 = require("rxjs");
|
|
10
11
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
11
12
|
const command_1 = require("./command");
|
|
12
13
|
const expand_arguments_1 = require("./command-parser/expand-arguments");
|
|
@@ -75,7 +76,10 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
75
76
|
group: !!options.group,
|
|
76
77
|
commands,
|
|
77
78
|
});
|
|
78
|
-
options.logger.output
|
|
79
|
+
options.logger.output
|
|
80
|
+
// Stop trying to write after there's been an error.
|
|
81
|
+
.pipe((0, rxjs_1.takeUntil)(outputWriter.error))
|
|
82
|
+
.subscribe(({ command, text }) => outputWriter.write(command, text));
|
|
79
83
|
}
|
|
80
84
|
const commandsLeft = commands.slice();
|
|
81
85
|
const maxProcesses = Math.max(1, (typeof options.maxProcesses === 'string' && options.maxProcesses.endsWith('%')
|
|
@@ -11,13 +11,16 @@ export declare class KillOthers implements FlowController {
|
|
|
11
11
|
private readonly abortController?;
|
|
12
12
|
private readonly conditions;
|
|
13
13
|
private readonly killSignal;
|
|
14
|
-
|
|
14
|
+
private readonly timeoutMs?;
|
|
15
|
+
constructor({ logger, abortController, conditions, killSignal, timeoutMs, }: {
|
|
15
16
|
logger: Logger;
|
|
16
17
|
abortController?: AbortController;
|
|
17
18
|
conditions: ProcessCloseCondition | ProcessCloseCondition[];
|
|
18
19
|
killSignal: string | undefined;
|
|
20
|
+
timeoutMs?: number;
|
|
19
21
|
});
|
|
20
22
|
handle(commands: Command[]): {
|
|
21
23
|
commands: Command[];
|
|
22
24
|
};
|
|
25
|
+
private maybeForceKill;
|
|
23
26
|
}
|
|
@@ -15,11 +15,13 @@ class KillOthers {
|
|
|
15
15
|
abortController;
|
|
16
16
|
conditions;
|
|
17
17
|
killSignal;
|
|
18
|
-
|
|
18
|
+
timeoutMs;
|
|
19
|
+
constructor({ logger, abortController, conditions, killSignal, timeoutMs, }) {
|
|
19
20
|
this.logger = logger;
|
|
20
21
|
this.abortController = abortController;
|
|
21
22
|
this.conditions = lodash_1.default.castArray(conditions);
|
|
22
23
|
this.killSignal = killSignal;
|
|
24
|
+
this.timeoutMs = timeoutMs;
|
|
23
25
|
}
|
|
24
26
|
handle(commands) {
|
|
25
27
|
const conditions = this.conditions.filter((condition) => condition === 'failure' || condition === 'success');
|
|
@@ -33,9 +35,23 @@ class KillOthers {
|
|
|
33
35
|
if (killableCommands.length) {
|
|
34
36
|
this.logger.logGlobalEvent(`Sending ${this.killSignal || 'SIGTERM'} to other processes..`);
|
|
35
37
|
killableCommands.forEach((command) => command.kill(this.killSignal));
|
|
38
|
+
this.maybeForceKill(killableCommands);
|
|
36
39
|
}
|
|
37
40
|
}));
|
|
38
41
|
return { commands };
|
|
39
42
|
}
|
|
43
|
+
maybeForceKill(commands) {
|
|
44
|
+
// No need to force kill when the signal already is SIGKILL.
|
|
45
|
+
if (!this.timeoutMs || this.killSignal === 'SIGKILL') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
const killableCommands = commands.filter((command) => command_1.Command.canKill(command));
|
|
50
|
+
if (killableCommands) {
|
|
51
|
+
this.logger.logGlobalEvent(`Sending SIGKILL to ${killableCommands.length} processes..`);
|
|
52
|
+
killableCommands.forEach((command) => command.kill('SIGKILL'));
|
|
53
|
+
}
|
|
54
|
+
}, this.timeoutMs);
|
|
55
|
+
}
|
|
40
56
|
}
|
|
41
57
|
exports.KillOthers = KillOthers;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { Writable } from 'stream';
|
|
4
|
+
import { Command } from '../command';
|
|
5
|
+
import { FlowController } from './flow-controller';
|
|
6
|
+
/**
|
|
7
|
+
* Kills processes and aborts further command spawning on output stream error (namely, SIGPIPE).
|
|
8
|
+
*/
|
|
9
|
+
export declare class OutputErrorHandler implements FlowController {
|
|
10
|
+
private readonly outputStream;
|
|
11
|
+
private readonly abortController;
|
|
12
|
+
constructor({ abortController, outputStream, }: {
|
|
13
|
+
abortController: AbortController;
|
|
14
|
+
outputStream: Writable;
|
|
15
|
+
});
|
|
16
|
+
handle(commands: Command[]): {
|
|
17
|
+
commands: Command[];
|
|
18
|
+
onFinish(): void;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OutputErrorHandler = void 0;
|
|
4
|
+
const observables_1 = require("../observables");
|
|
5
|
+
/**
|
|
6
|
+
* Kills processes and aborts further command spawning on output stream error (namely, SIGPIPE).
|
|
7
|
+
*/
|
|
8
|
+
class OutputErrorHandler {
|
|
9
|
+
outputStream;
|
|
10
|
+
abortController;
|
|
11
|
+
constructor({ abortController, outputStream, }) {
|
|
12
|
+
this.abortController = abortController;
|
|
13
|
+
this.outputStream = outputStream;
|
|
14
|
+
}
|
|
15
|
+
handle(commands) {
|
|
16
|
+
const subscription = (0, observables_1.fromSharedEvent)(this.outputStream, 'error').subscribe(() => {
|
|
17
|
+
commands.forEach((command) => command.kill());
|
|
18
|
+
// Avoid further commands from spawning, e.g. if `RestartProcess` is used.
|
|
19
|
+
this.abortController.abort();
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
commands,
|
|
23
|
+
onFinish: () => subscription.unsubscribe(),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.OutputErrorHandler = OutputErrorHandler;
|
|
@@ -53,7 +53,7 @@ class RestartProcess {
|
|
|
53
53
|
});
|
|
54
54
|
commands
|
|
55
55
|
.map((command) => command.close.pipe((0, operators_1.take)(this.tries), (0, operators_1.takeWhile)(({ exitCode }) => exitCode !== 0)))
|
|
56
|
-
.
|
|
56
|
+
.forEach((failure, index) => Rx.merge(
|
|
57
57
|
// Delay the emission (so that the restarts happen on time),
|
|
58
58
|
// explicitly telling the subscriber that a restart is needed
|
|
59
59
|
failure.pipe(delayOperator, (0, operators_1.map)(() => true)),
|
package/dist/src/index.d.ts
CHANGED
|
@@ -56,11 +56,23 @@ export type ConcurrentlyOptions = Omit<BaseConcurrentlyOptions, 'abortSignal' |
|
|
|
56
56
|
*/
|
|
57
57
|
restartTries?: number;
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* @deprecated Use `killOthersOn` instead.
|
|
61
60
|
* @see KillOthers
|
|
62
61
|
*/
|
|
63
62
|
killOthers?: ProcessCloseCondition | ProcessCloseCondition[];
|
|
63
|
+
/**
|
|
64
|
+
* Once the first command exits with one of these statuses, kill other commands.
|
|
65
|
+
* @see KillOthers
|
|
66
|
+
*/
|
|
67
|
+
killOthersOn?: ProcessCloseCondition | ProcessCloseCondition[];
|
|
68
|
+
/**
|
|
69
|
+
* Signal to send to killed processes.
|
|
70
|
+
*/
|
|
71
|
+
killSignal?: string;
|
|
72
|
+
/**
|
|
73
|
+
* How many milliseconds to wait before killing processes.
|
|
74
|
+
*/
|
|
75
|
+
killTimeout?: number;
|
|
64
76
|
/**
|
|
65
77
|
* Whether to output timing information for processes.
|
|
66
78
|
*
|
package/dist/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.RestartProcess = exports.LogTimings = exports.LogOutput = exports.LogExit = exports.LogError = exports.KillOthers = exports.KillOnSignal = exports.InputHandler = exports.Command = exports.Logger = exports.createConcurrently = exports.concurrently = void 0;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const assert_1 = require("./assert");
|
|
8
9
|
const command_1 = require("./command");
|
|
9
10
|
Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return command_1.Command; } });
|
|
10
11
|
const concurrently_1 = require("./concurrently");
|
|
@@ -24,27 +25,31 @@ Object.defineProperty(exports, "LogOutput", { enumerable: true, get: function ()
|
|
|
24
25
|
const log_timings_1 = require("./flow-control/log-timings");
|
|
25
26
|
Object.defineProperty(exports, "LogTimings", { enumerable: true, get: function () { return log_timings_1.LogTimings; } });
|
|
26
27
|
const logger_padding_1 = require("./flow-control/logger-padding");
|
|
28
|
+
const output_error_handler_1 = require("./flow-control/output-error-handler");
|
|
27
29
|
const restart_process_1 = require("./flow-control/restart-process");
|
|
28
30
|
Object.defineProperty(exports, "RestartProcess", { enumerable: true, get: function () { return restart_process_1.RestartProcess; } });
|
|
29
31
|
const teardown_1 = require("./flow-control/teardown");
|
|
30
32
|
const logger_1 = require("./logger");
|
|
31
33
|
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
|
|
32
34
|
function concurrently(commands, options = {}) {
|
|
35
|
+
(0, assert_1.assertDeprecated)(options.killOthers === undefined, 'killOthers', 'Use killOthersOn instead.');
|
|
33
36
|
// To avoid empty strings from hiding the output of commands that don't have a name,
|
|
34
37
|
// keep in the list of commands to hide only strings with some length.
|
|
35
38
|
// This might happen through the CLI when no `--hide` argument is specified, for example.
|
|
36
39
|
const hide = lodash_1.default.castArray(options.hide).filter((id) => id || id === 0);
|
|
37
|
-
const logger =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
const logger = options.logger ||
|
|
41
|
+
new logger_1.Logger({
|
|
42
|
+
hide,
|
|
43
|
+
prefixFormat: options.prefix,
|
|
44
|
+
commandLength: options.prefixLength,
|
|
45
|
+
raw: options.raw,
|
|
46
|
+
timestampFormat: options.timestampFormat,
|
|
47
|
+
});
|
|
44
48
|
if (options.prefixColors === false) {
|
|
45
49
|
logger.toggleColors(false);
|
|
46
50
|
}
|
|
47
51
|
const abortController = new AbortController();
|
|
52
|
+
const outputStream = options.outputStream || process.stdout;
|
|
48
53
|
return (0, concurrently_1.concurrently)(commands, {
|
|
49
54
|
maxProcesses: options.maxProcesses,
|
|
50
55
|
raw: options.raw,
|
|
@@ -52,7 +57,7 @@ function concurrently(commands, options = {}) {
|
|
|
52
57
|
cwd: options.cwd,
|
|
53
58
|
hide,
|
|
54
59
|
logger,
|
|
55
|
-
outputStream
|
|
60
|
+
outputStream,
|
|
56
61
|
group: options.group,
|
|
57
62
|
abortSignal: abortController.signal,
|
|
58
63
|
controllers: [
|
|
@@ -75,10 +80,12 @@ function concurrently(commands, options = {}) {
|
|
|
75
80
|
}),
|
|
76
81
|
new kill_others_1.KillOthers({
|
|
77
82
|
logger,
|
|
78
|
-
conditions: options.killOthers || [],
|
|
83
|
+
conditions: options.killOthersOn || options.killOthers || [],
|
|
84
|
+
timeoutMs: options.killTimeout,
|
|
79
85
|
killSignal: options.killSignal,
|
|
80
86
|
abortController,
|
|
81
87
|
}),
|
|
88
|
+
new output_error_handler_1.OutputErrorHandler({ abortController, outputStream }),
|
|
82
89
|
new log_timings_1.LogTimings({
|
|
83
90
|
logger: options.timings ? logger : undefined,
|
|
84
91
|
timestampFormat: options.timestampFormat,
|
package/dist/src/logger.js
CHANGED
|
@@ -77,9 +77,9 @@ class Logger {
|
|
|
77
77
|
const prefixLength = this.commandLength - ellipsis.length;
|
|
78
78
|
const endLength = Math.floor(prefixLength / 2);
|
|
79
79
|
const beginningLength = prefixLength - endLength;
|
|
80
|
-
const
|
|
80
|
+
const beginning = text.slice(0, beginningLength);
|
|
81
81
|
const end = text.slice(text.length - endLength, text.length);
|
|
82
|
-
return
|
|
82
|
+
return beginning + ellipsis + end;
|
|
83
83
|
}
|
|
84
84
|
getPrefixesFor(command) {
|
|
85
85
|
return {
|
|
@@ -121,7 +121,7 @@ class Logger {
|
|
|
121
121
|
}
|
|
122
122
|
colorText(command, text) {
|
|
123
123
|
let color;
|
|
124
|
-
if (command.prefixColor
|
|
124
|
+
if (command.prefixColor?.startsWith('#')) {
|
|
125
125
|
color = this.chalk.hex(command.prefixColor);
|
|
126
126
|
}
|
|
127
127
|
else {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import EventEmitter from 'events';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
/**
|
|
5
|
+
* Creates an observable for a specific event of an `EventEmitter` instance.
|
|
6
|
+
*
|
|
7
|
+
* The underlying event listener is set up only once across the application for that event emitter/name pair.
|
|
8
|
+
*/
|
|
9
|
+
export declare function fromSharedEvent(emitter: EventEmitter, event: string): Observable<unknown>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fromSharedEvent = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const sharedEvents = new WeakMap();
|
|
6
|
+
/**
|
|
7
|
+
* Creates an observable for a specific event of an `EventEmitter` instance.
|
|
8
|
+
*
|
|
9
|
+
* The underlying event listener is set up only once across the application for that event emitter/name pair.
|
|
10
|
+
*/
|
|
11
|
+
function fromSharedEvent(emitter, event) {
|
|
12
|
+
let emitterEvents = sharedEvents.get(emitter);
|
|
13
|
+
if (!emitterEvents) {
|
|
14
|
+
emitterEvents = new Map();
|
|
15
|
+
sharedEvents.set(emitter, emitterEvents);
|
|
16
|
+
}
|
|
17
|
+
let observable = emitterEvents.get(event);
|
|
18
|
+
if (!observable) {
|
|
19
|
+
observable = (0, rxjs_1.fromEvent)(emitter, event).pipe((0, rxjs_1.share)());
|
|
20
|
+
emitterEvents.set(event, observable);
|
|
21
|
+
}
|
|
22
|
+
return observable;
|
|
23
|
+
}
|
|
24
|
+
exports.fromSharedEvent = fromSharedEvent;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import * as Rx from 'rxjs';
|
|
2
3
|
import { Writable } from 'stream';
|
|
3
4
|
import { Command } from './command';
|
|
4
5
|
/**
|
|
@@ -9,11 +10,14 @@ export declare class OutputWriter {
|
|
|
9
10
|
private readonly group;
|
|
10
11
|
readonly buffers: string[][];
|
|
11
12
|
activeCommandIndex: number;
|
|
13
|
+
readonly error: Rx.Observable<unknown>;
|
|
14
|
+
private get errored();
|
|
12
15
|
constructor({ outputStream, group, commands, }: {
|
|
13
16
|
outputStream: Writable;
|
|
14
17
|
group: boolean;
|
|
15
18
|
commands: Command[];
|
|
16
19
|
});
|
|
20
|
+
private ensureWritable;
|
|
17
21
|
write(command: Command | undefined, text: string): void;
|
|
18
22
|
private flushBuffer;
|
|
19
23
|
}
|
|
@@ -25,6 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.OutputWriter = void 0;
|
|
27
27
|
const Rx = __importStar(require("rxjs"));
|
|
28
|
+
const observables_1 = require("./observables");
|
|
28
29
|
/**
|
|
29
30
|
* Class responsible for actually writing output onto a writable stream.
|
|
30
31
|
*/
|
|
@@ -33,8 +34,14 @@ class OutputWriter {
|
|
|
33
34
|
group;
|
|
34
35
|
buffers;
|
|
35
36
|
activeCommandIndex = 0;
|
|
37
|
+
error;
|
|
38
|
+
get errored() {
|
|
39
|
+
return this.outputStream.errored;
|
|
40
|
+
}
|
|
36
41
|
constructor({ outputStream, group, commands, }) {
|
|
37
42
|
this.outputStream = outputStream;
|
|
43
|
+
this.ensureWritable();
|
|
44
|
+
this.error = (0, observables_1.fromSharedEvent)(this.outputStream, 'error');
|
|
38
45
|
this.group = group;
|
|
39
46
|
this.buffers = commands.map(() => []);
|
|
40
47
|
if (this.group) {
|
|
@@ -53,7 +60,13 @@ class OutputWriter {
|
|
|
53
60
|
});
|
|
54
61
|
}
|
|
55
62
|
}
|
|
63
|
+
ensureWritable() {
|
|
64
|
+
if (this.errored) {
|
|
65
|
+
throw new TypeError('outputStream is in errored state', { cause: this.errored });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
56
68
|
write(command, text) {
|
|
69
|
+
this.ensureWritable();
|
|
57
70
|
if (this.group && command) {
|
|
58
71
|
if (command.index <= this.activeCommandIndex) {
|
|
59
72
|
this.outputStream.write(text);
|
|
@@ -68,7 +81,9 @@ class OutputWriter {
|
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
83
|
flushBuffer(index) {
|
|
71
|
-
this.
|
|
84
|
+
if (!this.errored) {
|
|
85
|
+
this.buffers[index].forEach((t) => this.outputStream.write(t));
|
|
86
|
+
}
|
|
72
87
|
this.buffers[index] = [];
|
|
73
88
|
}
|
|
74
89
|
}
|
|
@@ -34,7 +34,7 @@ function* createColorGenerator(customColors) {
|
|
|
34
34
|
const lastCustomColor = customColors[customColors.length - 1] || '';
|
|
35
35
|
if (lastCustomColor !== 'auto') {
|
|
36
36
|
while (true) {
|
|
37
|
-
yield lastCustomColor; // If last custom color was not "auto" then return same color forever, to maintain existing
|
|
37
|
+
yield lastCustomColor; // If last custom color was not "auto" then return same color forever, to maintain existing behavior
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
// Finish the initial set(s) of auto colors to avoid repetition
|
package/dist/src/spawn.js
CHANGED
|
@@ -38,7 +38,7 @@ const getSpawnOpts = ({ colorSupport = supports_color_1.default.stdout, cwd, pro
|
|
|
38
38
|
return {
|
|
39
39
|
cwd: cwd || process.cwd(),
|
|
40
40
|
stdio: stdioValues,
|
|
41
|
-
...(
|
|
41
|
+
...(process.platform.startsWith('win') && { detached: false }),
|
|
42
42
|
env: {
|
|
43
43
|
...(colorSupport ? { FORCE_COLOR: colorSupport.level.toString() } : {}),
|
|
44
44
|
...process.env,
|
package/docs/README.md
CHANGED
|
@@ -6,7 +6,9 @@ These articles cover using concurrently through CLI:
|
|
|
6
6
|
|
|
7
7
|
- [Prefixing](./cli/prefixing.md)
|
|
8
8
|
- [Output Control](./cli/output-control.md)
|
|
9
|
+
- [Success Conditions](./cli/success.md)
|
|
9
10
|
- [Shortcuts](./cli/shortcuts.md)
|
|
11
|
+
- [Terminating Commands](./cli/terminating.md)
|
|
10
12
|
- [Restarting Commands](./cli/restarting.md)
|
|
11
13
|
- [Input Handling](./cli/input-handling.md)
|
|
12
14
|
- [Passthrough Arguments](./cli/passthrough-arguments.md)
|
|
@@ -4,7 +4,7 @@ By default, concurrently doesn't send input to any commands it spawns.<br/>
|
|
|
4
4
|
In the below example, typing `rs` to manually restart [nodemon](https://nodemon.io/) does nothing:
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
$ concurrently
|
|
7
|
+
$ concurrently 'nodemon' 'npm run watch-js'
|
|
8
8
|
rs
|
|
9
9
|
```
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ To turn on input handling, it's necessary to set the `--handle-input`/`-i` flag.
|
|
|
12
12
|
This will send `rs` to the first command:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
$ concurrently --handle-input
|
|
15
|
+
$ concurrently --handle-input 'nodemon' 'npm run watch-js'
|
|
16
16
|
rs
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -20,14 +20,14 @@ To send input to a different command instead, it's possible to prefix the input
|
|
|
20
20
|
For example, the below sends `rs` to the second command:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
$ concurrently --handle-input
|
|
23
|
+
$ concurrently --handle-input 'npm run watch-js' 'nodemon'
|
|
24
24
|
1:rs
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
If the command has a name, it's also possible to target it using that command's name:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
$ concurrently --handle-input --names js,server
|
|
30
|
+
$ concurrently --handle-input --names js,server 'npm run watch-js' 'nodemon'
|
|
31
31
|
server:rs
|
|
32
32
|
```
|
|
33
33
|
|
|
@@ -35,6 +35,6 @@ It's also possible to change the default command that receives input.<br/>
|
|
|
35
35
|
To do this, set the `--default-input-target` flag to a command's index or name.
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
$ concurrently --handle-input --default-input-target 1
|
|
38
|
+
$ concurrently --handle-input --default-input-target 1 'npm run watch-js' 'nodemon'
|
|
39
39
|
rs
|
|
40
40
|
```
|
|
@@ -7,7 +7,7 @@ concurrently offers a few ways to control a command's output.
|
|
|
7
7
|
A command's outputs (and all its events) can be hidden by using the `--hide` flag.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
$ concurrently --hide 0
|
|
10
|
+
$ concurrently --hide 0 'echo Hello there' 'echo General Kenobi!'
|
|
11
11
|
[1] General Kenobi!
|
|
12
12
|
[1] echo 'General Kenobi!' exited with code 0
|
|
13
13
|
```
|
|
@@ -18,7 +18,7 @@ It might be useful at times to make sure that the commands outputs are grouped t
|
|
|
18
18
|
This can be done with the `--group` flag.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
$ concurrently --group
|
|
21
|
+
$ concurrently --group 'echo Hello there && sleep 2 && echo General Kenobi!' 'echo hi Star Wars fans'
|
|
22
22
|
[0] Hello there
|
|
23
23
|
[0] General Kenobi!
|
|
24
24
|
[0] echo Hello there && sleep 2 && echo 'General Kenobi!' exited with code 0
|
|
@@ -31,5 +31,5 @@ $ concurrently --group "echo Hello there && sleep 2 && echo 'General Kenobi!'" "
|
|
|
31
31
|
When piping concurrently's outputs to another command or file, you might want to force it to not use colors, as these can break the other command's parsing, or reduce the legibility of the output in non-terminal environments.
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
$ concurrently -c red,blue --no-color
|
|
34
|
+
$ concurrently -c red,blue --no-color 'echo Hello there' 'echo General Kenobi!'
|
|
35
35
|
```
|
package/docs/cli/prefixing.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
concurrently will by default prefix each command's outputs with a zero-based index, wrapped in square brackets:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
$ concurrently
|
|
8
|
+
$ concurrently 'echo Hello there' "echo 'General Kenobi!'"
|
|
9
9
|
[0] Hello there
|
|
10
10
|
[1] General Kenobi!
|
|
11
11
|
[0] echo Hello there exited with code 0
|
|
@@ -15,7 +15,7 @@ $ concurrently "echo Hello there" "echo 'General Kenobi!'"
|
|
|
15
15
|
If you've given the commands names, they are used instead:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
$ concurrently --names one,two
|
|
18
|
+
$ concurrently --names one,two 'echo Hello there' "echo 'General Kenobi!'"
|
|
19
19
|
[one] Hello there
|
|
20
20
|
[two] General Kenobi!
|
|
21
21
|
[one] echo Hello there exited with code 0
|
|
@@ -36,7 +36,7 @@ There are other prefix styles available too:
|
|
|
36
36
|
Any of these can be used by setting the `--prefix`/`-p` flag. For example:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
$ concurrently --prefix pid
|
|
39
|
+
$ concurrently --prefix pid 'echo Hello there' 'echo General Kenobi!'
|
|
40
40
|
[2222] Hello there
|
|
41
41
|
[2223] General Kenobi!
|
|
42
42
|
[2222] echo Hello there exited with code 0
|
|
@@ -47,7 +47,7 @@ It's also possible to have a prefix based on a template. Any of the styles liste
|
|
|
47
47
|
Doing so will also remove the square brackets:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
$ concurrently --prefix
|
|
50
|
+
$ concurrently --prefix '{index}-{pid}' 'echo Hello there' 'echo General Kenobi!'
|
|
51
51
|
0-2222 Hello there
|
|
52
52
|
1-2223 General Kenobi!
|
|
53
53
|
0-2222 echo Hello there exited with code 0
|
|
@@ -62,7 +62,7 @@ This can be changed by using the `--prefix-colors`/`-c` flag, which takes a comm
|
|
|
62
62
|
The available values are color names (e.g. `green`, `magenta`, `gray`, etc), a hex value (such as `#23de43`), or `auto`, to automatically select a color.
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
$ concurrently -c red,blue
|
|
65
|
+
$ concurrently -c red,blue 'echo Hello there' 'echo General Kenobi!'
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
<details>
|
|
@@ -82,7 +82,7 @@ $ concurrently -c red,blue "echo Hello there" "echo 'General Kenobi!'"
|
|
|
82
82
|
Colors can take modifiers too. Several can be applied at once by prepending `.<modifier 1>.<modifier 2>` and so on.
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
$ concurrently -c red,bold.blue.dim
|
|
85
|
+
$ concurrently -c red,bold.blue.dim 'echo Hello there' 'echo General Kenobi!'
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
<details>
|
|
@@ -98,10 +98,10 @@ $ concurrently -c red,bold.blue.dim "echo Hello there" "echo 'General Kenobi!'"
|
|
|
98
98
|
- `underline`
|
|
99
99
|
</details>
|
|
100
100
|
|
|
101
|
-
A background color can be set in a
|
|
101
|
+
A background color can be set in a similarly fashion.
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
$ concurrently -c bgGray,red.bgBlack
|
|
104
|
+
$ concurrently -c bgGray,red.bgBlack 'echo Hello there' 'echo General Kenobi!'
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
<details>
|
|
@@ -124,7 +124,7 @@ When using the `command` prefix style, it's possible that it'll be too long.<br/
|
|
|
124
124
|
It can be limited by setting the `--prefix-length`/`-l` flag:
|
|
125
125
|
|
|
126
126
|
```bash
|
|
127
|
-
$ concurrently -p command -l 10
|
|
127
|
+
$ concurrently -p command -l 10 'echo Hello there' 'echo General Kenobi!'
|
|
128
128
|
[echo..here] Hello there
|
|
129
129
|
[echo..bi!'] General Kenobi!
|
|
130
130
|
[echo..here] echo Hello there exited with code 0
|
|
@@ -135,7 +135,7 @@ It's also possible that some prefixes are too short, and you want all of them to
|
|
|
135
135
|
This can be done by setting the `--pad-prefix` flag:
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
|
-
$ concurrently -n foo,barbaz --pad-prefix
|
|
138
|
+
$ concurrently -n foo,barbaz --pad-prefix 'echo Hello there' 'echo General Kenobi!'
|
|
139
139
|
[foo ] Hello there
|
|
140
140
|
[foo ] echo Hello there exited with code 0
|
|
141
141
|
[barbaz] General Kenobi!
|
package/docs/cli/restarting.md
CHANGED
|
@@ -4,7 +4,7 @@ Sometimes it's useful to have commands that exited with a non-zero status to res
|
|
|
4
4
|
concurrently lets you configure how many times you wish for such a command to restart through the `--restart-tries` flag:
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
$ concurrently --restart-tries 2
|
|
7
|
+
$ concurrently --restart-tries 2 'exit 1'
|
|
8
8
|
[0] exit 1 exited with code 1
|
|
9
9
|
[0] exit 1 restarted
|
|
10
10
|
[0] exit 1 exited with code 1
|
|
@@ -16,7 +16,7 @@ Sometimes, it might be interesting to have commands wait before restarting.<br/>
|
|
|
16
16
|
To do this, simply set `--restart-after` to a the number of milliseconds you'd like to delay restarting.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
$ concurrently -p time --restart-tries 1 --restart-after 3000
|
|
19
|
+
$ concurrently -p time --restart-tries 1 --restart-after 3000 'exit 1'
|
|
20
20
|
[2024-09-01 23:43:55.871] exit 1 exited with code 1
|
|
21
21
|
[2024-09-01 23:43:58.874] exit 1 restarted
|
|
22
22
|
[2024-09-01 23:43:58.891] exit 1 exited with code 1
|
|
@@ -26,7 +26,7 @@ If a command is not having success spawning, you might want to instead apply an
|
|
|
26
26
|
Set `--restart-after exponential` to have commands respawn with a `2^N` seconds delay.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
$ concurrently -p time --restart-tries 3 --restart-after exponential
|
|
29
|
+
$ concurrently -p time --restart-tries 3 --restart-after exponential 'exit 1'
|
|
30
30
|
|
|
31
31
|
[2024-09-01 23:49:01.124] exit 1 exited with code 1
|
|
32
32
|
[2024-09-01 23:49:02.127] exit 1 restarted
|
package/docs/cli/shortcuts.md
CHANGED
|
@@ -35,9 +35,9 @@ For example, given the following `package.json` contents:
|
|
|
35
35
|
It's possible to run some of these with the following command line:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
$ concurrently
|
|
38
|
+
$ concurrently 'pnpm:lint:js'
|
|
39
39
|
# Is equivalent to
|
|
40
|
-
$ concurrently -n lint:js
|
|
40
|
+
$ concurrently -n lint:js 'pnpm run lint:js'
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Note that the command automatically receives a name equal to the script name.
|
|
@@ -46,17 +46,17 @@ If you have several scripts with similar name patterns, you can use the `*` wild
|
|
|
46
46
|
The spawned commands will receive names set to whatever the `*` wildcard matched.
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
$ concurrently
|
|
49
|
+
$ concurrently 'npm:lint:fix:*'
|
|
50
50
|
# is equivalent to
|
|
51
|
-
$ concurrently -n js,ts
|
|
51
|
+
$ concurrently -n js,ts 'npm run lint:fix:js' 'npm run lint:fix:ts'
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
If you specify a command name when using wildcards, it'll be a prefix of what the `*` wildcard matched:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
$ concurrently -n fix:
|
|
57
|
+
$ concurrently -n fix: 'npm:lint:fix:*'
|
|
58
58
|
# is equivalent to
|
|
59
|
-
$ concurrently -n fix:js,fix:ts
|
|
59
|
+
$ concurrently -n fix:js,fix:ts 'npm run lint:fix:js' 'npm run lint:fix:ts'
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
Filtering out commands matched by wildcard is also possible. Do this with by including `(!<some pattern>)` in the command line:
|
|
@@ -64,7 +64,7 @@ Filtering out commands matched by wildcard is also possible. Do this with by inc
|
|
|
64
64
|
```bash
|
|
65
65
|
$ concurrently 'yarn:lint:*(!fix)'
|
|
66
66
|
# is equivalent to
|
|
67
|
-
$ concurrently -n js,ts
|
|
67
|
+
$ concurrently -n js,ts 'yarn run lint:js' 'yarn run lint:ts'
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
> [!NOTE]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Success Conditions
|
|
2
|
+
|
|
3
|
+
When you're using concurrently in shell scripts or CI pipelines, the exit code matters.
|
|
4
|
+
It determines whether the next step runs, or if the script stops with a failure.
|
|
5
|
+
|
|
6
|
+
You can control concurrently's exit code using the `--success` flag.
|
|
7
|
+
This tells it **which command(s)** must succeed (exit with code `0`) for concurrently to return success overall.
|
|
8
|
+
|
|
9
|
+
There are several possible values:
|
|
10
|
+
|
|
11
|
+
## `all`
|
|
12
|
+
|
|
13
|
+
All commands must exit with code `0`.
|
|
14
|
+
This is the default value.
|
|
15
|
+
|
|
16
|
+
## `first`
|
|
17
|
+
|
|
18
|
+
The first command to exit must do so with code `0`.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# ✅ Exits with code 0 — second command exits first and succeeds
|
|
22
|
+
$ concurrently --success first 'sleep 1 && exit 1' 'exit 0'
|
|
23
|
+
|
|
24
|
+
# ❌ Exits with a non-zero code — second command exits first, but with code 1
|
|
25
|
+
$ concurrently --success first 'sleep 1 && exit 0' 'exit 1'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## `last`
|
|
29
|
+
|
|
30
|
+
The last command to exit must do so with code `0`.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# ✅ Exits with code 0 - first command exits last and succeeds
|
|
34
|
+
$ concurrently --success last 'sleep 1 && exit 0' 'exit 1'
|
|
35
|
+
|
|
36
|
+
# ❌ Exits with a non-zero code — first command exits last, but with code 1
|
|
37
|
+
$ concurrently --success last 'sleep 1 && exit 1' 'exit 0'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## `command-{name}` or `command-{index}`
|
|
41
|
+
|
|
42
|
+
A specific command, by name or index, must exit with code `0`.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Exits with code 0 only if 'npm test' (index 1) passes.
|
|
46
|
+
$ concurrently --success command-1 --kill-others 'npm run server' 'npm test'
|
|
47
|
+
|
|
48
|
+
# Exits with code 0 only if 'test' command passes.
|
|
49
|
+
$ concurrently --success command-test --names server,test --kill-others \
|
|
50
|
+
'npm start' \
|
|
51
|
+
'npm test'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> [!TIP]
|
|
55
|
+
> Use `--kill-others` to kill a long-running process, such as a server, once tests pass.
|
|
56
|
+
|
|
57
|
+
## `!command-{name}` or `!command-{index}`
|
|
58
|
+
|
|
59
|
+
All but a specific command, by name or index, must exit with code `0`.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Ignores 'npm start'; all others must succeed
|
|
63
|
+
$ concurrently --success '!command-2' --kill-others \
|
|
64
|
+
'npm test' \
|
|
65
|
+
'npm build' \
|
|
66
|
+
'npm start'
|
|
67
|
+
|
|
68
|
+
# Ignores 'server'; all others must succeed
|
|
69
|
+
$ concurrently --success '!command-server' --names test,build,server --kill-others \
|
|
70
|
+
'npm test' \
|
|
71
|
+
'npm build' \
|
|
72
|
+
'npm start'
|
|
73
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Terminating Commands
|
|
2
|
+
|
|
3
|
+
It's possible to have concurrently terminate other commands when one of them exits.<br/>
|
|
4
|
+
This can be done in the following ways:
|
|
5
|
+
|
|
6
|
+
## Terminating on either success or error
|
|
7
|
+
|
|
8
|
+
By using the `--kill-others` flag, concurrently will terminate other commands once the first one exits,
|
|
9
|
+
no matter the exit code.<br/>
|
|
10
|
+
This is useful to terminate the server process once the test is done.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
$ concurrently --kill-others --names server,test 'npm start' 'npm test'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Terminating on error only
|
|
17
|
+
|
|
18
|
+
By using the `--kill-others-on-fail` flag, concurrently will terminate other commands any command
|
|
19
|
+
exits with a non-zero code.<br/>
|
|
20
|
+
This is useful if you're building multiple applications, and you want to abort the others once you know
|
|
21
|
+
that any of them is broken.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
$ concurrently --kill-others-on-fail 'npm run app1:build' 'npm run app2:build'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuring termination
|
|
28
|
+
|
|
29
|
+
### Kill Signal
|
|
30
|
+
|
|
31
|
+
It's possible to configure which signal you want to send when terminating commands with the `--kill-signal` flag.
|
|
32
|
+
The default is `SIGTERM`, but it's also possible to send `SIGKILL`.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
$ concurrently --kill-others --kill-signal SIGKILL 'npm start' 'npm test'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Timeout
|
|
39
|
+
|
|
40
|
+
In case you have a misbehaving process that ignores the kill signal, you can force kill it after some
|
|
41
|
+
timeout (in milliseconds) by using the `--kill-timeout` flag.
|
|
42
|
+
This sends a `SIGKILL`, which cannot be caught.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
$ concurrently --kill-others --kill-timeout 1000 'sleep 1 && echo bye' './misbehaving'
|
|
46
|
+
[0] bye
|
|
47
|
+
[0] sleep 1 && echo bye exited with code 0
|
|
48
|
+
--> Sending SIGTERM to other processes..
|
|
49
|
+
[1] IGNORING SIGNAL
|
|
50
|
+
--> Sending SIGKILL to 1 processes..
|
|
51
|
+
[1] ./misbehaving exited with code SIGKILL
|
|
52
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "concurrently",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.2.0",
|
|
4
4
|
"description": "Run commands concurrently",
|
|
5
5
|
"packageManager": "pnpm@8.15.9+sha256.daa27a0b541bc635323ff96c2ded995467ff9fe6d69ff67021558aa9ad9dcc36",
|
|
6
6
|
"main": "index.js",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@hirez_io/observer-spy": "^2.2.0",
|
|
55
|
-
"@jest/types": "^
|
|
55
|
+
"@jest/types": "^30.0.0",
|
|
56
56
|
"@swc/core": "^1.7.23",
|
|
57
57
|
"@swc/jest": "^0.2.36",
|
|
58
|
-
"@types/jest": "^
|
|
58
|
+
"@types/jest": "^30.0.0",
|
|
59
59
|
"@types/lodash": "^4.17.7",
|
|
60
60
|
"@types/node": "^18.19.50",
|
|
61
61
|
"@types/shell-quote": "^1.7.5",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@typescript-eslint/parser": "^7.18.0",
|
|
66
66
|
"coveralls-next": "^4.2.1",
|
|
67
67
|
"ctrlc-wrapper": "^0.0.4",
|
|
68
|
-
"esbuild": "~0.
|
|
68
|
+
"esbuild": "~0.25.0",
|
|
69
69
|
"eslint": "^8.57.0",
|
|
70
70
|
"eslint-config-prettier": "^9.1.0",
|
|
71
71
|
"eslint-plugin-import": "^2.30.0",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"eslint-plugin-prettier": "^5.2.1",
|
|
74
74
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
75
75
|
"husky": "^9.1.5",
|
|
76
|
-
"jest": "^
|
|
76
|
+
"jest": "^30.0.0",
|
|
77
77
|
"jest-create-mock-instance": "^2.0.0",
|
|
78
78
|
"lint-staged": "^15.2.10",
|
|
79
79
|
"prettier": "^3.0.3",
|