mirror of https://github.com/actions/toolkit
Add initial logic for command wrapper and some basic unit tests
parent
b4ff0922c9
commit
2a75b5e2b3
|
@ -0,0 +1,53 @@
|
|||
import {Command} from '../src/exec-command-wrapper'
|
||||
import * as io from '@actions/io'
|
||||
|
||||
const IS_LINUX = process.platform === 'linux'
|
||||
|
||||
describe('Command', () => {
|
||||
it('creates a command object', async () => {
|
||||
if (IS_LINUX) {
|
||||
const toolpath = await io.which('echo', true)
|
||||
const command = new Command(`"${toolpath}"`, ['hello'])
|
||||
expect(command).toBeDefined()
|
||||
expect(command).toBeInstanceOf(Command)
|
||||
}
|
||||
})
|
||||
|
||||
it('runs a command with non-zero exit code', async () => {
|
||||
if (IS_LINUX) {
|
||||
const nonExistentDir = 'non-existent-dir'
|
||||
const toolpath = await io.which('ls', true)
|
||||
const args = ['-l', nonExistentDir]
|
||||
const command = new Command(`"${toolpath}"`, args)
|
||||
|
||||
let failed = false
|
||||
|
||||
await command.execute().catch(err => {
|
||||
failed = true
|
||||
expect(err.message).toContain(
|
||||
`The process '${toolpath}' failed with exit code `
|
||||
)
|
||||
})
|
||||
|
||||
expect(failed).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('runs a command with zero exit code', async () => {
|
||||
if (IS_LINUX) {
|
||||
const toolpath = await io.which('echo', true)
|
||||
const command = new Command(`"${toolpath}"`, ['hello'])
|
||||
const result = await command.execute()
|
||||
expect(result).toEqual('hello')
|
||||
}
|
||||
})
|
||||
|
||||
it('runs a command with empty output', async () => {
|
||||
if (IS_LINUX) {
|
||||
const toolpath = await io.which('echo', true)
|
||||
const command = new Command(`"${toolpath}"`, [''])
|
||||
const result = await command.execute()
|
||||
expect(result).toEqual('')
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,123 @@
|
|||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
|
||||
export class Command {
|
||||
private readonly commandText: string
|
||||
private readonly args: string[]
|
||||
private readonly options: exec.ExecOptions | undefined
|
||||
|
||||
private failOnError = false
|
||||
private throwOnError = false
|
||||
|
||||
private failOnEmptyOutput = false
|
||||
private throwOnEmptyOutput = false
|
||||
|
||||
constructor(
|
||||
commandText: string,
|
||||
args: string[],
|
||||
options: exec.ExecOptions | undefined = undefined
|
||||
) {
|
||||
this.commandText = commandText
|
||||
this.args = args
|
||||
this.options = options
|
||||
}
|
||||
|
||||
get failOn(): {error: () => Command; empty: () => Command} {
|
||||
return {
|
||||
error: this.setFailOnError,
|
||||
empty: this.setFailOnEmptyOutput
|
||||
}
|
||||
}
|
||||
|
||||
get throwOn(): {error: () => Command; empty: () => Command} {
|
||||
return {
|
||||
error: this.setThrowOnError,
|
||||
empty: this.setThrowOnEmptyOutput
|
||||
}
|
||||
}
|
||||
|
||||
private setFailOnError = (): Command => {
|
||||
this.failOnError = true
|
||||
return this
|
||||
}
|
||||
|
||||
private setThrowOnError = (): Command => {
|
||||
this.throwOnError = true
|
||||
return this
|
||||
}
|
||||
|
||||
private setFailOnEmptyOutput = (): Command => {
|
||||
this.failOnEmptyOutput = true
|
||||
return this
|
||||
}
|
||||
|
||||
private setThrowOnEmptyOutput = (): Command => {
|
||||
this.throwOnEmptyOutput = true
|
||||
return this
|
||||
}
|
||||
|
||||
private setFailedOnNonZeroExitCode(
|
||||
command: string,
|
||||
exitCode: number,
|
||||
error: string
|
||||
): void {
|
||||
if (exitCode !== 0) {
|
||||
error = !error.trim()
|
||||
? `The '${command}' command failed with exit code: ${exitCode}`
|
||||
: error
|
||||
core.setFailed(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private throwErrorOnNonZeroExitCode(
|
||||
command: string,
|
||||
exitCode: number,
|
||||
error: string
|
||||
): void {
|
||||
if (exitCode !== 0) {
|
||||
error = !error.trim()
|
||||
? `The '${command}' command failed with exit code: ${exitCode}`
|
||||
: error
|
||||
throw new Error(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
async execute(): Promise<string> {
|
||||
const {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
this.commandText,
|
||||
this.args,
|
||||
this.options
|
||||
)
|
||||
|
||||
if (this.failOnError) {
|
||||
this.setFailedOnNonZeroExitCode(this.commandText, exitCode, stderr)
|
||||
return stdout.trim()
|
||||
}
|
||||
|
||||
if (this.throwOnError) {
|
||||
this.throwErrorOnNonZeroExitCode(this.commandText, exitCode, stderr)
|
||||
return stdout.trim()
|
||||
}
|
||||
|
||||
if (this.failOnEmptyOutput && !stdout.trim()) {
|
||||
core.setFailed(
|
||||
`The '${this.commandText}' command failed with empty output`
|
||||
)
|
||||
return stdout.trim()
|
||||
}
|
||||
|
||||
if (this.throwOnEmptyOutput && !stdout.trim()) {
|
||||
throw new Error(
|
||||
`The '${this.commandText}' command failed with empty output`
|
||||
)
|
||||
}
|
||||
|
||||
return stdout.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// new Command('echo', ['hello', 'world'])
|
||||
// .failOn.error()
|
||||
// .execute()
|
Loading…
Reference in New Issue