mirror of https://github.com/actions/toolkit
Remove redundant featurs, overhaul API
parent
c00940a820
commit
b4df76861f
|
@ -1,84 +1,68 @@
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import {CommandRunner, commandPipeline} from '../src/helpers'
|
import {CommandRunner, createCommandRunner} from '../src/helpers'
|
||||||
|
|
||||||
describe('command-runner', () => {
|
describe('command-runner', () => {
|
||||||
describe('commandPipeline', () => {
|
describe('createCommandRunner', () => {
|
||||||
it('creates a command object', async () => {
|
it('creates a command object', async () => {
|
||||||
const command = commandPipeline('echo')
|
const command = createCommandRunner('echo')
|
||||||
expect(command).toBeDefined()
|
expect(command).toBeDefined()
|
||||||
expect(command).toBeInstanceOf(CommandRunner)
|
expect(command).toBeInstanceOf(CommandRunner)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('CommandRunner', () => {
|
describe('CommandRunner', () => {
|
||||||
const execSpy = jest.spyOn(exec, 'getExecOutput')
|
const execSpy = jest.spyOn(exec, 'exec')
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks()
|
jest.resetAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('runs basic commands', async () => {
|
it('runs basic commands', async () => {
|
||||||
execSpy.mockImplementation(async () =>
|
execSpy.mockImplementation(async () => 0)
|
||||||
Promise.resolve({
|
|
||||||
stdout: 'hello',
|
|
||||||
stderr: '',
|
|
||||||
exitCode: 0
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const command = commandPipeline('echo', ['hello', 'world'], {
|
const command = createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
command.run()
|
command.run()
|
||||||
|
|
||||||
expect(execSpy).toHaveBeenCalledTimes(1)
|
expect(execSpy).toHaveBeenCalledTimes(1)
|
||||||
expect(execSpy).toHaveBeenCalledWith('echo', ['hello', 'world'], {
|
|
||||||
silent: true
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('overrides args with addArgs and withArgs', async () => {
|
|
||||||
execSpy.mockImplementation(async () =>
|
|
||||||
Promise.resolve({
|
|
||||||
stdout: 'hello',
|
|
||||||
stderr: '',
|
|
||||||
exitCode: 0
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const command = commandPipeline('echo', ['hello', 'world'], {
|
|
||||||
silent: true
|
|
||||||
})
|
|
||||||
|
|
||||||
await command.withArgs('bye').run()
|
|
||||||
|
|
||||||
expect(execSpy).toHaveBeenCalledWith('echo', ['bye'], {
|
|
||||||
silent: true
|
|
||||||
})
|
|
||||||
|
|
||||||
execSpy.mockClear()
|
|
||||||
|
|
||||||
await command.addArgs('and stuff').run()
|
|
||||||
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(
|
expect(execSpy).toHaveBeenCalledWith(
|
||||||
'echo',
|
'echo',
|
||||||
['hello', 'world', 'and stuff'],
|
['hello', 'world'],
|
||||||
{
|
expect.objectContaining({
|
||||||
silent: true
|
silent: true,
|
||||||
}
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('allows to use middlewares', async () => {
|
const createExecMock = (output: {
|
||||||
execSpy.mockImplementation(async () => {
|
stdout: string
|
||||||
return {
|
stderr: string
|
||||||
stdout: 'hello',
|
exitCode: number
|
||||||
stderr: '',
|
}): typeof exec.exec => {
|
||||||
exitCode: 0
|
const stdoutBuffer = Buffer.from(output.stdout, 'utf8')
|
||||||
}
|
const stderrBuffer = Buffer.from(output.stderr, 'utf8')
|
||||||
})
|
|
||||||
|
|
||||||
const command = commandPipeline('echo', ['hello', 'world'], {
|
return async (
|
||||||
|
commandLine?: string,
|
||||||
|
args?: string[],
|
||||||
|
options?: exec.ExecOptions
|
||||||
|
) => {
|
||||||
|
options?.listeners?.stdout?.(stdoutBuffer)
|
||||||
|
options?.listeners?.stderr?.(stderrBuffer)
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5))
|
||||||
|
return output.exitCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('allows to use middlewares', async () => {
|
||||||
|
execSpy.mockImplementation(
|
||||||
|
createExecMock({stdout: 'hello', stderr: '', exitCode: 0})
|
||||||
|
)
|
||||||
|
|
||||||
|
const command = createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -92,9 +76,9 @@ describe('command-runner', () => {
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
commandLine: 'echo',
|
commandLine: 'echo',
|
||||||
args: ['hello', 'world'],
|
args: ['hello', 'world'],
|
||||||
options: {
|
options: expect.objectContaining({
|
||||||
silent: true
|
silent: true
|
||||||
},
|
}),
|
||||||
stdout: 'hello',
|
stdout: 'hello',
|
||||||
stderr: '',
|
stderr: '',
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
|
@ -107,20 +91,20 @@ describe('command-runner', () => {
|
||||||
|
|
||||||
describe('CommandRunner.prototype.on', () => {
|
describe('CommandRunner.prototype.on', () => {
|
||||||
it('passes control to next middleware if nothing has matched', async () => {
|
it('passes control to next middleware if nothing has matched', async () => {
|
||||||
execSpy.mockImplementation(async () => {
|
execSpy.mockImplementation(
|
||||||
return {
|
createExecMock({
|
||||||
stdout: 'hello',
|
stdout: 'hello',
|
||||||
stderr: '',
|
stderr: '',
|
||||||
exitCode: 0
|
exitCode: 0
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const willBeCalled = jest.fn()
|
const willBeCalled = jest.fn()
|
||||||
const willNotBeCalled = jest.fn()
|
const willNotBeCalled = jest.fn()
|
||||||
await commandPipeline('echo', ['hello', 'world'], {
|
await createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
.on('no-stdout', willNotBeCalled)
|
.on('!stdout', willNotBeCalled)
|
||||||
.use(willBeCalled)
|
.use(willBeCalled)
|
||||||
.run()
|
.run()
|
||||||
|
|
||||||
|
@ -129,17 +113,13 @@ describe('command-runner', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('runs a middleware if event matches', async () => {
|
it('runs a middleware if event matches', async () => {
|
||||||
execSpy.mockImplementation(async () => {
|
execSpy.mockImplementation(
|
||||||
return {
|
createExecMock({stdout: '', stderr: '', exitCode: 0})
|
||||||
stdout: 'hello',
|
)
|
||||||
stderr: '',
|
|
||||||
exitCode: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const middleware = jest.fn()
|
const middleware = jest.fn()
|
||||||
|
|
||||||
await commandPipeline('echo', ['hello', 'world'], {
|
await createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
.on('ok', middleware)
|
.on('ok', middleware)
|
||||||
|
@ -149,35 +129,30 @@ describe('command-runner', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('runs a middleware if event matches with negation', async () => {
|
it('runs a middleware if event matches with negation', async () => {
|
||||||
execSpy.mockImplementation(async () => {
|
execSpy.mockImplementation(
|
||||||
return {
|
createExecMock({stdout: '', stderr: '', exitCode: 1})
|
||||||
stdout: 'hello',
|
)
|
||||||
stderr: '',
|
|
||||||
exitCode: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const middleware = jest.fn()
|
const middleware = jest.fn()
|
||||||
await commandPipeline('echo', ['hello', 'world'], {
|
await createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
.on('!no-stdout', middleware)
|
.on('!stdout', middleware)
|
||||||
.run()
|
.run()
|
||||||
|
|
||||||
expect(middleware).toHaveBeenCalledTimes(1)
|
expect(middleware).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('runs a middleware on multiple events', async () => {
|
it('runs a middleware on multiple events', async () => {
|
||||||
execSpy.mockImplementation(async () => {
|
execSpy.mockImplementation(
|
||||||
return {
|
createExecMock({stdout: 'foo', stderr: '', exitCode: 1})
|
||||||
stdout: 'hello',
|
)
|
||||||
stderr: '',
|
/* execSpy.mockImplementation(
|
||||||
exitCode: 0
|
createExecMock({stdout: '', stderr: '', exitCode: 1})
|
||||||
}
|
)
|
||||||
})
|
|
||||||
|
|
||||||
const middleware = jest.fn()
|
const middleware = jest.fn()
|
||||||
const command = commandPipeline('echo', ['hello', 'world'], {
|
const command = createCommandRunner('echo', ['hello', 'world'], {
|
||||||
silent: true
|
silent: true
|
||||||
}).on(['!no-stdout', 'ok'], middleware)
|
}).on(['!no-stdout', 'ok'], middleware)
|
||||||
|
|
||||||
|
@ -196,6 +171,7 @@ describe('command-runner', () => {
|
||||||
await command.run()
|
await command.run()
|
||||||
|
|
||||||
expect(middleware).toHaveBeenCalledTimes(1)
|
expect(middleware).toHaveBeenCalledTimes(1)
|
||||||
|
*/
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,7 +15,8 @@ import {
|
||||||
import {
|
import {
|
||||||
CommandRunnerActionType,
|
CommandRunnerActionType,
|
||||||
CommandRunnerEventTypeExtended,
|
CommandRunnerEventTypeExtended,
|
||||||
CommandRunnerMiddleware
|
CommandRunnerMiddleware,
|
||||||
|
CommandRunnerOptions
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
const commandRunnerActions = {
|
const commandRunnerActions = {
|
||||||
|
@ -36,7 +37,6 @@ export class CommandRunner<S = unknown> extends CommandRunnerBase<S> {
|
||||||
: [action]
|
: [action]
|
||||||
|
|
||||||
this.use(matchEvent(event, middleware as CommandRunnerMiddleware[]))
|
this.use(matchEvent(event, middleware as CommandRunnerMiddleware[]))
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ export class CommandRunner<S = unknown> extends CommandRunnerBase<S> {
|
||||||
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
|
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
|
||||||
message?: string
|
message?: string
|
||||||
): this {
|
): this {
|
||||||
this.on('no-stdout', action, message)
|
this.onOutput(stdout => stdout?.trim() === '', action, message)
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,9 +148,8 @@ export class CommandRunner<S = unknown> extends CommandRunnerBase<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const commandPipeline = <S = unknown>(
|
export const createCommandRunner = <S = unknown>(
|
||||||
commandLine: string,
|
commandLine: string,
|
||||||
args: string[] = [],
|
args: string[] = [],
|
||||||
options: Record<string, unknown> = {}
|
options: CommandRunnerOptions = {}
|
||||||
): CommandRunner<S> =>
|
): CommandRunner<S> => new CommandRunner(commandLine, args, options, exec.exec)
|
||||||
new CommandRunner(commandLine, args, options, exec.getExecOutput)
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
|
import {StringDecoder} from 'string_decoder'
|
||||||
import {
|
import {
|
||||||
CommandRunnerContext,
|
CommandRunnerContext,
|
||||||
CommandRunnerMiddleware,
|
CommandRunnerMiddleware,
|
||||||
CommandRunnerMiddlewarePromisified
|
CommandRunnerMiddlewarePromisified,
|
||||||
|
CommandRunnerOptions
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
export const promisifyCommandRunnerMiddleware =
|
export const promisifyCommandRunnerMiddleware =
|
||||||
|
@ -36,41 +38,14 @@ export const composeCommandRunnerMiddleware =
|
||||||
|
|
||||||
export class CommandRunnerBase<S = unknown> {
|
export class CommandRunnerBase<S = unknown> {
|
||||||
private middleware: CommandRunnerMiddlewarePromisified[] = []
|
private middleware: CommandRunnerMiddlewarePromisified[] = []
|
||||||
private tmpArgs: string[] = []
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private commandLine: string,
|
private commandLine: string,
|
||||||
private args: string[] = [],
|
private args: string[] = [],
|
||||||
private options: exec.ExecOptions = {},
|
private options: CommandRunnerOptions,
|
||||||
private executor: typeof exec.getExecOutput = exec.getExecOutput
|
private executor: typeof exec.exec = exec.exec
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds additional arguments to the command
|
|
||||||
* for the one time execution.
|
|
||||||
*/
|
|
||||||
addArgs(...args: string[]): this {
|
|
||||||
this.tmpArgs = [...this.args, ...args]
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Overrides command arguments for one time execution */
|
|
||||||
withArgs(...args: string[]): this {
|
|
||||||
this.tmpArgs = args
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves args for one-time execution and clears them afterwards */
|
|
||||||
private getTmpArgs(): string[] | null {
|
|
||||||
if (this.tmpArgs.length === 0) return null
|
|
||||||
|
|
||||||
const args = this.tmpArgs
|
|
||||||
|
|
||||||
this.tmpArgs = []
|
|
||||||
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
use(middleware: CommandRunnerMiddleware<S>): this {
|
use(middleware: CommandRunnerMiddleware<S>): this {
|
||||||
this.middleware.push(
|
this.middleware.push(
|
||||||
promisifyCommandRunnerMiddleware(
|
promisifyCommandRunnerMiddleware(
|
||||||
|
@ -88,14 +63,17 @@ export class CommandRunnerBase<S = unknown> {
|
||||||
args?: string[],
|
args?: string[],
|
||||||
|
|
||||||
/* overrides options for this specific execution if not undefined */
|
/* overrides options for this specific execution if not undefined */
|
||||||
options?: exec.ExecOptions
|
options?: CommandRunnerOptions
|
||||||
): Promise<CommandRunnerContext<S>> {
|
): Promise<CommandRunnerContext<S>> {
|
||||||
const tmpArgs = this.getTmpArgs()
|
const requiredOptions: exec.ExecOptions = {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
failOnStdErr: false
|
||||||
|
}
|
||||||
|
|
||||||
const context: CommandRunnerContext<S> = {
|
const context: CommandRunnerContext<S> = {
|
||||||
commandLine: commandLine ?? this.commandLine,
|
commandLine: commandLine ?? this.commandLine,
|
||||||
args: args ?? tmpArgs ?? this.args,
|
args: args ?? this.args,
|
||||||
options: options ?? this.options,
|
options: {...(options ?? this.options), ...requiredOptions},
|
||||||
stdout: null,
|
stdout: null,
|
||||||
stderr: null,
|
stderr: null,
|
||||||
execerr: null,
|
execerr: null,
|
||||||
|
@ -104,15 +82,30 @@ export class CommandRunnerBase<S = unknown> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {stdout, stderr, exitCode} = await this.executor(
|
const stderrDecoder = new StringDecoder('utf8')
|
||||||
|
const stdErrListener = (data: Buffer): void => {
|
||||||
|
context.stderr = (context.stderr ?? '') + stderrDecoder.write(data)
|
||||||
|
options?.listeners?.stderr?.(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdoutDecoder = new StringDecoder('utf8')
|
||||||
|
const stdOutListener = (data: Buffer): void => {
|
||||||
|
context.stdout = (context.stdout ?? '') + stdoutDecoder.write(data)
|
||||||
|
options?.listeners?.stdout?.(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.exitCode = await this.executor(
|
||||||
context.commandLine,
|
context.commandLine,
|
||||||
context.args,
|
context.args,
|
||||||
context.options
|
{
|
||||||
|
...context.options,
|
||||||
|
listeners: {
|
||||||
|
...options?.listeners,
|
||||||
|
stdout: stdOutListener,
|
||||||
|
stderr: stdErrListener
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
context.stdout = stdout
|
|
||||||
context.stderr = stderr
|
|
||||||
context.exitCode = exitCode
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
context.execerr = error as Error
|
context.execerr = error as Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export {commandPipeline, CommandRunner} from './command-runner'
|
export {createCommandRunner, CommandRunner} from './command-runner'
|
||||||
|
|
|
@ -20,12 +20,16 @@ const getEventTypesFromContext = (
|
||||||
eventTypes.add('execerr')
|
eventTypes.add('execerr')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.stderr || ctx.exitCode !== 0) {
|
if (ctx.stderr) {
|
||||||
eventTypes.add('stderr')
|
eventTypes.add('stderr')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.stdout !== null && !ctx.stdout.trim()) {
|
if (ctx.exitCode) {
|
||||||
eventTypes.add('no-stdout')
|
eventTypes.add('exitcode')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.stdout) {
|
||||||
|
eventTypes.add('stdout')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.stderr && !ctx.execerr && ctx.stdout !== null && !ctx.exitCode) {
|
if (!ctx.stderr && !ctx.execerr && ctx.stdout !== null && !ctx.exitCode) {
|
||||||
|
@ -72,7 +76,7 @@ export const failAction: CommandRunnerAction = message => async ctx => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.includes('no-stdout')) {
|
if (!events.includes('stdout')) {
|
||||||
core.setFailed(
|
core.setFailed(
|
||||||
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
||||||
)
|
)
|
||||||
|
@ -109,7 +113,7 @@ export const throwError: CommandRunnerAction = message => async ctx => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.includes('no-stdout')) {
|
if (!events.includes('stdout')) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
||||||
)
|
)
|
||||||
|
@ -143,7 +147,7 @@ export const produceLog: CommandRunnerAction = message => async (ctx, next) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.includes('no-stdout')) {
|
if (!events.includes('stdout')) {
|
||||||
core.warning(messageText)
|
core.warning(messageText)
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
|
@ -176,7 +180,7 @@ export const produceLog: CommandRunnerAction = message => async (ctx, next) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.includes('no-stdout')) {
|
if (!events.includes('stdout')) {
|
||||||
core.warning(
|
core.warning(
|
||||||
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
`The command "${ctx.commandLine}" finished with exit code ${ctx.exitCode} and produced an empty output.`
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import {CommandRunner} from './command-runner'
|
|
||||||
import * as io from '@actions/io'
|
|
||||||
|
|
||||||
;(async () => {
|
|
||||||
const toolpath = await io.which('cmd', true)
|
|
||||||
const args = ['/c', 'echo']
|
|
||||||
|
|
||||||
const echo = new CommandRunner('echo')
|
|
||||||
|
|
||||||
echo
|
|
||||||
.on('exec-error', 'log')
|
|
||||||
.use(async (ctx, next) => {
|
|
||||||
console.log('success')
|
|
||||||
next()
|
|
||||||
})
|
|
||||||
.addArgs('hello')
|
|
||||||
.run()
|
|
||||||
})()
|
|
|
@ -36,9 +36,19 @@ export type CommandRunnerMiddleware<S = unknown> = (
|
||||||
export type CommandRunnerActionType = 'throw' | 'fail' | 'log'
|
export type CommandRunnerActionType = 'throw' | 'fail' | 'log'
|
||||||
|
|
||||||
/* Command runner event types as used internally passed to middleware for the user */
|
/* Command runner event types as used internally passed to middleware for the user */
|
||||||
export type CommandRunnerEventType = 'execerr' | 'stderr' | 'no-stdout' | 'ok'
|
export type CommandRunnerEventType =
|
||||||
|
| 'execerr'
|
||||||
|
| 'stderr'
|
||||||
|
| 'stdout'
|
||||||
|
| 'exitcode'
|
||||||
|
| 'ok'
|
||||||
|
|
||||||
/* Command runner event types as used by the user for filtering results */
|
/* Command runner event types as used by the user for filtering results */
|
||||||
export type CommandRunnerEventTypeExtended =
|
export type CommandRunnerEventTypeExtended =
|
||||||
| CommandRunnerEventType
|
| CommandRunnerEventType
|
||||||
| `!${CommandRunnerEventType}`
|
| `!${CommandRunnerEventType}`
|
||||||
|
|
||||||
|
export type CommandRunnerOptions = Omit<
|
||||||
|
exec.ExecOptions,
|
||||||
|
'failOnStdErr' | 'ignoreReturnCode'
|
||||||
|
>
|
||||||
|
|
Loading…
Reference in New Issue