concurrently 6.3.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +82 -35
  2. package/dist/bin/concurrently.d.ts +2 -0
  3. package/dist/bin/concurrently.js +193 -0
  4. package/dist/bin/concurrently.spec.d.ts +1 -0
  5. package/dist/bin/epilogue.d.ts +1 -0
  6. package/dist/bin/epilogue.js +65 -0
  7. package/dist/src/command-parser/command-parser.d.ts +19 -0
  8. package/dist/src/command-parser/command-parser.js +2 -0
  9. package/dist/src/command-parser/expand-npm-shortcut.d.ts +8 -0
  10. package/{src → dist/src}/command-parser/expand-npm-shortcut.js +10 -3
  11. package/dist/src/command-parser/expand-npm-shortcut.spec.d.ts +1 -0
  12. package/dist/src/command-parser/expand-npm-wildcard.d.ts +13 -0
  13. package/dist/src/command-parser/expand-npm-wildcard.js +73 -0
  14. package/dist/src/command-parser/expand-npm-wildcard.spec.d.ts +1 -0
  15. package/dist/src/command-parser/strip-quotes.d.ts +10 -0
  16. package/{src → dist/src}/command-parser/strip-quotes.js +10 -4
  17. package/dist/src/command-parser/strip-quotes.spec.d.ts +1 -0
  18. package/dist/src/command.d.ts +101 -0
  19. package/dist/src/command.js +101 -0
  20. package/dist/src/command.spec.d.ts +1 -0
  21. package/dist/src/completion-listener.d.ts +37 -0
  22. package/dist/src/completion-listener.js +60 -0
  23. package/dist/src/completion-listener.spec.d.ts +1 -0
  24. package/dist/src/concurrently.d.ts +77 -0
  25. package/dist/src/concurrently.js +120 -0
  26. package/dist/src/concurrently.spec.d.ts +1 -0
  27. package/dist/src/defaults.d.ts +52 -0
  28. package/dist/src/defaults.js +58 -0
  29. package/dist/src/flow-control/flow-controller.d.ts +13 -0
  30. package/dist/src/flow-control/flow-controller.js +2 -0
  31. package/dist/src/flow-control/input-handler.d.ts +33 -0
  32. package/dist/src/flow-control/input-handler.js +73 -0
  33. package/dist/src/flow-control/input-handler.spec.d.ts +1 -0
  34. package/dist/src/flow-control/kill-on-signal.d.ts +17 -0
  35. package/{src → dist/src}/flow-control/kill-on-signal.js +13 -11
  36. package/dist/src/flow-control/kill-on-signal.spec.d.ts +1 -0
  37. package/dist/src/flow-control/kill-others.d.ts +18 -0
  38. package/dist/src/flow-control/kill-others.js +35 -0
  39. package/dist/src/flow-control/kill-others.spec.d.ts +1 -0
  40. package/dist/src/flow-control/log-error.d.ts +15 -0
  41. package/dist/src/flow-control/log-error.js +21 -0
  42. package/dist/src/flow-control/log-error.spec.d.ts +1 -0
  43. package/dist/src/flow-control/log-exit.d.ts +15 -0
  44. package/dist/src/flow-control/log-exit.js +19 -0
  45. package/dist/src/flow-control/log-exit.spec.d.ts +1 -0
  46. package/dist/src/flow-control/log-output.d.ts +15 -0
  47. package/{src → dist/src}/flow-control/log-output.js +13 -5
  48. package/dist/src/flow-control/log-output.spec.d.ts +1 -0
  49. package/dist/src/flow-control/log-timings.d.ts +27 -0
  50. package/dist/src/flow-control/log-timings.js +88 -0
  51. package/dist/src/flow-control/log-timings.spec.d.ts +1 -0
  52. package/dist/src/flow-control/restart-process.d.ts +22 -0
  53. package/dist/src/flow-control/restart-process.js +71 -0
  54. package/dist/src/flow-control/restart-process.spec.d.ts +1 -0
  55. package/dist/src/get-spawn-opts.d.ts +30 -0
  56. package/dist/src/get-spawn-opts.js +11 -0
  57. package/dist/src/get-spawn-opts.spec.d.ts +1 -0
  58. package/dist/src/index.d.ts +69 -0
  59. package/dist/src/index.js +69 -0
  60. package/dist/src/logger.d.ts +72 -0
  61. package/dist/src/logger.js +199 -0
  62. package/dist/src/logger.spec.d.ts +1 -0
  63. package/dist/src/output-writer.d.ts +19 -0
  64. package/dist/src/output-writer.js +69 -0
  65. package/dist/src/output-writer.spec.d.ts +1 -0
  66. package/index.js +6 -60
  67. package/index.mjs +9 -0
  68. package/package.json +37 -11
  69. package/bin/concurrently.js +0 -170
  70. package/bin/concurrently.spec.js +0 -365
  71. package/bin/epilogue.txt +0 -42
  72. package/src/command-parser/expand-npm-shortcut.spec.js +0 -36
  73. package/src/command-parser/expand-npm-wildcard.js +0 -43
  74. package/src/command-parser/expand-npm-wildcard.spec.js +0 -58
  75. package/src/command-parser/strip-quotes.spec.js +0 -20
  76. package/src/command.js +0 -63
  77. package/src/command.spec.js +0 -183
  78. package/src/completion-listener.js +0 -39
  79. package/src/completion-listener.spec.js +0 -88
  80. package/src/concurrently.js +0 -111
  81. package/src/concurrently.spec.js +0 -199
  82. package/src/defaults.js +0 -31
  83. package/src/flow-control/base-handler.js +0 -16
  84. package/src/flow-control/input-handler.js +0 -50
  85. package/src/flow-control/input-handler.spec.js +0 -113
  86. package/src/flow-control/kill-on-signal.spec.js +0 -79
  87. package/src/flow-control/kill-others.js +0 -38
  88. package/src/flow-control/kill-others.spec.js +0 -66
  89. package/src/flow-control/log-error.js +0 -18
  90. package/src/flow-control/log-error.spec.js +0 -40
  91. package/src/flow-control/log-exit.js +0 -11
  92. package/src/flow-control/log-exit.spec.js +0 -36
  93. package/src/flow-control/log-output.spec.js +0 -41
  94. package/src/flow-control/restart-process.js +0 -56
  95. package/src/flow-control/restart-process.spec.js +0 -131
  96. package/src/get-spawn-opts.js +0 -16
  97. package/src/get-spawn-opts.spec.js +0 -30
  98. package/src/logger.js +0 -115
  99. package/src/logger.spec.js +0 -195
@@ -1,199 +0,0 @@
1
- const EventEmitter = require('events');
2
-
3
- const createFakeCommand = require('./flow-control/fixtures/fake-command');
4
- const FakeHandler = require('./flow-control/fixtures/fake-handler');
5
- const concurrently = require('./concurrently');
6
-
7
- let spawn, kill, controllers, processes = [];
8
- const create = (commands, options = {}) => concurrently(
9
- commands,
10
- Object.assign(options, { controllers, spawn, kill })
11
- );
12
-
13
- beforeEach(() => {
14
- processes = [];
15
- spawn = jest.fn(() => {
16
- const process = new EventEmitter();
17
- processes.push(process);
18
- process.pid = processes.length;
19
- return process;
20
- });
21
- kill = jest.fn();
22
- controllers = [new FakeHandler(), new FakeHandler()];
23
- });
24
-
25
- it('fails if commands is not an array', () => {
26
- const bomb = () => create('foo');
27
- expect(bomb).toThrowError();
28
- });
29
-
30
- it('fails if no commands were provided', () => {
31
- const bomb = () => create([]);
32
- expect(bomb).toThrowError();
33
- });
34
-
35
- it('spawns all commands', () => {
36
- create(['echo', 'kill']);
37
- expect(spawn).toHaveBeenCalledTimes(2);
38
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({}));
39
- expect(spawn).toHaveBeenCalledWith('kill', expect.objectContaining({}));
40
- });
41
-
42
- it('spawns commands up to configured limit at once', () => {
43
- create(['foo', 'bar', 'baz', 'qux'], { maxProcesses: 2 });
44
- expect(spawn).toHaveBeenCalledTimes(2);
45
- expect(spawn).toHaveBeenCalledWith('foo', expect.objectContaining({}));
46
- expect(spawn).toHaveBeenCalledWith('bar', expect.objectContaining({}));
47
-
48
- // Test out of order completion picking up new processes in-order
49
- processes[1].emit('close', 1, null);
50
- expect(spawn).toHaveBeenCalledTimes(3);
51
- expect(spawn).toHaveBeenCalledWith('baz', expect.objectContaining({}));
52
-
53
- processes[0].emit('close', null, 'SIGINT');
54
- expect(spawn).toHaveBeenCalledTimes(4);
55
- expect(spawn).toHaveBeenCalledWith('qux', expect.objectContaining({}));
56
-
57
- // Shouldn't attempt to spawn anything else.
58
- processes[2].emit('close', 1, null);
59
- expect(spawn).toHaveBeenCalledTimes(4);
60
- });
61
-
62
- it('runs controllers with the commands', () => {
63
- create(['echo', '"echo wrapped"']);
64
-
65
- controllers.forEach(controller => {
66
- expect(controller.handle).toHaveBeenCalledWith([
67
- expect.objectContaining({ command: 'echo', index: 0 }),
68
- expect.objectContaining({ command: 'echo wrapped', index: 1 }),
69
- ]);
70
- });
71
- });
72
-
73
- it('runs commands with a name or prefix color', () => {
74
- create([
75
- { command: 'echo', prefixColor: 'red', name: 'foo' },
76
- 'kill'
77
- ]);
78
-
79
- controllers.forEach(controller => {
80
- expect(controller.handle).toHaveBeenCalledWith([
81
- expect.objectContaining({ command: 'echo', index: 0, name: 'foo', prefixColor: 'red' }),
82
- expect.objectContaining({ command: 'kill', index: 1, name: '', prefixColor: '' }),
83
- ]);
84
- });
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
-
100
- it('passes commands wrapped from a controller to the next one', () => {
101
- const fakeCommand = createFakeCommand('banana', 'banana');
102
- controllers[0].handle.mockReturnValue({ commands: [fakeCommand] });
103
-
104
- create(['echo']);
105
-
106
- expect(controllers[0].handle).toHaveBeenCalledWith([
107
- expect.objectContaining({ command: 'echo', index: 0 })
108
- ]);
109
-
110
- expect(controllers[1].handle).toHaveBeenCalledWith([fakeCommand]);
111
-
112
- expect(fakeCommand.start).toHaveBeenCalledTimes(1);
113
- });
114
-
115
- it('merges extra env vars into each command', () => {
116
- create([
117
- { command: 'echo', env: { foo: 'bar' } },
118
- { command: 'echo', env: { foo: 'baz' } },
119
- 'kill'
120
- ]);
121
-
122
- expect(spawn).toHaveBeenCalledTimes(3);
123
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
124
- env: expect.objectContaining({ foo: 'bar' })
125
- }));
126
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
127
- env: expect.objectContaining({ foo: 'baz' })
128
- }));
129
- expect(spawn).toHaveBeenCalledWith('kill', expect.objectContaining({
130
- env: expect.not.objectContaining({ foo: expect.anything() })
131
- }));
132
- });
133
-
134
- it('uses cwd from options for each command', () => {
135
- create(
136
- [
137
- { command: 'echo', env: { foo: 'bar' } },
138
- { command: 'echo', env: { foo: 'baz' } },
139
- 'kill'
140
- ],
141
- {
142
- cwd: 'foobar',
143
- }
144
- );
145
-
146
- expect(spawn).toHaveBeenCalledTimes(3);
147
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
148
- env: expect.objectContaining({ foo: 'bar' }),
149
- cwd: 'foobar',
150
- }));
151
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
152
- env: expect.objectContaining({ foo: 'baz' }),
153
- cwd: 'foobar',
154
- }));
155
- expect(spawn).toHaveBeenCalledWith('kill', expect.objectContaining({
156
- env: expect.not.objectContaining({ foo: expect.anything() }),
157
- cwd: 'foobar',
158
- }));
159
- });
160
-
161
- it('uses overridden cwd option for each command if specified', () => {
162
- create(
163
- [
164
- { command: 'echo', env: { foo: 'bar' }, cwd: 'baz' },
165
- { command: 'echo', env: { foo: 'baz' } },
166
- ],
167
- {
168
- cwd: 'foobar',
169
- }
170
- );
171
-
172
- expect(spawn).toHaveBeenCalledTimes(2);
173
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
174
- env: expect.objectContaining({ foo: 'bar' }),
175
- cwd: 'baz',
176
- }));
177
- expect(spawn).toHaveBeenCalledWith('echo', expect.objectContaining({
178
- env: expect.objectContaining({ foo: 'baz' }),
179
- cwd: 'foobar',
180
- }));
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 DELETED
@@ -1,31 +0,0 @@
1
- /**
2
- * This file is meant to be a shared place for default configs.
3
- * It's read by the flow controllers, the executable, etc.
4
- *
5
- * Refer to tests for the meaning of the different possible values.
6
- */
7
- module.exports = {
8
- defaultInputTarget: 0,
9
- // Whether process.stdin should be forwarded to child processes
10
- handleInput: false,
11
- // How many processes to run at once
12
- maxProcesses: 0,
13
- nameSeparator: ',',
14
- // Which prefix style to use when logging processes output.
15
- prefix: '',
16
- // Refer to https://www.npmjs.com/package/chalk
17
- prefixColors: 'reset',
18
- // How many bytes we'll show on the command prefix
19
- prefixLength: 10,
20
- raw: false,
21
- // Number of attempts of restarting a process, if it exits with non-0 code
22
- restartTries: 0,
23
- // How many milliseconds concurrently should wait before restarting a process.
24
- restartDelay: 0,
25
- // Condition of success for concurrently itself.
26
- success: 'all',
27
- // Refer to https://date-fns.org/v2.0.1/docs/format
28
- timestampFormat: 'yyyy-MM-dd HH:mm:ss.SSS',
29
- // Current working dir passed as option to spawn command. Default: process.cwd()
30
- cwd: undefined
31
- };
@@ -1,16 +0,0 @@
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
- };
@@ -1,50 +0,0 @@
1
- const Rx = require('rxjs');
2
- const { map } = require('rxjs/operators');
3
-
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 });
10
-
11
- this.defaultInputTarget = defaultInputTarget || defaults.defaultInputTarget;
12
- this.inputStream = inputStream;
13
- this.pauseInputStreamOnFinish = pauseInputStreamOnFinish !== false;
14
- }
15
-
16
- handle(commands) {
17
- if (!this.inputStream) {
18
- return { commands };
19
- }
20
-
21
- Rx.fromEvent(this.inputStream, 'data')
22
- .pipe(map(data => data.toString()))
23
- .subscribe(data => {
24
- let [targetId, input] = data.split(/:(.+)/);
25
- targetId = input ? targetId : this.defaultInputTarget;
26
- input = input || data;
27
-
28
- const command = commands.find(command => (
29
- command.name === targetId ||
30
- command.index.toString() === targetId.toString()
31
- ));
32
-
33
- if (command && command.stdin) {
34
- command.stdin.write(input);
35
- } else {
36
- this.logger.logGlobalEvent(`Unable to find command ${targetId}, or it has no stdin open\n`);
37
- }
38
- });
39
-
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
- };
49
- }
50
- };
@@ -1,113 +0,0 @@
1
- const stream = require('stream');
2
- const { createMockInstance } = require('jest-create-mock-instance');
3
-
4
- const Logger = require('../logger');
5
- const createFakeCommand = require('./fixtures/fake-command');
6
- const InputHandler = require('./input-handler');
7
-
8
- let commands, controller, inputStream, logger;
9
-
10
- beforeEach(() => {
11
- commands = [
12
- createFakeCommand('foo', 'echo foo', 0),
13
- createFakeCommand('bar', 'echo bar', 1),
14
- ];
15
- inputStream = new stream.PassThrough();
16
- logger = createMockInstance(Logger);
17
- controller = new InputHandler({
18
- defaultInputTarget: 0,
19
- inputStream,
20
- logger
21
- });
22
- });
23
-
24
- it('returns same commands', () => {
25
- expect(controller.handle(commands)).toMatchObject({ commands });
26
-
27
- controller = new InputHandler({ logger });
28
- expect(controller.handle(commands)).toMatchObject({ commands });
29
- });
30
-
31
- it('forwards input stream to default target ID', () => {
32
- controller.handle(commands);
33
-
34
- inputStream.write('something');
35
-
36
- expect(commands[0].stdin.write).toHaveBeenCalledTimes(1);
37
- expect(commands[0].stdin.write).toHaveBeenCalledWith('something');
38
- expect(commands[1].stdin.write).not.toHaveBeenCalled();
39
- });
40
-
41
- it('forwards input stream to target index specified in input', () => {
42
- controller.handle(commands);
43
-
44
- inputStream.write('1:something');
45
-
46
- expect(commands[0].stdin.write).not.toHaveBeenCalled();
47
- expect(commands[1].stdin.write).toHaveBeenCalledTimes(1);
48
- expect(commands[1].stdin.write).toHaveBeenCalledWith('something');
49
- });
50
-
51
- it('forwards input stream to target index specified in input when input contains colon', () => {
52
- controller.handle(commands);
53
-
54
- inputStream.emit('data', Buffer.from('1::something'));
55
- inputStream.emit('data', Buffer.from('1:some:thing'));
56
-
57
- expect(commands[0].stdin.write).not.toHaveBeenCalled();
58
- expect(commands[1].stdin.write).toHaveBeenCalledTimes(2);
59
- expect(commands[1].stdin.write).toHaveBeenCalledWith(':something');
60
- expect(commands[1].stdin.write).toHaveBeenCalledWith('some:thing');
61
- });
62
-
63
- it('forwards input stream to target name specified in input', () => {
64
- controller.handle(commands);
65
-
66
- inputStream.write('bar:something');
67
-
68
- expect(commands[0].stdin.write).not.toHaveBeenCalled();
69
- expect(commands[1].stdin.write).toHaveBeenCalledTimes(1);
70
- expect(commands[1].stdin.write).toHaveBeenCalledWith('something');
71
- });
72
-
73
- it('logs error if command has no stdin open', () => {
74
- commands[0].stdin = null;
75
- controller.handle(commands);
76
-
77
- inputStream.write('something');
78
-
79
- expect(commands[1].stdin.write).not.toHaveBeenCalled();
80
- expect(logger.logGlobalEvent).toHaveBeenCalledWith('Unable to find command 0, or it has no stdin open\n');
81
- });
82
-
83
- it('logs error if command is not found', () => {
84
- controller.handle(commands);
85
-
86
- inputStream.write('foobar:something');
87
-
88
- expect(commands[0].stdin.write).not.toHaveBeenCalled();
89
- expect(commands[1].stdin.write).not.toHaveBeenCalled();
90
- expect(logger.logGlobalEvent).toHaveBeenCalledWith('Unable to find command foobar, or it has no stdin open\n');
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,79 +0,0 @@
1
- const EventEmitter = require('events');
2
-
3
- const createFakeCommand = require('./fixtures/fake-command');
4
- const KillOnSignal = require('./kill-on-signal');
5
-
6
- let commands, controller, process;
7
- beforeEach(() => {
8
- process = new EventEmitter();
9
- commands = [
10
- createFakeCommand(),
11
- createFakeCommand(),
12
- ];
13
- controller = new KillOnSignal({ process });
14
- });
15
-
16
- it('returns commands that keep non-close streams from original commands', () => {
17
- const { commands: 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
-
26
- it('returns commands that map SIGINT to exit code 0', () => {
27
- const { commands: newCommands } = controller.handle(commands);
28
- expect(newCommands).not.toBe(commands);
29
- expect(newCommands).toHaveLength(commands.length);
30
-
31
- const callback = jest.fn();
32
- newCommands[0].close.subscribe(callback);
33
- process.emit('SIGINT');
34
-
35
- // A fake command's .kill() call won't trigger a close event automatically...
36
- commands[0].close.next({ exitCode: 1 });
37
-
38
- expect(callback).not.toHaveBeenCalledWith({ exitCode: 'SIGINT' });
39
- expect(callback).toHaveBeenCalledWith({ exitCode: 0 });
40
- });
41
-
42
- it('returns commands that keep non-SIGINT exit codes', () => {
43
- const { commands: 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({ exitCode: 1 });
50
-
51
- expect(callback).toHaveBeenCalledWith({ exitCode: 1 });
52
- });
53
-
54
- it('kills all commands on SIGINT', () => {
55
- controller.handle(commands);
56
- process.emit('SIGINT');
57
-
58
- expect(process.listenerCount('SIGINT')).toBe(1);
59
- expect(commands[0].kill).toHaveBeenCalledWith('SIGINT');
60
- expect(commands[1].kill).toHaveBeenCalledWith('SIGINT');
61
- });
62
-
63
- it('kills all commands on SIGTERM', () => {
64
- controller.handle(commands);
65
- process.emit('SIGTERM');
66
-
67
- expect(process.listenerCount('SIGTERM')).toBe(1);
68
- expect(commands[0].kill).toHaveBeenCalledWith('SIGTERM');
69
- expect(commands[1].kill).toHaveBeenCalledWith('SIGTERM');
70
- });
71
-
72
- it('kills all commands on SIGHUP', () => {
73
- controller.handle(commands);
74
- process.emit('SIGHUP');
75
-
76
- expect(process.listenerCount('SIGHUP')).toBe(1);
77
- expect(commands[0].kill).toHaveBeenCalledWith('SIGHUP');
78
- expect(commands[1].kill).toHaveBeenCalledWith('SIGHUP');
79
- });
@@ -1,38 +0,0 @@
1
- const _ = require('lodash');
2
- const { filter, map } = require('rxjs/operators');
3
-
4
- const BaseHandler = require('./base-handler');
5
-
6
- module.exports = class KillOthers extends BaseHandler {
7
- constructor({ logger, conditions }) {
8
- super({ logger });
9
-
10
- this.conditions = _.castArray(conditions);
11
- }
12
-
13
- handle(commands) {
14
- const conditions = this.conditions.filter(condition => (
15
- condition === 'failure' ||
16
- condition === 'success'
17
- ));
18
-
19
- if (!conditions.length) {
20
- return { commands };
21
- }
22
-
23
- const closeStates = commands.map(command => command.close.pipe(
24
- map(({ exitCode }) => exitCode === 0 ? 'success' : 'failure'),
25
- filter(state => conditions.includes(state))
26
- ));
27
-
28
- closeStates.forEach(closeState => closeState.subscribe(() => {
29
- const killableCommands = commands.filter(command => command.killable);
30
- if (killableCommands.length) {
31
- this.logger.logGlobalEvent('Sending SIGTERM to other processes..');
32
- killableCommands.forEach(command => command.kill());
33
- }
34
- }));
35
-
36
- return { commands };
37
- }
38
- };
@@ -1,66 +0,0 @@
1
- const { createMockInstance } = require('jest-create-mock-instance');
2
-
3
- const Logger = require('../logger');
4
- const createFakeCommand = require('./fixtures/fake-command');
5
- const KillOthers = require('./kill-others');
6
-
7
- let commands, logger;
8
- beforeEach(() => {
9
- commands = [
10
- createFakeCommand(),
11
- createFakeCommand()
12
- ];
13
-
14
- logger = createMockInstance(Logger);
15
- });
16
-
17
- const createWithConditions = conditions => new KillOthers({
18
- logger,
19
- conditions
20
- });
21
-
22
- it('returns same commands', () => {
23
- expect(createWithConditions(['foo']).handle(commands)).toMatchObject({ commands });
24
- expect(createWithConditions(['failure']).handle(commands)).toMatchObject({ commands });
25
- });
26
-
27
- it('does not kill others if condition does not match', () => {
28
- createWithConditions(['failure']).handle(commands);
29
- commands[1].killable = true;
30
- commands[0].close.next({ exitCode: 0 });
31
-
32
- expect(logger.logGlobalEvent).not.toHaveBeenCalled();
33
- expect(commands[0].kill).not.toHaveBeenCalled();
34
- expect(commands[1].kill).not.toHaveBeenCalled();
35
- });
36
-
37
- it('kills other killable processes on success', () => {
38
- createWithConditions(['success']).handle(commands);
39
- commands[1].killable = true;
40
- commands[0].close.next({ exitCode: 0 });
41
-
42
- expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
43
- expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
44
- expect(commands[0].kill).not.toHaveBeenCalled();
45
- expect(commands[1].kill).toHaveBeenCalled();
46
- });
47
-
48
- it('kills other killable processes on failure', () => {
49
- createWithConditions(['failure']).handle(commands);
50
- commands[1].killable = true;
51
- commands[0].close.next({ exitCode: 1 });
52
-
53
- expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
54
- expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
55
- expect(commands[0].kill).not.toHaveBeenCalled();
56
- expect(commands[1].kill).toHaveBeenCalled();
57
- });
58
-
59
- it('does not try to kill processes already dead', () => {
60
- createWithConditions(['failure']).handle(commands);
61
- commands[0].close.next({ exitCode: 1 });
62
-
63
- expect(logger.logGlobalEvent).not.toHaveBeenCalled();
64
- expect(commands[0].kill).not.toHaveBeenCalled();
65
- expect(commands[1].kill).not.toHaveBeenCalled();
66
- });
@@ -1,18 +0,0 @@
1
- const { of } = require('rxjs');
2
-
3
- const BaseHandler = require('./base-handler');
4
-
5
- module.exports = class LogExit extends BaseHandler {
6
- handle(commands) {
7
- commands.forEach(command => command.error.subscribe(event => {
8
- this.logger.logCommandEvent(
9
- `Error occurred when executing command: ${command.command}`,
10
- command
11
- );
12
-
13
- this.logger.logCommandEvent(event.stack || event, command);
14
- }));
15
-
16
- return { commands };
17
- }
18
- };
@@ -1,40 +0,0 @@
1
- const { createMockInstance } = require('jest-create-mock-instance');
2
- const Logger = require('../logger');
3
- const LogError = require('./log-error');
4
- const createFakeCommand = require('./fixtures/fake-command');
5
-
6
- let controller, logger, commands;
7
- beforeEach(() => {
8
- commands = [
9
- createFakeCommand(),
10
- createFakeCommand(),
11
- ];
12
-
13
- logger = createMockInstance(Logger);
14
- controller = new LogError({ logger });
15
- });
16
-
17
- it('returns same commands', () => {
18
- expect(controller.handle(commands)).toMatchObject({ commands });
19
- });
20
-
21
- it('logs the error event of each command', () => {
22
- controller.handle(commands);
23
- commands[0].error.next('error from command 0');
24
-
25
- const error = new Error('some error message');
26
- commands[1].error.next(error);
27
-
28
- expect(logger.logCommandEvent).toHaveBeenCalledTimes(4);
29
- expect(logger.logCommandEvent).toHaveBeenCalledWith(
30
- `Error occurred when executing command: ${commands[0].command}`,
31
- commands[0]
32
- );
33
- expect(logger.logCommandEvent).toHaveBeenCalledWith('error from command 0', commands[0]);
34
-
35
- expect(logger.logCommandEvent).toHaveBeenCalledWith(
36
- `Error occurred when executing command: ${commands[1].command}`,
37
- commands[1]
38
- );
39
- expect(logger.logCommandEvent).toHaveBeenCalledWith(error.stack, commands[1]);
40
- });
@@ -1,11 +0,0 @@
1
- const BaseHandler = require('./base-handler');
2
-
3
- module.exports = class LogExit extends BaseHandler {
4
- handle(commands) {
5
- commands.forEach(command => command.close.subscribe(({ exitCode }) => {
6
- this.logger.logCommandEvent(`${command.command} exited with code ${exitCode}`, command);
7
- }));
8
-
9
- return { commands };
10
- }
11
- };