Skip to content

Commit

Permalink
Parallelize preparation steps
Browse files Browse the repository at this point in the history
  • Loading branch information
usimd committed Nov 9, 2024
1 parent b771736 commit f92839e
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 264 deletions.
5 changes: 3 additions & 2 deletions __test__/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,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 +40,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,6 +56,7 @@ describe('Actions', () => {
'should catch errors thrown during build and set build safely as failed',
async error => {
const errorMessage = 'any error'
jest.spyOn(core, 'getBooleanInput').mockReturnValueOnce(true)
jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
throw error
})
Expand Down
60 changes: 47 additions & 13 deletions src/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as core from '@actions/core'
import {configure} from './configure'
import {PiGenConfig} from './pi-gen-config'
import {installHostDependencies} from './install-dependencies'
import {build} from './build'
import {clonePigen} from './clone-pigen'
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 @@ -25,22 +28,53 @@ export async function piGen(): Promise<void> {
)
core.debug(`Increase runner disk size: ${increaseRunnerDiskSize}`)

const userConfig = await configure()
const promisesToWait: Array<Promise<PiGenConfig | void>> = []

promisesToWait.push(
core.group('Validating input and generating pi-gen config', () => {
return configure()
})
)

if (increaseRunnerDiskSize) {
core.info('Removing unused runner components to increase disk space')
await removeRunnerComponents()
promisesToWait.push(
core.group(
'Removing runner components to increase disk build space',
() => {
return removeRunnerComponents(verbose)
}
)
)
}

await clonePigen(piGenRepo, piGenDirectory, core.getInput('pi-gen-version'))
await installHostDependencies(
core.getInput('extra-host-dependencies'),
core.getInput('extra-host-modules'),
piGenDirectory
promisesToWait.push(
core.group('Cloning pi-gen repository', () => {
return clonePigen(
piGenRepo,
piGenDirectory,
core.getInput('pi-gen-version')
)
})
)

promisesToWait.push(
core.group('Installing build dependencies on host', () => {
return installHostDependencies(
core.getInput('extra-host-dependencies'),
core.getInput('extra-host-modules'),
piGenDirectory,
verbose
)
})
)

core.saveState(piGenBuildStartedState, true)
await build(piGenDirectory, userConfig)
Promise.all(promisesToWait).then(results => {
const filteredResults = results.filter(
result => typeof result !== 'undefined'
)
core.saveState(piGenBuildStartedState, true)
return build(piGenDirectory, filteredResults.at(0) as PiGenConfig)
})
} catch (error) {
core.setFailed((error as Error)?.message ?? error)
}
Expand All @@ -49,7 +83,7 @@ export async function piGen(): Promise<void> {
export async function cleanup(): Promise<void> {
try {
if (core.getState(piGenBuildStartedState)) {
await removeContainer('pigen_work')
return removeContainer('pigen_work')
} else {
core.info('No build started, nothing to clean')
}
Expand All @@ -60,9 +94,9 @@ export async function cleanup(): Promise<void> {

export async function run(): Promise<void> {
if (core.getState('main-executed')) {
await cleanup()
return cleanup()
} else {
core.saveState('main-executed', true)
await piGen()
return piGen()
}
}
45 changes: 20 additions & 25 deletions src/clone-pigen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,27 @@ export async function clonePigen(
piGenDirectory: string,
ref: string
): Promise<void> {
try {
const originalPiGenRepo = 'RPi-Distro/pi-gen'
const originalPiGenRepo = 'RPi-Distro/pi-gen'
const token = core.getInput('github-token')

core.startGroup('Cloning pi-gen repository')
const token = core.getInput('github-token')
const octokit = github.getOctokit(token)
const [owner, repoName] = repo.split('/')
const repoInfo = await octokit.rest.repos.get({
owner: owner,
repo: repoName
})

const octokit = github.getOctokit(token)
const [owner, repoName] = repo.split('/')
const repoInfo = await octokit.rest.repos.get({
owner: owner,
repo: repoName
})

if (
repo !== originalPiGenRepo &&
(!repoInfo.data.fork ||
repoInfo.data.source?.full_name !== originalPiGenRepo)
) {
throw new Error(`${repo} is not a fork from ${originalPiGenRepo}`)
}

core.debug(`Checking out ref ${ref} into ${piGenDirectory}`)
const verbose = core.getBooleanInput('verbose-output')
const git = await Git.getInstance(piGenDirectory, token, verbose)
await git.clone(`https://github.com/${repo}`, ref)
} finally {
core.endGroup()
if (
repo !== originalPiGenRepo &&
(!repoInfo.data.fork ||
repoInfo.data.source?.full_name !== originalPiGenRepo)
) {
throw new Error(`${repo} is not a fork from ${originalPiGenRepo}`)
}

core.debug(`Checking out ref ${ref} into ${piGenDirectory}`)
const verbose = core.getBooleanInput('verbose-output')
Git.getInstance(piGenDirectory, token, verbose).then(git => {
return git.clone(`https://github.com/${repo}`, ref)
})
}
137 changes: 65 additions & 72 deletions src/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,77 @@ import {DEFAULT_CONFIG, validateConfig, PiGenConfig} from './pi-gen-config'
import {colorize, color} from 'json-colorizer'

export async function configure(): Promise<PiGenConfig> {
try {
core.startGroup('Validating input and generating pi-gen config')
const userConfig = DEFAULT_CONFIG

const userConfig = DEFAULT_CONFIG
userConfig.imgName = core.getInput('image-name', {required: true})

userConfig.imgName = core.getInput('image-name', {required: true})
const stageList = core.getInput('stage-list').split(/\s+/)
userConfig.stageList =
stageList.length > 0 ? stageList : DEFAULT_CONFIG.stageList

const stageList = core.getInput('stage-list').split(/\s+/)
userConfig.stageList =
stageList.length > 0 ? stageList : DEFAULT_CONFIG.stageList
userConfig.release = core.getInput('release') || DEFAULT_CONFIG.release
userConfig.deployCompression =
core.getInput('compression') || DEFAULT_CONFIG.deployCompression
userConfig.compressionLevel =
core.getInput('compression-level') || DEFAULT_CONFIG.compressionLevel
userConfig.localeDefault =
core.getInput('locale') || DEFAULT_CONFIG.localeDefault
userConfig.targetHostname =
core.getInput('hostname') || DEFAULT_CONFIG.targetHostname
userConfig.keyboardKeymap =
core.getInput('keyboard-keymap') || DEFAULT_CONFIG.keyboardKeymap
userConfig.keyboardLayout =
core.getInput('keyboard-layout') || DEFAULT_CONFIG.keyboardLayout
userConfig.timezoneDefault =
core.getInput('timezone') || DEFAULT_CONFIG.timezoneDefault
userConfig.firstUserName =
core.getInput('username') || DEFAULT_CONFIG.firstUserName
userConfig.firstUserPass =
core.getInput('password') || DEFAULT_CONFIG.firstUserPass
userConfig.disableFirstBootUserRename =
core.getInput('disable-first-boot-user-rename') ||
DEFAULT_CONFIG.disableFirstBootUserRename
userConfig.wpaEssid = core.getInput('wpa-essid') || DEFAULT_CONFIG.wpaEssid
userConfig.wpaPassword =
core.getInput('wpa-password') || DEFAULT_CONFIG.wpaPassword
userConfig.wpaCountry =
core.getInput('wpa-country') || DEFAULT_CONFIG.wpaCountry
userConfig.enableSsh = core.getInput('enable-ssh') || DEFAULT_CONFIG.enableSsh
userConfig.pubkeySshFirstUser = core.getInput('pubkey-ssh-first-user')
userConfig.pubkeyOnlySsh =
core.getInput('pubkey-only-ssh') || DEFAULT_CONFIG.pubkeyOnlySsh
userConfig.enableNoobs =
core.getBooleanInput('enable-noobs')?.toString() ||
DEFAULT_CONFIG.enableNoobs

Check warning on line 47 in src/configure.ts

View check run for this annotation

Codecov / codecov/patch

src/configure.ts#L47

Added line #L47 was not covered by tests
userConfig.exportLastStageOnly =
core.getBooleanInput('export-last-stage-only')?.toString() ||
DEFAULT_CONFIG.exportLastStageOnly

Check warning on line 50 in src/configure.ts

View check run for this annotation

Codecov / codecov/patch

src/configure.ts#L50

Added line #L50 was not covered by tests
userConfig.dockerOpts = core.getInput('docker-opts')
userConfig.setfcap = core.getInput('setfcap') || DEFAULT_CONFIG.setfcap
userConfig.piGenRelease =
core.getInput('pi-gen-release') || DEFAULT_CONFIG.piGenRelease
userConfig.aptProxy = core.getInput('apt-proxy') || DEFAULT_CONFIG.aptProxy

userConfig.release = core.getInput('release') || DEFAULT_CONFIG.release
userConfig.deployCompression =
core.getInput('compression') || DEFAULT_CONFIG.deployCompression
userConfig.compressionLevel =
core.getInput('compression-level') || DEFAULT_CONFIG.compressionLevel
userConfig.localeDefault =
core.getInput('locale') || DEFAULT_CONFIG.localeDefault
userConfig.targetHostname =
core.getInput('hostname') || DEFAULT_CONFIG.targetHostname
userConfig.keyboardKeymap =
core.getInput('keyboard-keymap') || DEFAULT_CONFIG.keyboardKeymap
userConfig.keyboardLayout =
core.getInput('keyboard-layout') || DEFAULT_CONFIG.keyboardLayout
userConfig.timezoneDefault =
core.getInput('timezone') || DEFAULT_CONFIG.timezoneDefault
userConfig.firstUserName =
core.getInput('username') || DEFAULT_CONFIG.firstUserName
userConfig.firstUserPass =
core.getInput('password') || DEFAULT_CONFIG.firstUserPass
userConfig.disableFirstBootUserRename =
core.getInput('disable-first-boot-user-rename') ||
DEFAULT_CONFIG.disableFirstBootUserRename
userConfig.wpaEssid = core.getInput('wpa-essid') || DEFAULT_CONFIG.wpaEssid
userConfig.wpaPassword =
core.getInput('wpa-password') || DEFAULT_CONFIG.wpaPassword
userConfig.wpaCountry =
core.getInput('wpa-country') || DEFAULT_CONFIG.wpaCountry
userConfig.enableSsh =
core.getInput('enable-ssh') || DEFAULT_CONFIG.enableSsh
userConfig.pubkeySshFirstUser = core.getInput('pubkey-ssh-first-user')
userConfig.pubkeyOnlySsh =
core.getInput('pubkey-only-ssh') || DEFAULT_CONFIG.pubkeyOnlySsh
userConfig.enableNoobs =
core.getBooleanInput('enable-noobs')?.toString() ||
DEFAULT_CONFIG.enableNoobs
userConfig.exportLastStageOnly =
core.getBooleanInput('export-last-stage-only')?.toString() ||
DEFAULT_CONFIG.exportLastStageOnly
userConfig.dockerOpts = core.getInput('docker-opts')
userConfig.setfcap = core.getInput('setfcap') || DEFAULT_CONFIG.setfcap
userConfig.piGenRelease =
core.getInput('pi-gen-release') || DEFAULT_CONFIG.piGenRelease
userConfig.aptProxy = core.getInput('apt-proxy') || DEFAULT_CONFIG.aptProxy
await validateConfig(userConfig)

await validateConfig(userConfig)
core.info(
colorize(JSON.stringify(userConfig, filterConfigFormat, 2), {
colors: {
Bracket: color.magenta,
Brace: color.magenta,
StringKey: color.cyanBright,
BooleanLiteral: color.blueBright,
NumberLiteral: color.greenBright,
NullLiteral: color.blueBright,
StringLiteral: color.red,
Whitespace: color.reset,
Colon: color.white,
Comma: color.white
}
})
)

core.info(
colorize(JSON.stringify(userConfig, filterConfigFormat, 2), {
colors: {
Bracket: color.magenta,
Brace: color.magenta,
StringKey: color.cyanBright,
BooleanLiteral: color.blueBright,
NumberLiteral: color.greenBright,
NullLiteral: color.blueBright,
StringLiteral: color.red,
Whitespace: color.reset,
Colon: color.white,
Comma: color.white
}
})
)

return userConfig
} finally {
core.endGroup()
}
return userConfig
}

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
Expand Down
Loading

0 comments on commit f92839e

Please sign in to comment.