diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index baa6c0578..3524f737d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,8 @@ jobs: '1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', ruby-head, jruby, jruby-head, truffleruby, truffleruby-head, - truffleruby+graalvm, truffleruby+graalvm-head + truffleruby+graalvm, truffleruby+graalvm-head, + system ] include: - { os: windows-2019, ruby: mingw } @@ -56,6 +57,7 @@ jobs: - { os: windows-2022, ruby: truffleruby-head } - { os: windows-2022, ruby: truffleruby+graalvm } - { os: windows-2022, ruby: truffleruby+graalvm-head } + - { os: windows-2022, ruby: system } name: ${{ matrix.os }} ${{ matrix.ruby }} runs-on: ${{ matrix.os }} @@ -63,6 +65,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./ + id: setup-ruby with: ruby-version: ${{ matrix.ruby }} bundler-cache: true @@ -72,6 +75,8 @@ jobs: run: | # Show PATH with Powershell $f, $r = $env:PATH.split([IO.Path]::PathSeparator); $r + - name: Ruby prefix output + run: echo "${{ steps.setup-ruby.outputs.ruby-prefix }}" - name: build compiler run: | @@ -107,6 +112,7 @@ jobs: - run: gem env - name: C extension test + if: matrix.ruby != 'system' run: gem install json -v 2.2.0 - run: bundle --version # This step is redundant with `bundler-cache: true` but is there to check a redundant `bundle install` still works @@ -129,6 +135,7 @@ jobs: if: startsWith(matrix.os, 'windows') - name: Test `gem github:` in a Gemfile + if: matrix.ruby != 'system' || !startsWith(matrix.os, 'ubuntu') run: bundle install env: BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/gem_from_github.gemfile diff --git a/action.yml b/action.yml index c36fafdb2..5eba2de8b 100644 --- a/action.yml +++ b/action.yml @@ -6,7 +6,10 @@ branding: icon: download inputs: ruby-version: - description: 'Engine and version to use, see the syntax in the README. Reads from .ruby-version or .tool-versions if unset.' + description: | + Engine and version to use. Either 'default' (the default), 'system', or a engine/version syntax described in the README. + For 'default', reads from .ruby-version or .tool-versions. + For 'system', don't install any Ruby and use the first available Ruby on the PATH. default: 'default' rubygems: description: | diff --git a/bundler.js b/bundler.js index d0f40eca3..909f3541b 100644 --- a/bundler.js +++ b/bundler.js @@ -2,7 +2,9 @@ const fs = require('fs') const path = require('path') const core = require('@actions/core') const exec = require('@actions/exec') +const io = require('@actions/io') const cache = require('@actions/cache') +const semver = require('semver') const common = require('./common') export const DEFAULT_CACHE_VERSION = '0' @@ -58,7 +60,7 @@ async function afterLockFile(lockFile, platform, engine, rubyVersion) { } } -export async function installBundler(bundlerVersionInput, rubygemsInputSet, lockFile, platform, rubyPrefix, engine, rubyVersion) { +export async function installBundler(bundlerVersionInput, rubygemsInputSet, systemRubyUsed, lockFile, platform, rubyPrefix, engine, rubyVersion) { let bundlerVersion = bundlerVersionInput if (rubygemsInputSet && (bundlerVersion === 'default' || bundlerVersion === 'Gemfile.lock')) { @@ -79,7 +81,21 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock const floatVersion = common.floatVersion(rubyVersion) if (bundlerVersion === 'default') { - if (common.isBundler2dot2Default(engine, rubyVersion)) { + if (systemRubyUsed) { + if (await io.which('bundle', false)) { + bundlerVersion = await getBundlerVersion() + if (semver.lt(semver.coerce(bundlerVersion), '2.2.0')) { + console.log('Using latest Bundler because the system Bundler is too old') + bundlerVersion = 'latest' + } else { + console.log(`Using system Bundler ${bundlerVersion}`) + return bundlerVersion + } + } else { + console.log('Installing latest Bundler as we could not find a system Bundler') + bundlerVersion = 'latest' + } + } else if (common.isBundler2dot2Default(engine, rubyVersion)) { if (common.windows && engine === 'ruby' && (common.isStableVersion(engine, rubyVersion) || rubyVersion === 'head')) { // https://github.com/ruby/setup-ruby/issues/371 console.log(`Installing latest Bundler for ${engine}-${rubyVersion} on Windows because bin/bundle does not work in bash otherwise`) @@ -144,12 +160,38 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock const versionParts = [...bundlerVersion.matchAll(/\d+/g)].length const bundlerVersionConstraint = versionParts >= 3 ? bundlerVersion : `~> ${bundlerVersion}.0` - await exec.exec(gem, ['install', 'bundler', ...force, '-v', bundlerVersionConstraint]) + const args = ['install', 'bundler', ...force, '-v', bundlerVersionConstraint] + + let stderr = '' + try { + await exec.exec(gem, args, { + listeners: { + stderr: (data) => (stderr += data.toString()) + } + }) + } catch (error) { + if (systemRubyUsed && stderr.includes('Gem::FilePermissionError')) { + await exec.exec('sudo', [gem, ...args]); + } else { + throw error + } + } return bundlerVersion } -export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { +async function getBundlerVersion() { + let bundlerVersion = '' + await exec.exec('bundle', ['--version'], { + silent: true, + listeners: { + stdout: (data) => (bundlerVersion += data.toString()) + } + }) + return bundlerVersion.replace(/^Bundler version /, '').trim() +} + +export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion, systemRubyUsed) { if (gemfile === null) { console.log('Could not determine gemfile path, skipping "bundle install" and caching') return false @@ -182,7 +224,7 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer // cache key const paths = [cachePath] - const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile, cacheVersion) + const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile, cacheVersion, systemRubyUsed) 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}-`] @@ -232,7 +274,7 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer return true } -async function computeBaseKey(platform, engine, version, lockFile, cacheVersion) { +async function computeBaseKey(platform, engine, version, lockFile, cacheVersion, systemRubyUsed) { const cwd = process.cwd() const bundleWith = process.env['BUNDLE_WITH'] || '' const bundleWithout = process.env['BUNDLE_WITHOUT'] || '' @@ -259,6 +301,19 @@ async function computeBaseKey(platform, engine, version, lockFile, cacheVersion) } } + if (systemRubyUsed) { + let platform = '' + await exec.exec('ruby', ['-e', 'print RUBY_PLATFORM'], { + silent: true, + listeners: { + stdout: (data) => { + platform += data.toString(); + } + } + }); + key += `-platform-${platform}` + } + key += `-${lockFile}` return key } diff --git a/dist/index.js b/dist/index.js index 65f3bbfe0..621eecc02 100644 --- a/dist/index.js +++ b/dist/index.js @@ -16,7 +16,9 @@ const fs = __nccwpck_require__(7147) const path = __nccwpck_require__(1017) const core = __nccwpck_require__(2186) const exec = __nccwpck_require__(1514) +const io = __nccwpck_require__(7436) const cache = __nccwpck_require__(7799) +const semver = __nccwpck_require__(1383) const common = __nccwpck_require__(3143) const DEFAULT_CACHE_VERSION = '0' @@ -72,7 +74,7 @@ async function afterLockFile(lockFile, platform, engine, rubyVersion) { } } -async function installBundler(bundlerVersionInput, rubygemsInputSet, lockFile, platform, rubyPrefix, engine, rubyVersion) { +async function installBundler(bundlerVersionInput, rubygemsInputSet, systemRubyUsed, lockFile, platform, rubyPrefix, engine, rubyVersion) { let bundlerVersion = bundlerVersionInput if (rubygemsInputSet && (bundlerVersion === 'default' || bundlerVersion === 'Gemfile.lock')) { @@ -93,7 +95,21 @@ async function installBundler(bundlerVersionInput, rubygemsInputSet, lockFile, p const floatVersion = common.floatVersion(rubyVersion) if (bundlerVersion === 'default') { - if (common.isBundler2dot2Default(engine, rubyVersion)) { + if (systemRubyUsed) { + if (await io.which('bundle', false)) { + bundlerVersion = await getBundlerVersion() + if (semver.lt(semver.coerce(bundlerVersion), '2.2.0')) { + console.log('Using latest Bundler because the system Bundler is too old') + bundlerVersion = 'latest' + } else { + console.log(`Using system Bundler ${bundlerVersion}`) + return bundlerVersion + } + } else { + console.log('Installing latest Bundler as we could not find a system Bundler') + bundlerVersion = 'latest' + } + } else if (common.isBundler2dot2Default(engine, rubyVersion)) { if (common.windows && engine === 'ruby' && (common.isStableVersion(engine, rubyVersion) || rubyVersion === 'head')) { // https://github.com/ruby/setup-ruby/issues/371 console.log(`Installing latest Bundler for ${engine}-${rubyVersion} on Windows because bin/bundle does not work in bash otherwise`) @@ -158,12 +174,38 @@ async function installBundler(bundlerVersionInput, rubygemsInputSet, lockFile, p const versionParts = [...bundlerVersion.matchAll(/\d+/g)].length const bundlerVersionConstraint = versionParts >= 3 ? bundlerVersion : `~> ${bundlerVersion}.0` - await exec.exec(gem, ['install', 'bundler', ...force, '-v', bundlerVersionConstraint]) + const args = ['install', 'bundler', ...force, '-v', bundlerVersionConstraint] + + let stderr = '' + try { + await exec.exec(gem, args, { + listeners: { + stderr: (data) => (stderr += data.toString()) + } + }) + } catch (error) { + if (systemRubyUsed && stderr.includes('Gem::FilePermissionError')) { + await exec.exec('sudo', [gem, ...args]); + } else { + throw error + } + } return bundlerVersion } -async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { +async function getBundlerVersion() { + let bundlerVersion = '' + await exec.exec('bundle', ['--version'], { + silent: true, + listeners: { + stdout: (data) => (bundlerVersion += data.toString()) + } + }) + return bundlerVersion.replace(/^Bundler version /, '').trim() +} + +async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion, systemRubyUsed) { if (gemfile === null) { console.log('Could not determine gemfile path, skipping "bundle install" and caching') return false @@ -196,7 +238,7 @@ async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, b // cache key const paths = [cachePath] - const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile, cacheVersion) + const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile, cacheVersion, systemRubyUsed) 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}-`] @@ -246,7 +288,7 @@ async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, b return true } -async function computeBaseKey(platform, engine, version, lockFile, cacheVersion) { +async function computeBaseKey(platform, engine, version, lockFile, cacheVersion, systemRubyUsed) { const cwd = process.cwd() const bundleWith = process.env['BUNDLE_WITH'] || '' const bundleWithout = process.env['BUNDLE_WITHOUT'] || '' @@ -273,6 +315,19 @@ async function computeBaseKey(platform, engine, version, lockFile, cacheVersion) } } + if (systemRubyUsed) { + let platform = '' + await exec.exec('ruby', ['-e', 'print RUBY_PLATFORM'], { + silent: true, + listeners: { + stdout: (data) => { + platform += data.toString(); + } + } + }); + key += `-platform-${platform}` + } + key += `-${lockFile}` return key } @@ -65745,17 +65800,22 @@ async function setupRuby(options = {}) { process.chdir(inputs['working-directory']) const platform = common.getOSNameVersion() - const [engine, parsedVersion] = parseRubyEngineAndVersion(inputs['ruby-version']) + const [engine, parsedVersion] = await parseRubyEngineAndVersion(inputs['ruby-version']) + const systemRuby = inputs['ruby-version'] === 'system' - let installer - if (platform.startsWith('windows-') && engine === 'ruby' && !common.isSelfHostedRunner()) { - installer = __nccwpck_require__(3216) + let installer, version + if (systemRuby) { + version = parsedVersion } else { - installer = __nccwpck_require__(9974) - } + if (platform.startsWith('windows-') && engine === 'ruby' && !common.isSelfHostedRunner()) { + installer = __nccwpck_require__(3216) + } else { + installer = __nccwpck_require__(9974) + } - const engineVersions = installer.getAvailableVersions(platform, engine) - const version = validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) + const engineVersions = installer.getAvailableVersions(platform, engine) + version = validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) + } createGemRC(engine, version) envPreInstall() @@ -65767,7 +65827,12 @@ async function setupRuby(options = {}) { await (__nccwpck_require__(3216).installJRubyTools)() } - const rubyPrefix = await installer.install(platform, engine, version) + let rubyPrefix + if (systemRuby) { + rubyPrefix = await getSystemRubyPrefix() + } else { + rubyPrefix = await installer.install(platform, engine, version) + } await common.measure('Print Ruby version', async () => await exec.exec('ruby', ['--version'])) @@ -65790,18 +65855,18 @@ async function setupRuby(options = {}) { if (inputs['bundler'] !== 'none') { bundlerVersion = await common.measure('Installing Bundler', async () => - bundler.installBundler(inputs['bundler'], rubygemsInputSet, lockFile, platform, rubyPrefix, engine, version)) + bundler.installBundler(inputs['bundler'], rubygemsInputSet, systemRuby, lockFile, platform, rubyPrefix, engine, version)) } 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'], systemRuby)) } core.setOutput('ruby-prefix', rubyPrefix) } -function parseRubyEngineAndVersion(rubyVersion) { +async function parseRubyEngineAndVersion(rubyVersion) { if (rubyVersion === 'default') { if (fs.existsSync('.ruby-version')) { rubyVersion = '.ruby-version' @@ -65810,6 +65875,17 @@ function parseRubyEngineAndVersion(rubyVersion) { } else { throw new Error('input ruby-version needs to be specified if no .ruby-version or .tool-versions file exists') } + } else if (rubyVersion === 'system') { + rubyVersion = '' + await exec.exec('ruby', ['-e', 'print "#{RUBY_ENGINE}-#{RUBY_VERSION}"'], { + silent: true, + listeners: { + stdout: (data) => (rubyVersion += data.toString()) + } + }) + if (!rubyVersion.includes('-')) { + throw new Error('Could not determine system Ruby engine and version') + } } if (rubyVersion === '.ruby-version') { // Read from .ruby-version @@ -65888,6 +65964,20 @@ function envPreInstall() { } } +async function getSystemRubyPrefix() { + let rubyPrefix = '' + await exec.exec('ruby', ['-rrbconfig', '-e', 'print RbConfig::CONFIG["prefix"]'], { + silent: true, + listeners: { + stdout: (data) => (rubyPrefix += data.toString()) + } + }) + if (!rubyPrefix) { + throw new Error('Could not determine system Ruby prefix') + } + return rubyPrefix +} + if (__filename.endsWith('index.js')) { run() } })(); diff --git a/index.js b/index.js index a9735b567..0d6cd7f90 100644 --- a/index.js +++ b/index.js @@ -48,17 +48,22 @@ export async function setupRuby(options = {}) { process.chdir(inputs['working-directory']) const platform = common.getOSNameVersion() - const [engine, parsedVersion] = parseRubyEngineAndVersion(inputs['ruby-version']) + const [engine, parsedVersion] = await parseRubyEngineAndVersion(inputs['ruby-version']) + const systemRuby = inputs['ruby-version'] === 'system' - let installer - if (platform.startsWith('windows-') && engine === 'ruby' && !common.isSelfHostedRunner()) { - installer = require('./windows') + let installer, version + if (systemRuby) { + version = parsedVersion } else { - installer = require('./ruby-builder') - } + if (platform.startsWith('windows-') && engine === 'ruby' && !common.isSelfHostedRunner()) { + installer = require('./windows') + } else { + installer = require('./ruby-builder') + } - const engineVersions = installer.getAvailableVersions(platform, engine) - const version = validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) + const engineVersions = installer.getAvailableVersions(platform, engine) + version = validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) + } createGemRC(engine, version) envPreInstall() @@ -70,7 +75,12 @@ export async function setupRuby(options = {}) { await require('./windows').installJRubyTools() } - const rubyPrefix = await installer.install(platform, engine, version) + let rubyPrefix + if (systemRuby) { + rubyPrefix = await getSystemRubyPrefix() + } else { + rubyPrefix = await installer.install(platform, engine, version) + } await common.measure('Print Ruby version', async () => await exec.exec('ruby', ['--version'])) @@ -93,18 +103,18 @@ export async function setupRuby(options = {}) { if (inputs['bundler'] !== 'none') { bundlerVersion = await common.measure('Installing Bundler', async () => - bundler.installBundler(inputs['bundler'], rubygemsInputSet, lockFile, platform, rubyPrefix, engine, version)) + bundler.installBundler(inputs['bundler'], rubygemsInputSet, systemRuby, lockFile, platform, rubyPrefix, engine, version)) } 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'], systemRuby)) } core.setOutput('ruby-prefix', rubyPrefix) } -function parseRubyEngineAndVersion(rubyVersion) { +async function parseRubyEngineAndVersion(rubyVersion) { if (rubyVersion === 'default') { if (fs.existsSync('.ruby-version')) { rubyVersion = '.ruby-version' @@ -113,6 +123,17 @@ function parseRubyEngineAndVersion(rubyVersion) { } else { throw new Error('input ruby-version needs to be specified if no .ruby-version or .tool-versions file exists') } + } else if (rubyVersion === 'system') { + rubyVersion = '' + await exec.exec('ruby', ['-e', 'print "#{RUBY_ENGINE}-#{RUBY_VERSION}"'], { + silent: true, + listeners: { + stdout: (data) => (rubyVersion += data.toString()) + } + }) + if (!rubyVersion.includes('-')) { + throw new Error('Could not determine system Ruby engine and version') + } } if (rubyVersion === '.ruby-version') { // Read from .ruby-version @@ -191,4 +212,18 @@ function envPreInstall() { } } +async function getSystemRubyPrefix() { + let rubyPrefix = '' + await exec.exec('ruby', ['-rrbconfig', '-e', 'print RbConfig::CONFIG["prefix"]'], { + silent: true, + listeners: { + stdout: (data) => (rubyPrefix += data.toString()) + } + }) + if (!rubyPrefix) { + throw new Error('Could not determine system Ruby prefix') + } + return rubyPrefix +} + if (__filename.endsWith('index.js')) { run() } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy