この連載では、オープンソースの継続的インテグレーション(CI)サーバであるHudsonを利用した、ソフトウェア開発の生産性向上について解説しています。前回の記事では、プラグインを幾つか紹介し、また使って楽しいエクストリーム・フィードバック・デバイスについても触れました。さて、最終回となる今回は、Mavenと連携したりテストを効率よく実行したりするための高度なプロジェクトタイプを紹介します。
Mavenプロジェクトタイプ
さて、本稿では、今まで「フリースタイルプロジェクト」と呼ばれているHudsonの標準的なプロジェクトタイプを紹介してきました。この型のプロジェクトでは、任意のソースコード管理システムと、任意のビルドツールと、更に任意のビルド後処理を組み合わせることができます。この方式では、Hudsonは本質的には何がビルドされているのかまったく理解せず、単に手順を設定されたとおりに実行するだけです。この結果として、どのような種類のプロジェクトにも適用できて、高い汎用性を得ることができますが、他方、その分本質的に必要なもの以上に多くの設定を行う必要があります。何とか、この設定をより簡略化する方法はないものでしょうか。
HudsonのMavenプロジェクトタイプはこの問題を解決する一つの方法です。プロジェクトがMavenでビルドされている場合、ビルドに関する多くの情報(例えば生成されるjarファイル、テストレポート、javadocなど)はpom.xmlに既に書かれています。ビルドツールをMavenに固定する代わりに、この情報を最大限活用して自動化をよりいっそう推し進めるのが、Mavenプロジェクトタイプの基本的な発想です。このモードでは、Hudsonは実行されているMavenの中に監視ツールを配置して、Mavenが何をしているのかを追跡します。 surefireプラグインが実行されてユニットテストが走ったり、あるいはjavadocプラグインが実行されてjavadocが生成されれば、これらを記録する処理を自動的に行います。また、Mavenモジュールの一覧を表示したり、利用されたプラグインの一覧とそのバージョンを記録したりといった、Mavenに固有のユーザーインターフェースもHudson上に表示されるようになります。この結果、フリースタイルプロジェクトでは必要であった多くの設定項目が削減できます。
実際に簡単な例を見ましょう。Hudson自身はMavenでビルドされているので、HudsonをHudsonでビルドしてみます。次の画面は設定画面の主要な部分です。ご覧のように、SubversionのURL と、「clean install」というMavenのビルドフェーズが指定されている他は何の設定もありません。
ところが、ビルドを実際に実行してみると、適切に設定されたフリースタイルプロジェクトと同程度かそれ以上の情報がHudsonによって収集されていることが分かります。以下は、このプロジェクトに含まれるMavenモジュールの一覧です。
テスト結果も自動的に収集されて傾向が表示されます。
生成されたアーティファクトも自動的に記録されています。
実行されたプラグイン・mojo・及びそのバージョンとファイル指紋です。こっちのマシンではビルドできるのにあっちではビルドできないといった、プラグインのバージョンに起因するビルド関係のトラブルシューティングをする時に役立ちます。
この他に、目には見えない部分でも幾つかの処理が自動的にキックインします。例えばPOMの内容から依存関係を計算され、依存しているプロジェクトが Hudson上でビルドされていれば、それらのプロジェクトの間に上流・下流関係が設定されます。POMのを利用していればそれらのメールアドレスに通知も送られます。また、追加のHudsonプラグインを導入する事でHudsonが反応できるMaven mojoの種類が増えます。例えば、FindbugsプラグインをHudsonにインストールしていると、findbugs-maven-plugin が実行されるだけで自動的にfindbugsのレポートが収集されます。
Maven サポートでのもう一つのウリは、事後のデプロイメントです。Mavenの標準の動作では、モジュールが複数あった場合には個々のモジュール毎にビルドとデプロイが繰り返されます。この結果、後ろのモジュールがビルドに失敗した時には、それより以前のモジュールは既にデプロイされてしまっていて、結果としてリポジトリが一貫性の無い状態になってしまうことがあります。HudsonにはMavenのビルドが完全に終了してからデプロイをする機能があり、この問題を防ぐことができます。
また、これと前回紹介したビルド・プロモーションを組み合わせると、より複雑なテスト工程を実行してさらに緻密に動作を検証して、プロモートされたビルドだけをリポジトリへコピーしたりすることもできます。これによって、不安定なビルドが他のユーザーのところへ流出してしまうのを防ぐことができます。
この機能はHudsonの中では比較的新しく、まだまだ改善の余地は沢山ありますが、既に十分に有用な機能になっていると思います。試してみてください。
マルチ構成プロジェクト
マルチ構成プロジェクトは、ほぼ同一のビルドもしくはテストを数多くの異なる環境で行う場合に適したプロジェクトタイプです。この機能のユースケースは次のようなものです。
- ネイティブコードを含むプロジェクトを扱っています。ビルドは、対応している全てのプラットフォームで行う必要があります。
- データベースアプリケーションを書いていますが、テストはこのアプリケーションがサポートする全てのデータベースに対して行う必要があります。
- ライブラリを書いていますが、テストはSun,BEA,IBMのJDKで、それぞれJDK5とJDK6の両方で行う必要があります。
このような状況では、必要な構成の数だけ個別のプロジェクトをHudsonに設定してもよいのですが、同一の設定を何度も繰り返さなければならず、非効率的です。マルチ構成プロジェクトを使うと、ビルドの設定を一度行い、またどのような構成でビルドを行う必要があるのか(OS、JDKのバージョン、データベース、アプリケーション定義の任意の変数値など)を指定するだけで、Hudsonが自動的にそれらの構成を網羅的に組み合わせてビルドを実行し、結果を集計してくれます。全ての構成で同じソースコードセットが使用され、同一のビルド番号が割り当てられるので、どのビルドにどの変更が入っているのかの追跡も容易です。
筆者の職場では、この機能を使ってMetroウェブサービスライブラリを Windows, Linux, Solarisの3つのOSと、JDK5/6の都合3x2=6つの環境でテストしています。これによって、特定のOSでしか現れないバグがないか検査したり、JDKの動作の微妙な違いによるバグがないか検査したりできるようになっています。この例では同時に6つのテストが実行されますが、このように、マルチ構成プロジェクトを待ち時間なしに捌くためにはそれなりの数のスレーブを利用した分散ビルド環境が必要になります(分散ビルド環境を用意する方法については、本連載の第三回を参照してください)が、このように多くのテストを並行して走らせることによって、より多くのリグレッションを素早く検出することが出来ます。
これも、実際の例を見てみましょう。次の画面は設定画面の主要な部分です。
ビルドの基本的な部分はフリースタイルプロジェクトと一緒で、SCMの設定やビルド手順などはまったく同じですが、幾つかマルチ構成プロジェクト特有の設定項目があり、これらは「構成マトリックス」セクションにあります。
- もし分散ビルドが設定されていれば、「複数のノード上でのビルド」という設定項目が表示されます。複数のOSで同時にビルドする必要がある場合等には、これを使ってビルドを行うマシンを指定します。個別のマシンを直接指定することもできますが、例えば「Linux,Solaris,Windowsでビルドしたい」といった時にもし条件を満たすスレーブが十分に沢山あれば、マシン名を直接指定する代わりにラベルを利用することで、スケジューリングの自由度を高めることができます。
- もし複数のJDKが設定されて入れば、JDKをチェックボックスで複数選択することができます。これは、主にテストを複数のJDKを対象に行う時に便利です。何もチェックしないとディフォルトのJDKが使われ、また単に特定のJDKでビルド・テストしたいだけの場合には一つだけチェックします。
これら2つの構成軸に加えて、ユーザー定義の任意の軸を追加することが出来ます。軸は名前と値のセットからなり、例えば、複数のデータベースでテストするなら、名前="db"、値="mysql postgresql oracle"などと指定します。これらユーザー定義の軸は、環境変数としてビルドに渡されるので、ビルド側でこれらの値に応じて処理を切り替えます。例えば、ビルドがantで実行されていれば、異なるデータベースを使ったテストは次のようなものになるでしょう。
ant -Ddatabase=$db clean test
プロジェクトをビルドすると、次のような画面が表示されます。指定した軸の全ての組み合わせがテストされている事がわかります。
この機能もHudsonの中では比較的新しいですが、既に使えるものになっていると思います。試してみてください。
外部ジョブの監視
最後に紹介するHudsonのジョブタイプは、「外部ジョブの監視」です。この機能は、Hudsonの外で実行されるバッチジョブの実行結果をHudsonの内部に取り込みます。この機能のユースケースは次のようなものです:
- sendmailやprocmailなどでは、メールが配信された時にプログラムを使って自動処理ができます。が、このようなプログラムが正常に動作しているかを監視するのは煩雑です。
- 複数のマシン上で幾つものcronジョブが動いています。これらを一括して監視するのが煩雑です。
外部ジョブの監視機能は、ちょうどtimeやstraceのように、他のプロセスをラップします。そして、監視対象のプログラムの標準出力と終了コード、及び実行時間をHudsonにHTTP経由で送信します。
Hudson のモニタリングエージェントはhudson.warに含まれている/WEB-INF/lib/hudson-core-*.jarというファイルです。このプログラムは環境変数HUDSON_HOMEを参照して送信先を決定し、コマンドラインに子プロセスとその引数を受けとります。例えば、次の例は、backup.shを一時間毎に動かして、http://mserver.acme.org/hudson/で動いているHudsonの"backup" ジョブに実行結果を送信します。
HUDSON_HOME=http://myserver.acme.org/hudson/
0 * * * * export HUDSON_HOME=$HUDSON_HOME; java -jar hudson-core.jar "backup" backup.sh 2>&1 > /dev/null
実行結果の送信に使われるXMLは非常に単純なので、これ以外の方法でXMLを送信すれば、プロセスの実行以外の事もモニタできます。このフォーマットの詳細についてはこちらを参照してください。
終わりに
今日まで、5回に渡ってHudsonの様々な側面について紹介してきました。Hudsonを通して、ソフトウェアの開発工程の自動化と生産性の向上について考えてもらうきっかけになれば幸いです。Hudsonに関するより詳しい情報については、https://hudson.dev.java.net/と、筆者の日本語ブログhttp://d.hatena.ne.jp/kkawa/へどうぞ。