Compare commits

..
11 Commits
9 changed files with 201 additions and 73 deletions
+11
View File
@@ -102,6 +102,17 @@ jobs:
if: startsWith(matrix.os, 'windows') && startsWith(matrix.ruby, 'jruby') if: startsWith(matrix.os, 'windows') && startsWith(matrix.ruby, 'jruby')
run: gem install sassc -N 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.1.4
- run: bundle --version | grep -F 2.1.4
lint: lint:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
+3 -3
View File
@@ -14,9 +14,9 @@ This action currently supports these versions of MRI, JRuby and TruffleRuby:
| Interpreter | Versions | | 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 | | `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 | | `jruby` | 9.1.17.0, 9.2.9.0 - 9.2.13.0, head |
| TruffleRuby | 19.3.0 - 20.3.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`). `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. On Windows, `mingw` and `mswin` are `ruby-head` builds using the MSYS2/MinGW and the MSVC toolchains respectively.
+1 -1
View File
@@ -11,7 +11,7 @@ inputs:
default: 'default' default: 'default'
bundler: bundler:
description: | 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. 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. Defaults to 'Gemfile.lock' if the file exists and 'latest' otherwise.
required: false required: false
+25 -1
View File
@@ -40,6 +40,25 @@ export function isStableVersion(rubyVersion) {
return /^\d+(\.\d+)*$/.test(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) { 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')
@@ -77,7 +96,7 @@ export function getVirtualEnvironmentName() {
throw new Error(`Unknown ImageOS ${imageOS}`) throw new Error(`Unknown ImageOS ${imageOS}`)
} }
export function shouldExtractInToolCache(engine, version) { export function shouldUseToolCache(engine, version) {
return engine === 'ruby' && !isHeadVersion(version) return engine === 'ruby' && !isHeadVersion(version)
} }
@@ -99,6 +118,11 @@ export function getToolCacheRubyPrefix(platform, version) {
return path.join(toolCache, 'Ruby', version, 'x64') 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 // convert windows path like C:\Users\runneradmin to /c/Users/runneradmin
export function win2nix(path) { export function win2nix(path) {
if (/^[A-Z]:/i.test(path)) { if (/^[A-Z]:/i.test(path)) {
Generated Vendored
+95 -35
View File
@@ -27712,18 +27712,32 @@ async function install(platform, engine, version) {
} }
const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length) const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length)
let rubyPrefix let rubyPrefix, inToolCache
if (common.shouldExtractInToolCache(engine, version)) { if (common.shouldUseToolCache(engine, version)) {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version) inToolCache = tc.find('Ruby', version)
if (inToolCache) {
rubyPrefix = inToolCache
} else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else { } else {
rubyPrefix = `${drive}:\\${base}` rubyPrefix = `${drive}:\\${base}`
} }
const parentDir = path.dirname(rubyPrefix)
let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version) let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version)
common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) 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 () => { const downloadPath = await common.measure('Downloading Ruby', async () => {
console.log(url) console.log(url)
return await tc.downloadTool(url) return await tc.downloadTool(url)
@@ -27736,7 +27750,9 @@ async function install(platform, engine, version) {
await io.mv(path.join(parentDir, base), rubyPrefix) await io.mv(path.join(parentDir, base), rubyPrefix)
} }
return rubyPrefix if (common.shouldUseToolCache(engine, version)) {
common.createToolCacheCompleteFile(rubyPrefix)
}
} }
async function setupMingw(version) { async function setupMingw(version) {
@@ -32098,10 +32114,13 @@ __webpack_require__.r(__webpack_exports__);
/* 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__, "isStableVersion", function() { return isStableVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isBundler2Default", function() { return isBundler2Default; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "floatVersion", function() { return floatVersion; });
/* 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__, "shouldUseToolCache", function() { return shouldUseToolCache; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getToolCacheRubyPrefix", function() { return getToolCacheRubyPrefix; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getToolCacheRubyPrefix", function() { return getToolCacheRubyPrefix; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createToolCacheCompleteFile", function() { return createToolCacheCompleteFile; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "win2nix", function() { return win2nix; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "win2nix", function() { return win2nix; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setupPath", function() { return setupPath; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setupPath", function() { return setupPath; });
const os = __webpack_require__(87) const os = __webpack_require__(87)
@@ -32146,6 +32165,25 @@ function isStableVersion(rubyVersion) {
return /^\d+(\.\d+)*$/.test(rubyVersion) return /^\d+(\.\d+)*$/.test(rubyVersion)
} }
function isBundler2Default(engine, rubyVersion) {
if (engine === 'ruby') {
return isHeadVersion(rubyVersion) || floatVersion(rubyVersion) >= 2.7
} else if (engine === 'truffleruby') {
return isHeadVersion(rubyVersion)
} else {
return false
}
}
function floatVersion(rubyVersion) {
const match = rubyVersion.match(/^\d+\.\d+/)
if (match) {
return parseFloat(match[0])
} else {
return 0.0
}
}
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')
@@ -32183,7 +32221,7 @@ function getVirtualEnvironmentName() {
throw new Error(`Unknown ImageOS ${imageOS}`) throw new Error(`Unknown ImageOS ${imageOS}`)
} }
function shouldExtractInToolCache(engine, version) { function shouldUseToolCache(engine, version) {
return engine === 'ruby' && !isHeadVersion(version) return engine === 'ruby' && !isHeadVersion(version)
} }
@@ -32205,6 +32243,11 @@ function getToolCacheRubyPrefix(platform, version) {
return path.join(toolCache, 'Ruby', version, 'x64') return path.join(toolCache, 'Ruby', version, 'x64')
} }
function createToolCacheCompleteFile(toolCacheRubyPrefix) {
const completeFile = `${toolCacheRubyPrefix}.complete`
fs.writeFileSync(completeFile, '')
}
// convert windows path like C:\Users\runneradmin to /c/Users/runneradmin // convert windows path like C:\Users\runneradmin to /c/Users/runneradmin
function win2nix(path) { function win2nix(path) {
if (/^[A-Z]:/i.test(path)) { if (/^[A-Z]:/i.test(path)) {
@@ -44540,7 +44583,7 @@ 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.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.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", "2.7.0", "2.7.1", "2.7.2",
"3.0.0-preview1", "3.0.0-preview1", "3.0.0-preview2",
"head", "debug", "head", "debug",
], ],
"jruby": [ "jruby": [
@@ -51235,12 +51278,12 @@ async function setupRuby(options = {}) {
if (inputs['bundler'] !== 'none') { if (inputs['bundler'] !== 'none') {
const [gemfile, lockFile] = detectGemfiles() const [gemfile, lockFile] = detectGemfiles()
await common.measure('Installing Bundler', async () => const bundlerVersion = await common.measure('Installing Bundler', async () =>
installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version)) installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version))
if (inputs['bundler-cache'] === 'true') { if (inputs['bundler-cache'] === 'true') {
await common.measure('bundle install', async () => await common.measure('bundle install', async () =>
bundleInstall(gemfile, lockFile, platform, engine, version)) bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion))
} }
} }
@@ -51353,9 +51396,8 @@ function readBundledWithFromGemfileLock(lockFile) {
const nextLine = lines[bundledWithLine+1] const nextLine = lines[bundledWithLine+1]
if (nextLine && /^\d+/.test(nextLine.trim())) { if (nextLine && /^\d+/.test(nextLine.trim())) {
const bundlerVersion = nextLine.trim() const bundlerVersion = nextLine.trim()
const majorVersion = bundlerVersion.match(/^\d+/)[0] console.log(`Using Bundler ${bundlerVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`)
console.log(`Using Bundler ${majorVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`) return bundlerVersion
return majorVersion
} }
} }
} }
@@ -51383,7 +51425,7 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
} }
if (engine === 'ruby' && rubyVersion.match(/^2\.[12]/)) { if (engine === 'ruby' && rubyVersion.match(/^2\.[012]/)) {
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 (engine === 'ruby' && rubyVersion.startsWith('2.3')) { } else if (engine === 'ruby' && rubyVersion.startsWith('2.3')) {
@@ -51394,40 +51436,48 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
bundlerVersion = '1' bundlerVersion = '1'
} }
if ((engine === 'ruby' || engine === 'truffleruby') && common.isHeadVersion(rubyVersion) && bundlerVersion === '2') { if (common.isHeadVersion(rubyVersion) && common.isBundler2Default(engine, rubyVersion) && bundlerVersion.startsWith('2')) {
console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`)
} else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion === '1') { } else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion.startsWith('1')) {
console.log(`Using Bundler 1 shipped with ${engine}`) console.log(`Using Bundler 1 shipped with ${engine}`)
} else { } else {
const gem = path.join(rubyPrefix, 'bin', 'gem') const gem = path.join(rubyPrefix, 'bin', 'gem')
await exec.exec(gem, ['install', 'bundler', '-v', `~> ${bundlerVersion}`, '--no-document']) await exec.exec(gem, ['install', 'bundler', '-v', `~> ${bundlerVersion}`, '--no-document'])
} }
core.exportVariable('BUNDLER_VERSION', bundlerVersion) return bundlerVersion
} }
async function bundleInstall(gemfile, lockFile, platform, engine, version) { async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion) {
if (gemfile === null) { if (gemfile === null) {
console.log('Could not determine gemfile path, skipping "bundle install" and caching') console.log('Could not determine gemfile path, skipping "bundle install" and caching')
return false 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 // config
const path = 'vendor/bundle' const path = 'vendor/bundle'
await exec.exec('bundle', ['config', '--local', 'path', path]) await exec.exec('bundle', ['config', '--local', 'path', path], envOptions)
if (fs.existsSync(lockFile)) { if (fs.existsSync(lockFile)) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true']) await exec.exec('bundle', ['config', '--local', 'deployment', 'true'], envOptions)
} else { } else {
// Generate the lockfile so we can use it to compute the cache key. // 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. // This will also automatically pick up the latest gem versions compatible with the Gemfile.
await exec.exec('bundle', ['lock']) await exec.exec('bundle', ['lock'], envOptions)
} }
// cache key // cache key
const paths = [path] const paths = [path]
const baseKey = await computeBaseKey(platform, engine, version, lockFile) const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile)
const key = `${baseKey}-${await common.hashFile(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 // If only Gemfile.lock changes we can reuse part of the cache, and clean old gem versions below
const restoreKeys = [`${baseKey}-`] const restoreKeys = [`${baseKey}-`]
@@ -52910,7 +52960,6 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "install", function() { return install; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "install", function() { return install; });
const os = __webpack_require__(87) const os = __webpack_require__(87)
const path = __webpack_require__(622) const path = __webpack_require__(622)
const core = __webpack_require__(186)
const exec = __webpack_require__(514) const exec = __webpack_require__(514)
const io = __webpack_require__(436) const io = __webpack_require__(436)
const tc = __webpack_require__(188) const tc = __webpack_require__(188)
@@ -52927,24 +52976,33 @@ function getAvailableVersions(platform, engine) {
} }
async function install(platform, engine, version) { async function install(platform, engine, version) {
return await downloadAndExtract(platform, engine, version) let rubyPrefix, inToolCache
} if (common.shouldUseToolCache(engine, version)) {
inToolCache = tc.find('Ruby', version)
async function downloadAndExtract(platform, engine, version) { if (inToolCache) {
let rubyPrefix rubyPrefix = inToolCache
if (common.shouldExtractInToolCache(engine, version)) { } else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version) rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else if (windows) { } else if (windows) {
rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`) rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`)
} else { } else {
rubyPrefix = path.join(os.homedir(), '.rubies', `${engine}-${version}`) 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 // Set the PATH now, so the MSYS2 'tar' is in Path on Windows
common.setupPath([path.join(rubyPrefix, 'bin')]) 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.rmRF(rubyPrefix)
await io.mkdirP(parentDir) await io.mkdirP(parentDir)
@@ -52957,13 +53015,15 @@ async function downloadAndExtract(platform, engine, version) {
await common.measure('Extracting Ruby', async () => { await common.measure('Extracting Ruby', async () => {
if (windows) { if (windows) {
// Windows 2016 doesn't have system tar, use MSYS2's, it needs unix style paths // 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 { } 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) { function getDownloadURL(platform, engine, version) {
+21 -14
View File
@@ -63,12 +63,12 @@ export async function setupRuby(options = {}) {
if (inputs['bundler'] !== 'none') { if (inputs['bundler'] !== 'none') {
const [gemfile, lockFile] = detectGemfiles() const [gemfile, lockFile] = detectGemfiles()
await common.measure('Installing Bundler', async () => const bundlerVersion = await common.measure('Installing Bundler', async () =>
installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version)) installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version))
if (inputs['bundler-cache'] === 'true') { if (inputs['bundler-cache'] === 'true') {
await common.measure('bundle install', async () => await common.measure('bundle install', async () =>
bundleInstall(gemfile, lockFile, platform, engine, version)) bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion))
} }
} }
@@ -181,9 +181,8 @@ function readBundledWithFromGemfileLock(lockFile) {
const nextLine = lines[bundledWithLine+1] const nextLine = lines[bundledWithLine+1]
if (nextLine && /^\d+/.test(nextLine.trim())) { if (nextLine && /^\d+/.test(nextLine.trim())) {
const bundlerVersion = nextLine.trim() const bundlerVersion = nextLine.trim()
const majorVersion = bundlerVersion.match(/^\d+/)[0] console.log(`Using Bundler ${bundlerVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`)
console.log(`Using Bundler ${majorVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`) return bundlerVersion
return majorVersion
} }
} }
} }
@@ -211,7 +210,7 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
} }
if (engine === 'ruby' && rubyVersion.match(/^2\.[12]/)) { if (engine === 'ruby' && rubyVersion.match(/^2\.[012]/)) {
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 (engine === 'ruby' && rubyVersion.startsWith('2.3')) { } else if (engine === 'ruby' && rubyVersion.startsWith('2.3')) {
@@ -222,40 +221,48 @@ async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefi
bundlerVersion = '1' bundlerVersion = '1'
} }
if ((engine === 'ruby' || engine === 'truffleruby') && common.isHeadVersion(rubyVersion) && bundlerVersion === '2') { if (common.isHeadVersion(rubyVersion) && common.isBundler2Default(engine, rubyVersion) && bundlerVersion.startsWith('2')) {
console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`)
} else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion === '1') { } else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion.startsWith('1')) {
console.log(`Using Bundler 1 shipped with ${engine}`) console.log(`Using Bundler 1 shipped with ${engine}`)
} else { } else {
const gem = path.join(rubyPrefix, 'bin', 'gem') const gem = path.join(rubyPrefix, 'bin', 'gem')
await exec.exec(gem, ['install', 'bundler', '-v', `~> ${bundlerVersion}`, '--no-document']) await exec.exec(gem, ['install', 'bundler', '-v', `~> ${bundlerVersion}`, '--no-document'])
} }
core.exportVariable('BUNDLER_VERSION', bundlerVersion) return bundlerVersion
} }
async function bundleInstall(gemfile, lockFile, platform, engine, version) { async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion) {
if (gemfile === null) { if (gemfile === null) {
console.log('Could not determine gemfile path, skipping "bundle install" and caching') console.log('Could not determine gemfile path, skipping "bundle install" and caching')
return false 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 // config
const path = 'vendor/bundle' const path = 'vendor/bundle'
await exec.exec('bundle', ['config', '--local', 'path', path]) await exec.exec('bundle', ['config', '--local', 'path', path], envOptions)
if (fs.existsSync(lockFile)) { if (fs.existsSync(lockFile)) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true']) await exec.exec('bundle', ['config', '--local', 'deployment', 'true'], envOptions)
} else { } else {
// Generate the lockfile so we can use it to compute the cache key. // 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. // This will also automatically pick up the latest gem versions compatible with the Gemfile.
await exec.exec('bundle', ['lock']) await exec.exec('bundle', ['lock'], envOptions)
} }
// cache key // cache key
const paths = [path] const paths = [path]
const baseKey = await computeBaseKey(platform, engine, version, lockFile) const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile)
const key = `${baseKey}-${await common.hashFile(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 // If only Gemfile.lock changes we can reuse part of the cache, and clean old gem versions below
const restoreKeys = [`${baseKey}-`] const restoreKeys = [`${baseKey}-`]
+1 -1
View File
@@ -8,7 +8,7 @@ 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.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.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", "2.7.0", "2.7.1", "2.7.2",
"3.0.0-preview1", "3.0.0-preview1", "3.0.0-preview2",
"head", "debug", "head", "debug",
], ],
"jruby": [ "jruby": [
+23 -13
View File
@@ -1,6 +1,5 @@
const os = require('os') const os = require('os')
const path = require('path') const path = require('path')
const core = require('@actions/core')
const exec = require('@actions/exec') const exec = require('@actions/exec')
const io = require('@actions/io') const io = require('@actions/io')
const tc = require('@actions/tool-cache') const tc = require('@actions/tool-cache')
@@ -17,24 +16,33 @@ export function getAvailableVersions(platform, engine) {
} }
export async function install(platform, engine, version) { export async function install(platform, engine, version) {
return await downloadAndExtract(platform, engine, version) let rubyPrefix, inToolCache
} if (common.shouldUseToolCache(engine, version)) {
inToolCache = tc.find('Ruby', version)
async function downloadAndExtract(platform, engine, version) { if (inToolCache) {
let rubyPrefix rubyPrefix = inToolCache
if (common.shouldExtractInToolCache(engine, version)) { } else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version) rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else if (windows) { } else if (windows) {
rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`) rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`)
} else { } else {
rubyPrefix = path.join(os.homedir(), '.rubies', `${engine}-${version}`) 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 // Set the PATH now, so the MSYS2 'tar' is in Path on Windows
common.setupPath([path.join(rubyPrefix, 'bin')]) 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.rmRF(rubyPrefix)
await io.mkdirP(parentDir) await io.mkdirP(parentDir)
@@ -47,13 +55,15 @@ async function downloadAndExtract(platform, engine, version) {
await common.measure('Extracting Ruby', async () => { await common.measure('Extracting Ruby', async () => {
if (windows) { if (windows) {
// Windows 2016 doesn't have system tar, use MSYS2's, it needs unix style paths // 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 { } 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) { function getDownloadURL(platform, engine, version) {
+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) const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length)
let rubyPrefix let rubyPrefix, inToolCache
if (common.shouldExtractInToolCache(engine, version)) { if (common.shouldUseToolCache(engine, version)) {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version) inToolCache = tc.find('Ruby', version)
if (inToolCache) {
rubyPrefix = inToolCache
} else {
rubyPrefix = common.getToolCacheRubyPrefix(platform, version)
}
} else { } else {
rubyPrefix = `${drive}:\\${base}` rubyPrefix = `${drive}:\\${base}`
} }
const parentDir = path.dirname(rubyPrefix)
let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version) let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version)
common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) 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 () => { const downloadPath = await common.measure('Downloading Ruby', async () => {
console.log(url) console.log(url)
return await tc.downloadTool(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) await io.mv(path.join(parentDir, base), rubyPrefix)
} }
return rubyPrefix if (common.shouldUseToolCache(engine, version)) {
common.createToolCacheCompleteFile(rubyPrefix)
}
} }
async function setupMingw(version) { async function setupMingw(version) {