Skip to content

Commit 6129083

Browse files
committed
Warn about running on Snap
Closes #584
1 parent 5ee9c57 commit 6129083

3 files changed

Lines changed: 59 additions & 8 deletions

File tree

lib/assert.spec.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { afterEach, describe, expect, it, vi } from 'vitest';
1+
import { afterEach, beforeEach, describe, expect, it, MockInstance, vi } from 'vitest';
22

3-
import { assertDeprecated } from './assert.js';
3+
import { assertDeprecated, assertNotRuntime } from './assert.js';
44

5-
describe('#assertDeprecated()', () => {
6-
const consoleMock = vi.spyOn(console, 'warn').mockImplementation(() => {});
5+
let consoleMock: MockInstance;
6+
beforeEach(() => {
7+
consoleMock = vi.spyOn(console, 'warn').mockImplementation(() => {});
8+
});
79

8-
afterEach(() => {
9-
vi.clearAllMocks();
10-
});
10+
afterEach(() => {
11+
vi.clearAllMocks();
12+
});
1113

14+
describe('assertDeprecated()', () => {
1215
it('prints warning with name and message when condition is false', () => {
1316
assertDeprecated(false, 'example-flag', 'This is an example message.');
1417

@@ -33,3 +36,29 @@ describe('#assertDeprecated()', () => {
3336
expect(consoleMock).not.toHaveBeenCalled();
3437
});
3538
});
39+
40+
describe('assertNotRuntime()', () => {
41+
it('prints warning with name and message when condition is false', () => {
42+
assertNotRuntime(false, 'example-flag', 'This is an example message.');
43+
44+
expect(consoleMock).toHaveBeenLastCalledWith(
45+
'[concurrently] Running via example-flag is not well supported. This is an example message.',
46+
);
47+
});
48+
49+
it('prints same warning only once', () => {
50+
assertNotRuntime(false, 'example-flag', 'This is an example message.');
51+
assertNotRuntime(false, 'different-flag', 'This is another message.');
52+
53+
expect(consoleMock).toBeCalledTimes(1);
54+
expect(consoleMock).toHaveBeenLastCalledWith(
55+
'[concurrently] Running via different-flag is not well supported. This is another message.',
56+
);
57+
});
58+
59+
it('prints nothing if condition is true', () => {
60+
assertNotRuntime(true, 'example-flag', 'This is an example message.');
61+
62+
expect(consoleMock).not.toHaveBeenCalled();
63+
});
64+
});

lib/assert.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,17 @@ export function assertDeprecated(check: boolean, name: string, message: string)
1111
deprecations.add(name);
1212
}
1313
}
14+
15+
const runtimes = new Set<string>();
16+
17+
/**
18+
* Asserts that some condition is true, and if not, prints a warning about the runtime not being well supported.
19+
* The message is printed only once.
20+
*/
21+
export function assertNotRuntime(check: boolean, name: string, message: string) {
22+
if (!check && !runtimes.has(name)) {
23+
// eslint-disable-next-line no-console
24+
console.warn(`[concurrently] Running via ${name} is not well supported. ${message}`);
25+
runtimes.add(name);
26+
}
27+
}

lib/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import process from 'node:process';
22
import { Readable } from 'node:stream';
33

4-
import { assertDeprecated } from './assert.js';
4+
import { assertDeprecated, assertNotRuntime } from './assert.js';
55
import { CloseEvent, Command, CommandIdentifier, TimerEvent } from './command.js';
66
import {
77
concurrently as createConcurrently,
@@ -127,6 +127,14 @@ export function concurrently(
127127
options: Partial<ConcurrentlyOptions> = {},
128128
) {
129129
assertDeprecated(options.killOthers === undefined, 'killOthers', 'Use killOthersOn instead.');
130+
assertNotRuntime(
131+
// When run via /snap/bin/node, process.execPath maps to the actual snap path, but it also sets
132+
// several SNAP_* env variables. If the snap is run directly via e.g. /snap/node/current/bin/node,
133+
// the issues don't happen and no env variables are set.
134+
!String(process.env.SNAP).startsWith('/snap'),
135+
'Snap',
136+
'Snap confinement can interfere with spawning child processes. See issue #584',
137+
);
130138

131139
// To avoid empty strings from hiding the output of commands that don't have a name,
132140
// keep in the list of commands to hide only strings with some length.

0 commit comments

Comments
 (0)