Spaces:
Paused
Paused
| import {execSync, ExecSyncOptions} from 'child_process' | |
| import {execa, type Result} from 'execa' | |
| import {als} from './context' | |
| import pino from 'pino' | |
| const logger = pino({ level: process.env.LOG_LEVEL || 'info' }) | |
| /** | |
| * Executes a shell command using the current context's working directory. | |
| * Thread-safe for Probot. | |
| */ | |
| export const prixExec = ( | |
| command: string, | |
| options: ExecSyncOptions = {} | |
| ): string => { | |
| const context = als.getStore() | |
| const cwd = options.cwd || context?.workingDir || process.cwd() | |
| try { | |
| const result = execSync(command, { | |
| ...options, | |
| cwd, | |
| encoding: 'utf8' | |
| }) | |
| return result ? result.toString() : '' | |
| } catch (err: any) { | |
| if (err.status === 1 && command.includes('grep')) { | |
| return '' | |
| } | |
| const errorMessage = err.stderr ? err.stderr.toString() : err.message | |
| logger.error({ command, cwd, error: errorMessage }, 'prixExec failed') | |
| throw err | |
| } | |
| } | |
| export interface ExecAsyncOptions { | |
| cwd?: string | |
| timeout?: number | |
| env?: Record<string, string> | |
| } | |
| /** | |
| * Async version of prixExec using execa. | |
| * Non-blocking - suitable for production use. | |
| */ | |
| export const prixExecAsync = async ( | |
| command: string, | |
| args: string[] = [], | |
| options: ExecAsyncOptions = {} | |
| ): Promise<Result> => { | |
| const context = als.getStore() | |
| const cwd = options.cwd || context?.workingDir || process.cwd() | |
| const timeout = options.timeout || 60000 // Default 60s timeout | |
| logger.debug({ command, args, cwd, timeout }, 'Executing async command') | |
| try { | |
| const result = await execa(command, args, { | |
| cwd, | |
| timeout, | |
| env: { ...process.env, ...options.env }, | |
| reject: true | |
| }) | |
| logger.debug({ command, exitCode: result.exitCode }, 'Command completed') | |
| return result | |
| } catch (err: any) { | |
| if (err.exitCode === 1 && command.includes('grep')) { | |
| return { stdout: '', stderr: '', command, escapedCommand: command, cwd, durationMs: 0, failed: false, timedOut: false, isCanceled: false, killed: false, exitCode: 0 } as unknown as Result | |
| } | |
| logger.error({ command, args, cwd, error: err.message, exitCode: err.exitCode }, 'Async command failed') | |
| throw err | |
| } | |
| } | |