Skip to content

Commit 3a4d12e

Browse files
authored
Merge branch 'main' into fix/normalize-cli-command-quotes
2 parents d0a082b + 2822c28 commit 3a4d12e

23 files changed

Lines changed: 1425 additions & 1218 deletions

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,22 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
9797
- `options` (optional): an object containing any of the below:
9898
- `cwd`: the working directory to be used by all commands. Can be overridden per command.
9999
Default: `process.cwd()`.
100+
- `shell`: shell executable used to run command strings. When unset, uses `npm_config_script_shell` if present (for example when run via `npm run`), otherwise `cmd.exe` on Windows or `/bin/sh` elsewhere. See [shell resolution](./docs/shell-resolution.md).
100101
- `defaultInputTarget`: the default input target when reading from `inputStream`.
101102
Default: `0`.
102103
- `handleInput`: when `true`, reads input from `process.stdin`.
103-
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
104+
- `inputStream`: a [`Readable` stream](https://nodejs.org/docs/latest/api/stream.html#readable-streams)
104105
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`.
105106
- `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)).
106107
- `killOthersOn`: once the first command exits with one of these statuses, kill other commands.
107108
Can be an array containing the strings `success` (status code zero) and/or `failure` (non-zero exit status).
108109
- `maxProcesses`: how many processes should run at once.
109-
- `outputStream`: a [`Writable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_streams)
110+
- `outputStream`: a [`Writable` stream](https://nodejs.org/docs/latest/api/stream.html#writable-streams)
110111
to write logs to. Default: `process.stdout`.
111112
- `prefix`: the prefix type to use when logging processes output.
112113
Possible values: `index`, `pid`, `time`, `command`, `name`, `none`, or a template (eg `[{time} process: {pid}]`).
113114
Default: the name of the process, or its index if no name is set.
115+
Templates can wrap any portion of the prefix with `{color}` and `{/color}` to restrict coloring to that region (eg `[{color}{name}{/color}]` colors only the name, leaving the brackets uncolored). If either marker is omitted the missing side is implicit, so a template with no markers is colored in full.
114116
- `prefixColors`: a list of colors or a string as supported by [Chalk](https://www.npmjs.com/package/chalk) and additional style `auto` for an automatically picked color.
115117
Supports all Chalk color functions: `#RRGGBB`, `bg#RRGGBB`, `hex()`, `bgHex()`, `rgb()`, `bgRgb()`, `ansi256()`, `bgAnsi256()`.
116118
Functions and modifiers can be chained (e.g., `rgb(255,136,0).bold`, `black.bgHex(#00FF00).dim`).
@@ -221,16 +223,16 @@ It contains the following properties:
221223
222224
## FAQ
223225
224-
- Process exited with code _null_?
226+
- Process exited with code `null`?
225227
226-
From [Node child_process documentation](http://nodejs.org/api/child_process.html#child_process_event_exit), `exit` event:
228+
From [Node child_process documentation](https://nodejs.org/docs/latest/api/child_process.html#event-exit), `exit` event:
227229
228230
> This event is emitted after the child process ends. If the process
229231
> terminated normally, code is the final exit code of the process,
230232
> otherwise null. If the process terminated due to receipt of a signal,
231233
> signal is the string name of the signal, otherwise null.
232234
233-
So _null_ means the process didn't terminate normally. This will make **concurrently**
235+
So `null` means the process didn't terminate normally. This will make **concurrently**
234236
to return non-zero exit code too.
235237
236238
- Does this work with the npm-replacements [yarn](https://yarnpkg.com/), [pnpm](https://pnpm.io/), or [Bun](https://bun.sh/)?

bin/index.spec.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ const run = (args: string, ctrlcWrapper?: boolean) => {
5858
cwd: __dirname,
5959
env: {
6060
...process.env,
61+
// VS Code extension might allow colors, but this breaks assertions.
62+
// Force colors to be disabled to avoid that.
63+
FORCE_COLOR: '0',
6164
},
6265
});
6366

@@ -294,15 +297,6 @@ describe('--names', () => {
294297
expect(lines).toContainEqual(expect.stringContaining('[bar] bar'));
295298
});
296299
});
297-
298-
it('is split using --name-separator arg', async () => {
299-
const lines = await run(
300-
'--names "foo|bar" --name-separator "|" "echo foo" "echo bar"',
301-
).getLogLines();
302-
303-
expect(lines).toContainEqual(expect.stringContaining('[foo] foo'));
304-
expect(lines).toContainEqual(expect.stringContaining('[bar] bar'));
305-
});
306300
});
307301

308302
describe('specifies custom prefix', () => {

bin/index.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import process from 'node:process';
44
import yargs from 'yargs';
55
import { hideBin } from 'yargs/helpers';
66

7-
import { assertDeprecated } from '../lib/assert.js';
87
import * as defaults from '../lib/defaults.js';
98
import { concurrently } from '../lib/index.js';
109
import { castArray, splitOutsideParens } from '../lib/utils.js';
@@ -47,12 +46,6 @@ const program = yargs(hideBin(process.argv))
4746
'Example names: "main,browser,server"',
4847
type: 'string',
4948
},
50-
'name-separator': {
51-
describe:
52-
'The character to split <names> on. Example usage:\n' +
53-
'-n "styles|scripts|server" --name-separator "|"',
54-
default: defaults.nameSeparator,
55-
},
5649
success: {
5750
alias: 's',
5851
describe:
@@ -97,6 +90,11 @@ const program = yargs(hideBin(process.argv))
9790
type: 'boolean',
9891
default: defaults.timings,
9992
},
93+
shell: {
94+
describe:
95+
'Shell to run commands with. Defaults to cmd.exe on Windows and /bin/sh elsewhere.',
96+
type: 'string',
97+
},
10098
'passthrough-arguments': {
10199
alias: 'P',
102100
describe:
@@ -210,7 +208,7 @@ const program = yargs(hideBin(process.argv))
210208
},
211209
})
212210
.group(
213-
['m', 'n', 'name-separator', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'P', 'teardown'],
211+
['m', 'n', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'shell', 'P', 'teardown'],
214212
'General',
215213
)
216214
.group(['p', 'c', 'l', 't', 'pad-prefix'], 'Prefix styling')
@@ -220,14 +218,8 @@ const program = yargs(hideBin(process.argv))
220218
.epilogue(epilogue);
221219

222220
const args = program.parseSync();
223-
assertDeprecated(
224-
args.nameSeparator === defaults.nameSeparator,
225-
'name-separator',
226-
'Use commas as name separators instead.',
227-
);
228221

229-
// Get names of commands by the specified separator
230-
const names = (args.names || '').split(args.nameSeparator);
222+
const names = (args.names || '').split(',');
231223

232224
const additionalArguments = castArray(args['--'] ?? []).map(String);
233225
const commands = args.passthroughArguments ? args._ : args._.concat(additionalArguments);
@@ -266,6 +258,7 @@ concurrently(
266258
successCondition: args.success,
267259
timestampFormat: args.timestampFormat,
268260
timings: args.timings,
261+
shell: args.shell,
269262
teardown: args.teardown,
270263
additionalArguments: args.passthroughArguments ? additionalArguments : undefined,
271264
},

docs/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Concurrently Documentation
22

3+
## General
4+
5+
These articles apply when using either concurrently's CLI or API:
6+
7+
- [Shell Resolution](./shell-resolution.md)
8+
39
## CLI
410

511
These articles cover using concurrently through CLI:

docs/cli/prefixing.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ $ concurrently --prefix '{index}-{pid}' 'echo Hello there' 'echo General Kenobi!
5656

5757
## Prefix Colors
5858

59-
By default, there are no colors applied to concurrently prefixes, and they just use whatever the terminal's defaults are.
59+
By default, concurrently automatically assigns colors to each command's prefix, cycling through `cyan`, `magenta`, `green`, `yellow`, and `blue` (the same palette and order used by turborepo).
6060

6161
This can be changed by using the `--prefix-colors`/`-c` flag, which takes a comma-separated list of colors to use.<br/>
62-
The available values are color names (e.g. `green`, `magenta`, `gray`, etc), a hex value (such as `#23de43`), or `auto`, to automatically select a color.
62+
The available values are color names (e.g. `green`, `magenta`, `gray`, etc), a hex value (such as `#23de43`), `auto` to automatically select a color, or `reset` to disable coloring.
6363

6464
```bash
6565
$ concurrently -c red,blue 'echo Hello there' 'echo General Kenobi!'
@@ -146,6 +146,18 @@ $ concurrently -c 'rgb(255,136,0).bold,black.bgRgb(100,100,255)' 'echo Orange' '
146146
$ concurrently -c 'ansi256(199),ansi256(50).bgAnsi256(17)' 'echo Pink' 'echo Cyan on blue'
147147
```
148148

149+
### Scoping the Color to Part of a Template
150+
151+
By default, the entire prefix is colored. When using a template, you can restrict coloring to a specific region by wrapping it with the `{color}` and `{/color}` markers — anything outside the markers is rendered without color.
152+
153+
```bash
154+
$ concurrently -c red,blue --prefix '[{color}{name}{/color}] {pid}' --names one,two 'echo Hello there' 'echo General Kenobi!'
155+
```
156+
157+
In the example above, only `one` and `two` are colored — the surrounding brackets and the PID stay in the terminal's default color.
158+
159+
If only one of the markers is present, the missing side is implicit: an `{color}` without a matching `{/color}` colors everything from the opener to the end of the prefix, and a `{/color}` without a preceding `{color}` colors everything from the start of the prefix up to the closer. A template with neither marker is colored in full, matching the previous behavior.
160+
149161
## Prefix Length
150162

151163
When using the `command` prefix style, it's possible that it'll be too long.<br/>

docs/shell-resolution.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Shell Resolution
2+
3+
Each command runs inside a shell, not as a bare executable.
4+
By default, concurrently uses `cmd.exe` on Windows and `/bin/sh` elsewhere.
5+
6+
## Using a different shell
7+
8+
If the default shell isn't suitable, it's possible to instruct concurrently to use a specific shell in a few ways.
9+
10+
This is useful, for example, to use Unix-style syntax (for example `BROWSER=none npm start`) on Windows, if you set concurrently shell to e.g. Git Bash.
11+
12+
### Via explicit override
13+
14+
An explicit shell override takes precedence over every other configuration.
15+
To do that, pass the `--shell` flag to the CLI:
16+
17+
```bash
18+
concurrently --shell "C:\Program Files\Git\bin\bash.exe" "echo Hello world | xargs -n 1 echo"
19+
```
20+
21+
Or via the API:
22+
23+
```js
24+
concurrently(['echo Hello world | xargs -n 1 echo'], {
25+
shell: 'C:\\Program Files\\Git\\bin\\bash.exe',
26+
});
27+
```
28+
29+
### Via npm/pnpm/yarn v1
30+
31+
When using npm, pnpm or yarn v1 to run concurrently via a `package.json` script, the
32+
[`script-shell` configuration](https://docs.npmjs.com/cli/v6/using-npm/config#script-shell) is inherited and used to spawn commands.
33+
34+
```bash
35+
npm config set script-shell /bin/bash
36+
npm dev # Runs the dev script on bash. Concurrently will also run commands using bash.
37+
```
38+
39+
## Supported shells
40+
41+
If you've specified a different shell, concurrently detects its kind and spawns commands
42+
using the right syntax for that shell.
43+
44+
The following shell types are supported:
45+
46+
- Windows `cmd.exe`
47+
- Powershell
48+
- Any POSIX compliant shells (bash, zsh, dash, etc)

lib/concurrently.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ import { FlowController } from './flow-control/flow-controller.js';
2222
import { Logger } from './logger.js';
2323
import { OutputWriter } from './output-writer.js';
2424
import { PrefixColorSelector } from './prefix-color-selector.js';
25-
import { getSpawnOpts, spawn } from './spawn.js';
25+
import { createSpawn, getSpawnOpts } from './spawn.js';
2626
import { castArray } from './utils.js';
2727

2828
const defaults: ConcurrentlyOptions = {
29-
spawn,
29+
spawn: createSpawn(),
3030
kill: treeKill,
3131
raw: false,
3232
controllers: [],

lib/defaults.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ export const maxProcesses = 0;
2121
*/
2222
export const hide = '';
2323

24-
/**
25-
* The character to split <names> on.
26-
*/
27-
export const nameSeparator = ',';
28-
2924
/**
3025
* Which prefix style to use when logging processes output.
3126
*/
@@ -35,7 +30,7 @@ export const prefix = '';
3530
* Default prefix color.
3631
* @see https://www.npmjs.com/package/chalk
3732
*/
38-
export const prefixColors = 'reset';
33+
export const prefixColors = 'auto';
3934

4035
/**
4136
* How many bytes we'll show on the command prefix.

lib/flow-control/logger-padding.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ it('sets prefix length to the longest prefix of all commands', () => {
4242
expect(logger.setPrefixLength).toHaveBeenCalledWith(6);
4343
});
4444

45+
it('ignores color markers when measuring prefix length', () => {
46+
logger.getPrefixContent
47+
.mockReturnValueOnce({ type: 'template', value: '{color}foo{/color}' })
48+
.mockReturnValueOnce({ type: 'template', value: '{color}abcd{/color}' });
49+
50+
controller.handle(commands);
51+
expect(logger.setPrefixLength).toHaveBeenCalledWith(4);
52+
});
53+
4554
it('does not shorten the prefix length', () => {
4655
logger.getPrefixContent
4756
.mockReturnValueOnce({ type: 'default', value: '100' })

lib/flow-control/logger-padding.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { Command } from '../command.js';
2-
import { Logger } from '../logger.js';
2+
import { COLOR_MARKER_RE, Logger } from '../logger.js';
33
import { FlowController } from './flow-controller.js';
44

5+
function visibleLength(value: string | undefined): number {
6+
return value ? value.replace(COLOR_MARKER_RE, '').length : 0;
7+
}
8+
59
export class LoggerPadding implements FlowController {
610
private readonly logger: Logger;
711

@@ -14,7 +18,7 @@ export class LoggerPadding implements FlowController {
1418
// Compute the prefix length now, which works for all styles but those with a PID.
1519
let length = commands.reduce((length, command) => {
1620
const content = this.logger.getPrefixContent(command);
17-
return Math.max(length, content?.value.length || 0);
21+
return Math.max(length, visibleLength(content?.value));
1822
}, 0);
1923
this.logger.setPrefixLength(length);
2024

@@ -25,7 +29,7 @@ export class LoggerPadding implements FlowController {
2529
command.timer.subscribe((event) => {
2630
if (!event.endDate) {
2731
const content = this.logger.getPrefixContent(command);
28-
length = Math.max(length, content?.value.length || 0);
32+
length = Math.max(length, visibleLength(content?.value));
2933
this.logger.setPrefixLength(length);
3034
}
3135
}),

0 commit comments

Comments
 (0)