diff --git a/README.md b/README.md index c49027df3..2018b721e 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,19 @@ It is also possible to cache gems manually, but this is not recommended because There are many concerns which means using `actions/cache` is never enough for caching gems (e.g., incomplete cache key, cleaning old gems when restoring from another key, correctly hashing the lockfile if not checked in, OS versions, ABI compatibility for `ruby-head`, etc). So, please use `bundler-cache: true` instead and report any issue. +#### Caching with an ephemeral working directory + +A runner could be set up to use an ephemeral working directory per build, e.g. `/codebuild/output/src3500696690/src/actions-runner/_work/my-project`. +By default, the cache key includes the full working directory path; but for an ephemeral working directory, it wouldn't produce the same key across runs, resulting in an inability to restore from the cache. +To resolve this, set the `project-id` option to a name to identify your project. When provided, this is used instead of the working directory path in the cache key. + +```yaml + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + project-id: my-project +``` + ### Authentication Token By default, this action uses `${{ github.token }}` to authenticate when downloading Ruby release assets from GitHub. diff --git a/action.yml b/action.yml index ab758fba0..47fcd3fa0 100644 --- a/action.yml +++ b/action.yml @@ -50,6 +50,10 @@ inputs: When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting. default: ${{ github.server_url == 'https://github.com' && github.token || '' }} + project-id: + description: | + A name to identify your project, for inclusion in the Bundler cache key instead of the full working directory path. + Useful when your runner is set up to use an ephemeral working directory per build. outputs: ruby-prefix: diff --git a/bundler.js b/bundler.js index ff8fc9c3c..fb185615d 100644 --- a/bundler.js +++ b/bundler.js @@ -155,7 +155,7 @@ function bundlerConfigSetArgs(bundlerVersion, key, value) { } } -export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { +export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion, projectId) { if (gemfile === null) { console.log('Could not determine gemfile path, skipping "bundle install" and caching') return false @@ -189,7 +189,7 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer // cache key const paths = [cachePath] - const baseKey = await computeBaseKey(engine, rubyVersion, lockFile, cacheVersion) + const baseKey = await computeBaseKey(engine, rubyVersion, lockFile, cacheVersion, projectId) const key = `${baseKey}-${await common.hashFile(lockFile)}` // If only Gemfile.lock changes we can reuse part of the cache, and clean old gem versions below const restoreKeys = [`${baseKey}-`] @@ -242,12 +242,12 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer return true } -async function computeBaseKey(engine, version, lockFile, cacheVersion) { - const cwd = process.cwd() +async function computeBaseKey(engine, version, lockFile, cacheVersion, specifiedProjectId) { + const projectId = specifiedProjectId || `wd-${process.cwd()}` const bundleWith = process.env['BUNDLE_WITH'] || '' const bundleWithout = process.env['BUNDLE_WITHOUT'] || '' const bundleOnly = process.env['BUNDLE_ONLY'] || '' - let key = `setup-ruby-bundler-cache-v6-${common.getOSNameVersionArch()}-${engine}-${version}-wd-${cwd}-with-${bundleWith}-without-${bundleWithout}-only-${bundleOnly}` + let key = `setup-ruby-bundler-cache-v6-${common.getOSNameVersionArch()}-${engine}-${version}-${projectId}-with-${bundleWith}-without-${bundleWithout}-only-${bundleOnly}` if (cacheVersion !== DEFAULT_CACHE_VERSION) { key += `-v-${cacheVersion}` diff --git a/dist/index.js b/dist/index.js index 9f68aea27..9739e3459 100644 --- a/dist/index.js +++ b/dist/index.js @@ -169,7 +169,7 @@ function bundlerConfigSetArgs(bundlerVersion, key, value) { } } -async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { +async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion, projectId) { if (gemfile === null) { console.log('Could not determine gemfile path, skipping "bundle install" and caching') return false @@ -203,7 +203,7 @@ async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, b // cache key const paths = [cachePath] - const baseKey = await computeBaseKey(engine, rubyVersion, lockFile, cacheVersion) + const baseKey = await computeBaseKey(engine, rubyVersion, lockFile, cacheVersion, projectId) const key = `${baseKey}-${await common.hashFile(lockFile)}` // If only Gemfile.lock changes we can reuse part of the cache, and clean old gem versions below const restoreKeys = [`${baseKey}-`] @@ -256,12 +256,12 @@ async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, b return true } -async function computeBaseKey(engine, version, lockFile, cacheVersion) { - const cwd = process.cwd() +async function computeBaseKey(engine, version, lockFile, cacheVersion, specifiedProjectId) { + const projectId = specifiedProjectId || `wd-${process.cwd()}` const bundleWith = process.env['BUNDLE_WITH'] || '' const bundleWithout = process.env['BUNDLE_WITHOUT'] || '' const bundleOnly = process.env['BUNDLE_ONLY'] || '' - let key = `setup-ruby-bundler-cache-v6-${common.getOSNameVersionArch()}-${engine}-${version}-wd-${cwd}-with-${bundleWith}-without-${bundleWithout}-only-${bundleOnly}` + let key = `setup-ruby-bundler-cache-v6-${common.getOSNameVersionArch()}-${engine}-${version}-${projectId}-with-${bundleWith}-without-${bundleWithout}-only-${bundleOnly}` if (cacheVersion !== DEFAULT_CACHE_VERSION) { key += `-v-${cacheVersion}` @@ -92506,6 +92506,7 @@ const inputDefaults = { 'self-hosted': 'false', 'windows-toolchain': 'default', 'token': '', + 'project-id': null, } // entry point when this action is run on its own @@ -92587,7 +92588,7 @@ async function setupRuby(options = {}) { if (inputs['bundler-cache'] === 'true') { await common.time('bundle install', async () => - bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion, inputs['cache-version'])) + bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion, inputs['cache-version'], inputs['project-id'])) } core.setOutput('ruby-prefix', rubyPrefix) diff --git a/index.js b/index.js index 4edc71614..18a9e2345 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ const inputDefaults = { 'self-hosted': 'false', 'windows-toolchain': 'default', 'token': '', + 'project-id': null, } // entry point when this action is run on its own @@ -100,7 +101,7 @@ export async function setupRuby(options = {}) { if (inputs['bundler-cache'] === 'true') { await common.time('bundle install', async () => - bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion, inputs['cache-version'])) + bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion, inputs['cache-version'], inputs['project-id'])) } core.setOutput('ruby-prefix', rubyPrefix)