Skip to content

Commit

Permalink
Merge pull request #69 from AthennaIO/develop
Browse files Browse the repository at this point in the history
fix(exec): add missing exit code
  • Loading branch information
jlenon7 authored Sep 5, 2023
2 parents 8395103 + 42278d8 commit a1de763
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 28 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@athenna/common",
"version": "4.9.1",
"version": "4.9.2",
"description": "The Athenna common helpers to use in any Node.js ESM project.",
"license": "MIT",
"author": "João Lenon <[email protected]>",
Expand Down
3 changes: 2 additions & 1 deletion src/exceptions/NodeCommandException.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export class NodeCommandException extends Exception {
public constructor(command: string, error: any) {
let help = ''

help = help.concat(`Command stdout:\n\n ${error.stdout}`)
help = help.concat(`Command code:\n\n ${error.exitCode}`)
help = help.concat(`\n\n Command stdout:\n\n ${error.stdout}`)
help = help.concat(`\n\n Command stderr:\n\n ${error.stderr}`)

help = help.concat(`\n\n ${error.stack}`)
Expand Down
55 changes: 31 additions & 24 deletions src/helpers/Exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@

import { debug } from '#src/debug'
import { Is } from '#src/helpers/Is'
import { promisify } from 'node:util'
import { Transform } from 'node:stream'
import { File } from '#src/helpers/File'
import { Uuid } from '#src/helpers/Uuid'
import { exec } from 'node:child_process'
import { Options } from '#src/helpers/Options'
import { request as requestHttp } from 'node:http'
import { request as requestHttps } from 'node:https'
import type { ExecOptions } from 'node:child_process'
import { exec as childProcessExec } from 'node:child_process'
import type { CommandOutput } from '#src/types/CommandOutput'
import type { PaginationOptions, PaginatedResponse } from '#src/types'
import { NodeCommandException } from '#src/exceptions/NodeCommandException'

const exec = promisify(childProcessExec)

export class Exec {
/**
* Sleep the code in the line that this function
Expand All @@ -49,7 +47,7 @@ export class Exec {
public static async command(
command: string,
options?: { ignoreErrors?: boolean },
): Promise<{ stdout: string; stderr: string }> {
): Promise<CommandOutput> {
options = Options.create(options, {
ignoreErrors: false,
})
Expand All @@ -62,31 +60,40 @@ export class Exec {

debug('executing command: %s', command)

try {
const result = await exec(command, execOptions)
return new Promise((resolve, reject) => {
let execError = null

if (!result.stdout) result.stdout = ''
if (!result.stderr) result.stderr = ''
const result: CommandOutput = {
stdout: '',
stderr: '',
exitCode: 0,
}

debug('command executed successfully')
debug('command stdout: %s', result.stdout)
debug('command stderr: %s', result.stderr)
exec(command, execOptions, (error, stdout, stderr) => {
if (error) execError = error
if (stdout) result.stdout = stdout
if (stderr) result.stderr = stderr

return result
} catch (error) {
if (!error.stdout) error.stdout = ''
if (!error.stderr) error.stderr = ''
debug('command executed')
debug('command stdout: %s', result.stdout)
debug('command stderr: %s', result.stderr)
debug('command exitCode: %s', result.exitCode)

debug('command has failed')
debug('command stdout: %s', error.stdout)
debug('command stderr: %s', error.stderr)
if (!execError) {
return resolve(result)
}

if (options.ignoreErrors) {
return { stdout: error.stdout, stderr: error.stderr }
}
execError.stdout = result.stdout
execError.stderr = result.stderr
execError.exitCode = result.exitCode

throw new NodeCommandException(command, error)
}
if (options.ignoreErrors) {
return resolve(result)
}

return reject(new NodeCommandException(command, execError))
}).on('exit', exitCode => (result.exitCode = exitCode))
})
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/types/CommandOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @athenna/common
*
* (c) João Lenon <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

export type CommandOutput = {
stdout: string
stderr: string
exitCode: number
}
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type {
export * from '#src/types/Merge'
export * from '#src/types/Except'
export * from '#src/types/PathDirs'
export * from '#src/types/CommandOutput'
export * from '#src/types/ObjectBuilderOptions'

export * from '#src/types/json/FileJson'
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/ExecTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export default class ExecTest {

@Test()
public async shouldBeAbleToExecuteACommandInTheVMAndGetTheStdout({ assert }: Context) {
const { stdout } = await Exec.command('ls')
const { stdout, exitCode } = await Exec.command('ls')

assert.equal(exitCode, 0)
assert.isTrue(stdout.includes('README.md'))
}

Expand All @@ -44,8 +45,9 @@ export default class ExecTest {
return
}

const { stdout } = await Exec.command('echo "error thrown" && exit 255', { ignoreErrors: true })
const { stdout, exitCode } = await Exec.command('echo "error thrown" && exit 255', { ignoreErrors: true })

assert.equal(exitCode, 255)
assert.isTrue(stdout.includes('error thrown'))
}

Expand Down

0 comments on commit a1de763

Please sign in to comment.