I have been working on an update of my Bamboo ruby plugin which uses bundler to install all the gems for a given project within the working copy of the project and then run rake using these gems.
The aim of this post is to illustrate how this is done and how to craft an environment to run ruby once gems are “staged” within a working copy.
The aim of this post is to illustrate how a rails project is staged using bundler without installing any gems in the base ruby installation.
Firstly I will create a new rails project in an environment similar to that used when developing rails applications. I will be using an installation of ruby with bundler, rake and rails already installed, note I am passing the -T switch as I want to setup an alternate test framework.
rails new somenewrailsproj -T
Once created I navigate into the project and setup the test framework I am intending to use which is Rspec-2 for rails.
Add the following code to the end of the Gemfile.
group :test, :development do
gem "rspec-rails", "~> 2.0"
end
Run bundle install.
bundle install
Run the Rspec-2 generator to plugin into the rails project.
rails generate rspec:install
Scaffold a sample model.
rails generate scaffold post title body:text published:boolean
Migrate this to the database.
rake db:migrate
Remove the pending specs as their not important
rm ./spec/helpers/posts_helper_spec.rb ./spec/models/post_spec.rb
Run Rspec and we should be all green.
bundle exec rake spec
Now to complete isolate our test environment we need a clean bash shell, to do this we run the following.
env -i bash
Next we export the PATH variable, in my case I only want my specific ruby version, and indeed the only thing I want is this versions bins.
export PATH=/Users/markw/.rbenv/versions/1.9.2-p320/bin
This version ruby has just been installed and therefore only has the base set of gems
$ gem list
minitest (1.6.0)
rake (0.8.7)
rdoc (2.5.8)
To simulate a build server the only gem we will add to this installation is bundler.
gem install bundler
Now we run gem adding the vendor/bundle/ruby/1.9.1 directory to the GEM_PATH this shows the gems we had previously bundled.
GEM_PATH=vendor/bundle/ruby/1.9.1 gem list
Now to illustrate how this will work inside a build environment we need augment our path a little, this will ensure gem install can find tools like compilers and such if required.
export PATH=/Users/markw/.rbenv/versions/1.9.2-p320/bin:/bin:/sbin:/usr/bin:/usr/sbin
Now run bundle install to recreate vendor/bundle and bin
bundle install --path vendor/bundle --binstubs
Now run our specs with the augmented GEM_PATH.
$ GEM_PATH=vendor/bundle/ruby/1.9.1 bundle exec rake spec
...
Finished in 0.32614 seconds
28 examples, 0 failures
So I have illustrated how I can stage gems for a rails application and run it’s tests without installing anything in the base ruby. This should work for any gem or project which uses bundler.
Some points to consider about this approach are:
- One should note that ruby has a notion of STD Library API compatibility which is reflected in the ruby/1.9.1 section of the path, this may vary for each release.
- For commercial projects I would recommend using a frozen set of packaged and quality assured gems and running tests with just this set.
That said for things like Octopress projects and gems / projects used internally this is quite a flexible way to run a CI build.