concurrently 6.2.0 → 6.4.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 +31 -19
- package/bin/concurrently.js +16 -14
- package/bin/concurrently.spec.js +23 -3
- package/bin/epilogue.txt +1 -1
- package/index.js +6 -3
- package/package.json +2 -3
- package/src/command-parser/expand-npm-wildcard.js +11 -2
- package/src/concurrently.js +37 -19
- package/src/concurrently.spec.js +34 -2
- package/src/defaults.js +2 -0
- package/src/flow-control/base-handler.js +16 -0
- package/src/flow-control/input-handler.js +16 -5
- package/src/flow-control/input-handler.spec.js +31 -9
- package/src/flow-control/kill-on-signal.js +17 -12
- package/src/flow-control/kill-on-signal.spec.js +3 -3
- package/src/flow-control/kill-others.js +7 -4
- package/src/flow-control/kill-others.spec.js +2 -2
- package/src/flow-control/log-error.js +3 -5
- package/src/flow-control/log-error.spec.js +1 -1
- package/src/flow-control/log-exit.js +3 -5
- package/src/flow-control/log-exit.spec.js +1 -1
- package/src/flow-control/log-output.js +3 -5
- package/src/flow-control/log-output.spec.js +1 -1
- package/src/flow-control/restart-process.js +18 -14
- package/src/flow-control/restart-process.spec.js +4 -4
- package/src/logger.js +9 -1
- package/src/logger.spec.js +28 -0
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Concurrently
|
|
2
2
|
|
|
3
|
-
[](https://github.com/open-cli-tools/concurrently/actions?workflow=Tests)
|
|
4
|
+
[](https://coveralls.io/github/open-cli-tools/concurrently?branch=master)
|
|
4
5
|
|
|
5
6
|
[](https://www.npmjs.com/package/concurrently)
|
|
6
7
|
|
|
@@ -20,7 +21,7 @@ Like `npm run watch-js & npm run watch-less` but better.
|
|
|
20
21
|
|
|
21
22
|
## Why
|
|
22
23
|
|
|
23
|
-
I like [task automation with npm](
|
|
24
|
+
I like [task automation with npm](https://github.com/substack/blog/blob/master/npm_run.markdown)
|
|
24
25
|
but the usual way to run multiple commands concurrently is
|
|
25
26
|
`npm run watch-js & npm run watch-css`. That's fine but it's hard to keep
|
|
26
27
|
on track of different outputs. Also if one process fails, others still keep running
|
|
@@ -115,21 +116,25 @@ Help:
|
|
|
115
116
|
concurrently [options] <command ...>
|
|
116
117
|
|
|
117
118
|
General
|
|
118
|
-
-m, --max-processes
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-n, --names
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-r, --raw
|
|
127
|
-
|
|
128
|
-
-s, --success
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
-m, --max-processes How many processes should run at once.
|
|
120
|
+
New processes only spawn after all restart tries of a
|
|
121
|
+
process. [number]
|
|
122
|
+
-n, --names List of custom names to be used in prefix template.
|
|
123
|
+
Example names: "main,browser,server" [string]
|
|
124
|
+
--name-separator The character to split <names> on. Example usage:
|
|
125
|
+
concurrently -n "styles|scripts|server" --name-separator
|
|
126
|
+
"|" [default: ","]
|
|
127
|
+
-r, --raw Output only raw output of processes, disables
|
|
128
|
+
prettifying and concurrently coloring. [boolean]
|
|
129
|
+
-s, --success Return exit code of zero or one based on the success or
|
|
130
|
+
failure of the "first" child to terminate, the "last
|
|
131
|
+
child", or succeed only if "all" child processes
|
|
132
|
+
succeed.
|
|
131
133
|
[choices: "first", "last", "all"] [default: "all"]
|
|
132
|
-
|
|
134
|
+
--no-color Disables colors from logging [boolean]
|
|
135
|
+
--hide Comma-separated list of processes to hide the output.
|
|
136
|
+
The processes can be identified by their name or index.
|
|
137
|
+
[string] [default: ""]
|
|
133
138
|
|
|
134
139
|
Prefix styling
|
|
135
140
|
-p, --prefix Prefix used in logging for each process.
|
|
@@ -221,22 +226,26 @@ Examples:
|
|
|
221
226
|
|
|
222
227
|
$ concurrently npm:watch-*
|
|
223
228
|
|
|
224
|
-
For more details, visit https://github.com/
|
|
229
|
+
For more details, visit https://github.com/open-cli-tools/concurrently
|
|
225
230
|
```
|
|
226
231
|
|
|
227
232
|
## Programmatic Usage
|
|
228
233
|
concurrently can be used programmatically by using the API documented below:
|
|
229
234
|
|
|
230
235
|
### `concurrently(commands[, options])`
|
|
236
|
+
|
|
231
237
|
- `commands`: an array of either strings (containing the commands to run) or objects
|
|
232
238
|
with the shape `{ command, name, prefixColor, env, cwd }`.
|
|
239
|
+
|
|
233
240
|
- `options` (optional): an object containing any of the below:
|
|
234
241
|
- `cwd`: the working directory to be used by all commands. Can be overriden per command.
|
|
235
242
|
Default: `process.cwd()`.
|
|
236
243
|
- `defaultInputTarget`: the default input target when reading from `inputStream`.
|
|
237
244
|
Default: `0`.
|
|
245
|
+
- `handleInput`: when `true`, reads input from `process.stdin`.
|
|
238
246
|
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
|
|
239
|
-
to read the input from
|
|
247
|
+
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`.
|
|
248
|
+
- `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)).
|
|
240
249
|
- `killOthers`: an array of exitting conditions that will cause a process to kill others.
|
|
241
250
|
Can contain any of `success` or `failure`.
|
|
242
251
|
- `maxProcesses`: how many processes should run at once.
|
|
@@ -245,6 +254,9 @@ concurrently can be used programmatically by using the API documented below:
|
|
|
245
254
|
- `prefix`: the prefix type to use when logging processes output.
|
|
246
255
|
Possible values: `index`, `pid`, `time`, `command`, `name`, `none`, or a template (eg `[{time} process: {pid}]`).
|
|
247
256
|
Default: the name of the process, or its index if no name is set.
|
|
257
|
+
- `prefixColors`: a list of colors as supported by [chalk](https://www.npmjs.com/package/chalk).
|
|
258
|
+
If concurrently would run more commands than there are colors, the last color is repeated.
|
|
259
|
+
Prefix colors specified per-command take precedence over this list.
|
|
248
260
|
- `prefixLength`: how many characters to show when prefixing with `command`. Default: `10`
|
|
249
261
|
- `raw`: whether raw mode should be used, meaning strictly process output will
|
|
250
262
|
be logged, without any prefixes, colouring or extra stuff.
|
|
@@ -259,7 +271,7 @@ concurrently can be used programmatically by using the API documented below:
|
|
|
259
271
|
> Returns: a `Promise` that resolves if the run was successful (according to `successCondition` option),
|
|
260
272
|
> or rejects, containing an array of objects with information for each command that has been run, in the order
|
|
261
273
|
> that the commands terminated. The objects have the shape `{ command, index, exitCode, killed }`, where `command` is the object
|
|
262
|
-
> passed in the `commands` array, `index` its index there and `killed` indicates if the process was killed as a result of
|
|
274
|
+
> passed in the `commands` array, `index` its index there and `killed` indicates if the process was killed as a result of
|
|
263
275
|
> `killOthers`. Default values (empty strings or objects) are returned for the fields that were not specified.
|
|
264
276
|
|
|
265
277
|
Example:
|
package/bin/concurrently.js
CHANGED
|
@@ -55,6 +55,13 @@ const args = yargs
|
|
|
55
55
|
describe: 'Disables colors from logging',
|
|
56
56
|
type: 'boolean'
|
|
57
57
|
},
|
|
58
|
+
'hide': {
|
|
59
|
+
describe:
|
|
60
|
+
'Comma-separated list of processes to hide the output.\n' +
|
|
61
|
+
'The processes can be identified by their name or index.',
|
|
62
|
+
default: defaults.hide,
|
|
63
|
+
type: 'string'
|
|
64
|
+
},
|
|
58
65
|
|
|
59
66
|
// Kill others
|
|
60
67
|
'k': {
|
|
@@ -135,7 +142,7 @@ const args = yargs
|
|
|
135
142
|
'Can be either the index or the name of the process.'
|
|
136
143
|
}
|
|
137
144
|
})
|
|
138
|
-
.group(['m', 'n', 'name-separator', 'raw', 's', 'no-color'], 'General')
|
|
145
|
+
.group(['m', 'n', 'name-separator', 'raw', 's', 'no-color', 'hide'], 'General')
|
|
139
146
|
.group(['p', 'c', 'l', 't'], 'Prefix styling')
|
|
140
147
|
.group(['i', 'default-input-target'], 'Input handling')
|
|
141
148
|
.group(['k', 'kill-others-on-fail'], 'Killing other processes')
|
|
@@ -144,32 +151,27 @@ const args = yargs
|
|
|
144
151
|
.epilogue(fs.readFileSync(__dirname + '/epilogue.txt', { encoding: 'utf8' }))
|
|
145
152
|
.argv;
|
|
146
153
|
|
|
147
|
-
const prefixColors = args.prefixColors.split(',');
|
|
148
154
|
const names = (args.names || '').split(args.nameSeparator);
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
command,
|
|
156
|
-
prefixColor: lastColor,
|
|
157
|
-
name: names[index]
|
|
158
|
-
};
|
|
159
|
-
}), {
|
|
160
|
-
inputStream: args.handleInput && process.stdin,
|
|
156
|
+
concurrently(args._.map((command, index) => ({
|
|
157
|
+
command,
|
|
158
|
+
name: names[index]
|
|
159
|
+
})), {
|
|
160
|
+
handleInput: args.handleInput,
|
|
161
161
|
defaultInputTarget: args.defaultInputTarget,
|
|
162
162
|
killOthers: args.killOthers
|
|
163
163
|
? ['success', 'failure']
|
|
164
164
|
: (args.killOthersOnFail ? ['failure'] : []),
|
|
165
165
|
maxProcesses: args.maxProcesses,
|
|
166
166
|
raw: args.raw,
|
|
167
|
+
hide: args.hide.split(','),
|
|
167
168
|
prefix: args.prefix,
|
|
169
|
+
prefixColors: args.prefixColors.split(','),
|
|
168
170
|
prefixLength: args.prefixLength,
|
|
169
171
|
restartDelay: args.restartAfter,
|
|
170
172
|
restartTries: args.restartTries,
|
|
171
173
|
successCondition: args.success,
|
|
172
|
-
timestampFormat: args.timestampFormat
|
|
174
|
+
timestampFormat: args.timestampFormat,
|
|
173
175
|
}).then(
|
|
174
176
|
() => process.exit(0),
|
|
175
177
|
() => process.exit(1)
|
package/bin/concurrently.spec.js
CHANGED
|
@@ -163,6 +163,26 @@ describe('--raw', () => {
|
|
|
163
163
|
});
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
describe('--hide', () => {
|
|
167
|
+
it('hides the output of a process by its index', done => {
|
|
168
|
+
const child = run('--hide 1 "echo foo" "echo bar"');
|
|
169
|
+
child.log.pipe(buffer(child.close)).subscribe(lines => {
|
|
170
|
+
expect(lines).toContainEqual(expect.stringContaining('foo'));
|
|
171
|
+
expect(lines).not.toContainEqual(expect.stringContaining('bar'));
|
|
172
|
+
done();
|
|
173
|
+
}, done);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('hides the output of a process by its name', done => {
|
|
177
|
+
const child = run('-n foo,bar --hide bar "echo foo" "echo bar"');
|
|
178
|
+
child.log.pipe(buffer(child.close)).subscribe(lines => {
|
|
179
|
+
expect(lines).toContainEqual(expect.stringContaining('foo'));
|
|
180
|
+
expect(lines).not.toContainEqual(expect.stringContaining('bar'));
|
|
181
|
+
done();
|
|
182
|
+
}, done);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
166
186
|
describe('--names', () => {
|
|
167
187
|
it('is aliased to -n', done => {
|
|
168
188
|
const child = run('-n foo,bar "echo foo" "echo bar"');
|
|
@@ -193,7 +213,7 @@ describe('--names', () => {
|
|
|
193
213
|
});
|
|
194
214
|
|
|
195
215
|
describe('--prefix', () => {
|
|
196
|
-
it('is
|
|
216
|
+
it('is aliased to -p', done => {
|
|
197
217
|
const child = run('-p command "echo foo" "echo bar"');
|
|
198
218
|
child.log.pipe(buffer(child.close)).subscribe(lines => {
|
|
199
219
|
expect(lines).toContainEqual(expect.stringContaining('[echo foo] foo'));
|
|
@@ -213,7 +233,7 @@ describe('--prefix', () => {
|
|
|
213
233
|
});
|
|
214
234
|
|
|
215
235
|
describe('--prefix-length', () => {
|
|
216
|
-
it('is
|
|
236
|
+
it('is aliased to -l', done => {
|
|
217
237
|
const child = run('-p command -l 5 "echo foo" "echo bar"');
|
|
218
238
|
child.log.pipe(buffer(child.close)).subscribe(lines => {
|
|
219
239
|
expect(lines).toContainEqual(expect.stringContaining('[ec..o] foo'));
|
|
@@ -247,7 +267,7 @@ describe('--restart-tries', () => {
|
|
|
247
267
|
});
|
|
248
268
|
|
|
249
269
|
describe('--kill-others', () => {
|
|
250
|
-
it('is
|
|
270
|
+
it('is aliased to -k', done => {
|
|
251
271
|
const child = run('-k "sleep 10" "exit 0"');
|
|
252
272
|
child.log.pipe(buffer(child.close)).subscribe(lines => {
|
|
253
273
|
expect(lines).toContainEqual(expect.stringContaining('[1] exit 0 exited with code 0'));
|
package/bin/epilogue.txt
CHANGED
package/index.js
CHANGED
|
@@ -9,8 +9,9 @@ const RestartProcess = require('./src/flow-control/restart-process');
|
|
|
9
9
|
const concurrently = require('./src/concurrently');
|
|
10
10
|
const Logger = require('./src/logger');
|
|
11
11
|
|
|
12
|
-
module.exports = (commands, options = {}) => {
|
|
12
|
+
module.exports = exports = (commands, options = {}) => {
|
|
13
13
|
const logger = new Logger({
|
|
14
|
+
hide: options.hide,
|
|
14
15
|
outputStream: options.outputStream || process.stdout,
|
|
15
16
|
prefixFormat: options.prefix,
|
|
16
17
|
prefixLength: options.prefixLength,
|
|
@@ -30,7 +31,8 @@ module.exports = (commands, options = {}) => {
|
|
|
30
31
|
new InputHandler({
|
|
31
32
|
logger,
|
|
32
33
|
defaultInputTarget: options.defaultInputTarget,
|
|
33
|
-
inputStream: options.inputStream,
|
|
34
|
+
inputStream: options.inputStream || (options.handleInput && process.stdin),
|
|
35
|
+
pauseInputStreamOnFinish: options.pauseInputStreamOnFinish,
|
|
34
36
|
}),
|
|
35
37
|
new KillOnSignal({ process }),
|
|
36
38
|
new RestartProcess({
|
|
@@ -42,7 +44,8 @@ module.exports = (commands, options = {}) => {
|
|
|
42
44
|
logger,
|
|
43
45
|
conditions: options.killOthers
|
|
44
46
|
})
|
|
45
|
-
]
|
|
47
|
+
],
|
|
48
|
+
prefixColors: options.prefixColors || []
|
|
46
49
|
});
|
|
47
50
|
};
|
|
48
51
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "concurrently",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "Run commands concurrently",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/open-cli-tools/concurrently.git"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"bash",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"chalk": "^4.1.0",
|
|
33
33
|
"date-fns": "^2.16.1",
|
|
34
34
|
"lodash": "^4.17.21",
|
|
35
|
-
"read-pkg": "^5.2.0",
|
|
36
35
|
"rxjs": "^6.6.3",
|
|
37
36
|
"spawn-command": "^0.0.2-1",
|
|
38
37
|
"supports-color": "^8.1.0",
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const
|
|
2
|
+
const fs = require('fs');
|
|
3
3
|
|
|
4
4
|
module.exports = class ExpandNpmWildcard {
|
|
5
|
-
|
|
5
|
+
static readPackage() {
|
|
6
|
+
try {
|
|
7
|
+
const json = fs.readFileSync('package.json', { encoding: 'utf-8' });
|
|
8
|
+
return JSON.parse(json);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(readPackage = ExpandNpmWildcard.readPackage) {
|
|
6
15
|
this.readPackage = readPackage;
|
|
7
16
|
}
|
|
8
17
|
|
package/src/concurrently.js
CHANGED
|
@@ -32,27 +32,40 @@ module.exports = (commands, options) => {
|
|
|
32
32
|
new ExpandNpmWildcard()
|
|
33
33
|
];
|
|
34
34
|
|
|
35
|
+
let lastColor = '';
|
|
35
36
|
commands = _(commands)
|
|
36
37
|
.map(mapToCommandInfo)
|
|
37
38
|
.flatMap(command => parseCommand(command, commandParsers))
|
|
38
|
-
.map((command, index) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
.map((command, index) => {
|
|
40
|
+
// Use documented behaviour of repeating last color when specifying more commands than colors
|
|
41
|
+
lastColor = options.prefixColors && options.prefixColors[index] || lastColor;
|
|
42
|
+
return new Command(
|
|
43
|
+
Object.assign({
|
|
44
|
+
index,
|
|
45
|
+
spawnOpts: getSpawnOpts({
|
|
46
|
+
raw: options.raw,
|
|
47
|
+
env: command.env,
|
|
48
|
+
cwd: command.cwd || options.cwd,
|
|
49
|
+
}),
|
|
50
|
+
prefixColor: lastColor,
|
|
51
|
+
killProcess: options.kill,
|
|
52
|
+
spawn: options.spawn,
|
|
53
|
+
}, command)
|
|
54
|
+
);
|
|
55
|
+
})
|
|
50
56
|
.value();
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
(prevCommands, controller) =>
|
|
54
|
-
|
|
58
|
+
const handleResult = options.controllers.reduce(
|
|
59
|
+
({ commands: prevCommands, onFinishCallbacks }, controller) => {
|
|
60
|
+
const { commands, onFinish } = controller.handle(prevCommands);
|
|
61
|
+
return {
|
|
62
|
+
commands,
|
|
63
|
+
onFinishCallbacks: _.concat(onFinishCallbacks, onFinish ? [onFinish] : [])
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
{ commands, onFinishCallbacks: [] }
|
|
55
67
|
);
|
|
68
|
+
commands = handleResult.commands;
|
|
56
69
|
|
|
57
70
|
const commandsLeft = commands.slice();
|
|
58
71
|
const maxProcesses = Math.max(1, Number(options.maxProcesses) || commandsLeft.length);
|
|
@@ -60,17 +73,22 @@ module.exports = (commands, options) => {
|
|
|
60
73
|
maybeRunMore(commandsLeft);
|
|
61
74
|
}
|
|
62
75
|
|
|
63
|
-
return new CompletionListener({ successCondition: options.successCondition })
|
|
76
|
+
return new CompletionListener({ successCondition: options.successCondition })
|
|
77
|
+
.listen(commands)
|
|
78
|
+
.finally(() => {
|
|
79
|
+
handleResult.onFinishCallbacks.forEach((onFinish) => onFinish());
|
|
80
|
+
});
|
|
64
81
|
};
|
|
65
82
|
|
|
66
83
|
function mapToCommandInfo(command) {
|
|
67
|
-
return {
|
|
84
|
+
return Object.assign({
|
|
68
85
|
command: command.command || command,
|
|
69
86
|
name: command.name || '',
|
|
70
|
-
prefixColor: command.prefixColor || '',
|
|
71
87
|
env: command.env || {},
|
|
72
88
|
cwd: command.cwd || '',
|
|
73
|
-
}
|
|
89
|
+
}, command.prefixColor ? {
|
|
90
|
+
prefixColor: command.prefixColor,
|
|
91
|
+
} : {});
|
|
74
92
|
}
|
|
75
93
|
|
|
76
94
|
function parseCommand(command, parsers) {
|
package/src/concurrently.spec.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const EventEmitter = require('events');
|
|
2
2
|
|
|
3
3
|
const createFakeCommand = require('./flow-control/fixtures/fake-command');
|
|
4
|
+
const FakeHandler = require('./flow-control/fixtures/fake-handler');
|
|
4
5
|
const concurrently = require('./concurrently');
|
|
5
6
|
|
|
6
7
|
let spawn, kill, controllers, processes = [];
|
|
@@ -18,7 +19,7 @@ beforeEach(() => {
|
|
|
18
19
|
return process;
|
|
19
20
|
});
|
|
20
21
|
kill = jest.fn();
|
|
21
|
-
controllers = [
|
|
22
|
+
controllers = [new FakeHandler(), new FakeHandler()];
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
it('fails if commands is not an array', () => {
|
|
@@ -83,9 +84,22 @@ it('runs commands with a name or prefix color', () => {
|
|
|
83
84
|
});
|
|
84
85
|
});
|
|
85
86
|
|
|
87
|
+
it('runs commands with a list of colors', () => {
|
|
88
|
+
create(['echo', 'kill'], {
|
|
89
|
+
prefixColors: ['red']
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
controllers.forEach(controller => {
|
|
93
|
+
expect(controller.handle).toHaveBeenCalledWith([
|
|
94
|
+
expect.objectContaining({ command: 'echo', prefixColor: 'red' }),
|
|
95
|
+
expect.objectContaining({ command: 'kill', prefixColor: 'red' }),
|
|
96
|
+
]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
86
100
|
it('passes commands wrapped from a controller to the next one', () => {
|
|
87
101
|
const fakeCommand = createFakeCommand('banana', 'banana');
|
|
88
|
-
controllers[0].handle.mockReturnValue([fakeCommand]);
|
|
102
|
+
controllers[0].handle.mockReturnValue({ commands: [fakeCommand] });
|
|
89
103
|
|
|
90
104
|
create(['echo']);
|
|
91
105
|
|
|
@@ -165,3 +179,21 @@ it('uses overridden cwd option for each command if specified', () => {
|
|
|
165
179
|
cwd: 'foobar',
|
|
166
180
|
}));
|
|
167
181
|
});
|
|
182
|
+
|
|
183
|
+
it('runs onFinish hook after all commands run', async () => {
|
|
184
|
+
const promise = create(['foo', 'bar'], { maxProcesses: 1 });
|
|
185
|
+
expect(spawn).toHaveBeenCalledTimes(1);
|
|
186
|
+
expect(controllers[0].onFinish).not.toHaveBeenCalled();
|
|
187
|
+
expect(controllers[1].onFinish).not.toHaveBeenCalled();
|
|
188
|
+
|
|
189
|
+
processes[0].emit('close', 0, null);
|
|
190
|
+
expect(spawn).toHaveBeenCalledTimes(2);
|
|
191
|
+
expect(controllers[0].onFinish).not.toHaveBeenCalled();
|
|
192
|
+
expect(controllers[1].onFinish).not.toHaveBeenCalled();
|
|
193
|
+
|
|
194
|
+
processes[1].emit('close', 0, null);
|
|
195
|
+
await promise;
|
|
196
|
+
|
|
197
|
+
expect(controllers[0].onFinish).toHaveBeenCalled();
|
|
198
|
+
expect(controllers[1].onFinish).toHaveBeenCalled();
|
|
199
|
+
});
|
package/src/defaults.js
CHANGED
|
@@ -10,6 +10,8 @@ module.exports = {
|
|
|
10
10
|
handleInput: false,
|
|
11
11
|
// How many processes to run at once
|
|
12
12
|
maxProcesses: 0,
|
|
13
|
+
// Indices and names of commands whose output to be not logged
|
|
14
|
+
hide: '',
|
|
13
15
|
nameSeparator: ',',
|
|
14
16
|
// Which prefix style to use when logging processes output.
|
|
15
17
|
prefix: '',
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = class BaseHandler {
|
|
2
|
+
constructor(options = {}) {
|
|
3
|
+
const { logger } = options;
|
|
4
|
+
|
|
5
|
+
this.logger = logger;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
handle(commands) {
|
|
9
|
+
return {
|
|
10
|
+
commands,
|
|
11
|
+
// an optional callback to call when all commands have finished
|
|
12
|
+
// (either successful or not)
|
|
13
|
+
onFinish: null,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -2,17 +2,20 @@ const Rx = require('rxjs');
|
|
|
2
2
|
const { map } = require('rxjs/operators');
|
|
3
3
|
|
|
4
4
|
const defaults = require('../defaults');
|
|
5
|
+
const BaseHandler = require('./base-handler');
|
|
6
|
+
|
|
7
|
+
module.exports = class InputHandler extends BaseHandler {
|
|
8
|
+
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger }) {
|
|
9
|
+
super({ logger });
|
|
5
10
|
|
|
6
|
-
module.exports = class InputHandler {
|
|
7
|
-
constructor({ defaultInputTarget, inputStream, logger }) {
|
|
8
11
|
this.defaultInputTarget = defaultInputTarget || defaults.defaultInputTarget;
|
|
9
12
|
this.inputStream = inputStream;
|
|
10
|
-
this.
|
|
13
|
+
this.pauseInputStreamOnFinish = pauseInputStreamOnFinish !== false;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
handle(commands) {
|
|
14
17
|
if (!this.inputStream) {
|
|
15
|
-
return commands;
|
|
18
|
+
return { commands };
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
Rx.fromEvent(this.inputStream, 'data')
|
|
@@ -34,6 +37,14 @@ module.exports = class InputHandler {
|
|
|
34
37
|
}
|
|
35
38
|
});
|
|
36
39
|
|
|
37
|
-
return
|
|
40
|
+
return {
|
|
41
|
+
commands,
|
|
42
|
+
onFinish: () => {
|
|
43
|
+
if (this.pauseInputStreamOnFinish) {
|
|
44
|
+
// https://github.com/kimmobrunfeldt/concurrently/issues/252
|
|
45
|
+
this.inputStream.pause();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
38
49
|
}
|
|
39
50
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const stream = require('stream');
|
|
2
2
|
const { createMockInstance } = require('jest-create-mock-instance');
|
|
3
3
|
|
|
4
4
|
const Logger = require('../logger');
|
|
@@ -12,7 +12,7 @@ beforeEach(() => {
|
|
|
12
12
|
createFakeCommand('foo', 'echo foo', 0),
|
|
13
13
|
createFakeCommand('bar', 'echo bar', 1),
|
|
14
14
|
];
|
|
15
|
-
inputStream = new
|
|
15
|
+
inputStream = new stream.PassThrough();
|
|
16
16
|
logger = createMockInstance(Logger);
|
|
17
17
|
controller = new InputHandler({
|
|
18
18
|
defaultInputTarget: 0,
|
|
@@ -22,16 +22,16 @@ beforeEach(() => {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
it('returns same commands', () => {
|
|
25
|
-
expect(controller.handle(commands)).
|
|
25
|
+
expect(controller.handle(commands)).toMatchObject({ commands });
|
|
26
26
|
|
|
27
27
|
controller = new InputHandler({ logger });
|
|
28
|
-
expect(controller.handle(commands)).
|
|
28
|
+
expect(controller.handle(commands)).toMatchObject({ commands });
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
it('forwards input stream to default target ID', () => {
|
|
32
32
|
controller.handle(commands);
|
|
33
33
|
|
|
34
|
-
inputStream.
|
|
34
|
+
inputStream.write('something');
|
|
35
35
|
|
|
36
36
|
expect(commands[0].stdin.write).toHaveBeenCalledTimes(1);
|
|
37
37
|
expect(commands[0].stdin.write).toHaveBeenCalledWith('something');
|
|
@@ -41,7 +41,7 @@ it('forwards input stream to default target ID', () => {
|
|
|
41
41
|
it('forwards input stream to target index specified in input', () => {
|
|
42
42
|
controller.handle(commands);
|
|
43
43
|
|
|
44
|
-
inputStream.
|
|
44
|
+
inputStream.write('1:something');
|
|
45
45
|
|
|
46
46
|
expect(commands[0].stdin.write).not.toHaveBeenCalled();
|
|
47
47
|
expect(commands[1].stdin.write).toHaveBeenCalledTimes(1);
|
|
@@ -63,7 +63,7 @@ it('forwards input stream to target index specified in input when input contains
|
|
|
63
63
|
it('forwards input stream to target name specified in input', () => {
|
|
64
64
|
controller.handle(commands);
|
|
65
65
|
|
|
66
|
-
inputStream.
|
|
66
|
+
inputStream.write('bar:something');
|
|
67
67
|
|
|
68
68
|
expect(commands[0].stdin.write).not.toHaveBeenCalled();
|
|
69
69
|
expect(commands[1].stdin.write).toHaveBeenCalledTimes(1);
|
|
@@ -74,7 +74,7 @@ it('logs error if command has no stdin open', () => {
|
|
|
74
74
|
commands[0].stdin = null;
|
|
75
75
|
controller.handle(commands);
|
|
76
76
|
|
|
77
|
-
inputStream.
|
|
77
|
+
inputStream.write('something');
|
|
78
78
|
|
|
79
79
|
expect(commands[1].stdin.write).not.toHaveBeenCalled();
|
|
80
80
|
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Unable to find command 0, or it has no stdin open\n');
|
|
@@ -83,9 +83,31 @@ it('logs error if command has no stdin open', () => {
|
|
|
83
83
|
it('logs error if command is not found', () => {
|
|
84
84
|
controller.handle(commands);
|
|
85
85
|
|
|
86
|
-
inputStream.
|
|
86
|
+
inputStream.write('foobar:something');
|
|
87
87
|
|
|
88
88
|
expect(commands[0].stdin.write).not.toHaveBeenCalled();
|
|
89
89
|
expect(commands[1].stdin.write).not.toHaveBeenCalled();
|
|
90
90
|
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Unable to find command foobar, or it has no stdin open\n');
|
|
91
91
|
});
|
|
92
|
+
|
|
93
|
+
it('pauses input stream when finished', () => {
|
|
94
|
+
expect(inputStream.readableFlowing).toBeNull();
|
|
95
|
+
|
|
96
|
+
const { onFinish } = controller.handle(commands);
|
|
97
|
+
expect(inputStream.readableFlowing).toBe(true);
|
|
98
|
+
|
|
99
|
+
onFinish();
|
|
100
|
+
expect(inputStream.readableFlowing).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('does not pause input stream when pauseInputStreamOnFinish is set to false', () => {
|
|
104
|
+
controller = new InputHandler({ inputStream, pauseInputStreamOnFinish: false });
|
|
105
|
+
|
|
106
|
+
expect(inputStream.readableFlowing).toBeNull();
|
|
107
|
+
|
|
108
|
+
const { onFinish } = controller.handle(commands);
|
|
109
|
+
expect(inputStream.readableFlowing).toBe(true);
|
|
110
|
+
|
|
111
|
+
onFinish();
|
|
112
|
+
expect(inputStream.readableFlowing).toBe(true);
|
|
113
|
+
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
const { map } = require('rxjs/operators');
|
|
2
2
|
|
|
3
|
+
const BaseHandler = require('./base-handler');
|
|
3
4
|
|
|
4
|
-
module.exports = class KillOnSignal {
|
|
5
|
+
module.exports = class KillOnSignal extends BaseHandler {
|
|
5
6
|
constructor({ process }) {
|
|
7
|
+
super();
|
|
8
|
+
|
|
6
9
|
this.process = process;
|
|
7
10
|
}
|
|
8
11
|
|
|
@@ -15,16 +18,18 @@ module.exports = class KillOnSignal {
|
|
|
15
18
|
});
|
|
16
19
|
});
|
|
17
20
|
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
return {
|
|
22
|
+
commands: commands.map(command => {
|
|
23
|
+
const closeStream = command.close.pipe(map(exitInfo => {
|
|
24
|
+
const exitCode = caughtSignal === 'SIGINT' ? 0 : exitInfo.exitCode;
|
|
25
|
+
return Object.assign({}, exitInfo, { exitCode });
|
|
26
|
+
}));
|
|
27
|
+
return new Proxy(command, {
|
|
28
|
+
get(target, prop) {
|
|
29
|
+
return prop === 'close' ? closeStream : target[prop];
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
})
|
|
33
|
+
};
|
|
29
34
|
}
|
|
30
35
|
};
|
|
@@ -14,7 +14,7 @@ beforeEach(() => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it('returns commands that keep non-close streams from original commands', () => {
|
|
17
|
-
const newCommands = controller.handle(commands);
|
|
17
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
18
18
|
newCommands.forEach((newCommand, i) => {
|
|
19
19
|
expect(newCommand.close).not.toBe(commands[i].close);
|
|
20
20
|
expect(newCommand.error).toBe(commands[i].error);
|
|
@@ -24,7 +24,7 @@ it('returns commands that keep non-close streams from original commands', () =>
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('returns commands that map SIGINT to exit code 0', () => {
|
|
27
|
-
const newCommands = controller.handle(commands);
|
|
27
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
28
28
|
expect(newCommands).not.toBe(commands);
|
|
29
29
|
expect(newCommands).toHaveLength(commands.length);
|
|
30
30
|
|
|
@@ -40,7 +40,7 @@ it('returns commands that map SIGINT to exit code 0', () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('returns commands that keep non-SIGINT exit codes', () => {
|
|
43
|
-
const newCommands = controller.handle(commands);
|
|
43
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
44
44
|
expect(newCommands).not.toBe(commands);
|
|
45
45
|
expect(newCommands).toHaveLength(commands.length);
|
|
46
46
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const { filter, map } = require('rxjs/operators');
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const BaseHandler = require('./base-handler');
|
|
5
|
+
|
|
6
|
+
module.exports = class KillOthers extends BaseHandler {
|
|
5
7
|
constructor({ logger, conditions }) {
|
|
6
|
-
|
|
8
|
+
super({ logger });
|
|
9
|
+
|
|
7
10
|
this.conditions = _.castArray(conditions);
|
|
8
11
|
}
|
|
9
12
|
|
|
@@ -14,7 +17,7 @@ module.exports = class KillOthers {
|
|
|
14
17
|
));
|
|
15
18
|
|
|
16
19
|
if (!conditions.length) {
|
|
17
|
-
return commands;
|
|
20
|
+
return { commands };
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
const closeStates = commands.map(command => command.close.pipe(
|
|
@@ -30,6 +33,6 @@ module.exports = class KillOthers {
|
|
|
30
33
|
}
|
|
31
34
|
}));
|
|
32
35
|
|
|
33
|
-
return commands;
|
|
36
|
+
return { commands };
|
|
34
37
|
}
|
|
35
38
|
};
|
|
@@ -20,8 +20,8 @@ const createWithConditions = conditions => new KillOthers({
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
it('returns same commands', () => {
|
|
23
|
-
expect(createWithConditions(['foo']).handle(commands)).
|
|
24
|
-
expect(createWithConditions(['failure']).handle(commands)).
|
|
23
|
+
expect(createWithConditions(['foo']).handle(commands)).toMatchObject({ commands });
|
|
24
|
+
expect(createWithConditions(['failure']).handle(commands)).toMatchObject({ commands });
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('does not kill others if condition does not match', () => {
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
const { of } = require('rxjs');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
constructor({ logger }) {
|
|
5
|
-
this.logger = logger;
|
|
6
|
-
}
|
|
3
|
+
const BaseHandler = require('./base-handler');
|
|
7
4
|
|
|
5
|
+
module.exports = class LogExit extends BaseHandler {
|
|
8
6
|
handle(commands) {
|
|
9
7
|
commands.forEach(command => command.error.subscribe(event => {
|
|
10
8
|
this.logger.logCommandEvent(
|
|
@@ -15,6 +13,6 @@ module.exports = class LogExit {
|
|
|
15
13
|
this.logger.logCommandEvent(event.stack || event, command);
|
|
16
14
|
}));
|
|
17
15
|
|
|
18
|
-
return commands;
|
|
16
|
+
return { commands };
|
|
19
17
|
}
|
|
20
18
|
};
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
constructor({ logger }) {
|
|
3
|
-
this.logger = logger;
|
|
4
|
-
}
|
|
1
|
+
const BaseHandler = require('./base-handler');
|
|
5
2
|
|
|
3
|
+
module.exports = class LogExit extends BaseHandler {
|
|
6
4
|
handle(commands) {
|
|
7
5
|
commands.forEach(command => command.close.subscribe(({ exitCode }) => {
|
|
8
6
|
this.logger.logCommandEvent(`${command.command} exited with code ${exitCode}`, command);
|
|
9
7
|
}));
|
|
10
8
|
|
|
11
|
-
return commands;
|
|
9
|
+
return { commands };
|
|
12
10
|
}
|
|
13
11
|
};
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
constructor({ logger }) {
|
|
3
|
-
this.logger = logger;
|
|
4
|
-
}
|
|
1
|
+
const BaseHandler = require('./base-handler');
|
|
5
2
|
|
|
3
|
+
module.exports = class LogOutput extends BaseHandler {
|
|
6
4
|
handle(commands) {
|
|
7
5
|
commands.forEach(command => {
|
|
8
6
|
command.stdout.subscribe(text => this.logger.logCommandText(text.toString(), command));
|
|
9
7
|
command.stderr.subscribe(text => this.logger.logCommandText(text.toString(), command));
|
|
10
8
|
});
|
|
11
9
|
|
|
12
|
-
return commands;
|
|
10
|
+
return { commands };
|
|
13
11
|
}
|
|
14
12
|
};
|
|
@@ -2,19 +2,21 @@ const Rx = require('rxjs');
|
|
|
2
2
|
const { defaultIfEmpty, delay, filter, mapTo, skip, take, takeWhile } = require('rxjs/operators');
|
|
3
3
|
|
|
4
4
|
const defaults = require('../defaults');
|
|
5
|
+
const BaseHandler = require('./base-handler');
|
|
5
6
|
|
|
6
|
-
module.exports = class RestartProcess {
|
|
7
|
+
module.exports = class RestartProcess extends BaseHandler {
|
|
7
8
|
constructor({ delay, tries, logger, scheduler }) {
|
|
9
|
+
super({ logger });
|
|
10
|
+
|
|
8
11
|
this.delay = +delay || defaults.restartDelay;
|
|
9
12
|
this.tries = +tries || defaults.restartTries;
|
|
10
13
|
this.tries = this.tries < 0 ? Infinity : this.tries;
|
|
11
|
-
this.logger = logger;
|
|
12
14
|
this.scheduler = scheduler;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
handle(commands) {
|
|
16
18
|
if (this.tries === 0) {
|
|
17
|
-
return commands;
|
|
19
|
+
return { commands };
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
commands.map(command => command.close.pipe(
|
|
@@ -36,17 +38,19 @@ module.exports = class RestartProcess {
|
|
|
36
38
|
}
|
|
37
39
|
}));
|
|
38
40
|
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
return {
|
|
42
|
+
commands: commands.map(command => {
|
|
43
|
+
const closeStream = command.close.pipe(filter(({ exitCode }, emission) => {
|
|
44
|
+
// We let all success codes pass, and failures only after restarting won't happen again
|
|
45
|
+
return exitCode === 0 || emission >= this.tries;
|
|
46
|
+
}));
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
return new Proxy(command, {
|
|
49
|
+
get(target, prop) {
|
|
50
|
+
return prop === 'close' ? closeStream : target[prop];
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
})
|
|
54
|
+
};
|
|
51
55
|
}
|
|
52
56
|
};
|
|
@@ -91,17 +91,17 @@ it('restarts processes until they succeed', () => {
|
|
|
91
91
|
describe('returned commands', () => {
|
|
92
92
|
it('are the same if 0 tries are to be attempted', () => {
|
|
93
93
|
controller = new RestartProcess({ logger, scheduler });
|
|
94
|
-
expect(controller.handle(commands)).
|
|
94
|
+
expect(controller.handle(commands)).toMatchObject({ commands });
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('are not the same, but with same length if 1+ tries are to be attempted', () => {
|
|
98
|
-
const newCommands = controller.handle(commands);
|
|
98
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
99
99
|
expect(newCommands).not.toBe(commands);
|
|
100
100
|
expect(newCommands).toHaveLength(commands.length);
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
it('skip close events followed by restarts', () => {
|
|
104
|
-
const newCommands = controller.handle(commands);
|
|
104
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
105
105
|
|
|
106
106
|
const callback = jest.fn();
|
|
107
107
|
newCommands[0].close.subscribe(callback);
|
|
@@ -120,7 +120,7 @@ describe('returned commands', () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('keep non-close streams from original commands', () => {
|
|
123
|
-
const newCommands = controller.handle(commands);
|
|
123
|
+
const { commands: newCommands } = controller.handle(commands);
|
|
124
124
|
newCommands.forEach((newCommand, i) => {
|
|
125
125
|
expect(newCommand.close).not.toBe(commands[i].close);
|
|
126
126
|
expect(newCommand.error).toBe(commands[i].error);
|
package/src/logger.js
CHANGED
|
@@ -5,7 +5,11 @@ const formatDate = require('date-fns/format');
|
|
|
5
5
|
const defaults = require('./defaults');
|
|
6
6
|
|
|
7
7
|
module.exports = class Logger {
|
|
8
|
-
constructor({ outputStream, prefixFormat, prefixLength, raw, timestampFormat }) {
|
|
8
|
+
constructor({ hide, outputStream, prefixFormat, prefixLength, raw, timestampFormat }) {
|
|
9
|
+
// To avoid empty strings from hiding the output of commands that don't have a name,
|
|
10
|
+
// keep in the list of commands to hide only strings with some length.
|
|
11
|
+
// This might happen through the CLI when no `--hide` argument is specified, for example.
|
|
12
|
+
this.hide = _.castArray(hide).filter(name => name || name === 0).map(String);
|
|
9
13
|
this.raw = raw;
|
|
10
14
|
this.outputStream = outputStream;
|
|
11
15
|
this.prefixFormat = prefixFormat;
|
|
@@ -76,6 +80,10 @@ module.exports = class Logger {
|
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
logCommandText(text, command) {
|
|
83
|
+
if (this.hide.includes(String(command.index)) || this.hide.includes(command.name)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
const prefix = this.colorText(command, this.getPrefix(command));
|
|
80
88
|
return this.log(prefix + (prefix ? ' ' : ''), text);
|
|
81
89
|
}
|
package/src/logger.spec.js
CHANGED
|
@@ -176,6 +176,20 @@ describe('#logCommandText()', () => {
|
|
|
176
176
|
|
|
177
177
|
expect(logger.log).toHaveBeenCalledWith(chalk.hex(prefixColor)('[1]') + ' ', 'foo');
|
|
178
178
|
});
|
|
179
|
+
|
|
180
|
+
it('does nothing if command is hidden by name', () => {
|
|
181
|
+
const logger = createLogger({ hide: ['abc'] });
|
|
182
|
+
logger.logCommandText('foo', { name: 'abc' });
|
|
183
|
+
|
|
184
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('does nothing if command is hidden by index', () => {
|
|
188
|
+
const logger = createLogger({ hide: [3] });
|
|
189
|
+
logger.logCommandText('foo', { index: 3 });
|
|
190
|
+
|
|
191
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
192
|
+
});
|
|
179
193
|
});
|
|
180
194
|
|
|
181
195
|
describe('#logCommandEvent()', () => {
|
|
@@ -186,6 +200,20 @@ describe('#logCommandEvent()', () => {
|
|
|
186
200
|
expect(logger.log).not.toHaveBeenCalled();
|
|
187
201
|
});
|
|
188
202
|
|
|
203
|
+
it('does nothing if command is hidden by name', () => {
|
|
204
|
+
const logger = createLogger({ hide: ['abc'] });
|
|
205
|
+
logger.logCommandEvent('foo', { name: 'abc' });
|
|
206
|
+
|
|
207
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('does nothing if command is hidden by index', () => {
|
|
211
|
+
const logger = createLogger({ hide: [3] });
|
|
212
|
+
logger.logCommandEvent('foo', { index: 3 });
|
|
213
|
+
|
|
214
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
215
|
+
});
|
|
216
|
+
|
|
189
217
|
it('logs text in gray dim', () => {
|
|
190
218
|
const logger = createLogger();
|
|
191
219
|
logger.logCommandEvent('foo', { index: 1 });
|