jollygoodcode / jollygoodcode.github.io

:thought_balloon: Jolly Good Blog
https://jollygoodcode.github.io
137 stars 7 forks source link

Test gem with multiple dependencies on Travis CI #21

Open JuanitoFatas opened 8 years ago

JuanitoFatas commented 8 years ago

Intro

Sometimes you wrote a gem, you need to test it with multiple dependencies, and you use Travis CI. You don't know where to get started, this article is for you!

Gemfile for RubyGem

A RubyGem typically contains a .gemspec and a Gemfile. Personally I specified all runtime dependencies in .gemspec, and all non-runtime dependencies (gems for development, test environments) in Gemfile.

source "https://rubygems.org"

# Specify your gem's dependencies in your-gem.gemspec
gemspec

group :development do
  # development environment dependencies
end

group :test do
  # test environment dependencies
end

Suppose you wrote a gem foo that need to test from Ruby 2.0 to trunk Ruby, and from Rails 3 to Rails 5.

.travis.yml

Test with Multiple Ruby Versions

# .travis.yml

rvm:
  - 2.3.1
  - 2.2.5
  - 2.1
  - 2.0
  - ruby-head

This will run your build with Ruby:

The build will run according to this order. So it is important you put the version you care the most on top (cannot fail), and the version you care the least at bottom (those can fail).

Some builds are impossible to run on Rails 5, like unsuppoted Ruby version (<= 2.0). Some builds are safe to fail, like build with trunk Ruby; You can specify which Ruby versions in .travis.yml that can exclude or can fail:

# .travis.yml

matrix:
  fast_finish: true
  exclude:
    - rvm: 2.0
  allow_failures:
    - rvm: ruby-head

With fast_finish: true in place, as soon as these builds finish:

The whole build will be considered as PASSED / FAILED.

OK. So you now know how to run your build with different Ruby on Travis CI.

How about run the build with different dependencies (gems)?

Test with Multiple Dependencies

Thanks to Bundler, we can specify our dependencies in Gemfile. And Travis CI let you run your build with multiple Gemfile, if we want to test our build from Rails 3 to Rails 5:

gemfile:
  - gemfiles/rails_5.gemfile
  - gemfiles/rails_4.gemfile
  - gemfiles/rails_3.gemfile

Create a folder gemfiles on project root and put rails_3.gemfile, rails_4.gemfile, and rails_5.gemfile files. And you specify your dependencies in each file. Travis will now run your build with Ruby versions you specified combined with these gemfiles:

And you can also specify which Ruby with certain Rails version can fail, for example, Rails 5 required Ruby version 2.2.2, so Ruby version < 2.2.2 will fail:

# .travis.yml

matrix:
  fast_finish: true
  allow_failures:
    - gemfile: gemfiles/rails_5.gemfile
      rvm: 2.1
    - gemfile: gemfiles/rails_5.gemfile
      rvm: 2.0
    - rvm: ruby-head

OK how do we create these gemfiles:

We will use thoughtbot's Appraisal tool to do that.

thoughtbot/appraisal

Appraisal runs your tests across configurable, reproducible scenarios that describe variations in dependencies. For example, if you need to test with versions of Rails

First install appraisal gem to development environment:

# Gemfile
source "https://rubygems.org"

gemspec

group :development do
  gem "appraisal"
end

Then creates a Appraisals file with following content:

appraise "rails-3" do
  group :development do
    gem "bundler"
    gem "rake"
  end

  gem "rack", "< 2"
  gem "rails", "3.2.22.2"
end

appraise "rails-4" do
  group :development do
    gem "bundler"
    gem "rake"
  end

  gem "rack", "< 2"
  gem "rails", "~> 4.2.6"
end

appraise "rails-5" do
  group :development do
    gem "bundler"
    gem "rake"
  end

  gem "rails", "~> 5.0.0"
end

And put common dependencies in Gemfile:

source "https://rubygems.org"

gemspec

group :development do
  gem "bundler"
  gem "rake"
  gem "appraisal"
end

then Appraisal file can just be:

appraise "rails-3" do
  gem "rack", "< 2"
  gem "rails", "3.2.22.2"
end

appraise "rails-4" do
  gem "rack", "< 2"
  gem "rails", "~> 4.2.6"
end

appraise "rails-5" do
  gem "rails", "~> 5.0.0"
end

Add:

require "rubygems"
require "bundler/setup"

to the top of your Rakefile.

Run $ appraisal install command, appraisal command-line program will read your Appraisals file and generate multiple Gemfiles to gemfiles folder.

With everything in place, you can now run tests for Rails 3, 4, 5 with appraisal:

$ appraisal rails-3 rake
$ appraisal rails-4 rake
$ appraisal rails-5 rake

Or run tests with all Rails:

$ appraisal rake

To learn more about how appraisal works, please refer to the Appraisal README.md

Wrap Up

You learned...

See a real-life example here: https://github.com/jch/html-pipeline/pull/257.

tgxworld commented 7 years ago

@JuanitoFatas Thank you for this guide :+1: