出力を入力へ

プログラミングに関する自分が考えた事を中心にまとめます

SimpleCovを並列実行した結果をマージする

CircleCI実践入門で紹介されていたRubyアプリケーションのCI事例について、 SimpleCovでカバレッジを計測するとき、CircleCIを並列実行すると結果が分かれてしまうので 並列実行した結果をマージする必要がある。 このマージの実装が古くなっており動作しなかったのでその修正。

マージエラー

サンプルとなるコードはこちらのリポジトリで公開されている。 ただし、この設定で単にCIを実行してもエラーで動作しない。

原因は mimemagicのライセンス問題により過去のバージョンのgemが非公開されたこと。 これにより bundle installが失敗するようになった。

...
Install missing gems with `bundle install`
Fetching gem metadata from https://rubygems.org/............
Your bundle is locked to mimemagic (0.3.5), but that version could not be found
in any of the sources listed in your Gemfile. If you haven't changed sources,
that means the author of mimemagic (0.3.5) has removed it. You'll need to update
your bundle to a version other than mimemagic (0.3.5) that hasn't been removed
in order to install.
...

ちなみに、mimemagicのライセンス問題は以下が詳しい。

hackmd.io

では単に bundle updateしてgemを更新すればよいかというと、それでも上手くいかない。 当然アプリは動作するようになり、rspecも正常に動作するが、 標記のSimpleCovの並列実行結果をマージする処理で失敗する。

#!/bin/bash -eo pipefail
bundle exec rake simplecov:merge_results

rake aborted!
TypeError: no implicit conversion of Array into String
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/simplecov-0.21.2/lib/simplecov/result_merger.rb:57:in `exist?'
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/simplecov-0.21.2/lib/simplecov/result_merger.rb:57:in `read_file'
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/simplecov-0.21.2/lib/simplecov/result_merger.rb:52:in `parse_file'
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/simplecov-0.21.2/lib/simplecov/result_merger.rb:47:in `valid_results'
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/simplecov-0.21.2/lib/simplecov/result_merger.rb:37:in `merge_results'
/home/circleci/project/lib/tasks/simplecov.rake:14:in `store_result'
/home/circleci/project/lib/tasks/simplecov.rake:9:in `block (2 levels) in <main>'
/home/circleci/project/vendor/bundle/ruby/2.6.0/gems/rake-13.0.3/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => simplecov:merge_results
(See full trace by running task with --trace)
Coverage report generated for RSpec to /home/circleci/project/coverage. 0 / 33 LOC (0.0%) covered.
Stopped processing SimpleCov as a previous error not related to SimpleCov has been detected

Exited with code exit status 1
CircleCI received exit code 1

原因は SimpleCov 0.19.0より SimpleCov::Result.from_hashの挙動が変更になったことである。 このため、マージ処理の実装の修正が必要である。

github.com

解決策1: SimpleCovのバージョンを古いままにする

一番わかりやすい解決策としてSimpleCovのバージョンを0.18のままにすればよい。 以下の通り修正した上で bundle updateすればmimemagicの問題を解決しつつSimpleCovのカバレッジ結果のマージも問題なく動作する。

--- a/Gemfile
+++ b/Gemfile
@@ -52,7 +52,7 @@ group :test do
   gem 'selenium-webdriver'
   # Easy installation and use of web drivers to run system tests with browsers
   gem 'webdrivers'
-  gem 'simplecov', require: false
+  gem 'simplecov', '< 0.19.0', require: false
   gem 'rspec_junit_formatter'
 end

ただし、当然SimpleCovのアップデートができなくなるので、できれば別の方法で解決したい。

解決策2: Simplecov.collateでマージする

公式のREADMEにも並列環境での結果をマージする方法について記載がある。 公式には Simplecov.collateメソッドを利用する方法が紹介されている。 すなわち、自分でマージ処理を実装する必要はない。 (Simplecov.collate 自体は 0.18.0から実装されていた)

github.com

require "simplecov"

namespace :simplecov do
  desc "merge_results"
  task merge_results: :environment do
    SimpleCov.start 'rails' do
      merge_timeout(3600)
    end

    SimpleCov.collate Dir["coverage_results/.resultset-*.json"]
  end
end

これにより、最新のSimpleCovを利用しつつ、マージ処理も簡潔に実装できる。