diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0c7884..5b8730f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11.0, windows-2016, windows-2019 ] - ruby: [ 1.9, '2.0', 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, '3.0', ruby-head, jruby, jruby-head, truffleruby, truffleruby-head ] + ruby: [ 1.9, '2.0', 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, '3.0', ruby-head, jruby, jruby-head, truffleruby, truffleruby-head, truffleruby+graalvm, truffleruby+graalvm-head ] include: - { os: windows-2016, ruby: mingw } - { os: windows-2019, ruby: mingw } @@ -26,10 +26,14 @@ jobs: - { os: windows-2016, ruby: debug } - { os: windows-2016, ruby: truffleruby } - { os: windows-2016, ruby: truffleruby-head } + - { os: windows-2016, ruby: truffleruby+graalvm } + - { os: windows-2016, ruby: truffleruby+graalvm-head } - { os: windows-2019, ruby: 1.9 } - { os: windows-2019, ruby: debug } - { os: windows-2019, ruby: truffleruby } - { os: windows-2019, ruby: truffleruby-head } + - { os: windows-2019, ruby: truffleruby+graalvm } + - { os: windows-2019, ruby: truffleruby+graalvm-head } name: ${{ matrix.os }} ${{ matrix.ruby }} runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index 597ec95..f0a7f97 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ This action currently supports these versions of MRI, JRuby and TruffleRuby: | `ruby` | 1.9.3, 2.0.0, 2.1.9, 2.2, all versions from 2.3.0 until 3.0.2, head, debug, mingw, mswin | | `jruby` | 9.1.17.0, 9.2.9.0 - 9.2.19.0, head | | `truffleruby` | 19.3.0 - 21.2.0.1, head | +| `truffleruby+graalvm` | 21.2.0, head | `ruby-debug` is the same as `ruby-head` but with assertions enabled (`-DRUBY_DEBUG=1`). On Windows, `mingw` and `mswin` are `ruby-head` builds using the MSYS2/MinGW and the MSVC toolchains respectively. @@ -46,8 +47,9 @@ The prebuilt releases are generated by [ruby-builder](https://github.com/ruby/ru and on Windows by [RubyInstaller2](https://github.com/oneclick/rubyinstaller2). `mingw` and `mswin` builds are generated by [ruby-loco](https://github.com/MSP-Greg/ruby-loco). `ruby-head` is generated by [ruby-dev-builder](https://github.com/ruby/ruby-dev-builder), -`jruby-head` is generated by [jruby-dev-builder](https://github.com/ruby/jruby-dev-builder) -and `truffleruby-head` is generated by [truffleruby-dev-builder](https://github.com/ruby/truffleruby-dev-builder). +`jruby-head` is generated by [jruby-dev-builder](https://github.com/ruby/jruby-dev-builder), +`truffleruby-head` is generated by [truffleruby-dev-builder](https://github.com/ruby/truffleruby-dev-builder) +and `truffleruby+graalvm` is generated by [graalvm-ce-dev-builds](https://github.com/graalvm/graalvm-ce-dev-builds). The full list of available Ruby versions can be seen in [ruby-builder-versions.js](ruby-builder-versions.js) for Ubuntu and macOS and in [windows-versions.js](windows-versions.js) for Windows. diff --git a/bundler.js b/bundler.js index 56acda2..260e6e8 100644 --- a/bundler.js +++ b/bundler.js @@ -41,7 +41,7 @@ function readBundledWithFromGemfileLock(lockFile) { } async function afterLockFile(lockFile, platform, engine) { - if (engine === 'truffleruby' && platform.startsWith('ubuntu-')) { + if (engine.startsWith('truffleruby') && platform.startsWith('ubuntu-')) { const contents = fs.readFileSync(lockFile, 'utf8') if (contents.includes('nokogiri')) { await common.measure('Installing libxml2-dev libxslt-dev, required to install nokogiri on TruffleRuby', async () => @@ -86,7 +86,7 @@ export async function installBundler(bundlerVersionInput, lockFile, platform, ru // Avoid installing a newer Bundler version for head versions as it might not work. // For releases, even if they ship with Bundler 2 we install the latest Bundler. console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) - } else if (engine === 'truffleruby' && common.isBundler1Default(engine, rubyVersion) && bundlerVersion.startsWith('1')) { + } else if (engine.startsWith('truffleruby') && common.isBundler1Default(engine, rubyVersion) && bundlerVersion.startsWith('1')) { console.log(`Using Bundler 1 shipped with ${engine}-${rubyVersion}`) } else { const gem = path.join(rubyPrefix, 'bin', 'gem') diff --git a/common.js b/common.js index 28281de..d505d0a 100644 --- a/common.js +++ b/common.js @@ -62,7 +62,7 @@ export function isBundler1Default(engine, rubyVersion) { export function isBundler2Default(engine, rubyVersion) { if (engine === 'ruby') { return floatVersion(rubyVersion) >= 2.7 - } else if (engine === 'truffleruby') { + } else if (engine.startsWith('truffleruby')) { return floatVersion(rubyVersion) >= 21.0 } else if (engine === 'jruby') { return floatVersion(rubyVersion) >= 9.3 diff --git a/dist/index.js b/dist/index.js index 59c0d49..88212b9 100644 --- a/dist/index.js +++ b/dist/index.js @@ -55,7 +55,7 @@ function readBundledWithFromGemfileLock(lockFile) { } async function afterLockFile(lockFile, platform, engine) { - if (engine === 'truffleruby' && platform.startsWith('ubuntu-')) { + if (engine.startsWith('truffleruby') && platform.startsWith('ubuntu-')) { const contents = fs.readFileSync(lockFile, 'utf8') if (contents.includes('nokogiri')) { await common.measure('Installing libxml2-dev libxslt-dev, required to install nokogiri on TruffleRuby', async () => @@ -100,7 +100,7 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi // Avoid installing a newer Bundler version for head versions as it might not work. // For releases, even if they ship with Bundler 2 we install the latest Bundler. console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) - } else if (engine === 'truffleruby' && common.isBundler1Default(engine, rubyVersion) && bundlerVersion.startsWith('1')) { + } else if (engine.startsWith('truffleruby') && common.isBundler1Default(engine, rubyVersion) && bundlerVersion.startsWith('1')) { console.log(`Using Bundler 1 shipped with ${engine}-${rubyVersion}`) } else { const gem = path.join(rubyPrefix, 'bin', 'gem') @@ -304,7 +304,7 @@ function isBundler1Default(engine, rubyVersion) { function isBundler2Default(engine, rubyVersion) { if (engine === 'ruby') { return floatVersion(rubyVersion) >= 2.7 - } else if (engine === 'truffleruby') { + } else if (engine.startsWith('truffleruby')) { return floatVersion(rubyVersion) >= 21.0 } else if (engine === 'jruby') { return floatVersion(rubyVersion) >= 9.3 @@ -58773,7 +58773,7 @@ function getVersions(platform) { "2.6.0", "2.6.1", "2.6.2", "2.6.3", "2.6.4", "2.6.5", "2.6.6", "2.6.7", "2.6.8", "2.7.0", "2.7.1", "2.7.2", "2.7.3", "2.7.4", "3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0", "3.0.1", "3.0.2", - "head", "debug", + "head", "debug" ], "jruby": [ "9.1.17.0", @@ -58785,6 +58785,10 @@ function getVersions(platform) { "20.0.0", "20.1.0", "20.2.0", "20.3.0", "21.0.0", "21.1.0", "21.2.0", "21.2.0.1", "head" + ], + "truffleruby+graalvm": [ + "21.2.0", + "head" ] } @@ -58840,19 +58844,43 @@ async function install(platform, engine, version) { common.setupPath([path.join(rubyPrefix, 'bin')]) if (!inToolCache) { - await downloadAndExtract(platform, engine, version, rubyPrefix); + await preparePrefix(rubyPrefix) + if (engine === 'truffleruby+graalvm') { + await installWithRubyBuild(engine, version, rubyPrefix) + } else { + await downloadAndExtract(platform, engine, version, rubyPrefix) + } } return rubyPrefix } -async function downloadAndExtract(platform, engine, version, rubyPrefix) { +async function preparePrefix(rubyPrefix) { const parentDir = path.dirname(rubyPrefix) await io.rmRF(rubyPrefix) if (!(fs.existsSync(parentDir) && fs.statSync(parentDir).isDirectory())) { await io.mkdirP(parentDir) } +} + +async function installWithRubyBuild(engine, version, rubyPrefix) { + const tmp = process.env['RUNNER_TEMP'] || os.tmpdir() + const rubyBuildDir = path.join(tmp, 'ruby-build-for-setup-ruby') + await common.measure('Cloning ruby-build', async () => { + await exec.exec('git', ['clone', 'https://github.com/rbenv/ruby-build.git', rubyBuildDir]) + }) + + const rubyName = `${engine}-${version === 'head' ? 'dev' : version}` + await common.measure(`Installing ${engine}-${version} with ruby-build`, async () => { + await exec.exec(`${rubyBuildDir}/bin/ruby-build`, [rubyName, rubyPrefix]) + }) + + await io.rmRF(rubyBuildDir) +} + +async function downloadAndExtract(platform, engine, version, rubyPrefix) { + const parentDir = path.dirname(rubyPrefix) const downloadPath = await common.measure('Downloading Ruby', async () => { const url = getDownloadURL(platform, engine, version) diff --git a/ruby-builder-versions.js b/ruby-builder-versions.js index 98165e4..68cace4 100644 --- a/ruby-builder-versions.js +++ b/ruby-builder-versions.js @@ -11,7 +11,7 @@ export function getVersions(platform) { "2.6.0", "2.6.1", "2.6.2", "2.6.3", "2.6.4", "2.6.5", "2.6.6", "2.6.7", "2.6.8", "2.7.0", "2.7.1", "2.7.2", "2.7.3", "2.7.4", "3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0", "3.0.1", "3.0.2", - "head", "debug", + "head", "debug" ], "jruby": [ "9.1.17.0", @@ -23,6 +23,10 @@ export function getVersions(platform) { "20.0.0", "20.1.0", "20.2.0", "20.3.0", "21.0.0", "21.1.0", "21.2.0", "21.2.0.1", "head" + ], + "truffleruby+graalvm": [ + "21.2.0", + "head" ] } diff --git a/ruby-builder.js b/ruby-builder.js index 9d6b41b..e8ee9a2 100644 --- a/ruby-builder.js +++ b/ruby-builder.js @@ -35,19 +35,43 @@ export async function install(platform, engine, version) { common.setupPath([path.join(rubyPrefix, 'bin')]) if (!inToolCache) { - await downloadAndExtract(platform, engine, version, rubyPrefix); + await preparePrefix(rubyPrefix) + if (engine === 'truffleruby+graalvm') { + await installWithRubyBuild(engine, version, rubyPrefix) + } else { + await downloadAndExtract(platform, engine, version, rubyPrefix) + } } return rubyPrefix } -async function downloadAndExtract(platform, engine, version, rubyPrefix) { +async function preparePrefix(rubyPrefix) { const parentDir = path.dirname(rubyPrefix) await io.rmRF(rubyPrefix) if (!(fs.existsSync(parentDir) && fs.statSync(parentDir).isDirectory())) { await io.mkdirP(parentDir) } +} + +async function installWithRubyBuild(engine, version, rubyPrefix) { + const tmp = process.env['RUNNER_TEMP'] || os.tmpdir() + const rubyBuildDir = path.join(tmp, 'ruby-build-for-setup-ruby') + await common.measure('Cloning ruby-build', async () => { + await exec.exec('git', ['clone', 'https://github.com/rbenv/ruby-build.git', rubyBuildDir]) + }) + + const rubyName = `${engine}-${version === 'head' ? 'dev' : version}` + await common.measure(`Installing ${engine}-${version} with ruby-build`, async () => { + await exec.exec(`${rubyBuildDir}/bin/ruby-build`, [rubyName, rubyPrefix]) + }) + + await io.rmRF(rubyBuildDir) +} + +async function downloadAndExtract(platform, engine, version, rubyPrefix) { + const parentDir = path.dirname(rubyPrefix) const downloadPath = await common.measure('Downloading Ruby', async () => { const url = getDownloadURL(platform, engine, version)