概要
これはCIサービスであるShippableの紹介と、Herokuを使用したCIのための具体的な設定について説明する記事である。
経緯
自前でホスティングしているJenkinsのメンテとかさむAWS EC2の費用が嫌になった俺達は、クラウド型CIサービスを探す旅に出たのだった。
Travis CIは試用してみたもののそもそもの値段で却下(でも100回分お試しは堪能しました)。CircleCIは最近流行ってきていて候補の筆頭に上がったものの、以前と課金体験が変わりテスト時間短縮のために並列に走らせると値段が高くなってしまうことを知ったのでテンションが下って却下。
どうせだったら先駆者になろう(ただポッと出のサービスですぐに終了してあとで大変になるのはNG)と、Leanstakにあるサービスを漁って見つけた「安い!速い!上手い!」を兼ね備えたのがこのShippableである(※なお日本語の記事もぐぐればある程度見つかりました)。ちなみに昨年末$2Mの調達をしている。
注意
意欲的なサービスで抜本的に変わったりしたことがあったり、機能追加や不具合修正などが日々なされているサービスなのでその点は注意。(サポートの窓口であるGithubのIssuesを見るとよく分かります)
安い!速い!旨い!
安い!
- Privateリポジトリであろうが完全無料で無制限にビルド可能
- ただ制限として同時に走らせられるテストは1つのみ
- しかしその制約さえ守れば、リポジトリ数に制限は無い
- 5個並列にテストを走らせられるStartupプランは $12/YEAR !
- YEARだよYEAH!
- でも正直いつまでこれが続くのか不安だけどね!!
速い!
- テストに使用したコンテナはキャッシュすることが可能
- 安いにもある通り安価に、そして簡単に並列テストが出来る
- (でも全てのテストが通った時のみafter_successを実行するparallelized_testフラグが効いていない気がするんだけど気のせいかな……)
旨い!
- もちろんHerokuへのデプロイも意識している(公式にHeroku toolbeltを使ったデプロイサンプルもあるよ!)
- 並列デプロイ時には複数のデプロイをデプロイグループとしてまとめて個別に表示
- テストやカバレッジレポートを吐き出させればそれをウェブUI上で表示させることも可能
- 一応、.travis.yml互換(Travis CIで使用しているリポジトリがそのまま動く……はず)
- 余り入り組んだことはしていない私の過去のリポジトリはそのまま動いた
上記を網羅した設定例
- Ruby on Railsを想定
- PostgreSQLを想定 (Herokuなので)
- ユーザとデータベースががまだ無い場合は作成
- キャッシュ有効
- 3並列テスト
- テストとカバレッジレポートを出力
- テスト成功後Herokuへデプロイ
shippable.yml
language: ruby
rvm:
- 2.1.3
cache: true
parallelized_test: true
services:
- mongodb
script:
- RAILS_ENV=test bundle exec rake db:migrate
- bundle exec parallel_test spec -n $PARA_NUM_GROUPS --only-group $PARA_GROUPS --group-by filesize --type rspec
env:
matrix:
- "PARA_NUM_GROUPS=3 PARA_GROUPS=1"
- "PARA_NUM_GROUPS=3 PARA_GROUPS=2"
- "PARA_NUM_GROUPS=3 PARA_GROUPS=3"
global:
- COVERAGE_REPORTS=shippable/codecoverage
- SPEC_OPTS="--format RspecJunitFormatter --out shippable/testresults/results.xml"
- APP_NAME=heroku_application_name
- secure: # HEROKU_API_KEY=<your key here> を ENCRYPT ENV VARIABLE 機能で暗号化してここへ
before_install:
- which heroku || wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
after_success:
- test -f ~/.ssh/id_rsa.heroku || ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.heroku && heroku keys:add ~/.ssh/id_rsa.heroku
- git remote -v | grep ^heroku || heroku git:remote --app $APP_NAME
- git push heroku master
- heroku run rake db:migrate
before_script:
- psql -c "CREATE EXTENSION IF NOT EXISTS dblink" -U postgres
- |
c="DO
\$body\$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_catalog.pg_user
WHERE usename = 'alice') THEN
CREATE ROLE alice LOGIN PASSWORD 'password';
END IF;
END
\$body\$
"
- psql -c "$c" -U postgres
- |
c="DO
\$body\$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_database
WHERE datname = 'web_application_test') THEN
PERFORM dblink_exec('dbname=' || current_database(),
'CREATE DATABASE web_application_test OWNER alice;');
END IF;
END
\$body\$
"
- psql -c "$c" -U postgres
Gemfile
gem "parallel_tests", group: :development
group :test do
gem 'simplecov'
gem 'simplecov-csv'
gem 'rspec_junit_formatter'
spec/spec_helper.rb
require 'simplecov'
if ENV["COVERAGE_REPORTS"]
require 'simplecov-csv'
SimpleCov.formatter = SimpleCov::Formatter::CSVFormatter
SimpleCov.coverage_dir(ENV["COVERAGE_REPORTS"])
end
SimpleCov.start 'rails'
おわりに
PostgreSQLでMySQLの"CREATE DATABASE IF NOT EXISTS db_name"相当のことするの面倒なんですね……(はっけん)