Compare commits

..
10 Commits
Author SHA1 Message Date
Benoit Daloze 7c2bf7263d Ensure an engine-only ruby-version picks the latest stable version and not a preview or RC 2020-11-18 21:52:51 +01:00
Benoit Daloze 34fbbc1d36 Update README.md 2020-11-16 12:13:08 +01:00
Benoit Daloze 9bc07a3af0 No builds of truffleruby{,-head} on macos-11.0 yet 2020-11-13 10:48:04 +01:00
Benoit Daloze 63dde36864 Remove the Caching bundle install manually section
* It is too error prone and the automatic approach is a lot safer and easier.
2020-11-13 10:38:56 +01:00
Benoit Daloze fde3324171 Remove redundant bundle install in the usage examples 2020-11-13 10:38:56 +01:00
Benoit Daloze 59aafb8612 Add support for macos-11.0 2020-11-13 10:33:21 +01:00
Benoit Daloze ad1ebae995 Also include the version in the platform for macos and windows
* Guess the platform based on $ImageOS.
2020-11-12 20:23:53 +01:00
Benoit Daloze f4a8aa6c33 Use ImageOS for the cache key, so it also includes the OS version 2020-11-12 19:59:05 +01:00
Benoit Daloze bc0f274d1c Fix Bundler cache when there is no Gemfile.lock
* Always show the list of installed gems in the log.
2020-11-12 19:34:43 +01:00
Benoit Daloze 1c896c8ea1 Always use Bundler 1 for JRuby 9.1.x 2020-11-12 19:08:42 +01:00
6 changed files with 144 additions and 157 deletions
+3 -1
View File
@@ -15,7 +15,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ ubuntu-16.04, ubuntu-18.04, ubuntu-20.04, macos-10.15, windows-2016, windows-2019 ] os: [ ubuntu-16.04, ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11.0, windows-2016, windows-2019 ]
# Use various version syntax here for testing # Use various version syntax here for testing
ruby: [ 2.1, 2.2, 2.3, 2.4, 2.5, 2.6.6, 2.7, 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, ruby-head, debug, jruby-9.1, jruby, jruby-head, truffleruby, truffleruby-head ]
include: include:
@@ -29,6 +29,8 @@ jobs:
- { os: windows-2019, ruby: debug } - { os: windows-2019, ruby: debug }
- { os: windows-2019, ruby: truffleruby } - { os: windows-2019, ruby: truffleruby }
- { os: windows-2019, ruby: truffleruby-head } - { os: windows-2019, ruby: truffleruby-head }
- { os: macos-11.0, ruby: truffleruby }
- { os: macos-11.0, ruby: truffleruby-head }
name: ${{ matrix.os }} ${{ matrix.ruby }} name: ${{ matrix.os }} ${{ matrix.ruby }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
+2 -32
View File
@@ -39,7 +39,7 @@ The action works for all [GitHub-hosted runners](https://help.github.com/en/acti
| Operating System | Recommended | Other Supported Versions | | Operating System | Recommended | Other Supported Versions |
| ----------- | -------- | -------- | | ----------- | -------- | -------- |
| Ubuntu | `ubuntu-latest` (= `ubuntu-18.04`) | `ubuntu-20.04`, `ubuntu-16.04` | | Ubuntu | `ubuntu-latest` (= `ubuntu-18.04`) | `ubuntu-20.04`, `ubuntu-16.04` |
| macOS | `macos-latest` (= `macos-10.15`) | | | macOS | `macos-latest` (= `macos-10.15`) | `macos-11.0` |
| Windows | `windows-latest` (= `windows-2019`) | `windows-2016` | | Windows | `windows-latest` (= `windows-2019`) | `windows-2016` |
The prebuilt releases are generated by [ruby-builder](https://github.com/ruby/ruby-builder) The prebuilt releases are generated by [ruby-builder](https://github.com/ruby/ruby-builder)
@@ -67,7 +67,6 @@ jobs:
with: with:
ruby-version: 2.6 # Not needed with a .ruby-version file ruby-version: 2.6 # Not needed with a .ruby-version file
bundler-cache: true # runs 'bundle install' and caches installed gems automatically bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle install
- run: bundle exec rake - run: bundle exec rake
``` ```
@@ -93,7 +92,6 @@ jobs:
with: with:
ruby-version: ${{ matrix.ruby }} ruby-version: ${{ matrix.ruby }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle install
- run: bundle exec rake - run: bundle exec rake
``` ```
@@ -142,35 +140,6 @@ If there is a `Gemfile.lock` (or `$BUNDLE_GEMFILE.lock` or `gems.locked`), `bund
To perform caching, this action will use `bundle config --local path vendor/bundle`. To perform caching, this action will use `bundle config --local path vendor/bundle`.
Therefore, the Bundler `path` should not be changed in your workflow for the cache to work (no `bundle config path`). Therefore, the Bundler `path` should not be changed in your workflow for the cache to work (no `bundle config path`).
### Caching `bundle install` manually
You can also cache gems manually,
but this is not recommended because it is verbose and very difficult to use a correct cache key.
You can cache the installed gems with these two steps:
```yaml
- uses: actions/cache@v2
with:
path: vendor/bundle
key: bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby }}-
- name: bundle install
run: |
bundle config deployment true
bundle config path vendor/bundle
bundle install --jobs 4
```
When using a single OS, replace `${{ matrix.os }}` with the OS.
When using a single job with a Ruby version, replace `${{ matrix.ruby }}` with the Ruby version.
When using `.ruby-version`, replace `${{ matrix.ruby }}` with `${{ hashFiles('.ruby-version') }}`.
When using `.tool-versions`, replace `${{ matrix.ruby }}` with `${{ hashFiles('.tool-versions') }}`.
This uses the [cache action](https://github.com/actions/cache).
The code above is a more complete version of the [Ruby - Bundler example](https://github.com/actions/cache/blob/master/examples.md#ruby---bundler).
Make sure to include `use-ruby` in the `key` to avoid conflicting with previous caches.
## Windows ## Windows
Note that running CI on Windows can be quite challenging if you are not very familiar with Windows. Note that running CI on Windows can be quite challenging if you are not very familiar with Windows.
@@ -201,6 +170,7 @@ This action might work with [self-hosted runners](https://docs.github.com/en/act
if the [virtual environment](https://github.com/actions/virtual-environments) is very similar to the ones used by GitHub runners. Notably: if the [virtual environment](https://github.com/actions/virtual-environments) is very similar to the ones used by GitHub runners. Notably:
* Make sure to use the same operating system and version. * Make sure to use the same operating system and version.
* Set the environment variable `ImageOS` to the corresponding value on GitHub-hosted runners (e.g. `ubuntu18`/`macos1015`/`win19`). This is necessary to detect the operating system and version.
* Make sure to use the same version of libssl. * Make sure to use the same version of libssl.
* Make sure that the operating system has `libyaml-0` installed * Make sure that the operating system has `libyaml-0` installed
* The default tool cache directory (`/opt/hostedtoolcache` on Linux, `/Users/runner/hostedtoolcache` on macOS, * The default tool cache directory (`/opt/hostedtoolcache` on Linux, `/Users/runner/hostedtoolcache` on macOS,
+26 -16
View File
@@ -28,6 +28,10 @@ export function isHeadVersion(rubyVersion) {
return rubyVersion === 'head' || rubyVersion === 'debug' || rubyVersion === 'mingw' || rubyVersion === 'mswin' return rubyVersion === 'head' || rubyVersion === 'debug' || rubyVersion === 'mingw' || rubyVersion === 'mswin'
} }
export function isStableVersion(rubyVersion) {
return /^\d+(\.\d+)*$/.test(rubyVersion)
}
export async function hashFile(file) { export async function hashFile(file) {
// See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts // See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts
const hash = crypto.createHash('sha256') const hash = crypto.createHash('sha256')
@@ -36,27 +40,33 @@ export async function hashFile(file) {
return hash.digest('hex') return hash.digest('hex')
} }
export function getVirtualEnvironmentName() { function getImageOS() {
const platform = os.platform() const imageOS = process.env['ImageOS']
if (platform === 'linux') { if (!imageOS) {
return `ubuntu-${findUbuntuVersion()}` throw new Error('The environment variable ImageOS must be set')
} else if (platform === 'darwin') {
return 'macos-latest'
} else if (platform === 'win32') {
return 'windows-latest'
} else {
throw new Error(`Unknown platform ${platform}`)
} }
return imageOS
} }
function findUbuntuVersion() { export function getVirtualEnvironmentName() {
const lsb_release = fs.readFileSync('/etc/lsb-release', 'utf8') const imageOS = getImageOS()
const match = lsb_release.match(/^DISTRIB_RELEASE=(\d+\.\d+)$/m)
let match = imageOS.match(/^ubuntu(\d+)/) // e.g. ubuntu18
if (match) { if (match) {
return match[1] return `ubuntu-${match[1]}.04`
} else {
throw new Error('Could not find Ubuntu version')
} }
match = imageOS.match(/^macos(\d{2})(\d+)?/) // e.g. macos1015, macos11
if (match) {
return `macos-${match[1]}.${match[2] || '0'}`
}
match = imageOS.match(/^win(\d+)/) // e.g. win19
if (match) {
return `windows-20${match[1]}`
}
throw new Error(`Unknown ImageOS ${imageOS}`)
} }
export function shouldExtractInToolCache(engine, version) { export function shouldExtractInToolCache(engine, version) {
Generated Vendored
+70 -62
View File
@@ -32096,6 +32096,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "drive", function() { return drive; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "drive", function() { return drive; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "measure", function() { return measure; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "measure", function() { return measure; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isHeadVersion", function() { return isHeadVersion; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isHeadVersion", function() { return isHeadVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isStableVersion", function() { return isStableVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hashFile", function() { return hashFile; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hashFile", function() { return hashFile; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getVirtualEnvironmentName", function() { return getVirtualEnvironmentName; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getVirtualEnvironmentName", function() { return getVirtualEnvironmentName; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shouldExtractInToolCache", function() { return shouldExtractInToolCache; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shouldExtractInToolCache", function() { return shouldExtractInToolCache; });
@@ -32132,6 +32133,10 @@ function isHeadVersion(rubyVersion) {
return rubyVersion === 'head' || rubyVersion === 'debug' || rubyVersion === 'mingw' || rubyVersion === 'mswin' return rubyVersion === 'head' || rubyVersion === 'debug' || rubyVersion === 'mingw' || rubyVersion === 'mswin'
} }
function isStableVersion(rubyVersion) {
return /^\d+(\.\d+)*$/.test(rubyVersion)
}
async function hashFile(file) { async function hashFile(file) {
// See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts // See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts
const hash = crypto.createHash('sha256') const hash = crypto.createHash('sha256')
@@ -32140,27 +32145,33 @@ async function hashFile(file) {
return hash.digest('hex') return hash.digest('hex')
} }
function getVirtualEnvironmentName() { function getImageOS() {
const platform = os.platform() const imageOS = process.env['ImageOS']
if (platform === 'linux') { if (!imageOS) {
return `ubuntu-${findUbuntuVersion()}` throw new Error('The environment variable ImageOS must be set')
} else if (platform === 'darwin') {
return 'macos-latest'
} else if (platform === 'win32') {
return 'windows-latest'
} else {
throw new Error(`Unknown platform ${platform}`)
} }
return imageOS
} }
function findUbuntuVersion() { function getVirtualEnvironmentName() {
const lsb_release = fs.readFileSync('/etc/lsb-release', 'utf8') const imageOS = getImageOS()
const match = lsb_release.match(/^DISTRIB_RELEASE=(\d+\.\d+)$/m)
let match = imageOS.match(/^ubuntu(\d+)/) // e.g. ubuntu18
if (match) { if (match) {
return match[1] return `ubuntu-${match[1]}.04`
} else {
throw new Error('Could not find Ubuntu version')
} }
match = imageOS.match(/^macos(\d{2})(\d+)?/) // e.g. macos1015, macos11
if (match) {
return `macos-${match[1]}.${match[2] || '0'}`
}
match = imageOS.match(/^win(\d+)/) // e.g. win19
if (match) {
return `windows-20${match[1]}`
}
throw new Error(`Unknown ImageOS ${imageOS}`)
} }
function shouldExtractInToolCache(engine, version) { function shouldExtractInToolCache(engine, version) {
@@ -51227,25 +51238,15 @@ async function setupRuby(options = {}) {
core.setOutput('ruby-prefix', rubyPrefix) core.setOutput('ruby-prefix', rubyPrefix)
} }
// The returned gemfile is guaranteed to exist, the lockfile might not exist
function detectGemfiles() { function detectGemfiles() {
const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile' const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile'
if (fs.existsSync(gemfilePath)) { if (fs.existsSync(gemfilePath)) {
const lockPath = `${gemfilePath}.lock` return [gemfilePath, `${gemfilePath}.lock`]
if (fs.existsSync(lockPath)) {
return [gemfilePath, lockPath]
} else {
return [gemfilePath, null]
}
} }
const gemsRbPath = "gems.rb" if (fs.existsSync("gems.rb")) {
if (fs.existsSync(gemsRbPath)) { return ["gems.rb", "gems.locked"]
const lockPath = "gems.locked"
if (fs.existsSync(lockPath)) {
return [gemsRbPath, lockPath]
} else {
return [gemsRbPath, null]
}
} }
return [null, null] return [null, null]
@@ -51294,7 +51295,7 @@ function validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVe
let version = parsedVersion let version = parsedVersion
if (!engineVersions.includes(parsedVersion)) { if (!engineVersions.includes(parsedVersion)) {
const latestToFirstVersion = engineVersions.slice().reverse() const latestToFirstVersion = engineVersions.slice().reverse()
const found = latestToFirstVersion.find(v => !common.isHeadVersion(v) && v.startsWith(parsedVersion)) const found = latestToFirstVersion.find(v => common.isStableVersion(v) && v.startsWith(parsedVersion))
if (found) { if (found) {
version = found version = found
} else { } else {
@@ -51329,7 +51330,7 @@ function envPreInstall() {
} }
function readBundledWithFromGemfileLock(lockFile) { function readBundledWithFromGemfileLock(lockFile) {
if (lockFile !== null) { if (lockFile !== null && fs.existsSync(lockFile)) {
const contents = fs.readFileSync(lockFile, 'utf8') const contents = fs.readFileSync(lockFile, 'utf8')
const lines = contents.split(/\r?\n/) const lines = contents.split(/\r?\n/)
const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim())) const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim()))
@@ -51367,12 +51368,15 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
} }
if (rubyVersion.match(/^2\.[12]/)) { if (engine === 'ruby' && rubyVersion.match(/^2\.[12]/)) {
console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2') console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2')
bundlerVersion = '1' bundlerVersion = '1'
} else if (rubyVersion.startsWith('2.3')) { } 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') 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' 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') { if ((engine === 'ruby' || engine === 'truffleruby') && common.isHeadVersion(rubyVersion) && bundlerVersion === '2') {
@@ -51394,24 +51398,22 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
// config // config
const path = 'vendor/bundle' const path = 'vendor/bundle'
if (lockFile !== null) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true'])
}
await exec.exec('bundle', ['config', '--local', 'path', path]) 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 // cache key
const paths = [path] const paths = [path]
const baseKey = await computeBaseKey(platform, engine, version, gemfile) const baseKey = await computeBaseKey(platform, engine, version, lockFile)
let key = baseKey const key = `${baseKey}-${await common.hashFile(lockFile)}`
let restoreKeys // If only Gemfile.lock changes we can reuse part of the cache (but it will keep old gem versions in the cache)
if (lockFile !== null) { const restoreKeys = [`${baseKey}-`]
key += `-${lockFile}-${await common.hashFile(lockFile)}`
// If only Gemfile.lock changes we can reuse part of the cache (but it will keep old gem versions in the cache)
restoreKeys = [`${baseKey}-${lockFile}-`]
} else {
// Only exact key, to never mix native gems of different platforms or Ruby versions
restoreKeys = []
}
console.log(`Cache key: ${key}`) console.log(`Cache key: ${key}`)
// restore cache & install // restore cache & install
@@ -51430,15 +51432,11 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
console.log(`Found cache for key: ${cachedKey}`) console.log(`Found cache for key: ${cachedKey}`)
} }
let alreadyInstalled = false // Always run 'bundle install' to list the gems
if (cachedKey === key) { await exec.exec('bundle', ['install', '--jobs', '4'])
const exitCode = await exec.exec('bundle', ['check'], { ignoreReturnCode: true })
alreadyInstalled = (exitCode === 0)
}
if (!alreadyInstalled) {
await exec.exec('bundle', ['install', '--jobs', '4'])
// @actions/cache only allows to save for non-existing keys
if (cachedKey !== key) {
// Error handling from https://github.com/actions/cache/blob/master/src/save.ts // Error handling from https://github.com/actions/cache/blob/master/src/save.ts
console.log('Saving cache') console.log('Saving cache')
try { try {
@@ -51457,8 +51455,9 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
return true return true
} }
async function computeBaseKey(platform, engine, version, gemfile) { async function computeBaseKey(platform, engine, version, lockFile) {
let baseKey = `setup-ruby-toolcache-bundle-install-${platform}-${engine}-${version}-${gemfile}` let key = `setup-ruby-bundler-cache-v2-${platform}-${engine}-${version}`
if (engine !== 'jruby' && common.isHeadVersion(version)) { if (engine !== 'jruby' && common.isHeadVersion(version)) {
let revision = ''; let revision = '';
await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], { await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], {
@@ -51469,9 +51468,11 @@ async function computeBaseKey(platform, engine, version, gemfile) {
} }
} }
}); });
baseKey += `-revision-${revision}` key += `-revision-${revision}`
} }
return baseKey
key += `-${lockFile}`
return key
} }
if (__filename.endsWith('index.js')) { run() } if (__filename.endsWith('index.js')) { run() }
@@ -52945,10 +52946,17 @@ async function downloadAndExtract(platform, engine, version) {
} }
function getDownloadURL(platform, engine, version) { function getDownloadURL(platform, engine, version) {
let builderPlatform = platform
if (platform.startsWith('windows-')) {
builderPlatform = 'windows-latest'
} else if (platform.startsWith('macos-')) {
builderPlatform = 'macos-latest'
}
if (common.isHeadVersion(version)) { if (common.isHeadVersion(version)) {
return getLatestHeadBuildURL(platform, engine, version) return getLatestHeadBuildURL(builderPlatform, engine, version)
} else { } else {
return `${releasesURL}/download/${builderReleaseTag}/${engine}-${version}-${platform}.tar.gz` return `${releasesURL}/download/${builderReleaseTag}/${engine}-${version}-${builderPlatform}.tar.gz`
} }
} }
+34 -44
View File
@@ -75,25 +75,15 @@ export async function setupRuby(options = {}) {
core.setOutput('ruby-prefix', rubyPrefix) core.setOutput('ruby-prefix', rubyPrefix)
} }
// The returned gemfile is guaranteed to exist, the lockfile might not exist
function detectGemfiles() { function detectGemfiles() {
const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile' const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile'
if (fs.existsSync(gemfilePath)) { if (fs.existsSync(gemfilePath)) {
const lockPath = `${gemfilePath}.lock` return [gemfilePath, `${gemfilePath}.lock`]
if (fs.existsSync(lockPath)) {
return [gemfilePath, lockPath]
} else {
return [gemfilePath, null]
}
} }
const gemsRbPath = "gems.rb" if (fs.existsSync("gems.rb")) {
if (fs.existsSync(gemsRbPath)) { return ["gems.rb", "gems.locked"]
const lockPath = "gems.locked"
if (fs.existsSync(lockPath)) {
return [gemsRbPath, lockPath]
} else {
return [gemsRbPath, null]
}
} }
return [null, null] return [null, null]
@@ -142,7 +132,7 @@ function validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVe
let version = parsedVersion let version = parsedVersion
if (!engineVersions.includes(parsedVersion)) { if (!engineVersions.includes(parsedVersion)) {
const latestToFirstVersion = engineVersions.slice().reverse() const latestToFirstVersion = engineVersions.slice().reverse()
const found = latestToFirstVersion.find(v => !common.isHeadVersion(v) && v.startsWith(parsedVersion)) const found = latestToFirstVersion.find(v => common.isStableVersion(v) && v.startsWith(parsedVersion))
if (found) { if (found) {
version = found version = found
} else { } else {
@@ -177,7 +167,7 @@ function envPreInstall() {
} }
function readBundledWithFromGemfileLock(lockFile) { function readBundledWithFromGemfileLock(lockFile) {
if (lockFile !== null) { if (lockFile !== null && fs.existsSync(lockFile)) {
const contents = fs.readFileSync(lockFile, 'utf8') const contents = fs.readFileSync(lockFile, 'utf8')
const lines = contents.split(/\r?\n/) const lines = contents.split(/\r?\n/)
const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim())) const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim()))
@@ -215,12 +205,15 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
} }
if (rubyVersion.match(/^2\.[12]/)) { if (engine === 'ruby' && rubyVersion.match(/^2\.[12]/)) {
console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2') console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2')
bundlerVersion = '1' bundlerVersion = '1'
} else if (rubyVersion.startsWith('2.3')) { } 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') 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' 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') { if ((engine === 'ruby' || engine === 'truffleruby') && common.isHeadVersion(rubyVersion) && bundlerVersion === '2') {
@@ -242,24 +235,22 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
// config // config
const path = 'vendor/bundle' const path = 'vendor/bundle'
if (lockFile !== null) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true'])
}
await exec.exec('bundle', ['config', '--local', 'path', path]) 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 // cache key
const paths = [path] const paths = [path]
const baseKey = await computeBaseKey(platform, engine, version, gemfile) const baseKey = await computeBaseKey(platform, engine, version, lockFile)
let key = baseKey const key = `${baseKey}-${await common.hashFile(lockFile)}`
let restoreKeys // If only Gemfile.lock changes we can reuse part of the cache (but it will keep old gem versions in the cache)
if (lockFile !== null) { const restoreKeys = [`${baseKey}-`]
key += `-${lockFile}-${await common.hashFile(lockFile)}`
// If only Gemfile.lock changes we can reuse part of the cache (but it will keep old gem versions in the cache)
restoreKeys = [`${baseKey}-${lockFile}-`]
} else {
// Only exact key, to never mix native gems of different platforms or Ruby versions
restoreKeys = []
}
console.log(`Cache key: ${key}`) console.log(`Cache key: ${key}`)
// restore cache & install // restore cache & install
@@ -278,15 +269,11 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
console.log(`Found cache for key: ${cachedKey}`) console.log(`Found cache for key: ${cachedKey}`)
} }
let alreadyInstalled = false // Always run 'bundle install' to list the gems
if (cachedKey === key) { await exec.exec('bundle', ['install', '--jobs', '4'])
const exitCode = await exec.exec('bundle', ['check'], { ignoreReturnCode: true })
alreadyInstalled = (exitCode === 0)
}
if (!alreadyInstalled) {
await exec.exec('bundle', ['install', '--jobs', '4'])
// @actions/cache only allows to save for non-existing keys
if (cachedKey !== key) {
// Error handling from https://github.com/actions/cache/blob/master/src/save.ts // Error handling from https://github.com/actions/cache/blob/master/src/save.ts
console.log('Saving cache') console.log('Saving cache')
try { try {
@@ -305,8 +292,9 @@ async function bundleInstall(gemfile, lockFile, platform, engine, version) {
return true return true
} }
async function computeBaseKey(platform, engine, version, gemfile) { async function computeBaseKey(platform, engine, version, lockFile) {
let baseKey = `setup-ruby-toolcache-bundle-install-${platform}-${engine}-${version}-${gemfile}` let key = `setup-ruby-bundler-cache-v2-${platform}-${engine}-${version}`
if (engine !== 'jruby' && common.isHeadVersion(version)) { if (engine !== 'jruby' && common.isHeadVersion(version)) {
let revision = ''; let revision = '';
await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], { await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], {
@@ -317,9 +305,11 @@ async function computeBaseKey(platform, engine, version, gemfile) {
} }
} }
}); });
baseKey += `-revision-${revision}` key += `-revision-${revision}`
} }
return baseKey
key += `-${lockFile}`
return key
} }
if (__filename.endsWith('index.js')) { run() } if (__filename.endsWith('index.js')) { run() }
+9 -2
View File
@@ -57,10 +57,17 @@ async function downloadAndExtract(platform, engine, version) {
} }
function getDownloadURL(platform, engine, version) { function getDownloadURL(platform, engine, version) {
let builderPlatform = platform
if (platform.startsWith('windows-')) {
builderPlatform = 'windows-latest'
} else if (platform.startsWith('macos-')) {
builderPlatform = 'macos-latest'
}
if (common.isHeadVersion(version)) { if (common.isHeadVersion(version)) {
return getLatestHeadBuildURL(platform, engine, version) return getLatestHeadBuildURL(builderPlatform, engine, version)
} else { } else {
return `${releasesURL}/download/${builderReleaseTag}/${engine}-${version}-${platform}.tar.gz` return `${releasesURL}/download/${builderReleaseTag}/${engine}-${version}-${builderPlatform}.tar.gz`
} }
} }