Skip to content

Commit

Permalink
Drop support for Node 12 (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed May 10, 2022
1 parent fa9cc05 commit a09cbc0
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 46 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Expand Up @@ -10,21 +10,21 @@ jobs:
fail-fast: false
matrix:
node-version:
- 18
- 16
- 14
- 12
os:
- ubuntu-latest
- macos-latest
# - windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
- uses: codecov/codecov-action@v2
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 16
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 18
with:
fail_ci_if_error: true
9 changes: 2 additions & 7 deletions index.d.ts
Expand Up @@ -4,6 +4,7 @@ import {Stream, Readable as ReadableStream} from 'node:stream';

export type StdioOption =
| 'pipe'
| 'overlapped'
| 'ipc'
| 'ignore'
| 'inherit'
Expand Down Expand Up @@ -33,8 +34,6 @@ export interface CommonOptions<EncodingType> {
/**
Preferred path to find locally installed binaries in (use with `preferLocal`).
Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above.
@default process.cwd()
*/
readonly localDir?: string | URL;
Expand Down Expand Up @@ -113,8 +112,6 @@ export interface CommonOptions<EncodingType> {
/**
Current working directory of the child process.
Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above.
@default process.cwd()
*/
readonly cwd?: string | URL;
Expand All @@ -136,15 +133,13 @@ export interface CommonOptions<EncodingType> {
@default 'pipe'
*/
readonly stdio?: 'pipe' | 'ignore' | 'inherit' | readonly StdioOption[];
readonly stdio?: 'pipe' | 'overlapped' | 'ignore' | 'inherit' | readonly StdioOption[];

/**
Specify the kind of serialization used for sending messages between processes when using the `stdio: 'ipc'` option or `execaNode()`:
- `json`: Uses `JSON.stringify()` and `JSON.parse()`.
- `advanced`: Uses [`v8.serialize()`](https://nodejs.org/api/v8.html#v8_v8_serialize_value)
Requires Node.js `13.2.0` or later.
[More info.](https://nodejs.org/api/child_process.html#child_process_advanced_serialization)
@default 'json'
Expand Down
6 changes: 5 additions & 1 deletion index.test-d.ts
Expand Up @@ -97,20 +97,23 @@ execa('unicorns', {input: ''});
execa('unicorns', {input: Buffer.from('')});
execa('unicorns', {input: process.stdin});
execa('unicorns', {stdin: 'pipe'});
execa('unicorns', {stdin: 'overlapped'});
execa('unicorns', {stdin: 'ipc'});
execa('unicorns', {stdin: 'ignore'});
execa('unicorns', {stdin: 'inherit'});
execa('unicorns', {stdin: process.stdin});
execa('unicorns', {stdin: 1});
execa('unicorns', {stdin: undefined});
execa('unicorns', {stdout: 'pipe'});
execa('unicorns', {stdout: 'overlapped'});
execa('unicorns', {stdout: 'ipc'});
execa('unicorns', {stdout: 'ignore'});
execa('unicorns', {stdout: 'inherit'});
execa('unicorns', {stdout: process.stdout});
execa('unicorns', {stdout: 1});
execa('unicorns', {stdout: undefined});
execa('unicorns', {stderr: 'pipe'});
execa('unicorns', {stderr: 'overlapped'});
execa('unicorns', {stderr: 'ipc'});
execa('unicorns', {stderr: 'ignore'});
execa('unicorns', {stderr: 'inherit'});
Expand All @@ -127,10 +130,11 @@ execa('unicorns', {cwd: new URL('file:///test')});
execa('unicorns', {env: {PATH: ''}});
execa('unicorns', {argv0: ''});
execa('unicorns', {stdio: 'pipe'});
execa('unicorns', {stdio: 'overlapped'});
execa('unicorns', {stdio: 'ignore'});
execa('unicorns', {stdio: 'inherit'});
execa('unicorns', {
stdio: ['pipe', 'ipc', 'ignore', 'inherit', process.stdin, 1, undefined],
stdio: ['pipe', 'overlapped', 'ipc', 'ignore', 'inherit', process.stdin, 1, undefined],
});
execa('unicorns', {serialization: 'advanced'});
execa('unicorns', {detached: true});
Expand Down
4 changes: 1 addition & 3 deletions lib/stream.js
Expand Up @@ -4,9 +4,7 @@ import mergeStream from 'merge-stream';

// `input` option
export const handleInput = (spawned, input) => {
// Checking for stdin is workaround for https://github.com/nodejs/node/issues/26852
// @todo remove `|| spawned.stdin === undefined` once we drop support for Node.js <=12.2.0
if (input === undefined || spawned.stdin === undefined) {
if (input === undefined) {
return;
}

Expand Down
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -13,7 +13,7 @@
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": "^14.18.0 || ^16.14.0 || >=18.0.0"
},
"scripts": {
"test": "xo && c8 ava && tsd"
Expand Down Expand Up @@ -58,7 +58,6 @@
"get-node": "^12.0.0",
"is-running": "^2.1.0",
"p-event": "^5.0.1",
"semver": "^7.3.5",
"tempfile": "^4.0.0",
"tsd": "^0.19.1",
"xo": "^0.48.0"
Expand Down
6 changes: 0 additions & 6 deletions readme.md
Expand Up @@ -361,8 +361,6 @@ Default: `process.cwd()`

Preferred path to find locally installed binaries in (use with `preferLocal`).

Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above.

#### execPath

Type: `string`\
Expand Down Expand Up @@ -452,8 +450,6 @@ Default: `process.cwd()`

Current working directory of the child process.

Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above.

#### env

Type: `object`\
Expand Down Expand Up @@ -483,8 +479,6 @@ Specify the kind of serialization used for sending messages between processes wh
- `json`: Uses `JSON.stringify()` and `JSON.parse()`.
- `advanced`: Uses [`v8.serialize()`](https://nodejs.org/api/v8.html#v8_v8_serialize_value)

Requires Node.js `13.2.0` or later.

[More info.](https://nodejs.org/api/child_process.html#child_process_advanced_serialization)

#### detached
Expand Down
5 changes: 1 addition & 4 deletions test/error.js
Expand Up @@ -79,10 +79,7 @@ test('error.shortMessage does not contain stdout/stderr', async t => {

test('Original error.message is kept', async t => {
const {originalMessage} = await t.throwsAsync(execa('noop.js', {cwd: 1}));
// On Node >=14.18.0, the error message is
// `The "options.cwd" property must be of type string or an instance of Buffer or URL. Received type number (1)`
t.true(originalMessage.startsWith('The "options.cwd" property must be of type string'));
t.true(originalMessage.includes('. Received type number'));
t.true(originalMessage.startsWith('The "options.cwd" property must be of type string or an instance of Buffer or URL. Received type number'));
});

test('failed is false on success', async t => {
Expand Down
1 change: 0 additions & 1 deletion test/override-promise.js
Expand Up @@ -3,7 +3,6 @@ import process from 'node:process';
import {fileURLToPath} from 'node:url';
import test from 'ava';
// The helper module overrides Promise on import so has to be imported before `execa`.
// Can't use top-level await (TLA) + `import(…)` since Node.js 12 doesn't support TLA.
import {restorePromise} from './helpers/override-promise.js';
// eslint-disable-next-line import/order
import {execa} from '../index.js';
Expand Down
31 changes: 13 additions & 18 deletions test/test.js
Expand Up @@ -4,7 +4,6 @@ import {fileURLToPath, pathToFileURL} from 'node:url';
import test from 'ava';
import isRunning from 'is-running';
import getNode from 'get-node';
import semver from 'semver';
import {execa, execaSync} from '../index.js';

process.env.PATH = fileURLToPath(new URL('fixtures', import.meta.url)) + path.delimiter + process.env.PATH;
Expand Down Expand Up @@ -167,9 +166,7 @@ if (process.platform !== 'win32') {
});

test('execa() rejects with correct error and doesn\'t throw if running non-executable with input', async t => {
// On Node <12.6.0, `EACCESS` is emitted on `childProcess`.
// On Node >=12.6.0, `EPIPE` is emitted on `childProcess.stdin`.
await t.throwsAsync(execa('non-executable.js', {input: 'Hey!'}), {message: /EACCES|EPIPE/});
await t.throwsAsync(execa('non-executable.js', {input: 'Hey!'}), {message: /EACCES/});
});
}

Expand Down Expand Up @@ -207,21 +204,19 @@ test('can use `options.cwd` as a string', async t => {
t.is(path.toNamespacedPath(stdout), path.toNamespacedPath(cwd));
});

if (semver.satisfies(process.version, '^14.18.0 || >=16.4.0')) {
test('localDir option can be a URL', async t => {
const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH';
const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: pathToFileURL('/test')});
const envPaths = stdout.split(path.delimiter);
t.true(envPaths.some(envPath => envPath.endsWith('.bin')));
});
test('localDir option can be a URL', async t => {
const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH';
const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: pathToFileURL('/test')});
const envPaths = stdout.split(path.delimiter);
t.true(envPaths.some(envPath => envPath.endsWith('.bin')));
});

test('can use `options.cwd` as a URL', async t => {
const cwd = '/';
const cwdUrl = pathToFileURL(cwd);
const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl});
t.is(path.toNamespacedPath(stdout), path.toNamespacedPath(cwd));
});
}
test('can use `options.cwd` as a URL', async t => {
const cwd = '/';
const cwdUrl = pathToFileURL(cwd);
const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl});
t.is(path.toNamespacedPath(stdout), path.toNamespacedPath(cwd));
});

test('can use `options.shell: true`', async t => {
const {stdout} = await execa('node test/fixtures/noop.js foo', {shell: true});
Expand Down

0 comments on commit a09cbc0

Please sign in to comment.