gemを作っていると複数のrubyのバージョンや依存gemのバージョンをカジュアルに組み合わせてテストをしたいというのがよくあると思いますが、あまりやり方が知られていない気がするのでまとめてみます
今回のエントリのサンプルプロジェクト
渋谷.rb[:20150520] のLT資料
最初にまとめ
Travis CI使うのがめっちゃ楽。
セットアップ
bundle gem
コマンドでテストを生成
$ bundle gem multiple_version_test_sample -t --mit Creating gem 'multiple_version_test_sample'... create multiple_version_test_sample/Gemfile create multiple_version_test_sample/.gitignore create multiple_version_test_sample/lib/multiple_version_test_sample.rb create multiple_version_test_sample/lib/multiple_version_test_sample/version.rb create multiple_version_test_sample/multiple_version_test_sample.gemspec create multiple_version_test_sample/Rakefile create multiple_version_test_sample/README.md create multiple_version_test_sample/bin/console create multiple_version_test_sample/bin/setup create multiple_version_test_sample/LICENSE.txt create multiple_version_test_sample/.travis.yml create multiple_version_test_sample/.rspec create multiple_version_test_sample/spec/spec_helper.rb create multiple_version_test_sample/spec/multiple_version_test_sample_spec.rb
オプション解説
- -t = テストディレクトリを作成
- --mit = MITのLICENSE.txtを作成
- 昔はデフォルトで作ってくれてたんだけどいつの間にか作られなくなってた。。。
Travis CIを使う
CI系のサービスは CircleCI や wercker などがあるけど、複数のRubyのバージョンやgemのバージョンをカジュアルに組み合わせてテストできるのはTravis CIの強み
GithubのリポジトリをTravis CIと連携する方法
複数のrubyのバージョンでテストをする
bundle gem
コマンドで .travis.yml が作られているのでよしなに編集すればすぐに複数バージョンでのテストができます
rvm: - 2.0.0-p598 - 2.1.6 # こういう書き方をすれば2.2.x系の最新版を使う - 2.2 # 開発中のrubyのバージョン(いわゆるtrunk) - ruby-head matrix: allow_failures: # 開発中のrubyでテストがこけることはあるだろうから許容する - rvm: ruby-head
- https://github.com/sue445/multiple_version_test_sample/commit/f74c8aab6d2271102b13d521995666d64fe103f2
- https://travis-ci.org/sue445/multiple_version_test_sample/builds/62833647
複数のgemのバージョンでテストをする
.travis.yml のgemfileにこういうのを書いて
gemfile: - gemfiles/rails3_2.gemfile - gemfiles/rails4_0.gemfile - gemfiles/rails4_1.gemfile - gemfiles/rails4_2.gemfile
gemspec
spec.add_dependency "rails" # 下記のように書いても可 # spec.add_dependency "rails", ">= 3.2.0", "< 5.0"
バージョンごとにgemfileを必要なだけ用意するだけでok
source 'https://rubygems.org' gem 'rails', "~> 4.2.0" gemspec :path => '../'
- https://github.com/sue445/multiple_version_test_sample/commit/250f71b44718d6e3ab30e29d804b8f4feb3fdb1f
- https://travis-ci.org/sue445/multiple_version_test_sample/builds/62834795
補足
普通のgemでRailsの全ての機能に依存することはあまりないと思うので、actuverecordやactivesupportなどを指定するとベストです
参考
【おまけ】Rails 3系と4系でテストはしたいけど、Rails 4系でしか使えないgemも使いたい
とある社内gemで activerecord-turntable の対応をしてたのですが*1、Rails 3系と4系の両方をサポートする必要がありました
普通にやろうとすると「Bundler could not find compatible versions 」ってエラーになるのでちょっとした工夫が必要でした
multiple_version_test_sample (>= 0) ruby depends on rails (= 3.2.21) ruby depends on activerecord (= 3.2.21) ruby depends on activemodel (= 3.2.21) ruby depends on activesupport (= 3.2.21) ruby activerecord-turntable (>= 2.0.0) ruby depends on activesupport (>= 4.0.0) ruby
苦肉の策でグローバル変数経由でrailsのバージョンを渡すことで、Rails3系でテストする時にはgemspec内に存在しないようにしました('A`)
gemfile
source 'https://rubygems.org' $rails_version = "4.2.0" gem 'rails', "~> #{$rails_version}" gemspec :path => '../'
gemspec
# NOTE: turntableはrails4系でしか動かないのでgemfileでrails3系を使ってる時にはdependencyに追加しない if !$rails_version || $rails_version.to_i == 4 spec.add_development_dependency "activerecord-turntable", ">= 2.0.0" end
- 普通に
bundle install
するとグローバル変数がないので左側が評価 gemfile経由だとグローバル変数があるので右側が評価
- https://travis-ci.org/sue445/multiple_version_test_sample/builds/62836793
Travis系の参考URL
Jenkinsを使う
Jenkinsのプロジェクト作成時に「マルチ構成プロジェクトのビルド」を使えばよいです
「マトリックスの設定」のユーザ定義に変数名と値を追加すれば、この変数がexportされた状態でJenkinsのビルドがされるのでビルドスクリプト内でこの環境変数を使えば切り替えることは可能です
ビルド結果
ビルドスクリプトのサンプル
#!/bin/bash -xe export LANG=ja_JP.UTF-8 if [ -n "${GEMFILE}" ]; then export BUNDLE_GEMFILE=gemfiles/${GEMFILE} echo "use ${BUNDLE_GEMFILE}" fi # setup rbenv if [ -n "${RUBY}" ]; then export RBENV_VERSION=${RUBY} rbenv which ruby rbenv versions rbenv version echo "use ruby ${RUBY}" fi which ruby ruby --version bundle check || bundle install --jobs=2 --retry=3 bundle exec rspec exit 0
【注意点】Jenkins rbenv plugin を使わない
rbenv pluginがビルド変数に対応していないため(v0.016時点)*2
ビルドスクリプト内で RBENV_VERSION
をexportしてrubyのバージョンを変える
https://github.com/sue445/multiple_version_test_sample/commit/b421e4604548eaa5ffbd6b1fdaf36157fb490fd8
【注意点】Jenkinsのキューが詰まるのでslaveを増やす
1テストスイートが3分だとしても16通りあると48分かかるので、slaveを増やして同時に実行できるテストの並列数を増やした方がいいです。
カジュアルにslaveを増やせるようにchefやitamaeなどのプロビジョニングツールで環境構築を自動化できるとベスト
【おまけ】JenkinsのSlaveでrbenvを使う方法
Jenkinsからslaveに接続する時は non-interactive モードなので .bash_profile とかが読み込まれないので、rbenvみたいに.bash_proflleで初期化するやつが使えないです。
「起動方法」->「高度な設定」-> 「 Prefix Start Slave Command」に source ~/.bash_profile &&
(&&の後に空白が必要)を書いておけば Slaveの.bash_profile が読み込まれてrbenvが使えるようになります。
あと、「JVMオプション」に -Dfile.encoding=UTF-8
があるのはコンソールログの文字化け防止のため。
~/.bash_profile
はこんな感じ
export RBENV_ROOT=/home/jenkins/.rbenv export PATH="$RBENV_ROOT/bin:$PATH" eval "$(rbenv init -)"
まとめ
Jenkinsでも頑張ればできないことはないけど、Travis CI使うのがめっちゃ楽。