Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read Ruby version from Gemfile.lock #592

Closed
12 changes: 12 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ jobs:
rubygems: 3.2.3
- run: gem --version | grep -F "3.3.3"

testRubyVersionFromGemfile:
name: "Test RUBY VERSION from Gemfile.lock"
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/ruby-version.gemfile
steps:
- uses: actions/checkout@v4
- uses: ./
with:
ruby-version: gemfile
- run: ruby --version | grep -F "3.3.1"

testUseBundlerFromRubyGemsUpdate:
name: "Test rubygems: version uses the Bundler installed by the rubygems update"
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ruby-2.6.5
ruby-3.3.1
3 changes: 2 additions & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
nodejs 16.0.0
ruby 2.7.0
yarn 1.22.19
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
ruby 3.3.1
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This action currently supports these versions of MRI, JRuby and TruffleRuby:
| `truffleruby` | 19.3.0 - 24.0.1, head |
| `truffleruby+graalvm` | 21.2.0 - 24.0.1, 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`).
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved

Regarding Windows ruby master builds, `mingw` is a MSYS2/MinGW build, `head` & `ucrt` are MSYS2/UCRT64
builds, and `mswin` is a MSVC/VS 2022 build.
Expand Down Expand Up @@ -135,7 +135,8 @@ and the [condition and expression syntax](https://help.github.com/en/actions/ref
* engine only like `ruby` and `truffleruby`, uses the latest stable release of that implementation
* `.ruby-version` reads from the project's `.ruby-version` file
* `.tool-versions` reads from the project's `.tool-versions` file
* If the `ruby-version` input is not specified, `.ruby-version` is tried first, followed by `.tool-versions`
* `gemfile` reads from the project's `Gemfile.lock` file
* If the `ruby-version` input is not specified, `.ruby-version` is tried first, followed by `.tool-versions`, then `Gemfile.lock`.

### Working Directory

Expand Down Expand Up @@ -176,8 +177,8 @@ This action provides a way to automatically run `bundle install` and cache the r

Note that any step doing `bundle install` (for the root `Gemfile`) or `gem install bundler` can be removed with `bundler-cache: true`.

This caching speeds up installing gems significantly and avoids too many requests to RubyGems.org.
It needs a `Gemfile` (or `$BUNDLE_GEMFILE` or `gems.rb`) under the [`working-directory`](#working-directory).
This caching speeds up installing gems significantly and avoids too many requests to RubyGems.org.
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
Expand All @@ -191,7 +192,7 @@ They should be set in the `env` at the job level as shown in the [example](#matr
To find the correct the environment variable name, see the [Bundler docs](https://bundler.io/man/bundle-config.1.html) or look at `.bundle/config` after running `bundle config --local KEY VALUE` locally.
You might need to `"`-quote the environment variable name in YAML if it has unusual characters like `/`.

To perform caching, this action will use `bundle config --local path $PWD/vendor/bundle`.
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`).

#### How it Works
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ branding:
icon: download
inputs:
ruby-version:
description: 'Engine and version to use, see the syntax in the README. Reads from .ruby-version or .tool-versions if unset.'
description: 'Engine and version to use, see the syntax in the README. Reads from .ruby-version, .tool-versions or Gemfile.lock.'
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
default: 'default'
rubygems:
description: |
Expand Down
27 changes: 26 additions & 1 deletion dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions gemfiles/ruby-version.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source 'https://rubygems.org'

ruby "3.3.1"
15 changes: 15 additions & 0 deletions gemfiles/ruby-version.gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
GEM
remote: https://rubygems.org/
specs:

PLATFORMS
arm64-darwin-23
ruby

DEPENDENCIES

RUBY VERSION
ruby 3.3.1p55

BUNDLED WITH
2.5.9
27 changes: 26 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,29 @@ export async function setupRuby(options = {}) {
core.setOutput('ruby-prefix', rubyPrefix)
}

function readRubyVersionFromGemfileLock(lockFile) {
if (lockFile !== null && fs.existsSync(lockFile)) {
const contents = fs.readFileSync(lockFile, 'utf8')
const lines = contents.split(/\r?\n/)
const rubyVersionLine = lines.findIndex(line => /^RUBY VERSION$/.test(line.trim()))
if (rubyVersionLine !== -1) {
const nextLine = lines[rubyVersionLine+1].trim().replace(/p\d+$/, '') // Strip off patchlevel because ruby-builder can't be that precise
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
return nextLine
}
}
return null
}

function parseRubyEngineAndVersion(rubyVersion) {
if (rubyVersion === 'default') {
if (fs.existsSync('.ruby-version')) {
rubyVersion = '.ruby-version'
} else if (fs.existsSync('.tool-versions')) {
rubyVersion = '.tool-versions'
} else if (fs.existsSync('Gemfile.lock')) {
rubyVersion = 'gemfile'
} else {
throw new Error('input ruby-version needs to be specified if no .ruby-version or .tool-versions file exists')
throw new Error('input ruby-version needs to be specified if no .ruby-version, .tool-versions or Gemfile.lock file exists')
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -124,19 +139,29 @@ function parseRubyEngineAndVersion(rubyVersion) {
const rubyLine = toolVersions.split(/\r?\n/).filter(e => /^ruby\s/.test(e))[0]
rubyVersion = rubyLine.match(/^ruby\s+(.+)$/)[1]
console.log(`Using ${rubyVersion} as input from file .tool-versions`)
} else if (rubyVersion === 'gemfile') { // Read from Gemfile.lock
rubyVersion = readRubyVersionFromGemfileLock('Gemfile.lock')
if (rubyVersion === null) {
throw new Error('Could not find Ruby version in Gemfile.lock')
}
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
console.log(`Using ${rubyVersion} as input from Gemfile.lock`)
}

let engine, version
if (/^(\d+)/.test(rubyVersion) || common.isHeadVersion(rubyVersion)) { // X.Y.Z => ruby-X.Y.Z
engine = 'ruby'
version = rubyVersion
} else if (rubyVersion.includes(' ')) { // engine X.Y.Z
[engine, version] = common.partition(rubyVersion, ' ')
benlangfeld marked this conversation as resolved.
Show resolved Hide resolved
} else if (!rubyVersion.includes('-')) { // myruby -> myruby-stableVersion
engine = rubyVersion
version = '' // Let the logic in validateRubyEngineAndVersion() find the version
} else { // engine-X.Y.Z
[engine, version] = common.partition(rubyVersion, '-')
}

console.log(`Using ruby engine ${engine} and version ${version}`)

return [engine, version]
}

Expand Down
Loading