2014年12月5日金曜日

Shippable + Wandbox で C++ の CI 環境構築

C++ Advent Calendar 2014
こちらは C++ Advent Calendar 2014 5日目の記事になります。

前置き
CI 環境構築のお話ですが、まずは簡単に用語の説明をしたいと思います。
  • CI
    Continuous Integration (継続的インテグレーション) の頭文字を取って CI 。
    ビルドやテストなどを継続的に(繰り返し)実行することで、問題の発見などをする手法です。
    この CI 環境のためのツールがたくさんあります。代表的なのは Jenkins でしょうか。
  • Shippable
    Shippable は CI ツールの一つです。
    github や bitbucket と連携して push をトリガーに、任意の処理を実行できるサービスです。
    類似サービスに Travis-CI があり、こちらの方が有名だとは思います(私も使ってます)
    が、今回は Shippable を使います。
  • Wandbox
    Wandbox は説明するまでもないでしょう。Online Compiler のひとつです。

ということで、
今回は Shippable と Wandbox を利用して、 C++ のソースコードを定期的にビルド、テストしてみようと思います。

なぜ Shippable と Wandbox か?
Wandbox は便利である
今回 Wandbox を使う理由は、
  • 豊富なコンパイラー
  • API がある
の2点です。

Wandbox でなくとも複数のコンパイラーで動作検証することは可能です。
しかし、環境構築の手間がかなりあると思います。
Wandbox ならば、そのような面倒なことをしなくとも API でコードを投げるだけで、コンパイル結果と実行結果が得られます。

なぜ Shippable か?
実は、Shippable のサポート言語には C++ がありません。
なので、 C++ の CI 環境としては Shippable は通常適さないのですが、今回はコンパイルや実行は Wandbox にお任せなので、CI 環境の要件としては Wandbox に API でコードを投げれるかどうかになります。まぁ簡単に言えば、Wandbox さえあればなんでも OK です!

でも、なんでわざわざサポートされていない環境を使うの?と思う方もいると思います。

それは、前述した通り C++ がサポートされているかどうかは、Wandbox を使うので関係ないからです。
つまり、サポート言語の縛りがなく、料金体系や private リポジトリを扱えるのかどうかなど、他の条件で CI サービスを選ぶことができます。

私の場合、Travis-CI を既に利用しており、そちらはそちらでテストが稼働中だったのと、
「言語サポートされていない環境でも CI できる」というのがネタになると思ったので、Shippable にしました。

Shippable + Wandbox で C++ の CI 環境構築
前置きはこのくらいにして、ここからどのように環境を整えたのか説明していきます。
実例
長々と説明を始めてもわかりにくいと思いますので、
はじめに Shippable + Wandbox で CI をしている実例を紹介したいと思います。

https://github.com/srz-zumix/iutest
こちらは私が作成している C++ テスティングフレームワークです。
ページを開くと README にバッジが付いているのがわかると思います。

そこに Shippable のバッジがあります。(build:shippable と書かれている黄緑のやつです)

バッジをクリックすると Shippable のページにジャンプします。
https://app.shippable.com/projects/541904d2ac22859af743f867/builds/latest


コンソールログの script あたりに Wandbox での実行結果が出力されていると思います。
こんな感じで、push があるたびに Shippable が自動的にビルドとテストをしてくれます。

だいたいどんな感じで動いているか、わかりましたでしょうか?
それでは、仕組みについて説明をしていきます。

Wandbox API を使う
まずは、Wandbox にコードを投げられるようにします。
API のドキュメントがあるのでそちらを参考に作成しました。
https://github.com/melpon/wandbox/blob/master/kennel2/API.rst

import requests
import json;

class Wandbox:
 """wandbox api class"""
 api_url = 'http://melpon.org/wandbox/api'
 parameter = { 'code':'' }
 def get_compiler_list(self):
  r = requests.get(self.api_url + '/list.json')
  r.raise_for_status()
  return r.json()
 def run(self):
  headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
  payload = json.dumps(self.parameter)
  r = requests.post(self.api_url + '/compile.json', data=payload, headers=headers)
  r.raise_for_status()
  return r.json()
 def get_permlink(self, link):
  r = requests.get(self.api_url + '/permlink/' + link )
  r.raise_for_status()
  return r.json()

 def code(self, str):
  self.parameter.update({'code':str})
 def compiler(self, str):
  self.parameter.update({'compiler':str})
 def options(self, str):
  self.parameter.update({'options':str})
 def stdin(self, str):
  self.parameter.update({'stdin':str})
 def compiler_options(self, str):
  self.parameter.update({'compiler-option-raw':str})
 def runtime_options(self, str):
  self.parameter.update({'runtime-option-raw':str})
 def permanent_link(self, b):
  self.parameter.update({'save':b})
 def dump(self):
  print self.parameter

if __name__ == '__main__':
 w = Wandbox()
 w.compiler('gcc-head')
 w.options('warning,gnu++1y')
 w.compiler_options('-Dx=hogefuga\n-O3')
 w.code('#include <iostream>\nint main() { int x = 0; std::cout << "hoge" << std::endl; }')
 print w.run()

こちらはベースとなるコードで、
iutest ではコマンドラインオプションに対応などをした iuwandbox.py という形で提供しています。
https://github.com/srz-zumix/iutest/blob/master/tools/wandbox/iuwandbox.py
使い方に関しては前回のブログで書いてますのでそちらを参照してください。
ブログズミ: iutest v1.11.0 をリリースしました

Wandbox でのコンパイルと実行ができるようになったら、ローカルでテストしておくとよいでしょう。

Shippable の登録とプロジェクト設定
Shippable の設定をします。
まずは、アカウント登録をします。

github か bitbucket が選べるのでお好きな方を使ってください。
今回は github で説明します。


github を選ぶとアクセス権を要求されます。問題なければ許可してください。




アカウント登録が済んだら、ダッシュボードの Organizations から github/bitbucket のアカウントを選択、
Repos から実行させたいリポジトリを選択するとプロジェクトが作成されます。



Shippable.yml の設定
次に、実行する処理の設定をします。
Shippable はリポジトリ直下の shippable.yml ファイルの記述にしたがって動作します。
shippable.yml の書き方は公式ドキュメントも確認してください。

language: python

python: 2.7

install:
  - pip install requests

before_script:
  - export PYTHONDONTWRITEBYTECODE=1
  - make -C tools/fuse

script:
  - cd tools/wandbox
  - python ./iuwandbox.py ../../test/iutest_syntax_tests.cpp -c ${WANDBOX_COMPILER} -f"-DIUTEST_USE_MAIN=1" --encoding utf-8-sig --expand_include

env:
  - WANDBOX_COMPILER=gcc-head
  - WANDBOX_COMPILER=gcc-4.9.1
#  - WANDBOX_COMPILER=gcc-4.9.0 # wercker
  - WANDBOX_COMPILER=gcc-4.8.2
#  - WANDBOX_COMPILER=gcc-4.8.1 # travis
  - WANDBOX_COMPILER=gcc-4.7.3
#  - WANDBOX_COMPILER=gcc-4.6.4 # drone
  - WANDBOX_COMPILER=gcc-4.5.4
#  - WANDBOX_COMPILER=gcc-4.4.7 # wercker
  - WANDBOX_COMPILER=gcc-4.3.6
  - WANDBOX_COMPILER=clang-head
#  - WANDBOX_COMPILER=clang-3.5
#  - WANDBOX_COMPILER=clang-3.4 # travis
  - WANDBOX_COMPILER=clang-3.3
#  - WANDBOX_COMPILER=clang-3.2 # wercker
#  - WANDBOX_COMPILER=clang-3.1 # wercker
  - WANDBOX_COMPILER=clang-3.0

notifications:
  email:
    on_success: change
    on_failure: always
こちらは iutest で実際に使用している設定です。
https://github.com/srz-zumix/iutest/blob/master/shippable.yml

Wandbox 連携部分(iuwandbox.py)を Python で書いているので言語は Python にしています。
install や script、before_script などはそれぞれビルドしたい内容にあわせて書くことになると思います。

また、env にコンパイラーを列挙してマトリックスを組んでいます。
Wandbox を使うのですから、様々なコンパイラーでテストするよう設定しました。

設定は以上
設定は以上です。あとはリポジトリに push すれば、自動的にビルドが走り出し、テストまでやってくれます!

バッジをつける
せっかくなので、バッジを付けたいと思います。
README なんかでよく見るアレです。

Shippable もバッジに対応していてます。
プロジェクトページの Badge を開くと、画像のリンクか Markdown のテキストが出てくるので適宜コピーして使ってください。




まとめ
  • Wandbox 最高!
    今回 CI 環境構築の肝となったのが Wandbox でした。
    多種多様なコンパイラーが扱えるので、テストに大変役に立っています。
    ホントにありがとうございます。いつもお世話になっておりますm(__)m

    とはいえ、今回紹介した iutest では push する度に 3万行近くのソースコードを投げているのですが、(しかも、マトリックス組んでるので x 10)こういう使い方は大丈夫なんでしょうか…今のところ問題は出ていませんが…ただ、それだけが気がかりではあります。

    最近だと、paiza.IO というのもリリースされたようですので、そちらも試してみようかと思ってます。

  • 使える CI ツールの幅が広がった!
    C++ で絞ると割と数が限られていた CI サービスですが、今回の方法なら言語サポートを気にすることなく使えますので、選択の幅が大きく広がったと思います。
  • C++ の話はほとんどなかった…
    C++ の話は皆無でしたね…すみません(汗)

C++ Advent Calendar 2014
明日は Fuyutsubaki さんです。よろしくお願いします。

それでは!


おまけ
この記事を執筆中、Shippable が不安定だったため、別の CI サービスとして wercker も試していました。
おまけとして簡単に紹介しておきます。

wercker も Shippable と同様に CI サービスの一種です。
対応言語は、PHP/Python/Ruby/Node.js/Go/java:android 。こちらも C++ がサポート外ですが問題ありません。

wercker も yml で動作を設定します。http://devcenter.wercker.com/articles/werckeryml/
wercker は Box と Step の組み合わせで動作する仕組みが特徴です。
http://devcenter.wercker.com/articles/introduction/pipeline.html

これら Box や Step は自作も可能ですが、今回はやってません。

また、Shippable のようなマトリックスができなさそうだったので、直列に各コンパイラーごとに Step を記述しました。
iutest の wercker.yml はこちら。
https://github.com/srz-zumix/iutest/blob/master/wercker.yml
実行結果はこんな感じになります。
https://app.wercker.com/project/bykey/d385156052aa4118a7f24affe4a8f851

0 件のコメント:

コメントを投稿