concurrently 3.1.0 → 3.5.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 +1 -0
- package/CONTRIBUTING.md +1 -3
- package/README.md +14 -32
- package/appveyor.yml +1 -0
- package/package.json +7 -4
- package/src/main.js +130 -43
- package/test/test-functional.js +176 -36
- package/test/utils.js +28 -14
- package/demo.json +0 -32234
- package/hours.txt +0 -2
- package/test.js +0 -1
package/test/test-functional.js
CHANGED
|
@@ -5,8 +5,8 @@ var assert = require('assert');
|
|
|
5
5
|
var run = require('./utils').run;
|
|
6
6
|
var IS_WINDOWS = /^win/.test(process.platform);
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
|
|
8
|
+
// Note: Set the DEBUG_TESTS environment variable to `true` to see output of test commands.
|
|
9
|
+
|
|
10
10
|
var TEST_DIR = 'dir/';
|
|
11
11
|
|
|
12
12
|
// Abs path to test directory
|
|
@@ -17,7 +17,7 @@ describe('concurrently', function() {
|
|
|
17
17
|
this.timeout(5000);
|
|
18
18
|
|
|
19
19
|
it('help should be successful', () => {
|
|
20
|
-
return run('node ./src/main.js --help'
|
|
20
|
+
return run('node ./src/main.js --help')
|
|
21
21
|
.then(function(exitCode) {
|
|
22
22
|
// exit code 0 means success
|
|
23
23
|
assert.strictEqual(exitCode, 0);
|
|
@@ -25,36 +25,69 @@ describe('concurrently', function() {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('version should be successful', () => {
|
|
28
|
-
return run('node ./src/main.js -V'
|
|
28
|
+
return run('node ./src/main.js -V')
|
|
29
29
|
.then(function(exitCode) {
|
|
30
30
|
assert.strictEqual(exitCode, 0);
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('two successful commands should exit 0', () => {
|
|
35
|
-
return run('node ./src/main.js "echo test" "echo test"'
|
|
35
|
+
return run('node ./src/main.js "echo test" "echo test"')
|
|
36
36
|
.then(function(exitCode) {
|
|
37
37
|
assert.strictEqual(exitCode, 0);
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('at least one unsuccessful commands should exit non-zero', () => {
|
|
42
|
-
return run('node ./src/main.js "echo test" "nosuchcmd" "echo test"'
|
|
42
|
+
return run('node ./src/main.js "echo test" "nosuchcmd" "echo test"')
|
|
43
43
|
.then(function(exitCode) {
|
|
44
44
|
assert.notStrictEqual(exitCode, 0);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('--kill-others should kill other commands if one dies', () => {
|
|
49
|
-
|
|
50
|
-
return run('node ./src/main.js --kill-others "sleep 1000" "echo test" "sleep 1000"', {pipe: DEBUG_TESTS})
|
|
49
|
+
return run('node ./src/main.js --kill-others "sleep 1" "echo test" "sleep 0.1 && nosuchcmd"')
|
|
51
50
|
.then(function(exitCode) {
|
|
52
51
|
assert.notStrictEqual(exitCode, 0);
|
|
53
52
|
});
|
|
54
53
|
});
|
|
55
54
|
|
|
55
|
+
it('--kill-others-on-fail should kill other commands if one exits with non-zero status code', () => {
|
|
56
|
+
return run('node ./src/main.js --kill-others-on-fail "sleep 1" "exit 1" "sleep 1"')
|
|
57
|
+
.then(function(exitCode) {
|
|
58
|
+
assert.notStrictEqual(exitCode, 0);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('--kill-others-on-fail should NOT kill other commands if none of them exits with non-zero status code', (done) => {
|
|
63
|
+
var readline = require('readline');
|
|
64
|
+
var exits = 0;
|
|
65
|
+
var sigtermInOutput = false;
|
|
66
|
+
|
|
67
|
+
run('node ./src/main.js --kill-others-on-fail "echo killTest1" "echo killTest2" "echo killTest3"', {
|
|
68
|
+
onOutputLine: function(line) {
|
|
69
|
+
if (/SIGTERM/.test(line)) {
|
|
70
|
+
sigtermInOutput = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// waiting for exits
|
|
74
|
+
if (/killTest\d$/.test(line)) {
|
|
75
|
+
exits++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}).then(function() {
|
|
79
|
+
if(sigtermInOutput) {
|
|
80
|
+
done(new Error('There was a "SIGTERM" in console output'));
|
|
81
|
+
} else if (exits !== 3) {
|
|
82
|
+
done(new Error('There was wrong number of echoes(' + exits + ') from executed commands'));
|
|
83
|
+
} else {
|
|
84
|
+
done();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
56
89
|
it('--success=first should return first exit code', () => {
|
|
57
|
-
return run('node ./src/main.js -k --success first "echo test" "sleep
|
|
90
|
+
return run('node ./src/main.js -k --success first "echo test" "sleep 0.1 && nosuchcmd"')
|
|
58
91
|
// When killed, sleep returns null exit code
|
|
59
92
|
.then(function(exitCode) {
|
|
60
93
|
assert.strictEqual(exitCode, 0);
|
|
@@ -63,19 +96,138 @@ describe('concurrently', function() {
|
|
|
63
96
|
|
|
64
97
|
it('--success=last should return last exit code', () => {
|
|
65
98
|
// When killed, sleep returns null exit code
|
|
66
|
-
return run('node ./src/main.js -k --success last "echo test" "sleep
|
|
99
|
+
return run('node ./src/main.js -k --success last "echo test" "sleep 0.1 && nosuchcmd"')
|
|
67
100
|
.then(function(exitCode) {
|
|
68
101
|
assert.notStrictEqual(exitCode, 0);
|
|
69
102
|
});
|
|
70
103
|
});
|
|
71
104
|
|
|
72
105
|
it('&& nosuchcmd should return non-zero exit code', () => {
|
|
73
|
-
return run('node ./src/main.js "echo 1 && nosuchcmd" "echo 1 && nosuchcmd" '
|
|
106
|
+
return run('node ./src/main.js "echo 1 && nosuchcmd" "echo 1 && nosuchcmd" ')
|
|
74
107
|
.then(function(exitCode) {
|
|
75
108
|
assert.strictEqual(exitCode, 1);
|
|
76
109
|
});
|
|
77
110
|
});
|
|
78
111
|
|
|
112
|
+
it('--prefix-colors should handle non-existent colors without failing', () => {
|
|
113
|
+
return run('node ./src/main.js -c "not.a.color" "echo colors"')
|
|
114
|
+
.then(function(exitCode) {
|
|
115
|
+
assert.strictEqual(exitCode, 0);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('--prefix should default to "index"', () => {
|
|
120
|
+
var collectedLines = []
|
|
121
|
+
|
|
122
|
+
return run('node ./src/main.js "echo one" "echo two"', {
|
|
123
|
+
onOutputLine: (line) => {
|
|
124
|
+
if (/(one|two)$/.exec(line)) {
|
|
125
|
+
collectedLines.push(line)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
.then(function(exitCode) {
|
|
130
|
+
assert.strictEqual(exitCode, 0);
|
|
131
|
+
|
|
132
|
+
collectedLines.sort()
|
|
133
|
+
assert.deepEqual(collectedLines, [
|
|
134
|
+
'[0] one',
|
|
135
|
+
'[1] two'
|
|
136
|
+
])
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('--names should set a different default prefix', () => {
|
|
141
|
+
var collectedLines = []
|
|
142
|
+
|
|
143
|
+
return run('node ./src/main.js -n aa,bb "echo one" "echo two"', {
|
|
144
|
+
onOutputLine: (line) => {
|
|
145
|
+
if (/(one|two)$/.exec(line)) {
|
|
146
|
+
collectedLines.push(line)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.then(function(exitCode) {
|
|
151
|
+
assert.strictEqual(exitCode, 0);
|
|
152
|
+
|
|
153
|
+
collectedLines.sort()
|
|
154
|
+
assert.deepEqual(collectedLines, [
|
|
155
|
+
'[aa] one',
|
|
156
|
+
'[bb] two'
|
|
157
|
+
])
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('--allow-restart should restart a proccess with non-zero exit code', (done) => {
|
|
162
|
+
var readline = require('readline');
|
|
163
|
+
var exitedWithOne = false;
|
|
164
|
+
var restarted = false;
|
|
165
|
+
|
|
166
|
+
run('node ./src/main.js --allow-restart "sleep 0.1 && exit 1" "sleep 1"', {
|
|
167
|
+
pipe: false,
|
|
168
|
+
onOutputLine: (line) => {
|
|
169
|
+
var re = /exited with code (.+)/.exec(line);
|
|
170
|
+
if (re && re[1] === '1') {
|
|
171
|
+
exitedWithOne = true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (/restarted/.test(line)) {
|
|
175
|
+
restarted = true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}).then(function() {
|
|
179
|
+
if (exitedWithOne && restarted) {
|
|
180
|
+
done();
|
|
181
|
+
} else {
|
|
182
|
+
done(new Error('No restarted process exited with code 1'));
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('--restart-after=n should restart a proccess after n miliseconds', (done) => {
|
|
188
|
+
var readline = require('readline');
|
|
189
|
+
var start, end;
|
|
190
|
+
|
|
191
|
+
run('node ./src/main.js --allow-restart --restart-after 300 "exit 1" "sleep 1"', {
|
|
192
|
+
pipe: false,
|
|
193
|
+
onOutputLine: (line) => {
|
|
194
|
+
if (!start && /exited with code (.+)/.test(line)) {
|
|
195
|
+
start = new Date().getTime();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!end && /restarted/.test(line)) {
|
|
199
|
+
end = new Date().getTime();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}).then(function() {
|
|
203
|
+
// we accept 100 miliseconds of error
|
|
204
|
+
if (end - start >= 300 && end - start < 400) {
|
|
205
|
+
done();
|
|
206
|
+
} else {
|
|
207
|
+
done(new Error('No restarted process after 300 miliseconds'));
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
it('--restart-tries=n should restart a proccess at most n times', (done) => {
|
|
212
|
+
var readline = require('readline');
|
|
213
|
+
var restartedTimes = 0;
|
|
214
|
+
|
|
215
|
+
run('node ./src/main.js --allow-restart --restart-tries 2 "exit 1" "sleep 1"', {
|
|
216
|
+
pipe: false,
|
|
217
|
+
onOutputLine: (line) => {
|
|
218
|
+
if (/restarted/.test(line)) {
|
|
219
|
+
restartedTimes++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}).then(function() {
|
|
223
|
+
if (restartedTimes == 2) {
|
|
224
|
+
done();
|
|
225
|
+
} else {
|
|
226
|
+
done(new Error('No restarted process twice'));
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
79
231
|
['SIGINT', 'SIGTERM'].forEach((signal) => {
|
|
80
232
|
if (IS_WINDOWS) {
|
|
81
233
|
console.log('IS_WINDOWS=true');
|
|
@@ -97,32 +249,20 @@ describe('concurrently', function() {
|
|
|
97
249
|
}
|
|
98
250
|
|
|
99
251
|
run('node ./src/main.js "node ./test/support/signal.js" "node ./test/support/signal.js"', {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
252
|
+
onOutputLine: function(line, child) {
|
|
253
|
+
// waiting for startup
|
|
254
|
+
if (/STARTED/.test(line)) {
|
|
255
|
+
waitingStart--;
|
|
256
|
+
}
|
|
257
|
+
if (!waitingStart) {
|
|
258
|
+
// both processes are started
|
|
259
|
+
child.kill(signal);
|
|
260
|
+
}
|
|
106
261
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// waiting for startup
|
|
113
|
-
if (/STARTED/.test(line)) {
|
|
114
|
-
waitingStart--;
|
|
115
|
-
}
|
|
116
|
-
if (!waitingStart) {
|
|
117
|
-
// both processes are started
|
|
118
|
-
child.kill(signal);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// waiting for signal
|
|
122
|
-
if (new RegExp(signal).test(line)) {
|
|
123
|
-
waitingSignal--;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
262
|
+
// waiting for signal
|
|
263
|
+
if (new RegExp(signal).test(line)) {
|
|
264
|
+
waitingSignal--;
|
|
265
|
+
}
|
|
126
266
|
}
|
|
127
267
|
}).then(function() {
|
|
128
268
|
waitForSignal(done);
|
package/test/utils.js
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
var childProcess = require('child_process');
|
|
2
2
|
var _ = require('lodash');
|
|
3
|
-
var
|
|
3
|
+
var readline = require('readline')
|
|
4
4
|
var shellQuote = require('shell-quote');
|
|
5
5
|
|
|
6
|
+
// If true, output of commands are shown
|
|
7
|
+
var DEBUG_TESTS = process.env.DEBUG_TESTS === 'true';
|
|
8
|
+
|
|
6
9
|
function run(cmd, opts) {
|
|
7
10
|
opts = _.merge({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// Since we return promise, we need to provide
|
|
12
|
-
// this callback if one wants to access the child
|
|
13
|
-
// process reference
|
|
14
|
-
// Called immediately after successful child process
|
|
15
|
-
// spawn
|
|
16
|
-
}
|
|
11
|
+
// If set to a function, it will be called for each line
|
|
12
|
+
// written to the child process's stdout as (line, child)
|
|
13
|
+
onOutputLine: undefined,
|
|
17
14
|
}, opts);
|
|
18
15
|
|
|
19
16
|
var child;
|
|
20
17
|
var parts = shellQuote.parse(cmd);
|
|
21
18
|
try {
|
|
22
19
|
child = childProcess.spawn(_.head(parts), _.tail(parts), {
|
|
23
|
-
|
|
24
|
-
stdio: opts.pipe ? "inherit" : null
|
|
20
|
+
stdio: DEBUG_TESTS && !opts.onOutputLine ? 'inherit': null,
|
|
25
21
|
});
|
|
26
22
|
} catch (e) {
|
|
27
23
|
return Promise.reject(e);
|
|
28
24
|
}
|
|
29
|
-
|
|
25
|
+
|
|
26
|
+
if (opts.onOutputLine) {
|
|
27
|
+
readLines(child, opts.onOutputLine);
|
|
28
|
+
}
|
|
30
29
|
|
|
31
30
|
return new Promise(function(resolve, reject) {
|
|
32
31
|
child.on('error', function(err) {
|
|
@@ -39,6 +38,21 @@ function run(cmd, opts) {
|
|
|
39
38
|
});
|
|
40
39
|
}
|
|
41
40
|
|
|
41
|
+
function readLines(child, callback) {
|
|
42
|
+
var rl = readline.createInterface({
|
|
43
|
+
input: child.stdout,
|
|
44
|
+
output: null
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
rl.on('line', function(line) {
|
|
48
|
+
if (DEBUG_TESTS) {
|
|
49
|
+
console.log(line);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
callback(line, child)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
module.exports = {
|
|
43
57
|
run: run
|
|
44
|
-
};
|
|
58
|
+
};
|