Move runUnstableCommand out of main.ts

This commit is contained in:
TSR Berry 2023-07-31 03:03:39 +02:00
parent ecd8f1da70
commit 355d827df4
No known key found for this signature in database
GPG Key ID: 52353C0A4CCA15E2
3 changed files with 95 additions and 93 deletions

View File

@ -1,97 +1,6 @@
import * as core from '@actions/core'
import {spawnSync} from 'child_process'
import {getInputs} from './inputs'
import {Shell} from './shells'
import fs from 'fs/promises'
import path from 'path'
import os from 'os'
interface UnstableResult {
exitCode: number | null
error?: Error
}
export async function runUnstableCommand(
commands: string[],
shell: Shell,
workingDirectory: string,
timeoutMinutes: number,
maxRetries: number,
retryCodes: number[]
): Promise<number | null> {
const filepath = path.join(
os.tmpdir(),
`unstable-command${shell.scriptSuffix}`
)
if (shell.args.filter(x => x.includes('{0}')).length === 0) {
throw new Error("Shell does not contain the required argument: '{0}'")
}
core.debug(`Writing commands to temporary file: ${filepath}`)
await fs.writeFile(filepath, commands.join(os.EOL))
core.debug('File was written successfully!')
const shellArgs: string[] = []
for (const arg of shell.args) {
if (arg.includes('{0}')) {
shellArgs.push(arg.replace('{0}', filepath))
continue
}
shellArgs.push(arg)
}
let result: UnstableResult | null = null
for (let i = 1; i <= maxRetries; i++) {
result = await core.group(
`Attempt ${i}/${maxRetries}`,
async (): Promise<UnstableResult> => {
core.debug('Executing temporary script...')
const process = spawnSync(shell.executable, shellArgs, {
cwd: workingDirectory,
killSignal: 'SIGKILL',
timeout: timeoutMinutes * 60 * 1000,
stdio: 'inherit'
})
core.debug('Child process exited.')
const unstableResult: UnstableResult = {
exitCode: process.status
}
if (process.error !== undefined) {
unstableResult.error = process.error
}
return unstableResult
}
)
if (result.exitCode === null || retryCodes.includes(result.exitCode)) {
if (result.exitCode === null) {
core.warning(`Process was killed due to a timeout.`)
core.debug(`${result.error?.name}: ${result.error?.message}`)
} else {
core.warning(
`Process exited with code '${result.exitCode}' which is part of the specified retry-codes.`
)
}
} else {
core.info(`Process exited with code '${result.exitCode}'.`)
return result.exitCode
}
}
core.error(`Aborting after ${maxRetries} attempts.`)
core.setFailed(
result?.error ??
`Child process never returned with a good exit code. Giving up after ${maxRetries} attempts.`
)
return null
}
import {runUnstableCommand} from './run'
async function run(): Promise<void> {
try {

93
src/run.ts Normal file
View File

@ -0,0 +1,93 @@
import * as core from '@actions/core'
import {spawnSync} from 'child_process'
import {Shell} from './shells'
import fs from 'fs/promises'
import path from 'path'
import os from 'os'
interface UnstableResult {
exitCode: number | null
error?: Error
}
export async function runUnstableCommand(
commands: string[],
shell: Shell,
workingDirectory: string,
timeoutMinutes: number,
maxRetries: number,
retryCodes: number[]
): Promise<number | null> {
const filepath = path.join(
os.tmpdir(),
`unstable-command${shell.scriptSuffix}`
)
if (shell.args.filter(x => x.includes('{0}')).length === 0) {
throw new Error("Shell does not contain the required argument: '{0}'")
}
core.debug(`Writing commands to temporary file: ${filepath}`)
await fs.writeFile(filepath, commands.join(os.EOL))
core.debug('File was written successfully!')
const shellArgs: string[] = []
for (const arg of shell.args) {
if (arg.includes('{0}')) {
shellArgs.push(arg.replace('{0}', filepath))
continue
}
shellArgs.push(arg)
}
let result: UnstableResult | null = null
for (let i = 1; i <= maxRetries; i++) {
result = await core.group(
`Attempt ${i}/${maxRetries}`,
async (): Promise<UnstableResult> => {
core.debug('Executing temporary script...')
const process = spawnSync(shell.executable, shellArgs, {
cwd: workingDirectory,
killSignal: 'SIGKILL',
timeout: timeoutMinutes * 60 * 1000,
stdio: 'inherit'
})
core.debug('Child process exited.')
const unstableResult: UnstableResult = {
exitCode: process.status
}
if (process.error !== undefined) {
unstableResult.error = process.error
}
return unstableResult
}
)
if (result.exitCode === null || retryCodes.includes(result.exitCode)) {
if (result.exitCode === null) {
core.warning(`Process was killed due to a timeout.`)
core.debug(`${result.error?.name}: ${result.error?.message}`)
} else {
core.warning(
`Process exited with code '${result.exitCode}' which is part of the specified retry-codes.`
)
}
} else {
core.info(`Process exited with code '${result.exitCode}'.`)
return result.exitCode
}
}
core.error(`Aborting after ${maxRetries} attempts.`)
core.setFailed(
result?.error ??
`Child process never returned with a good exit code. Giving up after ${maxRetries} attempts.`
)
return null
}

View File

@ -1,5 +1,5 @@
import {expect, test} from '@jest/globals'
import {runUnstableCommand} from '../src/main'
import {runUnstableCommand} from '../src/run'
import {getShell} from '../src/shells'
test('unstable command succeeds', async () => {