diff --git a/action.yml b/action.yml index 9328b12c2..55dbb3e1f 100644 --- a/action.yml +++ b/action.yml @@ -30,6 +30,11 @@ inputs: description: | Arbitrary string that will be added to the cache key of the bundler cache. Set or change it if you need to invalidate the cache. + self-hosted: + description: | + Consider the runner as a self-hosted runner, which means not using prebuilt Ruby binaries which only work + on GitHub-hosted runners or self-hosted runners with a very similar image to the ones used by GitHub runners. + The default is to detect this automatically based on the OS, OS version and $RUNNER_TOOL_CACHE. outputs: ruby-prefix: description: 'The prefix of the installed ruby' diff --git a/common.js b/common.js index e1de56945..8fe2529f0 100644 --- a/common.js +++ b/common.js @@ -13,6 +13,10 @@ export const windows = (os.platform() === 'win32') // Extract to SSD on Windows, see https://github.com/ruby/setup-ruby/pull/14 export const drive = (windows ? (process.env['GITHUB_WORKSPACE'] || 'C')[0] : undefined) +export const inputs = { + selfHosted: undefined +} + export function partition(string, separator) { const i = string.indexOf(separator) if (i === -1) { @@ -162,9 +166,29 @@ const GitHubHostedPlatforms = [ 'windows-2022-x64', ] -// Actually a self-hosted runner which does not correspond to a GitHub-hosted runner image +// Actually a self-hosted runner for which either +// * the OS and OS version does not correspond to a GitHub-hosted runner image, +// * or the hosted tool cache is different from the default tool cache path export function isSelfHostedRunner() { - return !GitHubHostedPlatforms.includes(getOSNameVersionArch()) + if (inputs.selfHosted === undefined) { + throw new Error('inputs.selfHosted should have been already set') + } + + return inputs.selfHosted === 'true' || + !GitHubHostedPlatforms.includes(getOSNameVersionArch()) || + getRunnerToolCache() !== getDefaultToolCachePath() +} + +export function selfHostedRunnerReason() { + if (inputs.selfHosted === 'true') { + return 'the self-hosted input was set' + } else if (!GitHubHostedPlatforms.includes(getOSNameVersionArch())) { + return 'the platform does not match a GitHub-hosted runner image (or that image is deprecated and no longer supported)' + } else if (getRunnerToolCache() !== getDefaultToolCachePath()) { + return 'the $RUNNER_TOOL_CACHE is different than the default tool cache path (they must be the same to reuse prebuilt Ruby binaries)' + } else { + return 'unknown reason' + } } let virtualEnvironmentName = undefined @@ -213,28 +237,31 @@ export function shouldUseToolCache(engine, version) { return (engine === 'ruby' && !isHeadVersion(version)) || isSelfHostedRunner() } -function getPlatformToolCache(platform) { - if (isSelfHostedRunner()) { - const runnerToolCache = process.env['RUNNER_TOOL_CACHE'] - if (!runnerToolCache) { - throw new Error('$RUNNER_TOOL_CACHE must be set on self-hosted runners') - } - return runnerToolCache +export function getRunnerToolCache() { + const runnerToolCache = process.env['RUNNER_TOOL_CACHE'] + if (!runnerToolCache) { + throw new Error('$RUNNER_TOOL_CACHE must be set') } - // Hardcode paths rather than using $RUNNER_TOOL_CACHE because the prebuilt Rubies cannot be moved anyway + return runnerToolCache +} + +// Rubies prebuilt by this action embed this path rather than using $RUNNER_TOOL_CACHE, +// so they can only be used if the two paths are the same +function getDefaultToolCachePath() { + const platform = getVirtualEnvironmentName() if (platform.startsWith('ubuntu-')) { return '/opt/hostedtoolcache' } else if (platform.startsWith('macos-')) { return '/Users/runner/hostedtoolcache' } else if (platform.startsWith('windows-')) { - return 'C:/hostedtoolcache/windows' + return 'C:\\hostedtoolcache\\windows' } else { throw new Error('Unknown platform') } } export function getToolCacheRubyPrefix(platform, engine, version) { - const toolCache = getPlatformToolCache(platform) + const toolCache = getRunnerToolCache() const name = { ruby: 'Ruby', jruby: 'JRuby', diff --git a/dist/index.js b/dist/index.js index 21810eadb..1312e715b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -291,10 +291,12 @@ __nccwpck_require__.d(__webpack_exports__, { "drive": () => (/* binding */ drive), "floatVersion": () => (/* binding */ floatVersion), "getOSNameVersionArch": () => (/* binding */ getOSNameVersionArch), + "getRunnerToolCache": () => (/* binding */ getRunnerToolCache), "getToolCacheRubyPrefix": () => (/* binding */ getToolCacheRubyPrefix), "getVirtualEnvironmentName": () => (/* binding */ getVirtualEnvironmentName), "hasBundlerDefaultGem": () => (/* binding */ hasBundlerDefaultGem), "hashFile": () => (/* binding */ hashFile), + "inputs": () => (/* binding */ inputs), "isBundler1Default": () => (/* binding */ isBundler1Default), "isBundler2Default": () => (/* binding */ isBundler2Default), "isBundler2dot2Default": () => (/* binding */ isBundler2dot2Default), @@ -303,6 +305,7 @@ __nccwpck_require__.d(__webpack_exports__, { "isStableVersion": () => (/* binding */ isStableVersion), "measure": () => (/* binding */ measure), "partition": () => (/* binding */ partition), + "selfHostedRunnerReason": () => (/* binding */ selfHostedRunnerReason), "setupPath": () => (/* binding */ setupPath), "shouldUseToolCache": () => (/* binding */ shouldUseToolCache), "targetRubyVersion": () => (/* binding */ targetRubyVersion), @@ -365,6 +368,10 @@ const windows = (os.platform() === 'win32') // Extract to SSD on Windows, see https://github.com/ruby/setup-ruby/pull/14 const drive = (windows ? (process.env['GITHUB_WORKSPACE'] || 'C')[0] : undefined) +const inputs = { + selfHosted: undefined +} + function partition(string, separator) { const i = string.indexOf(separator) if (i === -1) { @@ -514,9 +521,29 @@ const GitHubHostedPlatforms = [ 'windows-2022-x64', ] -// Actually a self-hosted runner which does not correspond to a GitHub-hosted runner image +// Actually a self-hosted runner for which either +// * the OS and OS version does not correspond to a GitHub-hosted runner image, +// * or the hosted tool cache is different from the default tool cache path function isSelfHostedRunner() { - return !GitHubHostedPlatforms.includes(getOSNameVersionArch()) + if (inputs.selfHosted === undefined) { + throw new Error('inputs.selfHosted should have been already set') + } + + return inputs.selfHosted === 'true' || + !GitHubHostedPlatforms.includes(getOSNameVersionArch()) || + getRunnerToolCache() !== getDefaultToolCachePath() +} + +function selfHostedRunnerReason() { + if (inputs.selfHosted === 'true') { + return 'the self-hosted input was set' + } else if (!GitHubHostedPlatforms.includes(getOSNameVersionArch())) { + return 'the platform does not match a GitHub-hosted runner image (or that image is deprecated and no longer supported)' + } else if (getRunnerToolCache() !== getDefaultToolCachePath()) { + return 'the $RUNNER_TOOL_CACHE is different than the default tool cache path (they must be the same to reuse prebuilt Ruby binaries)' + } else { + return 'unknown reason' + } } let virtualEnvironmentName = undefined @@ -565,28 +592,31 @@ function shouldUseToolCache(engine, version) { return (engine === 'ruby' && !isHeadVersion(version)) || isSelfHostedRunner() } -function getPlatformToolCache(platform) { - if (isSelfHostedRunner()) { - const runnerToolCache = process.env['RUNNER_TOOL_CACHE'] - if (!runnerToolCache) { - throw new Error('$RUNNER_TOOL_CACHE must be set on self-hosted runners') - } - return runnerToolCache +function getRunnerToolCache() { + const runnerToolCache = process.env['RUNNER_TOOL_CACHE'] + if (!runnerToolCache) { + throw new Error('$RUNNER_TOOL_CACHE must be set') } - // Hardcode paths rather than using $RUNNER_TOOL_CACHE because the prebuilt Rubies cannot be moved anyway + return runnerToolCache +} + +// Rubies prebuilt by this action embed this path rather than using $RUNNER_TOOL_CACHE, +// so they can only be used if the two paths are the same +function getDefaultToolCachePath() { + const platform = getVirtualEnvironmentName() if (platform.startsWith('ubuntu-')) { return '/opt/hostedtoolcache' } else if (platform.startsWith('macos-')) { return '/Users/runner/hostedtoolcache' } else if (platform.startsWith('windows-')) { - return 'C:/hostedtoolcache/windows' + return 'C:\\hostedtoolcache\\windows' } else { throw new Error('Unknown platform') } } function getToolCacheRubyPrefix(platform, engine, version) { - const toolCache = getPlatformToolCache(platform) + const toolCache = getRunnerToolCache() const name = { ruby: 'Ruby', jruby: 'JRuby', @@ -68253,8 +68283,8 @@ async function install(platform, engine, version) { if (common.isSelfHostedRunner()) { const rubyBuildDefinition = engine === 'ruby' ? version : `${engine}-${version}` core.error( - `The current runner (${common.getOSNameVersionArch()}) was detected as self-hosted and not matching a GitHub-hosted runner image.\n` + - `In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build:\n` + + `The current runner (${common.getOSNameVersionArch()}, RUNNER_TOOL_CACHE=${common.getRunnerToolCache()}) was detected as self-hosted because ${common.selfHostedRunnerReason()}.\n` + + `In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build\n` + `You can take inspiration from this workflow for more details: https://github.com/ruby/ruby-builder/blob/master/.github/workflows/build.yml\n` + `$ ruby-build ${rubyBuildDefinition} ${toolCacheRubyPrefix}\n` + `Once that completes successfully, mark it as complete with:\n` + @@ -69015,6 +69045,7 @@ const inputDefaults = { 'bundler-cache': 'false', 'working-directory': '.', 'cache-version': bundler.DEFAULT_CACHE_VERSION, + 'self-hosted': 'false', } // entry point when this action is run on its own @@ -69038,6 +69069,7 @@ async function setupRuby(options = {}) { inputs[key] = core.getInput(key) || inputDefaults[key] } } + common.inputs.selfHosted = inputs['self-hosted'] process.chdir(inputs['working-directory']) diff --git a/index.js b/index.js index 2fe5aca97..bb8af7097 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,7 @@ const inputDefaults = { 'bundler-cache': 'false', 'working-directory': '.', 'cache-version': bundler.DEFAULT_CACHE_VERSION, + 'self-hosted': 'false', } // entry point when this action is run on its own @@ -39,6 +40,7 @@ export async function setupRuby(options = {}) { inputs[key] = core.getInput(key) || inputDefaults[key] } } + common.inputs.selfHosted = inputs['self-hosted'] process.chdir(inputs['working-directory']) diff --git a/ruby-builder.js b/ruby-builder.js index 4b124a35f..60388fde0 100644 --- a/ruby-builder.js +++ b/ruby-builder.js @@ -28,8 +28,8 @@ export async function install(platform, engine, version) { if (common.isSelfHostedRunner()) { const rubyBuildDefinition = engine === 'ruby' ? version : `${engine}-${version}` core.error( - `The current runner (${common.getOSNameVersionArch()}) was detected as self-hosted and not matching a GitHub-hosted runner image.\n` + - `In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build:\n` + + `The current runner (${common.getOSNameVersionArch()}, RUNNER_TOOL_CACHE=${common.getRunnerToolCache()}) was detected as self-hosted because ${common.selfHostedRunnerReason()}.\n` + + `In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build\n` + `You can take inspiration from this workflow for more details: https://github.com/ruby/ruby-builder/blob/master/.github/workflows/build.yml\n` + `$ ruby-build ${rubyBuildDefinition} ${toolCacheRubyPrefix}\n` + `Once that completes successfully, mark it as complete with:\n` +