(tasks, options = {})
| 9 | * @returns {Promise<void>} Rejects (process.exit) if any task fails |
| 10 | */ |
| 11 | export async function parallelTask(tasks, options = {}) { |
| 12 | const { timeoutMs = 30_000 } = options |
| 13 | const total = tasks.length |
| 14 | |
| 15 | const bgColors = [ |
| 16 | chalk.bgCyan, |
| 17 | chalk.bgMagenta, |
| 18 | chalk.bgBlue, |
| 19 | chalk.bgYellow, |
| 20 | chalk.bgGreenBright, |
| 21 | ] |
| 22 | const fgOnBg = [chalk.black, chalk.white, chalk.white, chalk.black, chalk.black] |
| 23 | |
| 24 | let done = 0 |
| 25 | let failed = 0 |
| 26 | |
| 27 | const spinner = ['◐', '◓', '◑', '◒'] |
| 28 | let tick = 0 |
| 29 | |
| 30 | const printProgress = () => { |
| 31 | const running = total - done - failed |
| 32 | const s = spinner[tick++ % spinner.length] |
| 33 | const status = failed |
| 34 | ? `${running} running, ${done} done, ${chalk.bgRed.white.bold(` ${failed} failed `)}` |
| 35 | : `${running} running, ${done} done` |
| 36 | process.stderr.write(`\r${chalk.bgCyan.black.bold(` ${s} ${done}/${total} `)} ${status} `) |
| 37 | } |
| 38 | |
| 39 | const timer = setInterval(printProgress, 1000) |
| 40 | printProgress() |
| 41 | |
| 42 | /** @type {{ label: string, output: string, exitCode: number | null, timedOut: boolean }[]} */ |
| 43 | const results = await Promise.all( |
| 44 | tasks.map( |
| 45 | (task) => |
| 46 | new Promise((resolve) => { |
| 47 | const chunks = /** @type {Buffer[]} */ ([]) |
| 48 | |
| 49 | const child = spawn('sh', ['-c', task.command], { |
| 50 | cwd: task.cwd, |
| 51 | env: { ...process.env, FORCE_COLOR: '1', NO_COLOR: '' }, |
| 52 | stdio: ['ignore', 'pipe', 'pipe'], |
| 53 | }) |
| 54 | |
| 55 | child.stdout.on('data', (d) => chunks.push(d)) |
| 56 | child.stderr.on('data', (d) => chunks.push(d)) |
| 57 | |
| 58 | const timeout = setTimeout(() => { |
| 59 | child.kill('SIGTERM') |
| 60 | }, timeoutMs) |
| 61 | |
| 62 | child.on('close', (code, signal) => { |
| 63 | clearTimeout(timeout) |
| 64 | const timedOut = signal === 'SIGTERM' |
| 65 | const exitCode = timedOut ? 1 : code |
| 66 | |
| 67 | if (exitCode === 0) done++ |
| 68 | else failed++ |
no test coverage detected