Skip to content

Commit

Permalink
Run preparation steps in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
usimd committed Nov 14, 2024
1 parent b771736 commit d34353f
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 181 deletions.
12 changes: 8 additions & 4 deletions __test__/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import * as actions from '../src/actions'
import {removeContainer} from '../src/remove-container'
import {build} from '../src/build'
import {removeRunnerComponents} from '../src/increase-runner-disk-size'
import {installHostDependencies} from '../src/install-dependencies'

jest.mock('../src/configure', () => ({
configure: jest.fn().mockReturnValue(DEFAULT_CONFIG)
}))
jest.mock('../src/install-dependencies')
jest.mock('../src/install-dependencies', () => ({
installHostDependencies: jest.fn().mockReturnValue(Promise.resolve())
}))
jest.mock('../src/build')
jest.mock('../src/clone-pigen')
jest.mock('../src/remove-container')
Expand All @@ -27,7 +30,7 @@ describe('Actions', () => {
})

it('should only increase disk space if requested', async () => {
jest.spyOn(core, 'getBooleanInput').mockReturnValueOnce(true)
jest.spyOn(core, 'getBooleanInput').mockReturnValue(true)

await actions.piGen()

Expand All @@ -40,7 +43,7 @@ describe('Actions', () => {
.mockReturnValueOnce('')
.mockReturnValueOnce('true')
.mockReturnValueOnce('true')
process.env['INPUT_INCREASE-RUNNER-DISK-SIZE'] = 'false'
jest.spyOn(core, 'getBooleanInput').mockReturnValue(false)

// expect build here
await actions.run()
Expand All @@ -56,7 +59,8 @@ describe('Actions', () => {
'should catch errors thrown during build and set build safely as failed',
async error => {
const errorMessage = 'any error'
jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
jest.spyOn(core, 'getBooleanInput').mockReturnValue(false)
jest.spyOn(core, 'getInput').mockImplementation((name, falseptions) => {
throw error
})
jest.spyOn(core, 'setFailed')
Expand Down
12 changes: 5 additions & 7 deletions __test__/increase-runner-disk-size.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,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()
)

Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
37 changes: 27 additions & 10 deletions src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {build} from './build'
import {clonePigen} from './clone-pigen'
import {removeContainer} from './remove-container'
import {removeRunnerComponents} from './increase-runner-disk-size'
import {printLogGroup} from './log'

const piGenBuildStartedState = 'pi-gen-build-started'

Expand All @@ -14,6 +15,8 @@ export async function piGen(): Promise<void> {
// See also https://github.com/chalk/supports-color/issues/106
process.env['FORCE_COLOR'] = '2'

const verbose = core.getBooleanInput('verbose-output')

const piGenDirectory = core.getInput('pi-gen-dir')
core.debug(`Using pi-gen directory: ${piGenDirectory}`)

Expand All @@ -27,17 +30,31 @@ export async function piGen(): Promise<void> {

const userConfig = await configure()

if (increaseRunnerDiskSize) {
core.info('Removing unused runner components to increase disk space')
await removeRunnerComponents()
}

await clonePigen(piGenRepo, piGenDirectory, core.getInput('pi-gen-version'))
await installHostDependencies(
core.getInput('extra-host-dependencies'),
core.getInput('extra-host-modules'),
piGenDirectory
)

const prepareActions = [
installHostDependencies(
core.getInput('extra-host-dependencies'),
core.getInput('extra-host-modules'),
piGenDirectory
).then(async logOutput => {
await core.group('Installing build dependencies on host', async () => {
printLogGroup(logOutput, verbose)
})
if (increaseRunnerDiskSize) {
return removeRunnerComponents().then(async logOutput => {
await core.group(

Check warning on line 46 in src/actions.ts

View check run for this annotation

Codecov / codecov/patch

src/actions.ts#L46

Added line #L46 was not covered by tests
'Removing runner components to increase disk build space',
async () => {
printLogGroup(logOutput, verbose)

Check warning on line 49 in src/actions.ts

View check run for this annotation

Codecov / codecov/patch

src/actions.ts#L48-L49

Added lines #L48 - L49 were not covered by tests
}
)
})
}
})
]

await Promise.all(prepareActions)

core.saveState(piGenBuildStartedState, true)
await build(piGenDirectory, userConfig)
Expand Down
199 changes: 106 additions & 93 deletions src/increase-runner-disk-size.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,130 @@
import * as exec from '@actions/exec'
import * as core from '@actions/core'
import {LogOutput} from './log'

export async function removeRunnerComponents(): Promise<void> {
try {
core.startGroup('Removing runner components to increase disk build space')
// 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'
]

const availableDiskSizeBeforeCleanup = await getAvailableDiskSize()
core.debug(
`Available disk space before cleanup: ${availableDiskSizeBeforeCleanup / 1024 / 1024}G`
)
export async function removeRunnerComponents(): Promise<LogOutput> {
const availableDiskSizeBeforeCleanup = await getAvailableDiskSize()

await exec
.getExecOutput(
'sudo',
['docker', 'system', 'prune', '--all', '--force'],
{
silent: true,
failOnStdErr: false,
ignoreReturnCode: true
}
)
.then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout))
// Running processes in parallel will mangle their logs. This will keep output in a common
// list with a prefix indicating from which process they stemmed (similar to what one gets
// from docker compose logs).
const log = {log: [], debug: []} as LogOutput

await exec
.getExecOutput(
'sudo',
[
'sh',
'-c',
'snap list | sed 1d | cut -d" " -f1 | xargs -I{} snap remove {}'
],
{
silent: true,
failOnStdErr: false,
ignoreReturnCode: true
const actions = []

actions.push(
exec.getExecOutput(
'sudo',
['docker', 'system', 'prune', '--all', '--force'],
{
silent: true,
listeners: {
errline: line => log.log.push(`docker-system-prune: ${line}`),
stdline: line => log.log.push(`docker-system-prune: ${line}`)

Check warning on line 44 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L43-L44

Added lines #L43 - L44 were not covered by tests
}
)
.then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout))
}
)
)

await exec
actions.push(
exec
.getExecOutput('sudo', ['swapoff', '-a'], {
silent: true,
failOnStdErr: false,
ignoreReturnCode: true
listeners: {
errline: line => log.log.push(`swapoff: ${line}`),
stdline: line => log.log.push(`swapoff: ${line}`)

Check warning on line 56 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L55-L56

Added lines #L55 - L56 were not covered by tests
}
})
.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'],
{
silent: true,
listeners: {
errline: line => log.log.push(`rm-swapfile: ${line}`),
stdline: line => log.log.push(`rm-swapfile: ${line}`)

Check warning on line 67 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L66-L67

Added lines #L66 - L67 were not covered by tests
}
}
)
})
.then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout))
)

await exec
.getExecOutput(
'sudo',
['apt', 'purge', 'snapd', 'php8*', 'r-base', 'imagemagick'],
{
silent: true,
ignoreReturnCode: true
}
)
.then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout))
await exec
.getExecOutput('sudo', ['apt-get', 'autoremove'], {
actions.push(
exec
.getExecOutput('sudo', ['rm', '-rf', ...HOST_PATHS_TO_REMOVE], {
silent: true,
ignoreReturnCode: true
listeners: {
errline: line => log.log.push(`rm-host-paths: ${line}`),
stdline: line => log.log.push(`rm-host-paths: ${line}`)

Check warning on line 80 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L79-L80

Added lines #L79 - L80 were not covered by tests
}
})
.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'],
{
silent: true,
listeners: {
stdline: line => log.log.push(`apt-purge-packages: ${line}`),
errline: line => log.log.push(`apt-purge-packages: ${line}`)

Check warning on line 92 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L91-L92

Added lines #L91 - L92 were not covered by tests
}
}
)
.then((returnValue: exec.ExecOutput) => {
return exec.getExecOutput(
'sudo',
['sh', '-c', 'apt-get autoremove && apt-get autoclean'],
{
silent: true,
listeners: {
stdline: line =>
log.log.push(`apt-autoremove-autoclean: ${line}`),

Check warning on line 104 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L104

Added line #L104 was not covered by tests
errline: line =>
log.log.push(`apt-autoremove-autoclean: ${line}`)

Check warning on line 106 in src/increase-runner-disk-size.ts

View check run for this annotation

Codecov / codecov/patch

src/increase-runner-disk-size.ts#L106

Added line #L106 was not covered by tests
}
}
)
})
})
.then((returnValue: exec.ExecOutput) => core.debug(returnValue.stdout))
)

return Promise.all(actions).then(async outputs => {
log.debug.push(
`Available disk space before cleanup: ${availableDiskSizeBeforeCleanup / 1024 / 1024}G`
)
const availableDiskSizeAfterCleanup = await getAvailableDiskSize()
core.debug(
log.debug.push(
`Available disk space after cleanup: ${availableDiskSizeAfterCleanup / 1024 / 1024}G`
)

core.info(
log.log.push(
`Reclaimed runner disk space: ${((availableDiskSizeAfterCleanup - availableDiskSizeBeforeCleanup) / 1024 / 1024).toFixed(2)}G`
)
} finally {
core.endGroup()
}

return log
})
}

async function getAvailableDiskSize(): Promise<number> {
Expand Down
Loading

0 comments on commit d34353f

Please sign in to comment.