この連載では、オープンソースの継続的インテグレーション(CI)サーバであるHudsonを利用した、ソフトウェア開発の生産性向上について解説しています。前回の記事では、規模の大きいソフトウェアプロジェクトの開発で、Hudsonを有効活用する方法について解説しました。今回は、Hudsonの魅力の一つであるプラグインシステムに触れます。プラグインは紹介しきれないほどあるので、ここでは比較的一般的だと思われる、Hudsonと外部システムの連携方法を見てみましょう。
プラグインの探し方とインストール
インハウスで開発されていて公開されていないものを除けば、HudsonのプラグインのほとんどはHudsonプロジェクト上で開発され公開されています。プラグインを探すには、まずHudson Wikiのプラグインページを見ましょう。ここには、公開されているほとんどのプラグインが種類によって分類されていて、説明を読むことが出来ます(もっとも説明書きの詳細さはプラグインによって大きなバラツキがあります)。ここで面白そうなプラグインを見つけたら、ダウンロードセクションからダウンロードします。この時、必ず推奨Hudsonバージョン(これはプラグインをビルドする時に使われたHudsonのバージョンです)が説明に書かれているので、このバージョン以降のHudsonがインストールされているかを確認しましょう。
ダウンロードしたプラグインは、Hudsonのユーザーインターフェースからアップロードできます。Hudsonのトップページから、「TODO」をクリックして、「プラグインの管理」を選んで下さい。ここからアップロードするプラグインを選んでインストールします。IDEのようにプラグインのインストールと更新が自動でできるインターフェースが付いているとよいのですが、現在のバージョンでは残念ながらそこまでの機能は実装されていません。
プラグインをアップロードしたら、プラグインを認識させるためにHudsonを再起動する必要があります。「java -jar hudson.war」のように起動している場合はCtrl+Cを押してプログラムを停止してから、もう一度起動すればOKです。既にアプリケーションサーバにインストールしてある場合には、アプリケーションサーバの再起動をしてください。Hudson再起動後、このプラグイン管理画面に戻ってくれば、プラグインのインストールが正常に終了したか、もしくは失敗したかがわかります。
バッチ処理プラグイン
最初に紹介するプラグインは、バッチ処理プラグインです。プラグインの名前は「batch-task」です。これは、ビルド毎に必要ではないけれども、時々実行される定例処理を自動化するための仕組みです。例えば、ビルドをウェブサイトにポストしたり、リリースを行ったり、最新バージョンのライブラリを取り込んだりするのがこれに相当します。
このプラグインをインストールすると、ジョブの設定画面にバッチ処理を設定するためのセクションが現れます。それぞれのバッチジョブにはシェルスクリプトを入力できます。例えば、バイナリをウェブサイトへアップロードするスクリプトは次のようになるでしょう。このようにして任意の数のバッチ処理が設定できます。
このような設定をしておくと、プロジェクトのページにバッチ処理へのリンクが現れ、ここからビルドを実行するのと同じ感覚でバッチ処理を実行できます。
ビルドプロモーションとプラグイン
次に紹介するプラグインは、ビルドプロモーションプラグインです。これは、Hudsonが生成するビルドのうちから、特に優れたビルドを峻別してマーキングするためのプラグインです。
このプラグインの出発点は次のような問題意識です。開発者へ素早くソースコードの状態をフィードバックするためには、一つのジョブにビルドやテストなどの多くの作業を詰め込むのではなく、ある程度細かい単位にわけて、複数のジョブに分解したほうが優れているという説明を、前回書きました。これは、パイプラインのあるCPUの方がそうでないものより沢山の命令を同じ時間で実行できるのに似ています。
ところが、この方法には一つ問題があります。通常、このように分解をするとビルドは一番最初に実行され、その下流ビルドとして沢山のテストが実行されることになります。この時、ビルドだけを行うジョブの履歴を見ていると、ビルドが完了したジョブは全て成功と認定されるのがわかるでしょう。しかし、ビルドが正常に完了したからといって、そのビルドが実際に使えるビルドであるとは限りません。実際、ビルドに失敗するような致命的な問題よりも、ビルドは成功するけれどもいくつかのテストに失敗する、というケースの方が普通でしょう。
さて、私達は今Hudson上でテストも実行しているのですから、成功したビルドはやがてテストされ、その結果は別のジョブ上に表示されます。これまた前回述べたように、ファイル指紋の追跡を利用していれば、Hudsonはどのテストがどのビルドに対して行われて結果がどうであったかを全て知っていることになります。テストの結果を人間が見に行くこともできますが、テストジョブの数が増えるとこの作業は煩雑になります。Hudsonの方で、テストの結果をビルドにオーバーレイしてみることはできないでしょうか?
ビルドプロモーションは、これを実現するための仕組みです。この仕組みの目標は、ただビルドに成功しただけでテストで失敗があった不良ビルドから、テストにも合格して品質に一定の保証ができる優良ビルドを峻別し、優良ビルドを「昇進」させることです。昇進したビルドには、その旨を示す☆マークが付き、また最終成功ビルドに永続リンクが提供されるように、最終昇進ビルドにも永続リングが提供されます。
シナリオ
例えば、あなたの開発しているコンポーネントをライブラリとして利用している別なチームがあったとしましょう。開発は同時平行で進められていますし、時にはこの下流のチームがあなたのコンポーネントにバグを発見するでしょう。バグフィクスや機能追加を届けるためにも、あなたの開発しているコンポーネントを定期的にこのチームに送付する必要があります。
あなたのコンポーネントのビルドがHudsonで行われていれば、あなたはHudsonのビルドをこのチームに送付するべきです。ビルドには番号がついていますから一意に識別できますし(この情報をjarファイルに埋め込むことだってできます)、そこから送ったビルドにどこまでの変更が入っているのかを厳密に調べることができます。ファイル指紋の機能を利用していれば、そのビルドで利用したライブラリのバージョンも全て厳密に追跡できます。下流チームも Hudsonを利用していれば、この追跡機能は更に広範囲に使えます。これは、あなたが自分のコンピュータでビルドしたバイナリを送付するよりも明らかに優れた方法です。
さて、しかし、下流チームの技術者にとっては、Hudson上のあなたのコンポーネントのビルドページにやってきて、適切なビルドを選ぶのはとても難しい作業です。彼はきちんとテストされて動作が確認されているものが欲しいのですが、最終成功ビルドがこの条件を満たしているとは限りません。従って、こういったケースでは、下流チームから「これこれこのバグが修正されたバージョンが欲しいんだけど」というリクエストがあなたに届いて、あなたがその条件を満たし、かつテストをパスしたビルドができ次第、そのビルド番号を通知する、という事が必要になります。
しかし、これは人間同士のコミュニケーションを必要とする分、面倒です。また、この方法だと、下流チームが必要性を感じない限り新しいバージョンのコンポーネントがインテグレートされないので、えてして長期にわたってコンポーネントが更新されない結果となり、いざ新しいバージョンを取り込むとなった時に問題が発生する危険が高くなります。また、古いバージョンを利用しているばかりに、既に上流で解決済みの問題に遭遇してその問題の切り分けに時間を無駄にする、というのもよくあるパターンです。
この問題を解決するために、ビルドプロモーションを行いましょう。下流チームとの間で話し合いをして、どれだけのテストがパスしたビルドであれば下流チームが満足かを決めます。もし二つのチームが非常に緊密に連携して作業していて、下流側でバグが頻繁に見つかるような状況であれば、テストを全て流すための時間を待つよりもリグレッションのリスクを覚悟しても早くバグ修正を受け取るほうがよい場合もあるでしょう。別なケースでは、最新のビルドがインテグレートされることはそれほど重要ではなく、テストを全て通過した高い品質のビルドだけがほしい、という場合もあるでしょう。
設定
この基準を決定したら、ビルドプロモーション基準の設定を行います。上流プロジェクトのビルドの設定画面に行き、「ビルドの昇進」を選びます。昇進の前提条件となる下流ジョブを選択しましょう。また、昇進条件が満たされた時に自動的に何かをするように設定することもできます。
特に有用なのは他のプロジェクトのバッチ処理をトリガする設定で、これを組み合わせればインテグレーションの自動化ができます。例として上流・下流が共に Antプロジェクトで、下流プロジェクトのソースコードリポジトリにjarファイルがチェックインされている場合を考えて見ましょう。
- コンポーネントをインテグレートしたい下流プロジェクトに、バッチ処理を設定します。このバッチ処理は、スクリプトを使って最後にプロモートされた上流のビルドを永続リンクから取得し、ライブラリフォルダを上書きし、最後に変更をコミットします。
- 上流でビルドプロモーションを設定し、ビルドがプロモートされたらこのバッチ処理を呼び出すようにします。
これで、プロモートされたビルドが自動的に下流にコミットされる仕組みが出来上がりました。Mavenの場合は、プロモートされたSNAPSHOTビルドをそれ専用のリポジトリに配備させる方法が使えるでしょう。
プロモーションは多段階に設計することもできます。例えば、複数のテストセットA,B,Cがあって、Cが特に大規模で時間を要するような場合を考えてみましょう。これらを全て直接下流プロジェクトに設定してもよいのですが、頻繁に変更が加わってビルドが行われているプロジェクトでは、全てのテストセットが同一のビルドに対して実行される確率がどうしても低くなってしまいます。このような場合に、実行時間の短いテストが完了した段階で一段目のプロモーションをし、これを受けて長時間のテストを走らせるようにすれば、長時間のテストを不良ビルドに費やす無駄を防ぐことができます。
ビルドプロモーションは、ビルド、テスト、及びチーム間の連携を自動化する、なかなか使いでのある機能だと思います。まだまだプラグインには発展途上の部分もありますが、筆者の職場でも便利に使っている機能の一つです。
外部のシステムと連携する
ソフトウェアの開発チームはどこでも大抵複数のツール・システムを組み合わせて使うのが普通です。代表的なものだけでも、IDE、バグトラッキングシステム、ソースコードリポジトリブラウザ、Wiki、プロジェクト管理システム、CRM、などが挙げられます。
大体の場合、これらのシステムは別々に開発された製品で、お互いの間の連携がないケースがありません。それぞれのシステムの中にはとても有用な情報がロックインされてしまっていて、これらを有機的に連携させている環境はなかなか見当たりません。しかし、開発者はこうしたシステムをすべて使うのですから、これらがより緊密に統合されていたほうが望ましいのは勿論のことです。
こうしたシステム間の連携はプラグインの花形分野といえるでしょう。Hudsonにもこういったプラグインが幾つもあります。今回は、この中からバグトラッキングシステムと連携するプラグインをいくつか紹介します。
Tracと連携
TracはPythonで書かれたSubversionリポジトリブラウザ+Wiki+バグトラッカーをひとつのパッケージにまとめたものです(日本人の間ではTrac月の方が有名かもしれません)。TracもHudsonもオープンソースソフトウェアな為かこれらを一緒に組み合わせて使う人が多く、TracとHudsonを連携させるプラグインはかなり古くから開発されているプラグインの一つです。
より正確には、TracとHudsonの最適な連携にはプラグインが2つ必要です──Trac側にインストールしてHudsonの情報をTrac上に表示するプラグインと、udson側にインストールしてHudsonからTracへのリンクを表示するプラグインHとの2つです。これらを使うことで、この2つのシステムを双方向に行き来することができるようになります。以下の画面はTracのタイムライン表示に Hudsonのビルドが表示されているところです。また、Hudson側からは、コミットメッセージにTracのチケット番号やWikiワードが含まれていると、それらがTracへのハイパーリンクになります。
JIRAと連携
JIRAは商用のバグトラッキングシステムで、特にオープンソースプロジェクト向けに無償ライセンスを提供していることから、ApacheやCodehausなどの大規模なオープンソースホスティングサイトで使われている製品です。JIRA用のHudsonプラグインの機能は基本的にはTrac用のそれと似ています。まず、コミットメッセージにJIRAのバグIDがあるとそれを自動的にハイパーリンクにしてくれて、この時ツールチップでバグのタイトルが表示されます。
また、設定によっては、HudsonがJIRA上の課題を自動的に更新して、ビルドに対するバックリンクが表示されるようになります。これを行うには、 JIRAの方で「accept remote API calls」をチェックして、プログラマブルに更新ができるように設定されている必要があります。
この組み合わせによって、やはり2つのツールの間を相互に行き来する事ができるようになります。
他のバグトラッキングシステム
筆者の知る限り、これ以外にもGoogle Code上のバグトラッカーと同様な事をするシステムや、SourceForge Enterprise Editionに対して類似のことを行うプラグインが存在しています。この分野に興味のある人は、ぜひ開発に参加してください!
リモートAPI
外部のシステムとの連携には2方向あります。Hudsonのデータを他のシステムへ向けて公開する方向のと、他のシステムのデータをHudsonに取り込む方向です。後者をHudson上で行う仕組みがプラグインですが、前者を行うための仕組みが「リモートAPI」です。
HudsonのリモートAPIは、Hudsonにプログラムからアクセスしてデータを取り出したり、その逆(例えば設定情報の更新など)をするためのメカニズムです。XMLとJSONの二種類のデータフォーマットがサポートされており、XMLは一般のプログラミング言語向け、JSONはブラウザ上のマッシュアップ向けです。
リモートAPIは、通常の閲覧可能なウェブページにオーバーレイする形で提供されています。例えば、NetBeansのHudsonトップページ「http://deadlock.netbeans.org/hudson/」の内容をリモートAPIで取得しようと思ったら、このURLに「api/」をつけて「http://deadlock.netbeans.org/hudson/api/」にアクセスしてみましょう。このページで利用可能な具体的なAPIが表示されます。XMLはいつも「api/xml/」、JSONはいつも「api/json/」サフィックスです。
HudsonのIDEプラグインの全てや、Hudson Googleデスクトップ・ガジェットがこの仕組みを使ってHudsonから情報を引き出しています。
認証が必要なデータにアクセスする際には、HTTP BASIC認証の仕組みを使ってください。これはJSONの場合も同様に有効ですが、ブラウザ上のJavaScriptからアクセスする場合にはユーザーにログインを促してこの有効なHTTPセッションに頼る方法が一般的でしょう。
エクストリーム・フィードバック・デバイスと連携する
皆さんは、エクストリーム・フィードバック・デバイス(XFD)を聞いたことがあるでしょうか? XFDは、プロジェクトの状態をもっと目立たせるために作られた機械で、CIのコンテキストではビルドの結果をコンピュータに向かっていなくても確認できるようにするものが多いようです。XFDのメリットは、体重計ダイエットのようなもので、開発者へのフィードバックを効果的に行い、ビルドの結果を常に意識させるだけで、自然と壊れたビルドの修復が早くなる、という点です。また、単にネタとしてのインパクトもかなりあります。
Hudsonのユーザーコミュニティの一部でもXFDがはやっているので、ここで幾つか紹介します。一つ目は、私が自作したXFDで、Hudsonのステータスを表示するオーブをそのまま実物にしようと思って作ったものです。
これはコンピュータにUSB接続して使います。中にはRGBの三色のLEDが入っていて、コンピュータ上から自由に色を制御できます(上の例は全ての色を表示するデモンストレーション)。実際には、コンピュータ上のプログラムがHudsonと通信して現在のビルド状態を取得し、それにあわせてオーブが点滅したり赤になったり青になったりします。このプロジェクトの詳細は筆者のブログにポストしました。
余談ですが、日本では信号色といえば赤・黄・青で、子供が絵を描く時にも青を使って書くことが多いのですが、アメリカでもヨーロッパでも信号の色は赤・黄・緑です。信号の実際の色は日本でももちろん緑なのですが、日本人は昔から青葉といったりして青と緑を非常に近く捉えるところがあるようです。このせいで、 Hudsonの青オーブは外人には不評で、何のことだか分からない、という人が多くいます。こんなところにも文化の差というのはあるようです。
これ以外にも、YahooでHadoop/Pigのテストに携わっているNigel Daleyという人が、市販のAmbient Orbを使って類似のものを作りました。詳細はこちらです。このセットアップにはハードウェアの知識は必要ないですし、Ambient orbはワイヤレスで見た目も美しくデザインされているので、アプローチしやすいXFDでしょう。
ワイヤレスで電源on/offをするアダプタとマグマランプを組み合わせるというのも電子工作の知識が必要なく、アプローチの容易な方法の一つでしょう。下はビルドがうまくいっている様子です。Hudsonからのデータを受け取ってon/offを制御するプログラムはここにあります。マグマランプは熱くなるので、つけっぱなしに注意しましょう。
最後に、最近ポストされたSimon WiestによるクマさんトリオによるXFDを紹介します。ビデオ自体も綺麗に編集されていてよく出来ています。
おわりに
今回は、Hudsonのうちバグトラッキングシステムに連携するプラグインを幾つか紹介しました。これ以外にも、ソースコード管理システムと連携するプラグインや、findbugsやPMDなどのツールと連携するプラグインもあります。詳細はプラグインページを見てください。最終回となる次回は、フリースタイル・プロジェクト以外のプロジェクトタイプを紹介します。