concurrently 4.0.1 → 4.1.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/.travis.yml +2 -0
- package/CONTRIBUTING.md +1 -4
- package/README.md +11 -8
- package/bin/concurrently.js +1 -1
- package/package.json +4 -2
- package/src/command-parser/expand-npm-shortcut.js +2 -2
- package/src/command-parser/expand-npm-shortcut.spec.js +21 -18
- package/src/command-parser/expand-npm-wildcard.js +2 -2
- package/src/command-parser/expand-npm-wildcard.spec.js +24 -20
- package/src/flow-control/kill-on-signal.spec.js +22 -0
- package/src/flow-control/restart-process.spec.js +10 -0
package/.travis.yml
CHANGED
package/CONTRIBUTING.md
CHANGED
|
@@ -6,7 +6,6 @@ updated.
|
|
|
6
6
|
|
|
7
7
|
**Pull requests:** You don't need to bump version numbers or modify anything related to releasing. That stuff is fully automated, just write the functionality.
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
# Maintaining
|
|
11
10
|
|
|
12
11
|
## Test
|
|
@@ -14,11 +13,9 @@ updated.
|
|
|
14
13
|
Tests can be run with command:
|
|
15
14
|
|
|
16
15
|
```bash
|
|
17
|
-
|
|
16
|
+
npm run test
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
You need to have *mocha* installed globally with `npm install -g mocha`.
|
|
21
|
-
|
|
22
19
|
## Release
|
|
23
20
|
|
|
24
21
|
* Commit all changes
|
package/README.md
CHANGED
|
@@ -225,25 +225,25 @@ For more details, visit https://github.com/kimmobrunfeldt/concurrently
|
|
|
225
225
|
concurrently can be used programmatically by using the API documented below:
|
|
226
226
|
|
|
227
227
|
### `concurrently(commands[, options])`
|
|
228
|
-
- `commands`: an array of either strings (containing the commands to run) or objects
|
|
228
|
+
- `commands`: an array of either strings (containing the commands to run) or objects
|
|
229
229
|
with the shape `{ command, name, prefixColor }`.
|
|
230
230
|
- `options` (optional): an object containing any of the below:
|
|
231
|
-
- `defaultInputTarget`: the default input target when reading from `inputStream`.
|
|
231
|
+
- `defaultInputTarget`: the default input target when reading from `inputStream`.
|
|
232
232
|
Default: `0`.
|
|
233
|
-
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
|
|
233
|
+
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
|
|
234
234
|
to read the input from, eg `process.stdin`.
|
|
235
|
-
- `killOthers`: an array of exitting conditions that will cause a process to kill others.
|
|
235
|
+
- `killOthers`: an array of exitting conditions that will cause a process to kill others.
|
|
236
236
|
Can contain any of `success` or `failure`.
|
|
237
237
|
- `outputStream`: a [`Writable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_streams)
|
|
238
238
|
to write logs to. Default: `process.stdout`.
|
|
239
|
-
- `prefix`: the prefix type to use when logging processes output.
|
|
240
|
-
Possible values: `index`, `pid`, `time`, `command`, `name`, `none`, or a template (eg `[{time} process: {pid}]`).
|
|
239
|
+
- `prefix`: the prefix type to use when logging processes output.
|
|
240
|
+
Possible values: `index`, `pid`, `time`, `command`, `name`, `none`, or a template (eg `[{time} process: {pid}]`).
|
|
241
241
|
Default: the name of the process, or its index if no name is set.
|
|
242
242
|
- `prefixLength`: how many characters to show when prefixing with `command`. Default: `10`
|
|
243
243
|
- `raw`: whether raw mode should be used, meaning strictly process output will
|
|
244
244
|
be logged, without any prefixes, colouring or extra stuff.
|
|
245
245
|
- `successCondition`: the condition to consider the run was successful.
|
|
246
|
-
If `first`, only the first process will make up the success of the run; if `last`, the last.
|
|
246
|
+
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.
|
|
247
247
|
Anything else means all processes should exit successfully.
|
|
248
248
|
- `restartTries`: how many attempts to restart a process that dies will be made. Default: `0`.
|
|
249
249
|
- `restartDelay`: how many milliseconds to wait between process restarts. Default: `0`.
|
|
@@ -258,7 +258,7 @@ Example:
|
|
|
258
258
|
```js
|
|
259
259
|
const concurrently = require('concurrently');
|
|
260
260
|
concurrently([
|
|
261
|
-
'npm:watch-*',
|
|
261
|
+
'npm:watch-*',
|
|
262
262
|
{ command: 'nodemon', name: 'server' }
|
|
263
263
|
], {
|
|
264
264
|
prefix: 'name',
|
|
@@ -282,3 +282,6 @@ concurrently([
|
|
|
282
282
|
So *null* means the process didn't terminate normally. This will make **concurrent**
|
|
283
283
|
to return non-zero exit code too.
|
|
284
284
|
|
|
285
|
+
* Does this work with the npm-replacement [yarn](https://github.com/yarnpkg/yarn)?
|
|
286
|
+
|
|
287
|
+
Yes! In all examples above, you may replace "`npm`" with "`yarn`".
|
package/bin/concurrently.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "concurrently",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Run commands concurrently",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"lint": "eslint . --ignore-path .gitignore",
|
|
14
|
+
"report-coverage": "cat coverage/lcov.info | coveralls",
|
|
14
15
|
"test": "jest"
|
|
15
16
|
},
|
|
16
17
|
"repository": {
|
|
@@ -32,13 +33,14 @@
|
|
|
32
33
|
"date-fns": "^1.23.0",
|
|
33
34
|
"lodash": "^4.17.10",
|
|
34
35
|
"read-pkg": "^4.0.1",
|
|
35
|
-
"rxjs": "6.
|
|
36
|
+
"rxjs": "^6.3.3",
|
|
36
37
|
"spawn-command": "^0.0.2-1",
|
|
37
38
|
"supports-color": "^4.5.0",
|
|
38
39
|
"tree-kill": "^1.1.0",
|
|
39
40
|
"yargs": "^12.0.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
43
|
+
"coveralls": "^3.0.2",
|
|
42
44
|
"eslint": "^5.4.0",
|
|
43
45
|
"jest": "^23.5.0",
|
|
44
46
|
"jest-create-mock-instance": "^1.1.0"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module.exports = class ExpandNpmShortcut {
|
|
2
2
|
parse(commandInfo) {
|
|
3
|
-
const [, cmdName, args] = commandInfo.command.match(/^npm:(\S+)(.*)/) || [];
|
|
3
|
+
const [, npmCmd, cmdName, args] = commandInfo.command.match(/^(npm|yarn):(\S+)(.*)/) || [];
|
|
4
4
|
if (!cmdName) {
|
|
5
5
|
return commandInfo;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
return Object.assign({}, commandInfo, {
|
|
9
9
|
name: commandInfo.name || cmdName,
|
|
10
|
-
command:
|
|
10
|
+
command: `${npmCmd} run ${cmdName}${args}`
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
};
|
|
@@ -9,25 +9,28 @@ it('returns same command if no npm: prefix is present', () => {
|
|
|
9
9
|
expect(parser.parse(commandInfo)).toBe(commandInfo);
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
for (const npmCmd of ['npm', 'yarn']) {
|
|
13
|
+
describe(`with ${npmCmd}: prefix`, () => {
|
|
14
|
+
it(`expands to "${npmCmd} run <script> <args>"`, () => {
|
|
15
|
+
const commandInfo = {
|
|
16
|
+
name: 'echo',
|
|
17
|
+
command: `${npmCmd}:foo -- bar`
|
|
18
|
+
};
|
|
19
|
+
expect(parser.parse(commandInfo)).toEqual({
|
|
20
|
+
name: 'echo',
|
|
21
|
+
command: `${npmCmd} run foo -- bar`
|
|
22
|
+
});
|
|
21
23
|
});
|
|
22
|
-
});
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
it('sets name to script name if none', () => {
|
|
26
|
+
const commandInfo = {
|
|
27
|
+
command: `${npmCmd}:foo -- bar`
|
|
28
|
+
};
|
|
29
|
+
expect(parser.parse(commandInfo)).toEqual({
|
|
30
|
+
name: 'foo',
|
|
31
|
+
command: `${npmCmd} run foo -- bar`
|
|
32
|
+
});
|
|
31
33
|
});
|
|
32
34
|
});
|
|
33
|
-
|
|
35
|
+
|
|
36
|
+
}
|
|
@@ -7,7 +7,7 @@ module.exports = class ExpandNpmWildcard {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
parse(commandInfo) {
|
|
10
|
-
const [, cmdName, args] = commandInfo.command.match(/npm run (\S+)([^&]*)/) || [];
|
|
10
|
+
const [, npmCmd, cmdName, args] = commandInfo.command.match(/(npm|yarn) run (\S+)([^&]*)/) || [];
|
|
11
11
|
const wildcardPosition = (cmdName || '').indexOf('*');
|
|
12
12
|
|
|
13
13
|
// If the regex didn't match an npm script, or it has no wildcard,
|
|
@@ -27,7 +27,7 @@ module.exports = class ExpandNpmWildcard {
|
|
|
27
27
|
return this.scripts
|
|
28
28
|
.filter(script => wildcardRegex.test(script))
|
|
29
29
|
.map(script => Object.assign({}, commandInfo, {
|
|
30
|
-
command:
|
|
30
|
+
command: `${npmCmd} run ${script}${args}`,
|
|
31
31
|
name: script
|
|
32
32
|
}));
|
|
33
33
|
}
|
|
@@ -31,24 +31,28 @@ it('expands to nothing if no scripts exist in package.json', () => {
|
|
|
31
31
|
expect(parser.parse({ command: 'npm run foo-*-baz qux' })).toEqual([]);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
scripts
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
for (const npmCmd of ['npm', 'yarn']) {
|
|
35
|
+
describe(`with an ${npmCmd}: prefix`, () => {
|
|
36
|
+
it('expands to all scripts matching pattern', () => {
|
|
37
|
+
readPkg.mockReturnValue({
|
|
38
|
+
scripts: {
|
|
39
|
+
'foo-bar-baz': '',
|
|
40
|
+
'foo--baz': '',
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(parser.parse({ command: `${npmCmd} run foo-*-baz qux` })).toEqual([
|
|
45
|
+
{ name: 'foo-bar-baz', command: `${npmCmd} run foo-bar-baz qux` },
|
|
46
|
+
{ name: 'foo--baz', command: `${npmCmd} run foo--baz qux` },
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('caches scripts upon calls', () => {
|
|
51
|
+
readPkg.mockReturnValue({});
|
|
52
|
+
parser.parse({ command: `${npmCmd} run foo-*-baz qux` });
|
|
53
|
+
parser.parse({ command: `${npmCmd} run foo-*-baz qux` });
|
|
54
|
+
|
|
55
|
+
expect(readPkg).toHaveBeenCalledTimes(1);
|
|
56
|
+
});
|
|
40
57
|
});
|
|
41
|
-
|
|
42
|
-
expect(parser.parse({ command: 'npm run foo-*-baz qux' })).toEqual([
|
|
43
|
-
{ name: 'foo-bar-baz', command: 'npm run foo-bar-baz qux' },
|
|
44
|
-
{ name: 'foo--baz', command: 'npm run foo--baz qux' },
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('caches scripts upon calls', () => {
|
|
49
|
-
readPkg.mockReturnValue({});
|
|
50
|
-
parser.parse({ command: 'npm run foo-*-baz qux' });
|
|
51
|
-
parser.parse({ command: 'npm run foo-*-baz qux' });
|
|
52
|
-
|
|
53
|
-
expect(readPkg).toHaveBeenCalledTimes(1);
|
|
54
|
-
});
|
|
58
|
+
}
|
|
@@ -13,6 +13,16 @@ beforeEach(() => {
|
|
|
13
13
|
controller = new KillOnSignal({ process });
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
it('returns commands that keep non-close streams from original commands', () => {
|
|
17
|
+
const newCommands = controller.handle(commands);
|
|
18
|
+
newCommands.forEach((newCommand, i) => {
|
|
19
|
+
expect(newCommand.close).not.toBe(commands[i].close);
|
|
20
|
+
expect(newCommand.error).toBe(commands[i].error);
|
|
21
|
+
expect(newCommand.stdout).toBe(commands[i].stdout);
|
|
22
|
+
expect(newCommand.stderr).toBe(commands[i].stderr);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
16
26
|
it('returns commands that map SIGINT to exit code 0', () => {
|
|
17
27
|
const newCommands = controller.handle(commands);
|
|
18
28
|
expect(newCommands).not.toBe(commands);
|
|
@@ -29,6 +39,18 @@ it('returns commands that map SIGINT to exit code 0', () => {
|
|
|
29
39
|
expect(callback).toHaveBeenCalledWith(0);
|
|
30
40
|
});
|
|
31
41
|
|
|
42
|
+
it('returns commands that keep non-SIGINT exit codes', () => {
|
|
43
|
+
const newCommands = controller.handle(commands);
|
|
44
|
+
expect(newCommands).not.toBe(commands);
|
|
45
|
+
expect(newCommands).toHaveLength(commands.length);
|
|
46
|
+
|
|
47
|
+
const callback = jest.fn();
|
|
48
|
+
newCommands[0].close.subscribe(callback);
|
|
49
|
+
commands[0].close.next(1);
|
|
50
|
+
|
|
51
|
+
expect(callback).toHaveBeenCalledWith(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
32
54
|
it('kills all commands on SIGINT', () => {
|
|
33
55
|
controller.handle(commands);
|
|
34
56
|
process.emit('SIGINT');
|
|
@@ -116,4 +116,14 @@ describe('returned commands', () => {
|
|
|
116
116
|
// 1 failure from commands[0], 1 success from commands[1]
|
|
117
117
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
118
118
|
});
|
|
119
|
+
|
|
120
|
+
it('keep non-close streams from original commands', () => {
|
|
121
|
+
const newCommands = controller.handle(commands);
|
|
122
|
+
newCommands.forEach((newCommand, i) => {
|
|
123
|
+
expect(newCommand.close).not.toBe(commands[i].close);
|
|
124
|
+
expect(newCommand.error).toBe(commands[i].error);
|
|
125
|
+
expect(newCommand.stdout).toBe(commands[i].stdout);
|
|
126
|
+
expect(newCommand.stderr).toBe(commands[i].stderr);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
119
129
|
});
|