ASDF/.tool-versions support / better Ruby version detection

So, in Bundler, you can refer to an ASDF .tool-versions file to set the version, with this code in your Gemfile:

ruby file: ".tool-versions"

And with Github CI, the ruby/setup-ruby action will automatically detect the Ruby version from .tool-versions as well (just don’t specify a version manually):

- name: Set up Ruby
  uses: ruby/setup-ruby@v1
  with:
    bundler-cache: true

… but then on Render, the deploy fails because it decides .tool-versions is actually the version number :sob::

Using Ruby version ".tool-versions" via /opt/render/project/src/Gemfile
...
!!! Failed to download https://raw.githubusercontent.com/postmodern/ruby-versions/master/ruby-".tool-versions"/versions.txt to /opt/render/.cache/ruby-install/ruby-".tool-versions"/versions.txt!

I feel like there’s two things to note here:

  • .tool-versions is a pretty common way to specify required versions of tools, so it’d be nice if that could be used to detect Ruby (and Node, etc) versions in the build process.
  • A Gemfile is Ruby code, but Gemfile.lock is not - so it’s much better to parse the version from that as it will be the appropriately calculated value.

I’ve noted this in a new feedback item, as per the discussion in an older thread here, should anyone wish to upvote that. But also, I found the internal Render build script that’s performing this logic (ruby-env.sh) and I’ve made some changes that I think cover off both of these issues, so hopefully this is helpful to accelerate the improvements? :crossed_fingers:

Hi there.

Thanks for the feedback and updated detection script.

Regards,

Keith
Render Support, UTC+10 :australia:

Thanks Keith and other Render folks - I see that this feature is now in place, greatly appreciate the super prompt turnaround! :smile:

Hi there,

No problem, our engineering manager picked this up very quickly. As it was much work and you had already provided the code, they just did it.

Regards,

Keith
Render Support, UTC+10 :australia:

Hi @pat and @Keith

Using the Gemfile.lock/gems.locked to detect the correct Ruby is definitely the way to go! However, the order of precedence is still a problem, unfortunately, the fix might be a breaking one for some.

To give you some context: I’ve kicked off a discussion a while ago in order to pave the way towards a formal specification of the .ruby-version file as part of Rubygems/Bundler. While the discussion is still ongoing, there’s pretty much consensus that .ruby-version is primarily a way to select the Ruby for development, but not for deployment where Gemfile.lock/gems.locked should be used.

This said, it’s quite likely, a formal specification for .ruby-version will allow fuzzy versions which omit the patchlevel (e.g. ruby-3.3 or 3.1) since this is how most Ruby version managers already work and it avoids tedious rebases across feature branches and potentially many developers whenever a new non-breaking patchlevel of Ruby is released.

Render currently reads .ruby-version first and falls back to Gemfile.lock/gems.locked. In other words, it prefers the development setting over the locked Ruby version ready for production. I’re already guessing what comes next. :wink:

It should be the other way round: If Gemfile.lock/gems.locked is present, the Ruby version should be read from there since it is locked and controlled by Bundler as are the versions of every Ruby gem in use. Updates of the Ruby version are not “by accident”, but as part of updating the Bundle e.g. with bundle update --ruby. As a fallback, the .ruby-version file should only be read if the project doesn’t use Bundler and therefore using the development Ruby version is the only indication available.

Flipping the precedence order is simple and in general it shouldn’t break projects since the version set locally in .ruby-version makes its way to Gemfile.lock/gems.locked whenever bundle update is used. But there might be edge cases e.g. for projects where Dependabot or similar are creating PR for minor gem updates. So in order to make the change, a heads-up to existing Ruby projects on Render might be a good idea.

What do you think?

PS: The documentation on docs.render.com is out of date it seems: Setting Your Ruby Version | Render Docs

@svoop flipping the precedence sounds like the right move to me!

1 Like