Compare commits

..

No commits in common. "main" and "0.1.0" have entirely different histories.
main ... 0.1.0

18 changed files with 110359 additions and 173863 deletions

View file

@ -1,25 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
setup-bazel:
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
os:
- macos
- ubuntu
- windows
steps:
- uses: actions/checkout@v6
- uses: ./
- if: failure() && runner.debug == '1'
uses: mxschmitt/action-tmate@v3

View file

@ -1,37 +0,0 @@
name: Release
run-name: Release ${{ inputs.tag }}
on:
workflow_dispatch:
inputs:
tag:
description: Tag to release
required: true
default: 0.1.0
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
cache: npm
node-version-file: package.json
- run: |
sed -ri 's/"version": ".+"/"version": "${{ inputs.tag }}"/' package.json
sed -ri 's/setup-bazel@.+$/setup-bazel@${{ inputs.tag }}/g' README.md
- run: npm install
- run: npm run build
- run: |
git config user.name github-actions
git config user.email github-actions@github.com
- run: git commit -am "Release ${{ inputs.tag }}"
- run: git push
- run: git tag -a ${{ inputs.tag }} -m "Release ${{ inputs.tag }}"
- run: git push --tags
- run: gh release create ${{ inputs.tag }} --generate-notes
env:
GH_TOKEN: ${{ github.token }}

View file

@ -1 +0,0 @@
nodejs 24.14.0

294
README.md
View file

@ -1,21 +1,8 @@
# setup-bazel
This action allows to properly configure Bazelisk and Bazel on all operating systems
This action allows to properly configure Bazel on all supported operating systems
and provides an advanced fine-grained caching to improve workflows performance.
## Usage
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
# Avoid downloading Bazel every time.
bazelisk-cache: true
# Store build cache per workflow.
disk-cache: ${{ github.workflow }}
# Share repository cache between workflows.
repository-cache: true
```
## Inputs
### `bazelisk-cache`
@ -24,89 +11,12 @@ Cache [`bazelisk`][1] downloads based on contents of a `.bazelversion` file.
Default `false`.
### `bazelisk-version`
[`bazelisk`][1] version to download and use.
Supports semver specification and ranges.
Leave empty to use [pre-installed Bazelisk][8].
Default `""`.
<details>
<summary>Examples</summary>
#### Install Bazelisk 1.x
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelisk-version: 1.x
```
#### Install exact Bazelisk version
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelisk-version: 1.19.0
```
</details>
### `bazelrc`
Extra contents to write to a user's [`bazelrc`][4] file.
You can use multiline YAML strings.
Default `""`.
<details>
<summary>Examples</summary>
#### Enable Bzlmod
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelrc: common --enable_bzlmod
```
#### Add colors and timestamps
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelrc: |
build --color=yes
build --show_timestamps
```
</details>
### `cache-save`
Whether to save caches at the end of the workflow.
Set to `false` for pull requests to allow cache restoration without saving,
which prevents PRs from polluting the cache while still benefiting from it.
Default `true`.
<details>
<summary>Examples</summary>
#### Disable cache saving on pull requests
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelisk-cache: true
disk-cache: ${{ github.workflow }}
repository-cache: true
cache-save: ${{ github.event_name != 'pull_request' }}
```
</details>
### `disk-cache`
Enable [`disk_cache`][2] and store it on GitHub based on contents of `BUILD` files.
@ -115,183 +25,83 @@ You can also pass a string to use as a cache key to separate caches from differe
Default `false`.
<details>
<summary>Examples</summary>
#### Share a single disk cache
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
disk-cache: true
```
#### Separate disk caches between workflows
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
disk-cache: ${{ github.workflow }}
```
</details>
### `external-cache`
Cache `external/` repositories based on contents of `MODULE.bazel` and `WORKSPACE` files.
Cache `external/` repositories based on contents of a `WORKSPACE` file.
Only repositories exceeding 10MB are being cached.
Each repository is stored in a separate cache.
You can also pass a `manifest` object where key is the name of the external repository
and value is a file (or list of files) which contents are used to calculate cache key.
If the value is `false`, the external repository won't be cached.
You can also pass a YAML object where key is the name of the external repository
and value is the list of files which contents are used to calculate cache key.
Default `false`.
<details>
<summary>Examples</summary>
#### Enable external repositories caches
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
external-cache: true
```
#### Cache NPM repositories based on `package-lock.json` contents
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
external-cache: |
manifest:
npm: package-lock.json
```
#### Do not cache Ruby on Windows
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
external-cache: |
manifest:
ruby: ${{ runner.os == 'Windows' && 'false' || 'true' }}
```
</details>
### `google-credentials`
Google Cloud account key to use for [remote caching authentication][9].
Default `""`.
<details>
<summary>Examples</summary>
#### Authenticate via key
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
google-credentials: ${{ secrets.GOOGLE_CLOUD_KEY }}
```
</details>
### `module-root`
Bazel module root directory, where `MODULE.bazel` and `WORKSPACE` is found.
Change this value to the module root if it's not the repository root.
Default `"."`.
### `output-base`
Change Bazel output base directory.
You might want to change it when running on self-hosted runners with a custom directory layout.
Default is one of the following:
- `$HOME/.bazel` on Linux and macOS
- `D:/_bazel` on Windows
<details>
<summary>Examples</summary>
#### Use `C` drive letter
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
output-base: C:/_bazel
```
</details>
### `repository-cache`
Enable [`repository_cache`][3] and store it on GitHub based on contents of `MODULE.bazel` and `WORKSPACE` files.
You can also pass a file (or list of files) which contents are used to calculate cache key.
Enable [`repository_cache`][3] and store it on GitHub based on contents of a `WORKSPACE` file.
Default `false`.
<details>
<summary>Examples</summary>
### `token`
#### Store a single repository cache
GitHub API token used by `external-cache` to fetch all available caches.
Not used when external cache is disabled.
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
repository-cache: true
```
Default `""`.
#### Store a repository cache from a custom location
### `use-gnu-tar-on-windows`
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
repository-cache: examples/gem/WORKSPACE
```
Enable GNU `tar` on Windows to optimize cache performance.
#### Store a repository cache from a list of custom locations
```yaml
- uses: bazel-contrib/setup-bazel@0.18.0
with:
repository-cache: |
- MODULE.bazel
- requirements_locked.txt
```
</details>
Default `true`.
## Migrating from [`bazelbuild/setup-bazelisk`][6]
## Examples
You can simply replace `bazelbuild/setup-bazelisk` action with `bazel-contrib/setup-bazel`.
However, if you used a `bazel-version` input before, you will need to remove it in favor
[other ways to specify Bazel version][7].
### Simple configuration
## Development
To build action, run the following command:
```sh
$ npm install
$ npm run build
```yaml
- uses: p0deje/setup-bazel@0.1.0
```
## Release
### Additional `.bazelrc` options
Use [Release][10] workflow to cut a new release.
```yaml
- uses: p0deje/setup-bazel@0.1.0
with:
bazelrc: |
build --show_timestamps
```
### Full caching enabled
```yaml
- uses: p0deje/setup-bazel@0.1.0
with:
bazelisk-cache: true
disk-cache: true
external-cache: true
repository-cache: true
token: ${{ secrets.GITHUB_TOKEN }}
```
### Separate disk cache between workflows
```yaml
- uses: p0deje/setup-bazel@0.1.0
with:
disk-cache: ${{ github.workflow }}}
```
### Cache external repository based on different files
```yaml
- uses: p0deje/setup-bazel@0.1.0
with:
external-cache: |
npm: package-lock.json
token: ${{ secrets.GITHUB_TOKEN }}
```
[1]: https://github.com/bazelbuild/bazelisk
[2]: https://bazel.build/remote/caching#disk-cache
[3]: https://docs-staging.bazel.build/2338/versions/main/guide.html#the-repository-cache
[4]: https://bazel.build/run/bazelrc
[5]: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
[6]: https://github.com/bazelbuild/setup-bazelisk
[7]: https://github.com/bazelbuild/bazelisk/blob/master/README.md#how-does-bazelisk-know-which-bazel-version-to-run
[8]: https://github.com/actions/runner-images/pull/490
[9]: https://bazel.build/reference/command-line-reference#flag--google_credentials
[10]: https://github.com/bazel-contrib/setup-bazel/actions/workflows/release.yml

View file

@ -1,57 +1,44 @@
name: Setup Bazel environment
description: Setup a Bazel environment, including Bazelisk and fine-grained caching
name: Setup Bazel
inputs:
bazelisk-cache:
description: Caches Bazelisk downloads based on .bazelversion
required: false
default: "false"
bazelisk-version:
description: The Bazelisk version to download and use if necessary
default: ""
default: false
bazelrc:
description: Extra contents to write to user .bazelrc
required: false
default: ""
cache-save:
description: Whether to save caches. Set to false for pull requests to allow restores but prevent saves.
required: false
default: "true"
cache-version:
description: Version of all caches
required: false
default: "1"
default: 1
disk-cache:
description: Cache actions outputs based on BUILD
required: false
default: "false"
default: false
external-cache:
description: Cache external 10MB+ repositories based on MODULE.bazel/WORKSPACE
description: Cache external 10MB+ repositories based on WORKSPACE
required: false
default: ""
google-credentials:
description: Google Cloud account key for remote cache
required: false
default: ""
module-root:
description: Bazel module root directory. Default is `.`
repository-cache:
description: Cache repositories based on WORKSPACE
required: false
default: "."
output-base:
description: Bazel output base directory. Default is $HOME/.cache/bazel (POSIX) or D:/_bazel (Windows)
default: false
token:
description: GitHub token to use for external cache
required: false
default: ""
repository-cache:
description: Cache repositories based on MODULE.bazel/WORKSPACE
use-gnu-tar-on-windows:
description: Use GNU tar on Windows
required: false
default: "false"
token:
description: GitHub token to query Bazelisk releases
required: false
default: ${{ github.token }}
default: true
runs:
using: node20
using: node16
main: dist/main/index.js
post: dist/post/index.js
post-if: "!cancelled()"

123
config.js
View file

@ -2,34 +2,16 @@ const fs = require('fs')
const os = require('os')
const yaml = require('yaml')
const core = require('@actions/core')
const github = require('@actions/github')
const bazeliskVersion = core.getInput('bazelisk-version')
const cacheSave = core.getBooleanInput('cache-save')
const cacheVersion = core.getInput('cache-version')
const moduleRoot = core.getInput('module-root')
const externalCacheConfig = yaml.parse(core.getInput('external-cache'))
const homeDir = os.homedir()
const arch = os.arch()
const platform = os.platform()
let bazelOutputBase = core.getInput('output-base')
if (!bazelOutputBase) {
if (platform === 'win32') {
// check if GITHUB_WORKSPACE starts with D:
if (process.env.GITHUB_WORKSPACE?.toLowerCase()?.startsWith('d:')) {
bazelOutputBase = 'D:/_bazel'
} else {
bazelOutputBase = `C:/_bazel`
}
} else {
bazelOutputBase = `${homeDir}/.bazel`
}
}
let bazelDisk = core.toPosixPath(`${homeDir}/.cache/bazel-disk`)
let bazelRepository = core.toPosixPath(`${homeDir}/.cache/bazel-repo`)
let bazelrcPaths = [core.toPosixPath(`${homeDir}/.bazelrc`)]
let bazelOutputBase = `${homeDir}/.bazel`
let userCacheDir = `${homeDir}/.cache`
switch (platform) {
@ -37,122 +19,85 @@ switch (platform) {
userCacheDir = `${homeDir}/Library/Caches`
break
case 'win32':
bazelDisk = `${bazelOutputBase}-disk`
bazelRepository = `${bazelOutputBase}-repo`
bazelDisk = 'D:/_bazel-disk'
bazelRepository = 'D:/_bazel-repo'
bazelOutputBase = 'D:/_bazel'
userCacheDir = `${homeDir}/AppData/Local`
if (process.env.HOME) {
bazelrcPaths.push(core.toPosixPath(`${process.env.HOME}/.bazelrc`))
}
break
}
const baseCacheKey = `setup-bazel-${cacheVersion}-${platform}-${arch}`
const baseCacheKey = `setup-bazel-${cacheVersion}-${platform}`
const bazelrc = core.getMultilineInput('bazelrc')
const diskCacheConfig = core.getInput('disk-cache')
const diskCacheEnabled = diskCacheConfig !== 'false'
let diskCacheName = 'disk'
if (diskCacheEnabled) {
// Before Bazel 6.3, providing --disk_cache to common is an error,
// with Bazel 6.3 and onwards, common accepts any legal Bazel option
// https://github.com/bazelbuild/bazel/issues/3054
bazelrc.push(`build --disk_cache=${bazelDisk}`)
if (diskCacheName !== 'true') {
diskCacheName = `${diskCacheName}-${diskCacheConfig}`
}
}
const repositoryCacheConfig = yaml.parse(core.getInput('repository-cache'))
const repositoryCacheEnabled = repositoryCacheConfig !== false
let repositoryCacheFiles = [
`${moduleRoot}/MODULE.bazel`,
`${moduleRoot}/WORKSPACE.bazel`,
`${moduleRoot}/WORKSPACE.bzlmod`,
`${moduleRoot}/WORKSPACE`
]
const repositoryCacheEnabled = core.getBooleanInput('repository-cache')
if (repositoryCacheEnabled) {
bazelrc.push(`common --repository_cache=${bazelRepository}`)
if (repositoryCacheConfig !== true) {
repositoryCacheFiles = Array(repositoryCacheConfig).flat()
}
bazelrc.push(`build --repository_cache=${bazelRepository}`)
}
const googleCredentials = core.getInput('google-credentials')
const googleCredentialsSaved = (core.getState('google-credentials-path').length > 0)
if (googleCredentials.length > 0 && !googleCredentialsSaved) {
const tmpDir = core.toPosixPath(fs.mkdtempSync(process.env.RUNNER_TEMP))
const tmpDir = core.toPosixPath(fs.mkdtempSync(os.tmpdir()))
const googleCredentialsPath = `${tmpDir}/key.json`
fs.writeFileSync(googleCredentialsPath, googleCredentials)
bazelrc.push(`build --google_credentials=${googleCredentialsPath}`)
core.saveState('google-credentials-path', googleCredentialsPath)
}
const externalCacheConfig = yaml.parse(core.getInput('external-cache'))
const bazelExternal = core.toPosixPath(`${bazelOutputBase}/external`)
const externalCache = {}
if (externalCacheConfig) {
const { workflow, job } = github.context
const manifestName = externalCacheConfig.name ||
`${workflow.toLowerCase().replaceAll(/[ /]/g, '-')}-${job}`
externalCache.enabled = true
externalCache.minSize = 10 // MB
externalCache.baseCacheKey = `${baseCacheKey}-external-`
externalCache.manifest = {
files: [
`${moduleRoot}/MODULE.bazel`,
`${moduleRoot}/WORKSPACE.bazel`,
`${moduleRoot}/WORKSPACE.bzlmod`,
`${moduleRoot}/WORKSPACE`
],
name: `external-${manifestName}-manifest`,
path: `${os.tmpdir()}/external-cache-manifest.txt`
}
externalCache.regexp = `^${baseCacheKey}-external-(?<name>.+)-[a-z0-9]+$`
externalCache.default = {
enabled: true,
files: [
`${moduleRoot}/MODULE.bazel`,
`${moduleRoot}/WORKSPACE.bazel`,
`${moduleRoot}/WORKSPACE.bzlmod`,
`${moduleRoot}/WORKSPACE`
],
name: (name) => { return `external-${name}` },
paths: (name) => {
return [
`${bazelExternal}/@${name}.marker`,
`${bazelExternal}/${name}`
]
}
'WORKSPACE.bazel',
'WORKSPACE'
]
}
externalCache.name = (name) => {
return `external-${name}`
}
externalCache.paths = (name) => {
return [
`${bazelExternal}/@${name}.marker`,
`${bazelExternal}/${name}`
]
}
for (const name in externalCacheConfig.manifest) {
for (const name in externalCacheConfig) {
externalCache[name] = {
enabled: externalCacheConfig.manifest[name] != false,
files: Array(externalCacheConfig.manifest[name]).flat()
files: Array(externalCacheConfig[name]).flat()
}
}
}
const token = core.getInput('token')
core.exportVariable('BAZELISK_GITHUB_TOKEN', token)
module.exports = {
baseCacheKey,
cacheSave,
bazeliskCache: {
enabled: core.getBooleanInput('bazelisk-cache'),
files: [`${moduleRoot}/.bazelversion`],
files: ['.bazelversion'],
name: 'bazelisk',
paths: [core.toPosixPath(`${userCacheDir}/bazelisk`)]
},
bazeliskVersion,
bazelrc,
diskCache: {
enabled: diskCacheEnabled,
files: [
...repositoryCacheFiles,
`${moduleRoot}/**/BUILD.bazel`,
`${moduleRoot}/**/BUILD`
'**/BUILD.bazel',
'**/BUILD'
],
name: diskCacheName,
paths: [bazelDisk]
@ -161,16 +106,18 @@ module.exports = {
paths: {
bazelExternal,
bazelOutputBase: core.toPosixPath(bazelOutputBase),
bazelrc: bazelrcPaths
},
os: {
arch,
platform,
bazelrc: core.toPosixPath(`${homeDir}/.bazelrc`)
},
platform,
repositoryCache: {
enabled: repositoryCacheEnabled,
files: repositoryCacheFiles,
files: [
'WORKSPACE.bazel',
'WORKSPACE'
],
name: 'repository',
paths: [bazelRepository]
},
token: core.getInput('token'),
useGnuTarOnWindows: core.getBooleanInput('use-gnu-tar-on-windows')
}

142626
dist/main/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

138432
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

238
index.js
View file

@ -1,13 +1,11 @@
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() {
async function run () {
try {
await setupBazel()
} catch (error) {
@ -15,174 +13,104 @@ async function run() {
}
}
async function setupBazel() {
async function setupBazel () {
core.startGroup('Configure Bazel')
core.info('Configuration:')
core.info(JSON.stringify(config, null, 2))
console.log('Configuration:')
console.log(JSON.stringify(config, null, 2))
await setupBazelrc()
core.endGroup()
await setupBazelisk()
await useGnuTarOnWindows()
await restoreCache(config.bazeliskCache)
await restoreCache(config.diskCache)
await restoreCache(config.repositoryCache)
await restoreExternalCaches(config.externalCache)
}
async function setupBazelisk() {
if (config.bazeliskVersion.length == 0) {
async function setupBazelrc () {
fs.writeFileSync(
config.paths.bazelrc,
`startup --output_base=${config.paths.bazelOutputBase}\n`
)
for (const line of config.bazelrc) {
fs.appendFileSync(config.paths.bazelrc, `${line}\n`)
}
}
// https://github.com/actions/cache/blob/main/tips-and-workarounds.md#improving-cache-restore-performance-on-windowsusing-cross-os-caching
async function useGnuTarOnWindows () {
if (config.useGnuTarOnWindows && config.platform === 'win32') {
if (config.bazeliskCache.enabled || config.diskCache.enabled ||
config.repositoryCache.enabled || config.externalCache.enabled) {
core.addPath('C:\\Program Files\\Git\\usr\\bin')
}
}
}
async function restoreExternalCaches (cacheConfig) {
if (!cacheConfig.enabled) {
return
}
core.startGroup('Setup Bazelisk')
let toolPath = tc.find('bazelisk', config.bazeliskVersion)
if (toolPath) {
core.debug(`Found in cache @ ${toolPath}`)
} else {
toolPath = await downloadBazelisk()
const repo = github.context.repo
const octokit = github.getOctokit(config.token)
const { data: { actions_caches: caches } } = await octokit.rest.actions.getActionsCacheList({
owner: repo.owner,
repo: repo.repo,
key: cacheConfig.baseCacheKey,
per_page: 100
})
const names = new Set([])
const regexp = new RegExp(cacheConfig.regexp)
for (const cache of caches) {
core.debug(`Cache key is ${cache.key}`)
const match = cache.key.match(regexp)
if (match) {
names.add(match.groups.name)
}
}
core.addPath(toolPath)
for (const name of names) {
await restoreCache({
enabled: true,
files: cacheConfig[name]?.files || cacheConfig.default.files,
name: cacheConfig.name(name),
paths: cacheConfig.paths(name)
})
}
}
async function restoreCache (cacheConfig) {
if (!cacheConfig.enabled) {
return
}
core.startGroup(`Restore cache for ${cacheConfig.name}`)
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}`
console.log(`Attempting to restore ${name} cache from ${key}`)
const restoredKey = await cache.restoreCache(paths, key, [restoreKey])
if (restoredKey) {
console.log(`Successfully restored cache from ${restoredKey}`)
if (restoredKey === key) {
core.saveState(`${name}-cache-hit`, 'true')
}
} else {
console.log(`Failed to restore ${name} cache`)
}
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()

1063
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,8 @@
{
"name": "setup-bazel",
"version": "0.18.0",
"version": "0.1.0",
"description": "Install and configure Bazel for GitHub Actions",
"main": "index.js",
"engines": {
"node": "24.x"
},
"scripts": {
"build": "ncc build index.js -s -o dist/main && ncc build post.js -s -o dist/post",
"test": "echo \"Error: no test specified\" && exit 1"
@ -13,12 +10,11 @@
"author": "Alex Rodionov <p0deje@gmail.com>",
"license": "MIT",
"dependencies": {
"@actions/cache": "^6.0.0",
"@actions/core": "^3.0.0",
"@actions/github": "^9.0.0",
"@actions/glob": "^0.6.0",
"@actions/tool-cache": "^4.0.0",
"@vercel/ncc": "^0.38.0",
"@actions/cache": "https://github.com/p0deje/toolkit/raw/119134874a4fac8906eaa42635597205de219a0b/packages/cache/actions-cache-3.1.1.tgz",
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"@actions/glob": "^0.3.0",
"@vercel/ncc": "^0.36.0",
"yaml": "^2.2.1"
}
}

41
post.js
View file

@ -1,30 +1,22 @@
const fs = require('fs')
const path = require('path')
const cache = require('@actions/cache')
const core = require('@actions/core')
const glob = require('@actions/glob')
const config = require('./config')
const { getFolderSize } = require('./util')
const process = require('node:process');
async function run() {
async function run () {
await saveCaches()
process.exit(0)
}
async function saveCaches() {
if (!config.cacheSave) {
core.info('Cache saving is disabled (cache-save: false)')
return
}
async function saveCaches () {
await saveCache(config.bazeliskCache)
await saveCache(config.diskCache)
await saveCache(config.repositoryCache)
await saveExternalCaches(config.externalCache)
}
async function saveExternalCaches(cacheConfig) {
async function saveExternalCaches (cacheConfig) {
if (!cacheConfig.enabled) {
return
}
@ -34,7 +26,6 @@ async function saveExternalCaches(cacheConfig) {
{ implicitDescendants: false }
)
const externalPaths = await globber.glob()
const savedCaches = []
for (const externalPath of externalPaths) {
const size = await getFolderSize(externalPath)
@ -44,28 +35,16 @@ async function saveExternalCaches(cacheConfig) {
if (sizeMB >= cacheConfig.minSize) {
const name = path.basename(externalPath)
await saveCache({
enabled: cacheConfig[name]?.enabled ?? cacheConfig.default.enabled,
enabled: true,
files: cacheConfig[name]?.files || cacheConfig.default.files,
name: cacheConfig.default.name(name),
paths: cacheConfig.default.paths(name)
name: cacheConfig.name(name),
paths: cacheConfig.paths(name)
})
savedCaches.push(name)
}
}
if (savedCaches.length > 0) {
const path = cacheConfig.manifest.path
fs.writeFileSync(path, savedCaches.join('\n'))
await saveCache({
enabled: true,
files: cacheConfig.manifest.files,
name: cacheConfig.manifest.name,
paths: [path]
})
}
}
async function saveCache(cacheConfig) {
async function saveCache (cacheConfig) {
if (!cacheConfig.enabled) {
return
}
@ -81,14 +60,12 @@ async function saveCache(cacheConfig) {
const paths = cacheConfig.paths
const hash = await glob.hashFiles(
cacheConfig.files.join('\n'),
undefined,
// We don't want to follow symlinks as it's extremely slow on macOS.
{ followSymbolicLinks: false }
)
const key = `${config.baseCacheKey}-${cacheConfig.name}-${hash}`
core.debug(`Attempting to save ${paths} cache to ${key}`)
console.log(`Attempting to save ${paths} cache to ${key}`)
await cache.saveCache(paths, key)
core.info('Successfully saved cache')
console.log('Successfully saved cache')
} catch (error) {
core.warning(error.stack)
} finally {

View file

@ -1,6 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}

11
util.js
View file

@ -12,9 +12,8 @@ async function getFolderSize (rootItemPath, options = {}) {
async function processItem (itemPath) {
if (options.ignore?.test(itemPath)) return
const stats = lstatSync(itemPath, { bigint: true })
const stats = fs.lstatSync(itemPath, { bigint: true })
if (typeof stats !== 'object') return
fileSizes.set(stats.ino, stats.size)
if (stats.isDirectory()) {
@ -40,12 +39,4 @@ async function getFolderSize (rootItemPath, options = {}) {
return folderSize
}
function lstatSync(path, opts) {
try {
return fs.lstatSync(path, opts)
} catch (error) {
return
}
}
module.exports = { getFolderSize }