GitHubを使っていて他の人のレポジトリを見てる時によく見る
このbuild
のバッジが欲しくて
Travis CIを使ってみました。
- Travis CI
- Travis CIでの設定
- レポジトリ側での設定: .travis.yml
- バッジを貼る
- travisコマンド
- Pushした際にコマンドを走らせないようにする
- Travis CIのページがやたら重くなった時の対処
- まとめ
Travis CI
Travis CIのCIはContinuous Integrationの略で、 プログラムのビルドやらテストを継続的に行っていく事を指す プログラマ用語だそうです。
自分でも大事なものはテスト用のスクリプトを書いたりMakefileにテストを書いておいたりして ちょっと変更してはテストして、みたいなことをしていましたが、 Travis CIを使うとGitHubにコードをPushするのをトリガーにして 指定したコマンドを行ってくれる、とのこと。
Travis CIのサービス自体はGitHub専用ですが、コード自体は GitHubに公開されていて 1 自分でGitHub以外で使うことも出来ます。
同じようなサービスには
Jenkins CI や CircleCI 等いくつかありますが、 GitHubで気軽に行うにはTravis CIが一番簡単そうだったので 今回はTravis CIで。
Travis CIはパブリックなレポジトリを使う限りではフリーです。 プライベートレポジトリを使いたい場合には課金して使うことも出来ます2。
Travis CIでの設定
GitHubのアカウントでサインアップ出来るので、サインアップすると アカウントの項目にRepositoriesのタブがるのでそこへ行くと 自分のGitHubのレポジトリ一覧があります。
そこで、CIしたいレポジトリのスイッチをONにしてあげれば 次にレポジトリにPushがあった時からコマンドが実行されます。
スパナのマークをクリックするとレポジトリ事の設定項目に行けます。
ここでBuild pushes
とBuild pull requests
はそれぞれ
Pushがあった時とプルリクエストがあった時にコマンドを走らせるかどうかです。
また、一番上のBuild Only if .travis.yml is present
は
デフォルトではOFFになってますが、
これだと.travis.ymlファイルが無いブランチでも無理やりデフォルトのテストを実行しようとして、
特に必要ないならONにしておいた方が良いです。
レポジトリ側での設定: .travis.yml
上にちょっと出てきましたが、どのようなコマンドを実行するかは レポジトリの中に.travis.ymlというファイルを作成し、 ここに指示を書きます。
基本的な設定はこんな感じ。
1 2 3 4 5 6 7 8 |
|
language
で言語を指定して、その言語のバージョン等を設定、
そしてscript
の項目で実際に行いたいコマンドを記述します。
実行されるコマンドの流れ
実際に実行されるコマンドのメインの記述は上にある
script
の部分です。
ここでは複数のコマンドを指定することが可能です。
シェルスクリプトの様な記述ですが、
if [ ... ]
みたいなテストコマンド的な物は(“クォートしないと”)使えません。
一方、&&
や||
なんかは使えます。
勿論、シェルスクリプトを作って、そのシェルスクリプトの中で testコマンドでもなんでも使えるので、 それをTravisで実行すれば基本的に何でも出来ます。
追記: 2014/09/08
ちょっと下のtwall/jna
のyml等を見ていて気づきましたが、コマンドを指定するときに
クォートしてあげることでtest
コマンドなども使えるようになります。
こんな感じでシングルクォートでもダブルクォートでも クォートで囲うとその中のコマンドをシェルスクリプトとして評価してくれるのか 普通に実行してくれます。
また、シェルスクリプトとかのクォートと違って、 シングルでもダブルでも中に書く変数は展開されます。
シングルクォートの中でダブルクォートを使ったり、
ダブルクォートの中で\
を使ってダブルクォートを使ったりすることも
出来ます。
これでもう、そのままシェルスクリプト的になんでも書けますね。
ただ、1つ注意があって、1つの行で最後がエラーで終わってしまうと そこで最終的にもエラーが上がってしまうので(installとかだとそこで止まってしまう)
- '[ "$val" = "aaa" ] && echo $val || :'
みたく、もし途中までの判定で偽だったとしてもそれが起こっても良い場合には
最後に||
を入れて:
(もしくはtrue
)コマンドを入れて
正常終了(返り値 0)として行を終わらせる必要があります。
追記ここまで
また、script
の前後で実行されるコマンドの定義として、
- before_install
- install
- before_script
- script
- after_success or after_failure
- after_script
と言うコマンドの定義があります 3。 上の項目に指定されたコマンドは上の順番に実行されていきます。 (after_successとafter_failureに関してはscriptまでで 成功してる時、失敗してる時に実行されるコマンド。)
最初、before_sriptなんかはscriptの中の各コマンドの実行前に
行われるのかな?とか思ってたんですが、そんなことはなく
単に上に定義された順で呼ばれて、その中のコマンドも順番に呼ばれていくだけです。
また、上のテストの中で見れるように
script
の中でも、前に行ったコマンドの影響が残ります。
(変数を設定したりファイルを作ったり。)
また、これらのコマンドの前に、まず指定のレポジトリをcloneしてきて そのレポジトリ内に移動し、さらに言語に対する初期設定が行われます。
ですので、コマンドは基本、レポジトリ内に居るとして実行されるので、
レポジトリトップにtest.sh
等を置いておけば、
./test.sh
で実行できる事になります。
上のコマンド定義群の中で、
before_installとinstallで失敗した(return値がnon 0)場合にはerrored
、
before_scriptとscriptとafter_scriptで失敗した場合にはfailed
のフラッグが付きます。
現時点ではafter_successとafter_failureでの成否は最終結果に 影響しません。
また、script以外の部分ではコマンドが失敗したら直ちにそこで終了いなりますが、 scriptの部分では1つのコマンドが失敗しても次のコマンドに移って実行し、 全てのコマンドを実行した上で次のステップに移ります。
ただし、scriptの中でexit
を使ってしまうとそこで全てジョブを終了します。
ちょっと特殊で、普通に0を返すexit
だとfailed
、
0以外を返すとerrored
とフラッグが付きます。
また、試しにreturn
とかを使ってみましたが、これは普通にコマンドが無いということで
その後もコマンドは続いた上でfailed
になりました。
インストール作業なんかは何も考えずにscriptの中で全て自分でやってしまっても 良い部分も多々ありますが、 デフォルトでinstall部分で実行される物があったりするので それらに注意して設定する必要があります。
Python なんかだと、installには
pip install -r requirements.txt
が設定されてるので、requirements.txtが用意されてないと エラーにはなりませんが、見つかりませんでしたと言うメッセージが出てしまいます。
installを自分で定義された場合はそれは上書きされます。
言語設定
まず、language
で言語を指定しますが、
この言語で指定した以外のものが一切実行できないわけではなくて、
ここで指定したものについては複数のバージョンの環境を作って
別々に実行することが出来る様になります。
Rubyの場合だとrvm
の項目をいくつか設定することで
それぞれのRubyのバージョンが入った環境下での別々のビルド結果が作られます。
Pythonだと
1 2 3 4 5 6 7 8 9 |
|
な感じでpython
でバージョン指定を行います。
このバージョン指定はドキュメントで言語によって
ダブルクォートで囲ったり囲ってなかったりしますが、
少なくともPythonやRubyに関しては何方でも大丈夫でした。
また、この例ではRubyも使ってますが、
上に書いたようにlanguage
で指定した物以外でも普通に実行できます。
ただし、ここでrvm
の項目を書いてバージョンを指定しても無視されて
デフォルトのバージョンが使われます。
(rvm
で複数項目書いてもそれについては1つしかコマンドも実行されない)
4
また、language
については以下のページにあるものだけが使えて、
それぞれ設定項目が決まっています
5。
たまにlanguage
にbash
等と書いて簡単なシェルスクリプトのテストを行ってる
レポジトリもありますが、
Bashはサポートされてません。
この様にサポートされてない言語が指定されると
デフォルトがRubyに設定されて居るようで、language: ruby
の状態として
実行される様です。
以下はrvm
を1.9.3
と2.1.0
に指定して、
language
をそれぞれruby
、aaa
、python
として実行した結果です。
ruby
、aaa
についてはそれぞれのRubyのバージョンで2ジョブ、
python
に関してはデフォルトのRuby1.9.3のみの1ジョブが実行されています。
なので、どうしてもRubyのバージョン2つ、Pythonのバージョン2つでそれぞれ テストしたい、とかの場合には どちらかの言語を自分でインストールする様にコマンドを書いて それを使う様にすれば出来ないことは無いと思います。
環境設定のマトリックス設定で別々のジョブを作れるので
そこでバージョン指定してインストール時に使ったりすれば
殆どlanguage
と同じように出来るかと。
また、次に詳しく下記ますが、言語の中でobjective-c
だけは特別で、
この設定の時だけOSが変わるので注意が必要です。
OS設定
コマンドが実行される環境のOSはデフォルトでは Ubuntu 12.04 LTS Server Edition 64 bitになります。
この環境下ではapt-get
などのコマンドが使えて、それらで
環境を整える事が可能です。
OSを変更する方法は現在の所一つだけで、
上に書いたようにlanguage
をobjective-c
にすること
6。
これにするとOSはMacのOS X 10.9.2になります。
この環境下ではすでにHomebrewがインストールされていて
brew
コマンドで環境を整える事が可能です。
一時期、os
という項目でlinux
とosx
としてOSを選べたり、
両方でテストを行う事が可能になっていたみたいですが、
負荷が大きすぎたので現在はこの機能は少なくともフリーのアカウントでは停止されている様です
7。
8。
実際テストしてみるとこんな感じ。
The Build Environment
に書いてあるTRAVIS_OS_NAME
という値は現在は空欄になっています。
ただ、有料の場合に使えるのか、それとも何か条件があるのか分かりませんが、
最近のジョブでもこのos
の機能をきちんと使えてるものもあります。
試しに同じ様な物を作ってやってみましたが、やっぱりダメでした。
ので、現状Macの環境でテストをしたいときには取り敢えず
何をテストするでもlanguage: objective-c
にしておく、
というのが定石です。
Macの中でさらに言語のバージョンを指定したい、とかの場合には、 仕方ないので自分で上に書いた複数言語で複数バージョンを使うみたいに 自分でインストールするコマンドを書けば一応使えることは使えます。
環境変数設定
Linux環境(言語Ruby)、OS X環境(Objective-C)でのそれぞれの デフォルトの環境変数は以下の様な物が最初に設定されています。
ここでもTRAVIS_OS_NAME
は定義されていますが空欄になっているのが分かります。
PATHを指定したり色々と環境変数を設定したい場合には
before_scriptの中でexport
したりするか、もしくは
env
という項目を作ってその中で指定することも出来ます。
ただし、env
はデフォルトではMatrix指定でそれぞれの項目ごとに
ジョブを作るので注意が必要です。
env
の指定した各項目ごとにジョブを作るので、
例えば
1 2 3 4 |
|
みたいな事をすると、2つのジョブが出来て、最初の方では
a=1 b=
後のほうではa= b=1
と言った結果になります。
Matrix指定と言っているのは、例えば
1 2 3 4 5 6 7 8 |
|
とすると、Pythonのバージョンが2つ、env
の設定で2つのジョブが出来るので、
- Python 2.7, env: a=1
- Python 2.7, env: b=1
- Python 3.2, env: a=1
- Python 3.2, env: b=1
の4つのジョブが出来るからです。
他にもジョブを複数作る設定項目があれば掛け算でジョブの数が増えていきます。
env
の設定で複数の項目を一度に指定したいときは、
env:
- a=1 b=1
の様に空白で続けて書くことも出来ます。
また、全体で一つだけの設定で良ければ、global
という項目をenv
の中で設定します。
この時にMatrix指定もしたいときにはmatrix
という項目も作ってあげればOK。
env:
global:
- a=1
- b=1
matrix:
- c=1
- d=1
とすれば、
- a=1, b=1, c=1
- a=1, b=1, d=1
の2つの環境設定状態のジョブが出来る事になります。
結果の通知手段
デフォルトでは結果が出た時の通知手段として
1 2 3 4 5 |
|
と言った感じの設定になっていて、 GitHubに登録してあるメールアドレスに結果の通知が来ます。
失敗した場合は毎回、成功した場合は、その前に失敗していた時に限り送られてきます。
on_success
とon_failure
では、それぞれalways
、never
、change
という
項目が設定できて、常にメールをするか、常にしないか、
もしくはその前の実行時とステータスが変わった時にみ送るか設定できます。
また、メール以外にも色々なサービスに直接通知を行うことも出来るみたいです。
あまり長い表示になる様なコマンドは実行できない
テストしてる時に沢山ログを吐くような物を作ったら
...
The log length has exeeded the limit of 4 Megabytes (this usually means that test suite is raising the some exception over and over).
The build has been terminated.
という表示とともに途中で終わってfailed
になってしまいました。
(直前までは何も問題なく動いてた感じ。)
テストでも沢山ログを吐くような物も在るとは思いますが、 Travisの場合は4 MBまでということなので あまりに沢山ログを出すコマンドについてはファイルに出力するなどする必要があります。
インタラクティブなコマンドは避けるように
当然ですがインタラクティブに入力を求める様なコマンドは使えません。
そのような場合には10分程待って反応が無いとfailする、と言う仕組みになってるようです。 (入力待で待つのはタダの無駄。)
プログラムを作る場合にも-y
オプションとかで全てyes
を選べたり、
入力が必要な物も引数で全て渡すことも可能なように作る必要があります。
sudoは使える
OS Xでpip install
するとPermission denied
等と言われます。
この場合にはsudo
がパスワードなしで使えるので、
sudo pip install...
と書いておけばOK。
バッジを貼る
設定が出来てテストなどを行えたら結果の表示をしたいわけですが、 バッジはTravis CIにある各レポジトリの右上のバッジ部分をクリックすると バッジのURLなどが出てきます 9。
いくつか表示形式が選べるので、 GitHubのREADMEなんかに貼るにはMarkdownを選んで貼るります。
そうするとよく見るこのボタンがREADMEにあらわれてくれます。
ブランチ毎にバッジのURLが違うのでそのブランチの物を使ってください。
バッジのURLの形式は
https://travis-ci.org/<user>/<repository>.svg?branch=<branch>)
の様な形になっています。
TravisにおけるレポジトリのURLは
https://travis-ci.org/<user>/<repository>
です。
e.g.:
[![Build Status](https://travis-ci.org/rcmdnk/travis-test.svg?branch=master)](https://travis-ci.org/rcmdnk/travis-test)
travisコマンド
Travis CI用にtravisというgemが用意されていて、
これをインストールすると、travis
というコマンドが使えるようになって
コマンドラインから色々情報を読んだり設定したり出来るようになります。
ただ、ウェブでの設定が簡単なのと、 結果をローカルでCUIで色々見たいのであれば、 そもそもGitHubにPushする前にローカルでテストを動かして結果を見れば。。。 という気もするので余り使うことはないかな、と。
Pushした際にコマンドを走らせないようにする
一度設定してしまうとPushするたびにTravis CIでコマンドが走るわけですが、
このコマンド実行をスキップさせたい場合には
Pushするコミットの中のメッセージに[ci skip]
、もしくは[skip ci]
という
文字列を入れます
10。
Travis CIのページがやたら重くなった時の対処
色々Travis CIで遊んでいたら、 Firefoxでのページ表示がやたら重くなって殆ど実用できない位になってしまいました。
ビルド結果がやたら長いものを幾つか行った後のことです。
同じ端末からGoogle Chromeで見ると大丈夫なのでFirefoxの問題かな?と思ってたんですが、 他の端末のFirefoxでは問題なく見れました。
そこでキャッシュを消去してみるとすぐに問題なく表示される様に。
ということで、恐らくGoogle Chromeでも同じ事が起こる可能性もあるのかと思いますが、 やたら長い結果を出すTravis CIのジョブを沢山見て表示が遅くなってきたかな? と思ったらキャッシュの消去を行うと解決出来る事があります。
まとめ
ちょっと長くなりましたが、基本的には
- Travis CIのウェブページでコマンドを実行したいGitHubのレポジトリを有効化する。
- Settingで
.travis.yml
が内部ランチは無視するようにしておいた方が吉。
- Settingで
- レポジトリに
.travis.yml
というファイルを作ってコマンドの指示を書く。- script:の項目に実行したいコマンドを書く。
- コマンドは普通にコマンドラインから実行するような(シェルスクリプト的な)感じで書く。
- ただし
test
(if [ ]
)コマンド的な物はクォートすれば使える。
- ただし
- コマンドは普通にコマンドラインから実行するような(シェルスクリプト的な)感じで書く。
- 基本Linux環境だが、Macで行いたいとき(OS X/iOSのアプリやHomebrew関係のテストなど)は
実際にどの言語を使うかに依らず、
language: objective-c
を指定する。
- script:の項目に実行したいコマンドを書く。
- 後はPushするたびに勝手に実行される。
- バッジをレポジトリのREADMEに貼って、眺めて満足する。
と言った感じ。
これを知らずに暫くどうしても
brew
コマンドが使えなくて困った。。。 ↩-
Travis CI: Testing Your Project on Multiple Operating Systems
The Travis CI Blog: Multi-OS Feature Available
Support Windows and OS X · Issue #216 · travis-ci/travis-ci ↩
ちょっと前までだとこの項目がセッティング項目内(右の歯車ボタン)に
Status Images
という名前でありましたが 今はそちらにはなく、バッジ部分をクリックすることで取得できます。 ↩