Compare commits

...
36 Commits
Author SHA1 Message Date
Benoit Daloze 5aaa89ff0d Automatically install libxml2-dev libxslt-dev on TruffleRuby if needed
* This is a special case, because TruffleRuby needs an extra system
  dependency that other Rubies do not, and GitHub runners do not have
  these packages installed by default, while TravisCI has them.
2021-01-09 14:48:58 +01:00
Benoit Daloze 3460195737 Update exact Bundler version test
* So that we test it does not pick the next patch version (2.2.4).
* See https://github.com/ruby/setup-ruby/issues/138
2021-01-08 21:06:57 +01:00
Benoit Daloze d195ecb9ec Move Bundler-related logic to a separate file 2021-01-08 20:56:31 +01:00
Manuel Meurer c34fe21c5f Install specific bundler version when minor and patch versions are given (#139) 2021-01-07 14:03:20 +01:00
Benoit Daloze 324b8ce0e9 Update issue templates 2021-01-03 13:37:45 +01:00
Benoit Daloze ce63da5b3b Make it clear bundler-cache: true is correct, and doing it manually is not good enough 2020-12-30 16:57:15 +01:00
Benoit Daloze 0d3b8b502e Make it clear manually caching gems is a bad idea 2020-12-30 12:36:20 +01:00
Benoit Daloze 2320cdc287 Use on: [push, pull_request] in examples 2020-12-30 11:48:57 +01:00
Benoit Daloze 95193d6d48 Ensure no \r are added when running generate-windows-versions.rb on Windows 2020-12-28 12:40:07 +01:00
MSP-Greg 9aeedd9a81 Update windows-version.js with 3.0.0, add Windows 3.0.0 to CI 2020-12-28 12:40:07 +01:00
Benoit Daloze 72d75bd883 Avoid explicit line break in README 2020-12-25 13:23:13 +01:00
Benoit Daloze 473e4d8fe5 Add Ruby 3.0.0 2020-12-25 13:14:24 +01:00
Benoit Daloze 3cb8cff23d Consistency 2020-12-22 11:49:37 +01:00
Benoit Daloze f36eef7a2f Add an example with a matrix of Gemfiles 2020-12-22 11:46:12 +01:00
Benoit Daloze ec4649be90 Add test for a Gemfile depending on Bundler 1 2020-12-22 11:46:12 +01:00
Benoit Daloze 1771151f64 Error if $BUNDLE_GEMFILE is set but does not exist 2020-12-22 11:46:12 +01:00
Benoit Daloze f5db46ebcb Fix version check 2020-12-22 11:18:45 +01:00
Benoit Daloze dc58db7220 Use an absolute path for bundle config --local path
* See https://github.com/ruby/setup-ruby/issues/131
2020-12-21 21:13:02 +01:00
Benoit Daloze 0e7d36a67f Add test using BUNDLE_GEMFILE 2020-12-21 21:12:42 +01:00
Benoit Tigeot e5b6990d51 Add 3.0.0-rc1 2020-12-21 12:30:17 +01:00
Benoit Daloze c3f248a282 Update docs about Bundler 2020-12-14 12:55:47 +01:00
Benoit Daloze a9926985f9 Small tweaks to the README example 2020-12-12 19:38:17 +01:00
Benoit Daloze 07b100f2a1 Reduce the number of CI jobs since it is becoming impractical
* It was > 100 jobs and the GitHub limits to 100 jobs.
2020-12-12 15:17:54 +01:00
Benoit Daloze 515629a013 Update to latest actions/cache to fix cache saving on Windows with MSYS2 tar
* See https://github.com/actions/toolkit/issues/632
* Fixes https://github.com/ruby/setup-ruby/issues/102
2020-12-12 14:51:32 +01:00
Benoit Daloze 0981b5ec00 Add jruby-9.2.14.0 2020-12-12 14:04:27 +01:00
Benoit Daloze c101335f33 Add test checking using an exact Bundler version works 2020-12-11 14:46:33 +01:00
Benoit Daloze 1482e9180a Install the exact same Bundler version as in the lockfile if there is a lockfile 2020-12-11 14:46:33 +01:00
Jonathan del Strother 3e7640a17e Document the bundler: "x.y.z" feature 2020-12-11 14:46:33 +01:00
Benoit Daloze f6f61ea575 Fix checks for Bundler version to consider an exact version like 2.1.4 2020-12-11 14:46:33 +01:00
Benoit Daloze 084885eaca Only set $BUNDLER_VERSION when needed (Bundler 1, Ruby >= 2.7) 2020-12-09 16:51:47 +01:00
Benoit Daloze efd6675fc9 Add 3.0.0-preview2 2020-12-08 18:42:10 +01:00
Benoit Daloze e5a267414f Fix value for options 2020-12-07 21:12:36 +01:00
ojab cadade3366 Pass selected Bundler version to bundle config & bundle lock 2020-12-07 21:06:26 +01:00
Benoit Daloze d3562e70d9 Use lowercase names for interpreters
* So the mapping to `engine-version` versions is clearer.
2020-12-05 17:23:19 +01:00
Benoit Daloze 23b2b5e5f1 Create the .complete file so tc.find() can find it for future runs for self-hosted runners 2020-12-05 16:36:46 +01:00
Benoit Daloze 42fc2d3bce Reuse builds in the toolcache when they exist 2020-12-05 16:18:50 +01:00
19 changed files with 1810 additions and 856 deletions
+19
View File
@@ -0,0 +1,19 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
<!--
Before filing this issue:
* If the issue happens on JRuby or TruffleRuby, and does not happen on CRuby (please check), file an issue there instead. It's very unlikely ruby/setup-ruby is the cause.
* Try to reproduce the issue locally by following the workflow steps (including all all commands done by ruby/setup-ruby, except for `Downloading Ruby` & `Extracting Ruby`). If it does reproduce locally, it's not a ruby/setup-ruby issue.
Please provide:
* the code of or a link to the workflow used
* the link to the log of a failed workflow job
* the command and output of the step failing
-->
+57 -4
View File
@@ -15,19 +15,17 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-16.04, ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11.0, windows-2016, windows-2019 ]
os: [ ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11.0, windows-2016, windows-2019 ]
# Use various version syntax here for testing
ruby: [ 2.1, 2.2, 2.3, 2.4, 2.5, 2.6.6, 2.7, '3.0', ruby-head, debug, jruby-9.1, jruby, jruby-head, truffleruby, truffleruby-head ]
ruby: [ 2.1, 2.2, 2.3, 2.4, 2.5, 2.6.6, 2.7, '3.0', ruby-head, jruby, jruby-head, truffleruby, truffleruby-head ]
include:
- { os: windows-2016, ruby: mingw }
- { os: windows-2019, ruby: mingw }
- { os: windows-2019, ruby: mswin }
exclude:
- { os: windows-2016, ruby: '3.0' }
- { os: windows-2016, ruby: debug }
- { os: windows-2016, ruby: truffleruby }
- { os: windows-2016, ruby: truffleruby-head }
- { os: windows-2019, ruby: '3.0' }
- { os: windows-2019, ruby: debug }
- { os: windows-2019, ruby: truffleruby }
- { os: windows-2019, ruby: truffleruby-head }
@@ -102,6 +100,61 @@ jobs:
if: startsWith(matrix.os, 'windows') && startsWith(matrix.ruby, 'jruby')
run: gem install sassc -N
testExactBundlerVersion:
name: "Test with an exact Bundler version"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./
with:
ruby-version: 2.6
bundler: 2.2.3
- run: bundle --version | grep -F "Bundler version 2.2.3"
testDependencyOnBundler1:
name: "Test gemfile depending on Bundler 1"
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: gemfiles/bundler1.gemfile
steps:
- uses: actions/checkout@v2
- uses: ./
with:
ruby-version: 2.7
bundler: 1
bundler-cache: true
- run: bundle --version | grep -F "Bundler version 1."
testGemfileMatrix:
strategy:
fail-fast: false
matrix:
gemfile: [ rails5, rails6 ]
name: "Test with ${{ matrix.gemfile }} gemfile"
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
steps:
- uses: actions/checkout@v2
- uses: ./
with:
ruby-version: 2.6
bundler-cache: true
- run: bundle exec rails --version
testTruffleRubyNokogiri:
name: "Test installing a Gemfile with nokogiri on TruffleRuby"
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: gemfiles/nokogiri.gemfile
steps:
- uses: actions/checkout@v2
- uses: ./
with:
ruby-version: truffleruby-head
bundler-cache: true
- run: bundle list | grep nokogiri
lint:
runs-on: ubuntu-20.04
steps:
+47 -28
View File
@@ -14,9 +14,9 @@ This action currently supports these versions of MRI, JRuby and TruffleRuby:
| Interpreter | Versions |
| ----------- | -------- |
| Ruby | 2.1.9, 2.2, 2.3.0 - 2.3.8, 2.4.0 - 2.4.10, 2.5.0 - 2.5.8, 2.6.0 - 2.6.6, 2.7.2, head, debug, mingw, mswin |
| JRuby | 9.1.17.0, 9.2.9.0 - 9.2.13.0, head |
| TruffleRuby | 19.3.0 - 20.3.0, head |
| `ruby` | 2.1.9, 2.2, 2.3.0 - 2.3.8, 2.4.0 - 2.4.10, 2.5.0 - 2.5.8, 2.6.0 - 2.6.6, 2.7.2, 3.0.0, head, debug, mingw, mswin |
| `jruby` | 9.1.17.0, 9.2.9.0 - 9.2.13.0, head |
| `truffleruby` | 19.3.0 - 20.3.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.
@@ -57,7 +57,7 @@ for Ubuntu and macOS and in [windows-versions.js](windows-versions.js) for Windo
```yaml
name: My workflow
on: [push]
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
@@ -70,21 +70,21 @@ jobs:
- run: bundle exec rake
```
### Matrix
### Matrix of Ruby Versions
This matrix tests all stable releases and `head` versions of MRI, JRuby and TruffleRuby on Ubuntu and macOS.
```yaml
name: My workflow
on: [push]
on: [push, pull_request]
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos]
ruby: [2.5, 2.6, 2.7, head, debug, jruby, jruby-head, truffleruby, truffleruby-head]
runs-on: ${{ matrix.os }}-latest
os: [ubuntu-latest, macos-latest]
ruby: [2.5, 2.6, 2.7, '3.0', head, jruby, jruby-head, truffleruby, truffleruby-head]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
@@ -94,6 +94,29 @@ jobs:
- run: bundle exec rake
```
### Matrix of Gemfiles
```yaml
name: My workflow
on: [push, pull_request]
jobs:
test:
strategy:
fail-fast: false
matrix:
gemfile: [ rails5, rails6 ]
runs-on: ubuntu-latest
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
steps:
- uses: actions/checkout@v2
- uses: ./
with:
ruby-version: 2.6
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle exec rake
```
See the GitHub Actions documentation for more details about the
[workflow syntax](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions)
and the [condition and expression syntax](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions).
@@ -116,10 +139,10 @@ if they are not at the root of the repository, see [action.yml](action.yml) for
### Bundler
By default, if there is a `Gemfile.lock` file (or `$BUNDLE_GEMFILE.lock` or `gems.locked`) with a `BUNDLED WITH` section,
the latest version of Bundler with the same major version will be installed.
that version of Bundler will be installed and used.
Otherwise, the latest compatible Bundler version is installed (Bundler 2 on Ruby >= 2.4, Bundler 1 on Ruby < 2.4).
This behavior can be customized, see [action.yml](action.yml) for details about the `bundler` input.
This behavior can be customized, see [action.yml](action.yml) for more details about the `bundler` input.
### Caching `bundle install` automatically
@@ -136,26 +159,22 @@ This caching speeds up installing gems significantly and avoids too many request
It needs a `Gemfile` (or `$BUNDLE_GEMFILE` or `gems.rb`) under the [`working-directory`](#working-directory).
If there is a `Gemfile.lock` (or `$BUNDLE_GEMFILE.lock` or `gems.locked`), `bundle config --local deployment true` is used.
To use a `Gemfile` which is not at the root or has a different name, set `BUNDLE_GEMFILE` in the `env` at the job level, so it is set for all steps:
```yaml
jobs:
test:
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: subdir/mygemfile
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
- run: bundle exec rake
```
Of course you can also use a matrix of gemfiles if you need to test multiple gemfiles.
To use a `Gemfile` which is not at the root or has a different name, set `BUNDLE_GEMFILE` in the `env` at the job level
as shown in the [example](#matrix-of-gemfiles).
To perform caching, this action will use `bundle config --local path vendor/bundle`.
When there is no lockfile, one is generated with `bundle lock`, which is the same as `bundle install` would do first before actually fetching any gem.
In other words, it works exactly like `bundle install`.
The hash of the generated lockfile is then used for caching, which is the only correct approach.
To perform caching, this action will use `bundle config --local path $PWD/vendor/bundle`.
Therefore, the Bundler `path` should not be changed in your workflow for the cache to work (no `bundle config path`).
#### Caching `bundle install` manually
It is also possible to cache gems manually, but this is not recommended because it is verbose and *very difficult* to do correctly.
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.
## Windows
Note that running CI on Windows can be quite challenging if you are not very familiar with Windows.
+1 -1
View File
@@ -11,7 +11,7 @@ inputs:
default: 'default'
bundler:
description: |
The version of Bundler to install. Either 'none', 1, 2, 'latest' or 'Gemfile.lock'.
The version of Bundler to install. Either 'none', 'latest', 'Gemfile.lock', or a version number (e.g., 1, 2, 2.1.4).
For 'Gemfile.lock', the version is determined based on the BUNDLED WITH section from the file Gemfile.lock, $BUNDLE_GEMFILE.lock or gems.locked.
Defaults to 'Gemfile.lock' if the file exists and 'latest' otherwise.
required: false
+196
View File
@@ -0,0 +1,196 @@
const fs = require('fs')
const path = require('path')
const core = require('@actions/core')
const exec = require('@actions/exec')
const cache = require('@actions/cache')
const common = require('./common')
// The returned gemfile is guaranteed to exist, the lockfile might not exist
export function detectGemfiles() {
const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile'
if (fs.existsSync(gemfilePath)) {
return [gemfilePath, `${gemfilePath}.lock`]
} else if (process.env['BUNDLE_GEMFILE']) {
throw new Error(`$BUNDLE_GEMFILE is set to ${gemfilePath} but does not exist`)
}
if (fs.existsSync("gems.rb")) {
return ["gems.rb", "gems.locked"]
}
return [null, null]
}
function readBundledWithFromGemfileLock(lockFile) {
if (lockFile !== null && fs.existsSync(lockFile)) {
const contents = fs.readFileSync(lockFile, 'utf8')
const lines = contents.split(/\r?\n/)
const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim()))
if (bundledWithLine !== -1) {
const nextLine = lines[bundledWithLine+1]
if (nextLine && /^\d+/.test(nextLine.trim())) {
const bundlerVersion = nextLine.trim()
console.log(`Using Bundler ${bundlerVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`)
return bundlerVersion
}
}
}
return null
}
async function afterLockFile(lockFile, platform, engine) {
if (engine === '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 () =>
exec.exec('sudo', ['apt-get', '-yqq', 'install', 'libxml2-dev', 'libxslt-dev'], { silent: true }))
}
}
}
export async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefix, engine, rubyVersion) {
let bundlerVersion = bundlerVersionInput
if (bundlerVersion === 'default' || bundlerVersion === 'Gemfile.lock') {
bundlerVersion = readBundledWithFromGemfileLock(lockFile)
if (!bundlerVersion) {
bundlerVersion = 'latest'
}
}
if (bundlerVersion === 'latest') {
bundlerVersion = '2'
}
if (/^\d+/.test(bundlerVersion)) {
// OK
} else {
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
}
if (engine === 'ruby' && rubyVersion.match(/^2\.[012]/)) {
console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2')
bundlerVersion = '1'
} else if (engine === 'ruby' && rubyVersion.startsWith('2.3')) {
console.log('Ruby 2.3 has a bug with Bundler 2 (https://github.com/rubygems/rubygems/issues/3570), using Bundler 1 instead on Ruby 2.3')
bundlerVersion = '1'
} else if (engine === 'jruby' && rubyVersion.startsWith('9.1')) { // JRuby 9.1 targets Ruby 2.3, treat it the same
console.log('JRuby 9.1 has a bug with Bundler 2 (https://github.com/ruby/setup-ruby/issues/108), using Bundler 1 instead on JRuby 9.1')
bundlerVersion = '1'
}
if (common.isHeadVersion(rubyVersion) && common.isBundler2Default(engine, rubyVersion) && bundlerVersion.startsWith('2')) {
console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`)
} else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion.startsWith('1')) {
console.log(`Using Bundler 1 shipped with ${engine}`)
} else {
const gem = path.join(rubyPrefix, 'bin', 'gem')
const bundlerVersionConstraint = bundlerVersion.match(/^\d+\.\d+\.\d+/) ? bundlerVersion : `~> ${bundlerVersion}`
await exec.exec(gem, ['install', 'bundler', '-v', bundlerVersionConstraint, '--no-document'])
}
return bundlerVersion
}
export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion) {
if (gemfile === null) {
console.log('Could not determine gemfile path, skipping "bundle install" and caching')
return false
}
let envOptions = {}
if (bundlerVersion.startsWith('1') && common.isBundler2Default(engine, rubyVersion)) {
// If Bundler 1 is specified on Rubies which ship with Bundler 2,
// we need to specify which Bundler version to use explicitly until the lockfile exists.
console.log(`Setting BUNDLER_VERSION=${bundlerVersion} for "bundle config|lock" commands below to ensure Bundler 1 is used`)
envOptions = { env: { ...process.env, BUNDLER_VERSION: bundlerVersion } }
}
// config
const cachePath = 'vendor/bundle'
// An absolute path, so it is reliably under $PWD/vendor/bundle, and not relative to the gemfile's directory
const bundleCachePath = path.join(process.cwd(), cachePath)
await exec.exec('bundle', ['config', '--local', 'path', bundleCachePath], envOptions)
if (fs.existsSync(lockFile)) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true'], envOptions)
} else {
// Generate the lockfile so we can use it to compute the cache key.
// This will also automatically pick up the latest gem versions compatible with the Gemfile.
await exec.exec('bundle', ['lock'], envOptions)
}
await afterLockFile(lockFile, platform, engine)
// cache key
const paths = [cachePath]
const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile)
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}-`]
console.log(`Cache key: ${key}`)
// restore cache & install
let cachedKey = null
try {
cachedKey = await cache.restoreCache(paths, key, restoreKeys)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error;
} else {
core.info(`[warning] There was an error restoring the cache ${error.message}`)
}
}
if (cachedKey) {
console.log(`Found cache for key: ${cachedKey}`)
}
// Always run 'bundle install' to list the gems
await exec.exec('bundle', ['install', '--jobs', '4'])
// @actions/cache only allows to save for non-existing keys
if (cachedKey !== key) {
if (cachedKey) { // existing cache but Gemfile.lock differs, clean old gems
await exec.exec('bundle', ['clean'])
}
// Error handling from https://github.com/actions/cache/blob/master/src/save.ts
console.log('Saving cache')
try {
await cache.saveCache(paths, key)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error;
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message);
} else {
core.info(`[warning]${error.message}`)
}
}
}
return true
}
async function computeBaseKey(platform, engine, version, lockFile) {
let key = `setup-ruby-bundler-cache-v3-${platform}-${engine}-${version}`
if (engine !== 'jruby' && common.isHeadVersion(version)) {
let revision = '';
await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], {
silent: true,
listeners: {
stdout: (data) => {
revision += data.toString();
}
}
});
key += `-revision-${revision}`
}
key += `-${lockFile}`
return key
}
+42 -3
View File
@@ -19,8 +19,10 @@ export function partition(string, separator) {
return [string.slice(0, i), string.slice(i + separator.length, string.length)]
}
let inGroup = false
export async function measure(name, block) {
return await core.group(name, async () => {
const body = async () => {
const start = performance.now()
try {
return await block()
@@ -29,7 +31,20 @@ export async function measure(name, block) {
const duration = (end - start) / 1000.0
console.log(`Took ${duration.toFixed(2).padStart(6)} seconds`)
}
})
}
if (inGroup) {
// Nested groups are not yet supported on GitHub Actions
console.log(`> ${name}`)
return await body()
} else {
inGroup = true
try {
return await core.group(name, body)
} finally {
inGroup = false
}
}
}
export function isHeadVersion(rubyVersion) {
@@ -40,6 +55,25 @@ export function isStableVersion(rubyVersion) {
return /^\d+(\.\d+)*$/.test(rubyVersion)
}
export function isBundler2Default(engine, rubyVersion) {
if (engine === 'ruby') {
return isHeadVersion(rubyVersion) || floatVersion(rubyVersion) >= 2.7
} else if (engine === 'truffleruby') {
return isHeadVersion(rubyVersion)
} else {
return false
}
}
export function floatVersion(rubyVersion) {
const match = rubyVersion.match(/^\d+\.\d+/)
if (match) {
return parseFloat(match[0])
} else {
return 0.0
}
}
export async function hashFile(file) {
// See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts
const hash = crypto.createHash('sha256')
@@ -77,7 +111,7 @@ export function getVirtualEnvironmentName() {
throw new Error(`Unknown ImageOS ${imageOS}`)
}
export function shouldExtractInToolCache(engine, version) {
export function shouldUseToolCache(engine, version) {
return engine === 'ruby' && !isHeadVersion(version)
}
@@ -99,6 +133,11 @@ export function getToolCacheRubyPrefix(platform, version) {
return path.join(toolCache, 'Ruby', version, 'x64')
}
export function createToolCacheCompleteFile(toolCacheRubyPrefix) {
const completeFile = `${toolCacheRubyPrefix}.complete`
fs.writeFileSync(completeFile, '')
}
// convert windows path like C:\Users\runneradmin to /c/Users/runneradmin
export function win2nix(path) {
if (/^[A-Z]:/i.test(path)) {
Generated Vendored
+1366 -617
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem "bundler", "~> 1.0"
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "nokogiri"
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "rails", "~> 5.2.0"
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "rails", "~> 6.0.0"
+1 -1
View File
@@ -30,4 +30,4 @@ versions['mingw'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/rub
versions['mswin'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z'
js = "export const versions = #{JSON.pretty_generate(versions)}\n"
File.write 'windows-versions.js', js
File.binwrite 'windows-versions.js', js
+5 -172
View File
@@ -2,9 +2,8 @@ const os = require('os')
const fs = require('fs')
const path = require('path')
const core = require('@actions/core')
const exec = require('@actions/exec')
const cache = require('@actions/cache')
const common = require('./common')
const bundler = require('./bundler')
const windows = common.windows
@@ -61,34 +60,20 @@ export async function setupRuby(options = {}) {
}
if (inputs['bundler'] !== 'none') {
const [gemfile, lockFile] = detectGemfiles()
const [gemfile, lockFile] = bundler.detectGemfiles()
await common.measure('Installing Bundler', async () =>
installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version))
const bundlerVersion = await common.measure('Installing Bundler', async () =>
bundler.installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version))
if (inputs['bundler-cache'] === 'true') {
await common.measure('bundle install', async () =>
bundleInstall(gemfile, lockFile, platform, engine, version))
bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion))
}
}
core.setOutput('ruby-prefix', rubyPrefix)
}
// The returned gemfile is guaranteed to exist, the lockfile might not exist
function detectGemfiles() {
const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile'
if (fs.existsSync(gemfilePath)) {
return [gemfilePath, `${gemfilePath}.lock`]
}
if (fs.existsSync("gems.rb")) {
return ["gems.rb", "gems.locked"]
}
return [null, null]
}
function parseRubyEngineAndVersion(rubyVersion) {
if (rubyVersion === 'default') {
if (fs.existsSync('.ruby-version')) {
@@ -172,156 +157,4 @@ function envPreInstall() {
}
}
function readBundledWithFromGemfileLock(lockFile) {
if (lockFile !== null && fs.existsSync(lockFile)) {
const contents = fs.readFileSync(lockFile, 'utf8')
const lines = contents.split(/\r?\n/)
const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim()))
if (bundledWithLine !== -1) {
const nextLine = lines[bundledWithLine+1]
if (nextLine && /^\d+/.test(nextLine.trim())) {
const bundlerVersion = nextLine.trim()
const majorVersion = bundlerVersion.match(/^\d+/)[0]
console.log(`Using Bundler ${majorVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`)
return majorVersion
}
}
}
return null
}
async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefix, engine, rubyVersion) {
let bundlerVersion = bundlerVersionInput
if (bundlerVersion === 'default' || bundlerVersion === 'Gemfile.lock') {
bundlerVersion = readBundledWithFromGemfileLock(lockFile)
if (!bundlerVersion) {
bundlerVersion = 'latest'
}
}
if (bundlerVersion === 'latest') {
bundlerVersion = '2'
}
if (/^\d+/.test(bundlerVersion)) {
// OK
} else {
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
}
if (engine === 'ruby' && rubyVersion.match(/^2\.[12]/)) {
console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2')
bundlerVersion = '1'
} else if (engine === 'ruby' && rubyVersion.startsWith('2.3')) {
console.log('Ruby 2.3 has a bug with Bundler 2 (https://github.com/rubygems/rubygems/issues/3570), using Bundler 1 instead on Ruby 2.3')
bundlerVersion = '1'
} else if (engine === 'jruby' && rubyVersion.startsWith('9.1.')) { // JRuby 9.1 targets Ruby 2.3, treat it the same
console.log('JRuby 9.1 has a bug with Bundler 2 (https://github.com/ruby/setup-ruby/issues/108), using Bundler 1 instead on JRuby 9.1')
bundlerVersion = '1'
}
if ((engine === 'ruby' || engine === 'truffleruby') && common.isHeadVersion(rubyVersion) && bundlerVersion === '2') {
console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`)
} else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion === '1') {
console.log(`Using Bundler 1 shipped with ${engine}`)
} else {
const gem = path.join(rubyPrefix, 'bin', 'gem')
await exec.exec(gem, ['install', 'bundler', '-v', `~> ${bundlerVersion}`, '--no-document'])
}
core.exportVariable('BUNDLER_VERSION', bundlerVersion)
}
async function bundleInstall(gemfile, lockFile, platform, engine, version) {
if (gemfile === null) {
console.log('Could not determine gemfile path, skipping "bundle install" and caching')
return false
}
// config
const path = 'vendor/bundle'
await exec.exec('bundle', ['config', '--local', 'path', path])
if (fs.existsSync(lockFile)) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true'])
} else {
// Generate the lockfile so we can use it to compute the cache key.
// This will also automatically pick up the latest gem versions compatible with the Gemfile.
await exec.exec('bundle', ['lock'])
}
// cache key
const paths = [path]
const baseKey = await computeBaseKey(platform, engine, version, lockFile)
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}-`]
console.log(`Cache key: ${key}`)
// restore cache & install
let cachedKey = null
try {
cachedKey = await cache.restoreCache(paths, key, restoreKeys)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error;
} else {
core.info(`[warning] There was an error restoring the cache ${error.message}`)
}
}
if (cachedKey) {
console.log(`Found cache for key: ${cachedKey}`)
}
// Always run 'bundle install' to list the gems
await exec.exec('bundle', ['install', '--jobs', '4'])
// @actions/cache only allows to save for non-existing keys
if (cachedKey !== key) {
if (cachedKey) { // existing cache but Gemfile.lock differs, clean old gems
await exec.exec('bundle', ['clean'])
}
// Error handling from https://github.com/actions/cache/blob/master/src/save.ts
console.log('Saving cache')
try {
await cache.saveCache(paths, key)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error;
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message);
} else {
core.info(`[warning]${error.message}`)
}
}
}
return true
}
async function computeBaseKey(platform, engine, version, lockFile) {
let key = `setup-ruby-bundler-cache-v2-${platform}-${engine}-${version}`
if (engine !== 'jruby' && common.isHeadVersion(version)) {
let revision = '';
await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], {
silent: true,
listeners: {
stdout: (data) => {
revision += data.toString();
}
}
});
key += `-revision-${revision}`
}
key += `-${lockFile}`
return key
}
if (__filename.endsWith('index.js')) { run() }
+1 -1
View File
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/ruby/setup-ruby",
"dependencies": {
"@actions/cache": "^1.0.2",
"@actions/cache": "^1.0.5",
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.3",
"@actions/io": "^1.0.2",
+2 -2
View File
@@ -8,12 +8,12 @@ export function getVersions(platform) {
"2.5.0", "2.5.1", "2.5.2", "2.5.3", "2.5.4", "2.5.5", "2.5.6", "2.5.7", "2.5.8",
"2.6.0", "2.6.1", "2.6.2", "2.6.3", "2.6.4", "2.6.5", "2.6.6",
"2.7.0", "2.7.1", "2.7.2",
"3.0.0-preview1",
"3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0",
"head", "debug",
],
"jruby": [
"9.1.17.0",
"9.2.9.0", "9.2.10.0", "9.2.11.0", "9.2.11.1", "9.2.12.0", "9.2.13.0",
"9.2.9.0", "9.2.10.0", "9.2.11.0", "9.2.11.1", "9.2.12.0", "9.2.13.0", "9.2.14.0",
"head"
],
"truffleruby": [
+23 -13
View File
@@ -1,6 +1,5 @@
const os = require('os')
const path = require('path')
const core = require('@actions/core')
const exec = require('@actions/exec')
const io = require('@actions/io')
const tc = require('@actions/tool-cache')
@@ -17,24 +16,33 @@ export function getAvailableVersions(platform, engine) {
}
export async function install(platform, engine, version) {
return await downloadAndExtract(platform, engine, version)
}
async function downloadAndExtract(platform, engine, version) {
let rubyPrefix
if (common.shouldExtractInToolCache(engine, version)) {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
let rubyPrefix, inToolCache
if (common.shouldUseToolCache(engine, version)) {
inToolCache = tc.find('Ruby', version)
if (inToolCache) {
rubyPrefix = inToolCache
} else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else if (windows) {
rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`)
} else {
rubyPrefix = path.join(os.homedir(), '.rubies', `${engine}-${version}`)
}
const parentDir = path.dirname(rubyPrefix)
// Set the PATH now, so the MSYS2 'tar' is in Path on Windows
common.setupPath([path.join(rubyPrefix, 'bin')])
if (!inToolCache) {
await downloadAndExtract(platform, engine, version, rubyPrefix);
}
return rubyPrefix
}
async function downloadAndExtract(platform, engine, version, rubyPrefix) {
const parentDir = path.dirname(rubyPrefix)
await io.rmRF(rubyPrefix)
await io.mkdirP(parentDir)
@@ -47,13 +55,15 @@ async function downloadAndExtract(platform, engine, version) {
await common.measure('Extracting Ruby', async () => {
if (windows) {
// Windows 2016 doesn't have system tar, use MSYS2's, it needs unix style paths
await exec.exec('tar', [ '-xz', '-C', common.win2nix(parentDir), '-f', common.win2nix(downloadPath) ])
await exec.exec('tar', ['-xz', '-C', common.win2nix(parentDir), '-f', common.win2nix(downloadPath)])
} else {
await exec.exec('tar', [ '-xz', '-C', parentDir, '-f', downloadPath ])
await exec.exec('tar', ['-xz', '-C', parentDir, '-f', downloadPath])
}
})
return rubyPrefix
if (common.shouldUseToolCache(engine, version)) {
common.createToolCacheCompleteFile(rubyPrefix)
}
}
function getDownloadURL(platform, engine, version) {
+3 -2
View File
@@ -19,17 +19,18 @@ export const versions = {
"2.5.5": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.5-1/rubyinstaller-2.5.5-1-x64.7z",
"2.5.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.6-1/rubyinstaller-2.5.6-1-x64.7z",
"2.5.7": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.7-1/rubyinstaller-2.5.7-1-x64.7z",
"2.5.8": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.8-1/rubyinstaller-2.5.8-1-x64.7z",
"2.5.8": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.8-2/rubyinstaller-2.5.8-2-x64.7z",
"2.6.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.0-1/rubyinstaller-2.6.0-1-x64.7z",
"2.6.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.1-1/rubyinstaller-2.6.1-1-x64.7z",
"2.6.2": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.2-1/rubyinstaller-2.6.2-1-x64.7z",
"2.6.3": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.3-1/rubyinstaller-2.6.3-1-x64.7z",
"2.6.4": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.4-1/rubyinstaller-2.6.4-1-x64.7z",
"2.6.5": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.5-1/rubyinstaller-2.6.5-1-x64.7z",
"2.6.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.6-1/rubyinstaller-2.6.6-1-x64.7z",
"2.6.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.6-2/rubyinstaller-2.6.6-2-x64.7z",
"2.7.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.0-1/rubyinstaller-2.7.0-1-x64.7z",
"2.7.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.1-1/rubyinstaller-2.7.1-1-x64.7z",
"2.7.2": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.2-1/rubyinstaller-2.7.2-1-x64.7z",
"3.0.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.0-1/rubyinstaller-3.0.0-1-x64.7z",
"head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z",
"mingw": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z",
"mswin": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z"
+21 -5
View File
@@ -36,18 +36,32 @@ export async function install(platform, engine, version) {
}
const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length)
let rubyPrefix
if (common.shouldExtractInToolCache(engine, version)) {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
let rubyPrefix, inToolCache
if (common.shouldUseToolCache(engine, version)) {
inToolCache = tc.find('Ruby', version)
if (inToolCache) {
rubyPrefix = inToolCache
} else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else {
rubyPrefix = `${drive}:\\${base}`
}
const parentDir = path.dirname(rubyPrefix)
let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version)
common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths])
if (!inToolCache) {
await downloadAndExtract(engine, version, url, base, rubyPrefix);
}
return rubyPrefix
}
async function downloadAndExtract(engine, version, url, base, rubyPrefix) {
const parentDir = path.dirname(rubyPrefix)
const downloadPath = await common.measure('Downloading Ruby', async () => {
console.log(url)
return await tc.downloadTool(url)
@@ -60,7 +74,9 @@ export async function install(platform, engine, version) {
await io.mv(path.join(parentDir, base), rubyPrefix)
}
return rubyPrefix
if (common.shouldUseToolCache(engine, version)) {
common.createToolCacheCompleteFile(rubyPrefix)
}
}
async function setupMingw(version) {
Generated
+14 -7
View File
@@ -2,22 +2,22 @@
# yarn lockfile v1
"@actions/cache@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@actions/cache/-/cache-1.0.2.tgz#a223dcc752c7f988016d28ee7232f930f85cec61"
integrity sha512-CzAseaJ4cKmOI58EIWUb/LfeYdM7Y25s39OEMtWAhEPrPPzrbSEjGHCLaYjJ0V8C4iojo8vBYh5B3OIJ37EiJw==
"@actions/cache@^1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@actions/cache/-/cache-1.0.5.tgz#ba98725d38611b5426fc57a2f00bd8b0d9202f36"
integrity sha512-TcvJOduwsPP27KLmIa5cqXsQYFK2GzILcEpnhvYmhGwi1aYx9XwhKmp6Im8X6DJMBxbvupKPsOntG6f6sSkIPA==
dependencies:
"@actions/core" "^1.2.4"
"@actions/core" "^1.2.6"
"@actions/exec" "^1.0.1"
"@actions/glob" "^0.1.0"
"@actions/http-client" "^1.0.8"
"@actions/http-client" "^1.0.9"
"@actions/io" "^1.0.1"
"@azure/ms-rest-js" "^2.0.7"
"@azure/storage-blob" "^12.1.2"
semver "^6.1.0"
uuid "^3.3.3"
"@actions/core@^1.2.0", "@actions/core@^1.2.3", "@actions/core@^1.2.4", "@actions/core@^1.2.6":
"@actions/core@^1.2.0", "@actions/core@^1.2.3", "@actions/core@^1.2.6":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.6.tgz#a78d49f41a4def18e88ce47c2cac615d5694bf09"
integrity sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==
@@ -44,6 +44,13 @@
dependencies:
tunnel "0.0.6"
"@actions/http-client@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.9.tgz#af1947d020043dbc6a3b4c5918892095c30ffb52"
integrity sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==
dependencies:
tunnel "0.0.6"
"@actions/io@^1.0.1", "@actions/io@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.0.2.tgz#2f614b6e69ce14d191180451eb38e6576a6e6b27"