We get requests to install different Ruby versions into our images. It takes some time to update, test, and roll out images into our build fleet, and our current Ubuntu 12 image has 81 preinstalled Ruby versions, in response to user requests.
If we don’t have a pre-installed ruby version you want, there’s an easy way to make this quickly available for your builds. Here’s an example of compiling Ruby 2.3.3 and caching it.
machine:
post:
- "echo Removing project .rvmrc, contents were: &&
cat $CIRCLE_PROJECT_REPONAME/.rvmrc"
- "rm $CIRCLE_PROJECT_REPONAME/.rvmrc"
- "echo Removing project .ruby-version, contents were: &&
cat $CIRCLE_PROJECT_REPONAME/.ruby-version"
- "rm $CIRCLE_PROJECT_REPONAME/.ruby-version"
- |
if [[ -e ~/rvm_binaries/ruby-2.3.3.tar.bz2 ]]
then
rvm mount ~/rvm_binaries/ruby-2.3.3.tar.bz2
else
mkdir -p ~/rvm_binaries
rvm install 2.3.3
cd ~/rvm_binaries && rvm prepare 2.3.3
fi
- rvm --default use 2.3.3
dependencies:
cache_directories:
- ~/rvm_binaries
test:
override:
- gem list
- ruby --version
Ruby installs could be ~30 seconds or 4-5 minutes (as is the case with ruby 2.3.3), depending on whether RVM has a pre-compiled binary available for your platform (Ubuntu 12/14, x86_64). Once Ruby is compiled, rvm prepare makes a .tar.bz2 file that can be loaded by rvm mount.
A build with the above circle.yml will take 4-5 minutes to install Ruby the first time, and about 30 seconds after that.
This configuration also ensures that any .rvmrc and .ruby-version files are removed from the project before the dependencies phase.
Credit goes to this blog post for researching the nuances of RVM subcommands.
Edit: cleaned up circle.yml file to only run commands if they’re necessary
Unfortunately, cache restore happens in the dependencies phase. If CircleCI spots a ruby-version file, rvmrc file, or a ruby version section in Circle.yml, it will attempt to install that version in the machine phase. Also, rvm needs either mount or install to be aware of a Ruby version, AFAIK.
hey so this is cool! I am curious though, it look like this is just causing my ruby build to be triggered twice…? It happens once when the command is loaded into the container, and then again once it hits the if statement. Is this intended? I have removed the .ruby_versionm we don’t have a .rvmrc file, and I don’t declare a ruby version when setting up the machine portion of the yml file. I am confused why CircleCI is trying to build ruby 2.3.3 before that if statement is ever run?
I’m not sure why you saw that behavior–I don’t have enough info to debug it without seeing the build. But glad you found a solution that works for you!
@Dorian for some reason your snippet caused problems with the rake commands in the database building phase. Also I don’t think we need to rename ruby-version, so I simplified things a bit:
machine:
post:
- |
RUBY_VERSION=$(cat $CIRCLE_PROJECT_REPONAME/.ruby-version)
if [[ -e ~/rvm_binaries/ruby-$RUBY_VERSION.tar.bz2 ]]
then
rvm mount ~/rvm_binaries/ruby-$RUBY_VERSION.tar.bz2
else
mkdir -p ~/rvm_binaries
rvm install $RUBY_VERSION
cd ~/rvm_binaries && rvm prepare $RUBY_VERSION
fi
- rvm --default use $RUBY_VERSION
dependencies:
pre:
- gem install bundler --pre
cache_directories:
- ~/rvm_binaries
test:
override:
- gem list
- ruby --version