Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: open-cli-tools/concurrently
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v7.6.0
Choose a base ref
...
head repository: open-cli-tools/concurrently
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v8.0.0
Choose a head ref
  • 16 commits
  • 27 files changed
  • 5 contributors

Commits on Nov 24, 2022

  1. Fixed broken link in the readme (#390)

    * Fixed broken link in the readme
    
    Link to "task automation with npm" pointed to 404, now pointing to an archive of James` post with the same content.
    
    * Changed link to archive.org mirror
    abstractpoint authored Nov 24, 2022

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    LastDragon-ru Aleksei Lebedev
    Copy the full SHA
    2c98a91 View commit details

Commits on Nov 26, 2022

  1. Drop support for Node.js v12 & add support for Node.js v18 (#342)

    * Drop support for Node.js v12 & add support for Node.js v18
    
    * Minor dependencies updates & update lint-staged to v13
    
    * Replace depreacted 'rmdirSync' & use top-level-await in sleep fixture
    
    * Downgrade @types/node to lowest supported Node.js version (14)
    
    * Update package-lock.json
    
    * Clean-up tsconfig
    
    - allowJs / noImplicitAny are default values
    - Align with https://github.com/tsconfig/bases/blob/main/bases/node14.json
    
    * Simplify "engines" definition
    
    * Test against Node.js v19 (current)
    
    * Update lint-staged
    paescuj authored Nov 26, 2022

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    LastDragon-ru Aleksei Lebedev
    Copy the full SHA
    8e7af9d View commit details
  2. Update dependencies (#391)

    paescuj authored Nov 26, 2022
    Copy the full SHA
    d41e78d View commit details

Commits on Nov 27, 2022

  1. Revert "Simplify "engines" definition" (#392)

    This reverts commit 6bb5443.
    paescuj authored Nov 27, 2022
    Copy the full SHA
    ed3c18f View commit details

Commits on Dec 28, 2022

  1. Add release workflow (#387)

    paescuj authored Dec 28, 2022
    Copy the full SHA
    a6fc612 View commit details
  2. Update CI badge

    paescuj authored Dec 28, 2022
    Copy the full SHA
    633b1cb View commit details

Commits on Dec 29, 2022

  1. Switch to pnpm (#354)

    paescuj authored Dec 29, 2022
    Copy the full SHA
    ebc52c4 View commit details
  2. Clean-up after switch to pnpm

    paescuj committed Dec 29, 2022
    Copy the full SHA
    dbad224 View commit details

Commits on Jan 3, 2023

  1. Switch from 'simple-git-hooks' to 'husky'

    To be able to get rid of the workaround introduced in dbad224
    paescuj committed Jan 3, 2023
    Copy the full SHA
    08a7d46 View commit details
  2. Copy the full SHA
    ecc9d3c View commit details
  3. Copy the full SHA
    08c971d View commit details
  4. Update dependencies (#400)

    paescuj authored Jan 3, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    ramsey Ben Ramsey
    Copy the full SHA
    d4c3b21 View commit details

Commits on Jan 4, 2023

  1. Verified

    This commit was signed with the committer’s verified signature.
    ramsey Ben Ramsey
    Copy the full SHA
    388a9df View commit details

Commits on Feb 26, 2023

  1. Verified

    This commit was signed with the committer’s verified signature.
    ramsey Ben Ramsey
    Copy the full SHA
    91c2448 View commit details

Commits on Mar 28, 2023

  1. Copy the full SHA
    a469388 View commit details
  2. 8.0.0

    gustavohenke committed Mar 28, 2023
    2
    Copy the full SHA
    5115c43 View commit details
14 changes: 0 additions & 14 deletions .github/actions/setup-npm-cache/action.yml

This file was deleted.

23 changes: 23 additions & 0 deletions .github/actions/setup-pnpm/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See also https://github.com/actions/cache/blob/main/examples.md#node---npm

name: Setup pnpm
runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7

- name: Get pnpm store directory
id: pnpm-cache-dir
shell: bash
run: echo "dir=$(pnpm store path)" >> $GITHUB_OUTPUT

- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
8 changes: 4 additions & 4 deletions .github/workflows/lint-format.yml
Original file line number Diff line number Diff line change
@@ -25,11 +25,11 @@ jobs:
with:
node-version: 16

- name: Setup NPM cache
uses: ./.github/actions/setup-npm-cache
- name: Setup pnpm
uses: ./.github/actions/setup-pnpm

- name: Install dependencies
run: npm ci && npm install --global concurrently
run: pnpm install && pnpm add --global concurrently

- name: Lint & Format
run: concurrently --prefix none --group "npm:lint" "npm:format"
run: concurrently --prefix none --group "pnpm:lint" "pnpm:format"
43 changes: 43 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Release

on:
push:
tags:
- 'v*'

jobs:
gh-release:
name: Create GitHub Release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release create "$GITHUB_REF_NAME" --generate-notes

publish-npm:
name: Publish to NPM
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org

- name: Setup pnpm
uses: ./.github/actions/setup-pnpm

- name: Install dependencies
run: pnpm install

- name: Publish to NPM
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: pnpm publish
12 changes: 6 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -28,10 +28,10 @@ jobs:
fail-fast: false
matrix:
node:
- 12
- 14
- 16
- 17
- 18
- 19
os:
- name: Ubuntu
version: ubuntu-latest
@@ -48,14 +48,14 @@ jobs:
with:
node-version: ${{ matrix.node }}

- name: Setup NPM cache
uses: ./.github/actions/setup-npm-cache
- name: Setup pnpm
uses: ./.github/actions/setup-pnpm

- name: Install dependencies
run: npm ci && npm install --global concurrently
run: pnpm install && pnpm add --global concurrently

- name: Build & Test
run: concurrently --prefix none --group "npm:build" "npm:test"
run: concurrently --prefix none --group "pnpm:build" "pnpm:test"

- name: Submit coverage
uses: coverallsapp/github-action@master
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

./node_modules/.bin/lint-staged
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dist
coverage
pacakge-lock.json
pnpm-lock.yaml
10 changes: 3 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -10,19 +10,15 @@ updated.

## Code Format & Linting

Code format and lint checks are performed locally when committing to ensure the changes align with the configured rules of this repository. This happens with the help of the tools [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) and [lint-staged](https://github.com/okonet/lint-staged) which are automatically installed and configured on `npm install` (no further steps required).
Code format and lint checks are performed locally when committing to ensure the changes align with the configured rules of this repository. This happens with the help of the tools [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) and [lint-staged](https://github.com/okonet/lint-staged) which are automatically installed and configured on `pnpm install` (no further steps required).

In case of problems, a corresponding message is displayed in your terminal.
Please fix them and then run the commit command again.

## Test

Tests can be run with the command:
Tests can be executed with the following command:

```bash
npm test
pnpm test
```

## Release

Use [np](https://www.npmjs.com/package/np) to create a new release.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
[![Latest Release](https://img.shields.io/github/v/release/open-cli-tools/concurrently?label=Release)](https://github.com/open-cli-tools/concurrently/releases)
[![License](https://img.shields.io/github/license/open-cli-tools/concurrently?label=License)](https://github.com/open-cli-tools/concurrently/blob/main/LICENSE)
[![Weekly Downloads on NPM](https://img.shields.io/npm/dw/concurrently?label=Downloads&logo=npm)](https://www.npmjs.com/package/concurrently)
[![CI Status](https://img.shields.io/github/workflow/status/open-cli-tools/concurrently/Test?label=CI&logo=github)](https://github.com/open-cli-tools/concurrently/actions/workflows/test.yml)
[![CI Status](https://img.shields.io/github/actions/workflow/status/open-cli-tools/concurrently/test.yml?label=CI&logo=github)](https://github.com/open-cli-tools/concurrently/actions/workflows/test.yml)
[![Coverage Status](https://img.shields.io/coveralls/github/open-cli-tools/concurrently/main?label=Coverage&logo=coveralls)](https://coveralls.io/github/open-cli-tools/concurrently?branch=main)

Run multiple commands concurrently.
@@ -25,7 +25,7 @@ Like `npm run watch-js & npm run watch-less` but better.

## Why

I like [task automation with npm](https://github.com/substack/blog/blob/master/npm_run.markdown)
I like [task automation with npm](https://web.archive.org/web/20220531064025/https://github.com/substack/blog/blob/master/npm_run.markdown)
but the usual way to run multiple commands concurrently is
`npm run watch-js & npm run watch-css`. That's fine but it's hard to keep
on track of different outputs. Also if one process fails, others still keep running
@@ -45,12 +45,12 @@ tired of opening terminals and made **concurrently**.

**concurrently** can be installed in the global scope (if you'd like to have it available and use it on the whole system) or locally for a specific package (for example if you'd like to use it in the `scripts` section of your package):

| | npm | Yarn | pnpm |
| ----------- | ----------------------- | ------------------------------ | -------------------------- |
| **Global** | `npm i -g concurrently` | `yarn global add concurrently` | `pnpm add -g concurrently` |
| **Local**\* | `npm i concurrently -D` | `yarn add concurrently -D` | `pnpm add -D concurrently` |
| | npm | Yarn | pnpm | Bun |
| ----------- | ----------------------- | ------------------------------ | -------------------------- | ------------------------- |
| **Global** | `npm i -g concurrently` | `yarn global add concurrently` | `pnpm add -g concurrently` | `bun add -g concurrently` |
| **Local**\* | `npm i -D concurrently` | `yarn add -D concurrently` | `pnpm add -D concurrently` | `bun add -d concurrently` |

<sub>\* It's recommended to add **concurrently** as `devDependencies` as it's usually used for developing purposes. Please change this flag if this doesn't apply in your case.</sub>
<sub>\* It's recommended to add **concurrently** to `devDependencies` as it's usually used for developing purposes. Please adjust the command if this doesn't apply in your case.</sub>

## Usage

@@ -219,6 +219,8 @@ Killing other processes
-k, --kill-others Kill other processes if one exits or dies.[boolean]
--kill-others-on-fail Kill other processes if one exits with non zero
status code. [boolean]
--kill-signal Signal to send to other processes if one exits or dies.
(SIGTERM/SIGKILL, defaults to SIGTERM) [string]
Restarting
--restart-tries How many times a process that died should restart.
@@ -427,6 +429,6 @@ It contains the following properties:
So _null_ means the process didn't terminate normally. This will make **concurrently**
to return non-zero exit code too.

- Does this work with the npm-replacements [yarn](https://github.com/yarnpkg/yarn) or [pnpm](https://pnpm.js.org/)?
- Does this work with the npm-replacements [yarn](https://github.com/yarnpkg/yarn), [pnpm](https://pnpm.js.org/), or [Bun](https://bun.sh/)?

Yes! In all examples above, you may replace "`npm`" with "`yarn`" or "`pnpm`".
Yes! In all examples above, you may replace "`npm`" with "`yarn`", "`pnpm`", or "`bun`".
2 changes: 1 addition & 1 deletion bin/concurrently.spec.ts
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ beforeAll(async () => {
afterAll(() => {
// Remove the temporary directory where 'concurrently' was stored
if (tmpDir) {
fs.rmdirSync(tmpDir, { recursive: true });
fs.rmSync(tmpDir, { recursive: true });
}
});

10 changes: 9 additions & 1 deletion bin/concurrently.ts
Original file line number Diff line number Diff line change
@@ -110,6 +110,13 @@ const args = yargs(argsBeforeSep)
describe: 'Kill other processes if one exits with non zero status code.',
type: 'boolean',
},
'kill-signal': {
alias: 'ks',
describe:
'Signal to send to other processes if one exits or dies. (SIGTERM/SIGKILL, defaults to SIGTERM)',
type: 'string',
default: defaults.killSignal,
},

// Prefix
prefix: {
@@ -185,7 +192,7 @@ const args = yargs(argsBeforeSep)
)
.group(['p', 'c', 'l', 't'], 'Prefix styling')
.group(['i', 'default-input-target'], 'Input handling')
.group(['k', 'kill-others-on-fail'], 'Killing other processes')
.group(['k', 'kill-others-on-fail', 'kill-signal'], 'Killing other processes')
.group(['restart-tries', 'restart-after'], 'Restarting')
.epilogue(epilogue)
.parseSync();
@@ -208,6 +215,7 @@ concurrently(
: args.killOthersOnFail
? ['failure']
: [],
killSignal: args.killSignal,
maxProcesses: args.maxProcesses,
raw: args.raw,
hide: args.hide.split(','),
12 changes: 4 additions & 8 deletions bin/fixtures/sleep.mjs
Original file line number Diff line number Diff line change
@@ -7,14 +7,10 @@

/* eslint-disable no-console */

async function run(s) {
await new Promise((resolve) => setTimeout(resolve, s * 1000));
}

const s = process.argv[2];
if (!s || isNaN(s) || process.argv.length > 3) {
const seconds = process.argv[2];
if (!seconds || isNaN(seconds) || process.argv.length > 3) {
// Mimic behavior from native 'sleep' command
console.error(`usage: sleep seconds`);
console.error('usage: sleep seconds');
process.exit(1);
}
run(s);
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* While in local development, make sure you've run `npm run build` first.
* While in local development, make sure you've run `pnpm run build` first.
*/

// eslint-disable-next-line @typescript-eslint/no-var-requires
2 changes: 1 addition & 1 deletion index.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* While in local development, make sure you've run `npm run build` first.
* While in local development, make sure you've run `pnpm run build` first.
*/

import concurrently from './dist/src/index.js';
12,454 changes: 0 additions & 12,454 deletions package-lock.json

This file was deleted.

71 changes: 35 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "concurrently",
"version": "7.6.0",
"version": "8.0.0",
"description": "Run commands concurrently",
"main": "index.js",
"types": "dist/src/index.d.ts",
@@ -10,7 +10,7 @@
"conc": "./dist/bin/concurrently.js"
},
"engines": {
"node": "^12.20.0 || ^14.13.0 || >=16.0.0"
"node": "^14.13.0 || >=16.0.0"
},
"exports": {
".": {
@@ -26,12 +26,13 @@
"postbuild": "chmod +x dist/bin/concurrently.js",
"clean": "tsc --build --clean",
"format": "prettier --check '**/*.{json,y?(a)ml,md}'",
"format:fix": "npm run format -- --write",
"format:fix": "pnpm run format --write",
"lint": "eslint --ignore-path .gitignore --ext mjs,js,ts .",
"lint:fix": "npm run lint -- --fix",
"prepublishOnly": "npm run build",
"lint:fix": "pnpm run lint --fix",
"prepublishOnly": "safe-publish-latest && pnpm run build",
"report-coverage": "cat coverage/lcov.info | coveralls",
"test": "jest"
"test": "jest",
"prepare": "husky install"
},
"repository": {
"type": "git",
@@ -49,44 +50,45 @@
"author": "Kimmo Brunfeldt",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.0",
"date-fns": "^2.29.1",
"chalk": "^4.1.2",
"date-fns": "^2.29.3",
"lodash": "^4.17.21",
"rxjs": "^7.0.0",
"shell-quote": "^1.7.3",
"spawn-command": "^0.0.2-1",
"supports-color": "^8.1.0",
"rxjs": "^7.8.0",
"shell-quote": "^1.7.4",
"spawn-command": "0.0.2-1",
"supports-color": "^8.1.1",
"tree-kill": "^1.2.2",
"yargs": "^17.3.1"
"yargs": "^17.6.2"
},
"devDependencies": {
"@hirez_io/observer-spy": "^2.2.0",
"@swc/core": "^1.2.224",
"@swc/jest": "^0.2.21",
"@types/jest": "^28.1.8",
"@types/lodash": "^4.14.178",
"@types/node": "^16.11.47",
"@swc/core": "^1.3.24",
"@swc/jest": "^0.2.24",
"@types/jest": "^29.2.5",
"@types/lodash": "^4.14.191",
"@types/node": "^14.18.36",
"@types/shell-quote": "^1.7.1",
"@types/supports-color": "^8.1.1",
"@types/yargs": "^17.0.11",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"coveralls-next": "^4.1.2",
"@types/yargs": "^17.0.18",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"coveralls-next": "^4.2.0",
"ctrlc-wrapper": "^0.0.4",
"esbuild": "^0.15.1",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.5.0",
"esbuild": "^0.16.13",
"eslint": "^8.31.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.0.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-jest": "^27.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-simple-import-sort": "^8.0.0",
"jest": "^28.1.3",
"husky": "^8.0.3",
"jest": "^29.3.1",
"jest-create-mock-instance": "^2.0.0",
"lint-staged": "^12.4.1",
"prettier": "^2.6.2",
"simple-git-hooks": "^2.7.0",
"lint-staged": "^13.1.0",
"prettier": "^2.8.1",
"safe-publish-latest": "^2.0.0",
"string-argv": "^0.3.1",
"typescript": "~4.9.3"
"typescript": "~4.9.4"
},
"files": [
"dist",
@@ -96,11 +98,8 @@
"!**/*.spec.js",
"!**/*.spec.d.ts"
],
"simple-git-hooks": {
"pre-commit": "npx lint-staged"
},
"lint-staged": {
"*.m?{js,ts}": "eslint --fix",
"*.?(m){js,ts}": "eslint --fix",
"*.{json,y?(a)ml,md}": "prettier --write"
}
}
4,267 changes: 4,267 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/command-parser/expand-npm-shortcut.spec.ts
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ it('returns same command if no npm: prefix is present', () => {
expect(parser.parse(commandInfo)).toBe(commandInfo);
});

for (const npmCmd of ['npm', 'yarn', 'pnpm']) {
for (const npmCmd of ['npm', 'yarn', 'pnpm', 'bun']) {
describe(`with ${npmCmd}: prefix`, () => {
it(`expands to "${npmCmd} run <script> <args>"`, () => {
const commandInfo = createCommandInfo(`${npmCmd}:foo -- bar`, 'echo');
4 changes: 2 additions & 2 deletions src/command-parser/expand-npm-shortcut.ts
Original file line number Diff line number Diff line change
@@ -2,12 +2,12 @@ import { CommandInfo } from '../command';
import { CommandParser } from './command-parser';

/**
* Expands commands prefixed with `npm:`, `yarn:` or `pnpm:` into the full version `npm run <command>` and so on.
* Expands commands prefixed with `npm:`, `yarn:`, `pnpm:`, or `bun:` into the full version `npm run <command>` and so on.
*/
export class ExpandNpmShortcut implements CommandParser {
parse(commandInfo: CommandInfo) {
const [, npmCmd, cmdName, args] =
commandInfo.command.match(/^(npm|yarn|pnpm):(\S+)(.*)/) || [];
commandInfo.command.match(/^(npm|yarn|pnpm|bun):(\S+)(.*)/) || [];
if (!cmdName) {
return commandInfo;
}
2 changes: 1 addition & 1 deletion src/command-parser/expand-npm-wildcard.spec.ts
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ it('expands to nothing if no scripts exist in package.json', () => {
expect(parser.parse(createCommandInfo('npm run foo-*-baz qux'))).toEqual([]);
});

for (const npmCmd of ['npm', 'yarn', 'pnpm']) {
for (const npmCmd of ['npm', 'yarn', 'pnpm', 'bun']) {
describe(`with an ${npmCmd}: prefix`, () => {
it('expands to all scripts matching pattern', () => {
readPkg.mockReturnValue({
4 changes: 2 additions & 2 deletions src/command-parser/expand-npm-wildcard.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ import { CommandParser } from './command-parser';
const OMISSION = /\(!([^)]+)\)/;

/**
* Finds wildcards in npm/yarn/pnpm run commands and replaces them with all matching scripts in the
* Finds wildcards in npm/yarn/pnpm/bun run commands and replaces them with all matching scripts in the
* `package.json` file of the current directory.
*/
export class ExpandNpmWildcard implements CommandParser {
@@ -26,7 +26,7 @@ export class ExpandNpmWildcard implements CommandParser {

parse(commandInfo: CommandInfo) {
const [, npmCmd, cmdName, args] =
commandInfo.command.match(/(npm|yarn|pnpm) run (\S+)([^&]*)/) || [];
commandInfo.command.match(/(npm|yarn|pnpm|bun) run (\S+)([^&]*)/) || [];
const wildcardPosition = (cmdName || '').indexOf('*');

// If the regex didn't match an npm script, or it has no wildcard,
5 changes: 5 additions & 0 deletions src/concurrently.ts
Original file line number Diff line number Diff line change
@@ -110,6 +110,11 @@ export type ConcurrentlyOptions = {
*/
kill: KillProcess;

/**
* Signal to send to killed processes.
*/
killSignal?: string;

/**
* List of additional arguments passed that will get replaced in each command.
* If not defined, no argument replacing will happen.
7 changes: 7 additions & 0 deletions src/defaults.ts
Original file line number Diff line number Diff line change
@@ -80,3 +80,10 @@ export const timings = false;
* Passthrough additional arguments to commands (accessible via placeholders) instead of treating them as commands.
*/
export const passthroughArguments = false;

/**
* Signal to send to other processes if one exits or dies.
*
* Defaults to OS specific signal. (SIGTERM on Linux/MacOS)
*/
export const killSignal: string | undefined = undefined;
29 changes: 26 additions & 3 deletions src/flow-control/kill-others.spec.ts
Original file line number Diff line number Diff line change
@@ -19,10 +19,11 @@ beforeEach(() => {
logger = createMockInstance(Logger);
});

const createWithConditions = (conditions: ProcessCloseCondition[]) =>
const createWithConditions = (conditions: ProcessCloseCondition[], killSignal?: string) =>
new KillOthers({
logger,
conditions,
killSignal,
});

it('returns same commands', () => {
@@ -48,7 +49,18 @@ it('kills other killable processes on success', () => {
expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
expect(commands[0].kill).not.toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalledWith(undefined);
});

it('kills other killable processes on success, with specified signal', () => {
createWithConditions(['success'], 'SIGKILL').handle(commands);
commands[1].isKillable = true;
commands[0].close.next(createFakeCloseEvent({ exitCode: 0 }));

expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGKILL to other processes..');
expect(commands[0].kill).not.toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalledWith('SIGKILL');
});

it('does nothing if called without conditions', () => {
@@ -69,7 +81,18 @@ it('kills other killable processes on failure', () => {
expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
expect(commands[0].kill).not.toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalledWith(undefined);
});

it('kills other killable processes on failure, with specified signal', () => {
createWithConditions(['failure'], 'SIGKILL').handle(commands);
commands[1].isKillable = true;
commands[0].close.next(createFakeCloseEvent({ exitCode: 1 }));

expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGKILL to other processes..');
expect(commands[0].kill).not.toHaveBeenCalled();
expect(commands[1].kill).toHaveBeenCalledWith('SIGKILL');
});

it('does not try to kill processes already dead', () => {
10 changes: 8 additions & 2 deletions src/flow-control/kill-others.ts
Original file line number Diff line number Diff line change
@@ -13,16 +13,20 @@ export type ProcessCloseCondition = 'failure' | 'success';
export class KillOthers implements FlowController {
private readonly logger: Logger;
private readonly conditions: ProcessCloseCondition[];
private readonly killSignal: string | undefined;

constructor({
logger,
conditions,
killSignal,
}: {
logger: Logger;
conditions: ProcessCloseCondition | ProcessCloseCondition[];
killSignal: string | undefined;
}) {
this.logger = logger;
this.conditions = _.castArray(conditions);
this.killSignal = killSignal;
}

handle(commands: Command[]) {
@@ -47,8 +51,10 @@ export class KillOthers implements FlowController {
closeState.subscribe(() => {
const killableCommands = commands.filter((command) => Command.canKill(command));
if (killableCommands.length) {
this.logger.logGlobalEvent('Sending SIGTERM to other processes..');
killableCommands.forEach((command) => command.kill());
this.logger.logGlobalEvent(
`Sending ${this.killSignal || 'SIGTERM'} to other processes..`
);
killableCommands.forEach((command) => command.kill(this.killSignal));
}
})
);
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -131,6 +131,7 @@ export default (
new KillOthers({
logger,
conditions: options.killOthers || [],
killSignal: options.killSignal,
}),
new LogTimings({
logger: options.timings ? logger : undefined,
8 changes: 4 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
"target": "ES2019",
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "node",
"noImplicitAny": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"allowJs": false
"forceConsistentCasingInFileNames": true
},
"include": ["./bin", "./declarations", "./src"]
}