Recently I had to convert a non-trivial Rails app from MRI to JRuby for one of our customers. The process was quite smooth overall, but business requirements change and the client may need to be able to run the app on either MRI or JRuby.
To make sure code changes won’t break on either platform, I configured CircleCI
to build both versions at the same time. I decided to manually configure parallelism
, so the different platforms build in different containers (MRI in container 0, JRuby in container 1) at the same time.
The configuration starts with adding some environment variables for specifying the different Ruby versions. I also added a combined RUBY_VERSIONS variable, which is used for running RVM
commands on both platforms with rvm do. I also added some Java specific tuning options to make sure the JRuby builds run reasonably fast and don’t consume too much memory.
JRUBY_OPTS: '--debug -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-Xms512m -J-Xmx1024m'
# other environment variables
This is a simple override for CircleCI’s usual dependency installation: update RVM to get the newest Ruby versions, install the ones specified in RUBY_VERSIONS, then use rvm do to install Bundler and the gems specified in the Gemfile(using platforms
it’s fairly easy to build a Gemfile that works for both Ruby versions).
- rvm get head
- rvm install $RUBY_VERSIONS
- rvm $RUBY_VERSIONS do gem install bundler
- rvm $RUBY_VERSIONS do bundle install
This is a neat trick I picked up from CircleCI’s documentation. You can use a shell case statement inside the configuration to run different commands in different containers. In combination with rvm use this allowed me to “pin” MRI to container 0 and JRuby to container 1, so we immediately know which version failed the build.
- case $CIRCLE_NODE_INDEX in 0) rvm use $MRI_VERSION && bundle exec rspec ;; 1) rvm use $JRUBY_VERSION && bundle exec rspec ;; esac:
While CircleCI in its current form lacks support for something like Travis’ build matrix
, it’s flexible enough to allow for workarounds. While I hope that version 2.0
will simplify this process, the current solution is easy enough and works well for our purposes.