先日、Railsのマイグレーションファイルをもっと便利に生成するGem、miのバージョン1.0.0をリリースしました。
このGemではRailsの4と5両方に対応しており、また4と5では挙動が異なります。
このため4と5両方のバージョンでテストを行う必要がありました。
しかし、通常の方法だと4あるいは5のどちらか一方でしかテストを行うことが出来ません。
Appraisal
そこで Appraisal Gem の出番です。
Appraisal を使うと複数バージョンのGemを使用したテストを簡単に実行することが出来ます。
手順
まず、development dependency に Appraisal を追加しましょう。
gemspec
に以下を追記します。
Gem::Specification.new do |spec| # ... spec.add_development_dependency 'appraisal' # ... end
そして、bundle install
します。
次に、トップのディレクトリにAppraisals
というファイルを作成します。
このファイルの中で使用するGemのバージョンを指定します。
appraise 'rails40' do gem 'rails', '~> 4.0.0' end appraise 'rails41' do gem 'rails', '~> 4.1.0' end appraise 'rails42' do gem 'rails', '~> 4.2.0' end appraise 'rails50' do gem 'rails', '~> 5.0.0' end
今回は Rails 4.0から5.0までの4つのバージョンでのテストを行うように設定しました。
ここまで終えたらappraisal install
を実行します。
するとgemfiles/
ディレクトリの下に各バージョンに対応するGemfile
が生成され、各バージョンのGemがインストールされます。
また、.travis.yml
に以下の2点を追記します。
before_script: - bundle exec appraisal install script: - 'bundle exec appraisal rspec'
最後に、.gitignore
に以下を追記しましょう。
gemfiles/*.gemfile.lock
公式でもlockファイルをバージョン管理から外すように書かれています。
When using Appraisal, we recommend you check in the Gemfiles that Appraisal generates within the gemfiles directory, but exclude the lockfiles there (*.gemfile.lock.) The Gemfiles are useful when running your tests against a continuous integration server such as Travis CI.
そしてコミットしてGitHubにpushすることで、指定した全てのRailsのバージョンでTravis上でテストが実行されます。
他の例との違い
公式のREADMEや他のブログ記事などには、Travisとの連携のときに違う方法を使うように書かれています。
# In .travis.yml gemfile: - gemfiles/rails40.gemfile - gemfiles/rails41.gemfile - gemfiles/rails42.gemfile - gemfiles/rails50.gemfile
私も最初この方法で実行していたのですが、一つ問題が発生しました。 以下のように大量のビルドがTravisで発生してしまい、キューが詰まってしまうのです。
https://travis-ci.org/pocke/mi/builds/143520513
これは、Rubyのバージョン数 * Gemのバージョン数分のビルドが走ってしまうためです。
Travisはビルド数が多くなるとキューが詰まるようで、全てビルドし終えるまでにかなりの時間がかかってしまいました。
そのため、この記事のtravis.ymlの例では、一つのタスクで全てのバージョンのテストを実行するようになっています。
https://travis-ci.org/pocke/mi/builds/143533584
これによりビルド数はRubyのバージョン数のみで抑えられ、高速にビルドを終えることが可能になりました。
同じくCIサービスを作っている身としては、Travis側の負荷も抑えられてるのかなーとか思っています。