188 lines
5.3 KiB
JavaScript
188 lines
5.3 KiB
JavaScript
const fs = require('fs')
|
|
const { setTimeout } = require('timers/promises')
|
|
const core = require('@actions/core')
|
|
const cache = require('@actions/cache')
|
|
const github = require('@actions/github')
|
|
const glob = require('@actions/glob')
|
|
const tc = require('@actions/tool-cache')
|
|
const config = require('./config')
|
|
|
|
async function run() {
|
|
try {
|
|
await setupBazel()
|
|
} catch (error) {
|
|
core.setFailed(error.stack)
|
|
}
|
|
}
|
|
|
|
async function setupBazel() {
|
|
core.startGroup('Configure Bazel')
|
|
core.info('Configuration:')
|
|
core.info(JSON.stringify(config, null, 2))
|
|
|
|
await setupBazelrc()
|
|
core.endGroup()
|
|
|
|
await setupBazelisk()
|
|
await restoreCache(config.bazeliskCache)
|
|
await restoreCache(config.diskCache)
|
|
await restoreCache(config.repositoryCache)
|
|
await restoreExternalCaches(config.externalCache)
|
|
}
|
|
|
|
async function setupBazelisk() {
|
|
if (config.bazeliskVersion.length == 0) {
|
|
return
|
|
}
|
|
|
|
core.startGroup('Setup Bazelisk')
|
|
let toolPath = tc.find('bazelisk', config.bazeliskVersion)
|
|
if (toolPath) {
|
|
core.debug(`Found in cache @ ${toolPath}`)
|
|
} else {
|
|
toolPath = await downloadBazelisk()
|
|
}
|
|
core.addPath(toolPath)
|
|
core.endGroup()
|
|
}
|
|
|
|
async function downloadBazelisk() {
|
|
const version = config.bazeliskVersion
|
|
core.debug(`Attempting to download ${version}`)
|
|
|
|
// Possible values are 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x' and 'x64'.
|
|
// Bazelisk filenames use 'amd64' and 'arm64'.
|
|
let arch = config.os.arch
|
|
if (arch == 'x64') {
|
|
arch = 'amd64'
|
|
}
|
|
|
|
// Possible values are 'aix', 'darwin', 'freebsd', 'linux', 'openbsd', 'sunos' and 'win32'.
|
|
// Bazelisk filenames use 'darwin', 'linux' and 'windows'.
|
|
let platform = config.os.platform
|
|
if (platform == "win32") {
|
|
platform = "windows"
|
|
}
|
|
|
|
let filename = `bazelisk-${platform}-${arch}`
|
|
if (platform == 'windows') {
|
|
filename = `${filename}.exe`
|
|
}
|
|
|
|
const token = process.env.BAZELISK_GITHUB_TOKEN
|
|
const octokit = github.getOctokit(token, {
|
|
baseUrl: 'https://api.github.com'
|
|
})
|
|
const { data: releases } = await octokit.rest.repos.listReleases({
|
|
owner: 'bazelbuild',
|
|
repo: 'bazelisk'
|
|
})
|
|
|
|
// Find version matching semver specification.
|
|
const tagName = tc.evaluateVersions(releases.map((r) => r.tag_name), version)
|
|
const release = releases.find((r) => r.tag_name === tagName)
|
|
if (!release) {
|
|
throw new Error(`Unable to find Bazelisk version ${version}`)
|
|
}
|
|
|
|
const asset = release.assets.find((a) => a.name == filename)
|
|
if (!asset) {
|
|
throw new Error(`Unable to find Bazelisk version ${version} for platform ${platform}/${arch}`)
|
|
}
|
|
|
|
const url = asset.browser_download_url
|
|
core.debug(`Downloading from ${url}`)
|
|
const downloadPath = await tc.downloadTool(url, undefined, `token ${token}`)
|
|
|
|
core.debug('Adding to the cache...');
|
|
fs.chmodSync(downloadPath, '755');
|
|
let bazel_name = "bazel";
|
|
if (platform == 'windows') {
|
|
bazel_name = `${bazel_name}.exe`
|
|
}
|
|
const cachePath = await tc.cacheFile(downloadPath, bazel_name, 'bazelisk', version)
|
|
core.debug(`Successfully cached bazelisk to ${cachePath}`)
|
|
|
|
return cachePath
|
|
}
|
|
|
|
async function setupBazelrc() {
|
|
for (const bazelrcPath of config.paths.bazelrc) {
|
|
fs.writeFileSync(
|
|
bazelrcPath,
|
|
`startup --output_base=${config.paths.bazelOutputBase}\n`
|
|
)
|
|
fs.appendFileSync(bazelrcPath, config.bazelrc.join("\n"))
|
|
}
|
|
}
|
|
|
|
async function restoreExternalCaches(cacheConfig) {
|
|
if (!cacheConfig.enabled) {
|
|
return
|
|
}
|
|
|
|
// First fetch the manifest of external caches used.
|
|
const path = cacheConfig.manifest.path
|
|
await restoreCache({
|
|
enabled: true,
|
|
files: cacheConfig.manifest.files,
|
|
name: cacheConfig.manifest.name,
|
|
paths: [path]
|
|
})
|
|
|
|
// Now restore all external caches defined in manifest
|
|
if (fs.existsSync(path)) {
|
|
const manifest = fs.readFileSync(path, { encoding: 'utf8' })
|
|
const restorePromises = manifest.split('\n').filter(s => s)
|
|
.map(name => {
|
|
return restoreCache({
|
|
enabled: cacheConfig[name]?.enabled ?? cacheConfig.default.enabled,
|
|
files: cacheConfig[name]?.files || cacheConfig.default.files,
|
|
name: cacheConfig.default.name(name),
|
|
paths: cacheConfig.default.paths(name)
|
|
});
|
|
});
|
|
await Promise.all(restorePromises);
|
|
}
|
|
}
|
|
|
|
async function restoreCache(cacheConfig) {
|
|
if (!cacheConfig.enabled) {
|
|
return
|
|
}
|
|
|
|
const delay = Math.random() * 1000 // timeout <= 1 sec to reduce 429 errors
|
|
await setTimeout(delay)
|
|
|
|
core.startGroup(`Restore cache for ${cacheConfig.name}`)
|
|
try {
|
|
const hash = await glob.hashFiles(cacheConfig.files.join('\n'))
|
|
const name = cacheConfig.name
|
|
const paths = cacheConfig.paths
|
|
const restoreKey = `${config.baseCacheKey}-${name}-`
|
|
const key = `${restoreKey}${hash}`
|
|
|
|
core.debug(`Attempting to restore ${name} cache from ${key}`)
|
|
|
|
const restoredKey = await cache.restoreCache(
|
|
paths, key, [restoreKey],
|
|
{ segmentTimeoutInMs: 300000 } // 5 minutes
|
|
)
|
|
|
|
if (restoredKey) {
|
|
core.info(`Successfully restored cache from ${restoredKey}`)
|
|
|
|
if (restoredKey === key) {
|
|
core.saveState(`${name}-cache-hit`, 'true')
|
|
}
|
|
} else {
|
|
core.info(`Failed to restore ${name} cache`)
|
|
}
|
|
} catch (err) {
|
|
core.warning(`Failed to restore ${name} cache with error: ${err}`)
|
|
} finally {
|
|
core.endGroup()
|
|
}
|
|
}
|
|
|
|
run()
|