From 3a971e9423c2082173b5842c0c3bed5fccb4ee5d Mon Sep 17 00:00:00 2001 From: usimd <11619247+usimd@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:35:30 +0100 Subject: [PATCH] Run preparation steps in parallel --- __test__/increase-runner-disk-size.test.ts | 30 +++- package.json | 3 +- src/actions.ts | 6 +- src/increase-runner-disk-size.ts | 178 ++++++++++----------- 4 files changed, 116 insertions(+), 101 deletions(-) diff --git a/__test__/increase-runner-disk-size.test.ts b/__test__/increase-runner-disk-size.test.ts index 852c459..f63462d 100644 --- a/__test__/increase-runner-disk-size.test.ts +++ b/__test__/increase-runner-disk-size.test.ts @@ -1,5 +1,9 @@ import * as exec from '@actions/exec' -import {removeRunnerComponents} from '../src/increase-runner-disk-size' +import * as core from '@actions/core' +import { + getExecOptions, + removeRunnerComponents +} from '../src/increase-runner-disk-size' jest.mock('@actions/exec') @@ -14,6 +18,8 @@ describe('Increasing runner disk size', () => { return Promise.resolve({} as exec.ExecOutput) } }) + jest.spyOn(core, 'getBooleanInput').mockReturnValueOnce(true) + await removeRunnerComponents() expect(exec.getExecOutput).toHaveBeenCalledWith( @@ -30,13 +36,11 @@ describe('Increasing runner disk size', () => { expect(exec.getExecOutput).toHaveBeenCalledWith( 'sudo', - expect.arrayContaining(['apt-get', 'autoremove']), - expect.anything() - ) - - expect(exec.getExecOutput).toHaveBeenCalledWith( - 'sudo', - expect.arrayContaining(['apt-get', 'autoclean']), + expect.arrayContaining([ + 'sh', + '-c', + 'apt-get autoremove && apt-get autoclean' + ]), expect.anything() ) @@ -46,4 +50,14 @@ describe('Increasing runner disk size', () => { expect.anything() ) }) + + it('should invoke execution log callbacks only when verbose', async () => { + jest.spyOn(core, 'info') + const opts = getExecOptions('docker-system-prune', true) + + opts.listeners?.stdline('test') + opts.listeners?.errline('test') + + expect(core.info).toHaveBeenCalledTimes(2) + }) }) diff --git a/package.json b/package.json index 8bc9fa5..8c04b20 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,10 @@ "author": "Simon Domke", "main": "dist/index.js", "scripts": { - "build": "tsc", "lint": "eslint src/**/*.ts", "package": "ncc build src/main.ts -m --no-source-map-register --license licenses.txt", "test": "jest", - "all": "npm run build && npm run format && npm run lint && npm test && npm run package && npm run update-readme", + "all": "npm run format && npm run lint && npm test && npm run package && npm run update-readme", "format": "prettier --write '**/*.ts'", "format-check": "prettier --check '**/*.ts'", "update-readme": "ts-node src/misc/update-readme.ts" diff --git a/src/actions.ts b/src/actions.ts index 6df5496..205cfcd 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -28,8 +28,10 @@ export async function piGen(): Promise { const userConfig = await configure() if (increaseRunnerDiskSize) { - core.info('Removing unused runner components to increase disk space') - await removeRunnerComponents() + await core.group( + 'Removing runner components to increase disk build space', + () => removeRunnerComponents() + ) } await clonePigen(piGenRepo, piGenDirectory, core.getInput('pi-gen-version')) diff --git a/src/increase-runner-disk-size.ts b/src/increase-runner-disk-size.ts index 59db128..6be3ed3 100644 --- a/src/increase-runner-disk-size.ts +++ b/src/increase-runner-disk-size.ts @@ -1,116 +1,116 @@ import * as exec from '@actions/exec' import * as core from '@actions/core' +import * as colors from 'ansi-colors' + +// See https://github.com/actions/runner-images/issues/2840#issuecomment-2272410832 +const HOST_PATHS_TO_REMOVE = [ + '/opt/google/chrome', + '/opt/microsoft/msedge', + '/opt/microsoft/powershell', + '/opt/mssql-tools', + '/opt/hostedtoolcache', + '/opt/pipx', + '/usr/lib/mono', + '/usr/local/julia*', + '/usr/local/lib/android', + '/usr/local/lib/node_modules', + '/usr/local/share/chromium', + '/usr/local/share/powershell', + '/usr/share/dotnet', + '/usr/share/swift', + '/var/cache/snapd', + '/var/lib/snapd', + '/tmp/*', + '/usr/share/doc' +] export async function removeRunnerComponents(): Promise { - try { - core.startGroup('Removing runner components to increase disk build space') + const verbose = core.getBooleanInput('verbose-output') + const availableDiskSizeBeforeCleanup = await getAvailableDiskSize() + const actions = [] - const availableDiskSizeBeforeCleanup = await getAvailableDiskSize() - core.debug( - `Available disk space before cleanup: ${availableDiskSizeBeforeCleanup / 1024 / 1024}G` + actions.push( + exec.getExecOutput( + 'sudo', + ['docker', 'system', 'prune', '--all', '--force'], + getExecOptions('docker-system-prune', verbose) ) + ) - await exec - .getExecOutput( - 'sudo', - ['docker', 'system', 'prune', '--all', '--force'], - { - silent: true, - failOnStdErr: false, - ignoreReturnCode: true - } - ) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) - - await exec + actions.push( + exec .getExecOutput( 'sudo', - [ - 'sh', - '-c', - 'snap list | sed 1d | cut -d" " -f1 | xargs -I{} snap remove {}' - ], - { - silent: true, - failOnStdErr: false, - ignoreReturnCode: true - } + ['swapoff', '-a'], + getExecOptions('swapoff', verbose) ) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) - - await exec - .getExecOutput('sudo', ['swapoff', '-a'], { - silent: true, - failOnStdErr: false, - ignoreReturnCode: true - }) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) - - // See https://github.com/actions/runner-images/issues/2840#issuecomment-2272410832 - const hostPathsToRemove = [ - '/opt/google/chrome', - '/opt/microsoft/msedge', - '/opt/microsoft/powershell', - '/opt/mssql-tools', - '/opt/hostedtoolcache', - '/opt/pipx', - '/usr/lib/mono', - '/usr/local/julia*', - '/usr/local/lib/android', - '/usr/local/lib/node_modules', - '/usr/local/share/chromium', - '/usr/local/share/powershell', - '/usr/share/dotnet', - '/usr/share/swift', - '/mnt/swapfile', - '/swapfile', - '/var/cache/snapd', - '/var/lib/snapd', - '/tmp/*', - '/usr/share/doc' - ] - - await exec - .getExecOutput('sudo', ['rm', '-rf', ...hostPathsToRemove], { - silent: true, - ignoreReturnCode: true, - failOnStdErr: false + .then(result => { + return exec.getExecOutput( + 'sudo', + ['rm', '-rf', '/mnt/swapfile', '/swapfile'], + getExecOptions('rm-swapfile', verbose) + ) }) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) + ) - await exec + actions.push( + exec .getExecOutput( 'sudo', - ['apt', 'purge', 'snapd', 'php8*', 'r-base', 'imagemagick'], - { - silent: true, - ignoreReturnCode: true - } + ['rm', '-rf', ...HOST_PATHS_TO_REMOVE], + getExecOptions('rm-host-paths', verbose) ) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) - await exec - .getExecOutput('sudo', ['apt-get', 'autoremove'], { - silent: true, - ignoreReturnCode: true - }) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) - await exec - .getExecOutput('sudo', ['apt-get', 'autoclean'], { - silent: true, - ignoreReturnCode: true + .then((returnValue: exec.ExecOutput) => { + return exec + .getExecOutput( + 'sudo', + ['apt', 'purge', 'snapd', 'php8*', 'r-base', 'imagemagick'], + getExecOptions('apt-purge-packages', verbose) + ) + .then((returnValue: exec.ExecOutput) => { + return exec.getExecOutput( + 'sudo', + ['sh', '-c', 'apt-get autoremove && apt-get autoclean'], + getExecOptions('apt-autoremove-autoclean', verbose) + ) + }) }) - .then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout)) + ) + return Promise.all(actions).then(async outputs => { + core.debug( + `Available disk space before cleanup: ${availableDiskSizeBeforeCleanup / 1024 / 1024}G` + ) const availableDiskSizeAfterCleanup = await getAvailableDiskSize() core.debug( `Available disk space after cleanup: ${availableDiskSizeAfterCleanup / 1024 / 1024}G` ) - core.info( `Reclaimed runner disk space: ${((availableDiskSizeAfterCleanup - availableDiskSizeBeforeCleanup) / 1024 / 1024).toFixed(2)}G` ) - } finally { - core.endGroup() + }) +} + +const logPrefixColorTheme: Record = { + 'docker-system-prune': colors.cyan, + swapoff: colors.redBright, + 'rm-swapfile': colors.green, + 'rm-host-paths': colors.magenta, + 'apt-purge-packages': colors.yellow, + 'apt-autoremove-autoclean': colors.blue +} + +export function getExecOptions(logPrefix: string, verbose: boolean) { + return { + silent: true, + ...(verbose && { + listeners: { + stdline: (line: string) => + core.info(`${logPrefixColorTheme[logPrefix](logPrefix)}: ${line}`), + errline: (line: string) => + core.info(`${logPrefixColorTheme[logPrefix](logPrefix)}: ${line}`) + } + }) } }