Skip to content

Commit

Permalink
feat: always include code/signal in output
Browse files Browse the repository at this point in the history
  • Loading branch information
jedwards1211 committed May 8, 2020
1 parent cc8f6b3 commit 507e539
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 45 deletions.
19 changes: 8 additions & 11 deletions index.d.ts
Expand Up @@ -6,29 +6,26 @@ import {
ForkOptions,
} from 'child_process'

interface Output {
export interface Output {
stdout?: string | Buffer | null | undefined
stderr?: string | Buffer | null | undefined
code?: number | null
signal?: string | null
}

interface ExitReason {
code?: number
signal?: string
}

type ErrorWithOutput = Error & Output & ExitReason
export type ErrorWithOutput = Error & Output

type ChildProcessPromise = ChildProcess & Promise<Output>
export type ChildProcessPromise = ChildProcess & Promise<Output>

interface PromisifyChildProcessOptions {
export interface PromisifyChildProcessOptions {
encoding?: string
killSignal?: string
maxBuffer?: number
}

type PromisifySpawnOptions = SpawnOptions & PromisifyChildProcessOptions
export type PromisifySpawnOptions = SpawnOptions & PromisifyChildProcessOptions

type PromisifyForkOptions = ForkOptions & PromisifyChildProcessOptions
export type PromisifyForkOptions = ForkOptions & PromisifyChildProcessOptions

export function promisifyChildProcess(
child: ChildProcess,
Expand Down
26 changes: 14 additions & 12 deletions src/index.js
Expand Up @@ -4,17 +4,19 @@ import type { ChildProcess } from 'child_process'
const child_process = require('child_process')

export type ChildProcessOutput = {
stdout: ?(string | Buffer),
stderr: ?(string | Buffer),
}

export type ErrorWithOutput = Error & {
stdout?: ?(string | Buffer),
stderr?: ?(string | Buffer),
code?: ?number,
signal?: ?string,
code?: number | null,
signal?: string | null,
}

export interface ExitReason {
code?: number | null;
signal?: string | null;
}

export type ErrorWithOutput = Error & ChildProcessOutput

export type ChildProcessPromise = ChildProcess & Promise<ChildProcessOutput>

type PromisifyChildProcessBaseOpts = {
Expand Down Expand Up @@ -100,6 +102,8 @@ export function promisifyChildProcess(
}
}
function defineOutputs(obj: Object) {
obj.code = code
obj.signal = signal
if (captureStdio) {
obj.stdout = joinChunks(stdoutChunks, encoding)
obj.stderr = joinChunks(stderrChunks, encoding)
Expand All @@ -124,15 +128,13 @@ export function promisifyChildProcess(
})
}
}
const output: ChildProcessOutput = ({}: any)
defineOutputs(output)
const finalError: ?ErrorWithOutput = error
if (finalError) {
finalError.code = code
finalError.signal = signal
defineOutputs(finalError)
reject(finalError)
} else {
const output: ChildProcessOutput = ({}: any)
defineOutputs(output)
resolve(output)
}
}
Expand Down Expand Up @@ -190,7 +192,7 @@ function promisifyExecMethod(method: any): any {
err.stderr = stderr
reject(err)
} else {
resolve({ stdout, stderr })
resolve({ code: 0, signal: null, stdout, stderr })
}
}
)
Expand Down
68 changes: 46 additions & 22 deletions test/index.js
Expand Up @@ -52,7 +52,7 @@ describe('spawn', function() {

it('resolves with process output', async () => {
let finallyDone = false
const { stdout, stderr } = await spawn(
const { code, signal, stdout, stderr } = await spawn(
process.execPath,
[require.resolve('./resolvesWithProcessOutput')],
{ maxBuffer: 200 * 1024 }
Expand All @@ -61,6 +61,8 @@ describe('spawn', function() {
finallyDone = true
})
expect(finallyDone, 'finally handler finished').to.be.true
expect(code, 'code').to.equal(0)
expect(signal, 'signal').to.equal(null)
if (stdout == null || stderr == null) throw new Error('missing output')
if (!(stdout instanceof Buffer))
throw new Error('expected stdout to be a buffer')
Expand All @@ -85,7 +87,11 @@ describe('spawn', function() {
{ maxBuffer: 1 }
).catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { stdout, stderr } = error
const { code, signal, stdout, stderr } = error
if (process.env.BABEL_ENV !== 'coverage')
expect(code, 'code').to.equal(null)
if (process.env.BABEL_ENV !== 'coverage')
expect(signal, 'signal').to.equal('SIGTERM')
expect(stdout.toString('utf8')).to.equal('h')
expect(stderr.toString('utf8')).to.equal('')
})
Expand All @@ -112,9 +118,10 @@ describe('spawn', function() {
.catch(err => (error = err))
expect(finallyDone, 'finally handler finished').to.be.true
if (error == null) throw new Error('missing error')
const { code, message, stdout, stderr } = error
const { code, signal, message, stdout, stderr } = error
expect(message).to.equal('Process exited with code 2')
expect(code).to.equal(2)
expect(code, 'code').to.equal(2)
expect(signal, 'signal').to.equal(null)
if (!(stdout instanceof Buffer))
throw new Error('expected stdout to be a buffer')
if (!(stderr instanceof Buffer))
Expand Down Expand Up @@ -145,9 +152,10 @@ describe('spawn', function() {
})
await child.catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { signal, message, stdout, stderr } = error
const { code, signal, message, stdout, stderr } = error
expect(message).to.equal('Process was killed with SIGINT')
expect(signal).to.equal('SIGINT')
expect(code, 'code').to.equal(null)
expect(signal, 'signal').to.equal('SIGINT')
if (!(stdout instanceof Buffer))
throw new Error('expected stdout to be a buffer')
if (!(stderr instanceof Buffer))
Expand All @@ -171,13 +179,15 @@ describe('fork', function() {

it('resolves with process output', async () => {
let finallyDone = false
const { stdout, stderr } = await fork(
const { code, signal, stdout, stderr } = await fork(
require.resolve('./resolvesWithProcessOutput'),
{ silent: true, maxBuffer: 200 * 1024 }
).finally(async () => {
await delay(50)
finallyDone = true
})
expect(code, 'code').to.equal(0)
expect(signal, 'signal').to.equal(null)
expect(finallyDone, 'finally handler finished').to.be.true
if (stdout == null || stderr == null) throw new Error('missing output')
if (!(stdout instanceof Buffer))
Expand All @@ -202,7 +212,11 @@ describe('fork', function() {
maxBuffer: 1,
}).catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { stdout, stderr } = error
const { code, signal, stdout, stderr } = error
if (process.env.BABEL_ENV !== 'coverage')
expect(code, 'code').to.equal(null)
if (process.env.BABEL_ENV !== 'coverage')
expect(signal, 'signal').to.equal('SIGTERM')
expect(stdout.toString('utf8')).to.equal('h')
expect(stderr.toString('utf8')).to.equal('')
})
Expand All @@ -229,9 +243,10 @@ describe('fork', function() {
.catch(err => (error = err))
expect(finallyDone, 'finally handler finished').to.be.true
if (error == null) throw new Error('missing error')
const { code, message, stdout, stderr } = error
const { code, signal, message, stdout, stderr } = error
expect(message).to.equal('Process exited with code 2')
expect(code).to.equal(2)
expect(code, 'code').to.equal(2)
expect(signal, 'signal').to.equal(null)
if (!(stdout instanceof Buffer))
throw new Error('expected stdout to be a buffer')
if (!(stderr instanceof Buffer))
Expand Down Expand Up @@ -259,9 +274,10 @@ describe('fork', function() {
})
await child.catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { signal, message, stdout, stderr } = error
const { code, signal, message, stdout, stderr } = error
expect(message).to.equal('Process was killed with SIGINT')
expect(signal).to.equal('SIGINT')
expect(code, 'code').to.equal(null)
expect(signal, 'signal').to.equal('SIGINT')
if (!(stdout instanceof Buffer))
throw new Error('expected stdout to be a buffer')
if (!(stderr instanceof Buffer))
Expand All @@ -281,10 +297,12 @@ describe('exec', function() {
this.timeout(30000)

it('resolves with process output', async () => {
const { stdout, stderr } = await exec(
const { code, signal, stdout, stderr } = await exec(
`${process.execPath} ${require.resolve('./resolvesWithProcessOutput')}`
)
if (stdout == null || stderr == null) throw new Error('missing output')
expect(code, 'code').to.equal(0)
expect(signal, 'signal').to.equal(null)
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand All @@ -294,8 +312,9 @@ describe('exec', function() {
`${process.execPath} ${require.resolve('./rejectsWithExitCode')}`
).catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { code, stdout, stderr } = error
expect(code).to.equal(2)
const { code, signal, stdout, stderr } = error
expect(code, 'code').to.equal(2)
expect(signal, 'signal').to.equal(null)
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand All @@ -318,8 +337,9 @@ describe('exec', function() {
})
await child.catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { signal, stdout, stderr } = error
expect(signal).to.equal('SIGINT')
const { code, signal, stdout, stderr } = error
expect(code, 'code').to.equal(null)
expect(signal, 'signal').to.equal('SIGINT')
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand All @@ -329,10 +349,12 @@ describe('execFile', function() {
this.timeout(30000)

it('resolves with process output', async () => {
const { stdout, stderr } = await execFile(
const { code, signal, stdout, stderr } = await execFile(
require.resolve('./resolvesWithProcessOutput')
)
if (stdout == null || stderr == null) throw new Error('missing output')
expect(code, 'code').to.equal(0)
expect(signal, 'signal').to.equal(null)
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand All @@ -342,8 +364,9 @@ describe('execFile', function() {
err => (error = err)
)
if (error == null) throw new Error('missing error')
const { code, stdout, stderr } = error
expect(code).to.equal(2)
const { code, signal, stdout, stderr } = error
expect(code, 'code').to.equal(2)
expect(signal, 'signal').to.equal(null)
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand All @@ -364,8 +387,9 @@ describe('execFile', function() {
})
await child.catch(err => (error = err))
if (error == null) throw new Error('missing error')
const { signal, stdout, stderr } = error
expect(signal).to.equal('SIGINT')
const { code, signal, stdout, stderr } = error
expect(code, 'code').to.equal(null)
expect(signal, 'signal').to.equal('SIGINT')
expect(stdout).to.equal('hello')
expect(stderr).to.equal('world')
})
Expand Down

0 comments on commit 507e539

Please sign in to comment.