この連載では、オープンソースの継続的インテグレーション(CI)サーバであるHudsonを利用した、ソフトウェア開発の生産性向上について解説しています。前回の記事では、Hudsonの紹介と、インストール手順について解説しました。今回は、実際にHudsonでプロジェクトをビルドをする過程をより詳しく見ていきます。
ジョブの種類を選ぶ
まずはHudsonの新規ジョブ作成画面(http://localhost:8080/hudson/newJob)に戻りましょう。ここでは、新しいジョブの作成に先だって、ジョブの種類を選びます。これは、IDEに似ています---ここで適切な種類を選択することによって、プロジェクトにあわせて特化したサポートが提供されるわけです。何もプラグインをインストールしない状態では次の選択肢が表示されます。
- フリースタイルプロジェクトのビルド
- 本記事では主にこれを解説します。ソースコードをチェックアウトし、ビルドし、その結果生成されたものについて色々な処理をするという、いわゆる基本的なCIを実行するジョブです。
- Maven2プロジェクトのビルド
- フリースタイルプロジェクトと似ていますが、Maven2プロジェクトのみに対応しMavenと連携する結果、ほとんど設定をしないでも色々な処理が自動的に行われるようになります。Maven2でプロジェクトをビルドしているチームには便利なオプションです。これについては連載の後の方で解説します。
- マルチ構成プロジェクトのビルド
- ある種のプロジェクト、例えばネイティブコードを含むプロジェクトでは、同じソフトウェアを異なる環境でビルドする必要があることがあります。似たような必要性はテストを自動化する際にも起こります。この種類のビルドはフリースタイルプロジェクトと似ていますが、それに加えて、同一の設定のプロジェクトを複数の環境で同時にビルドする機能が付け加わります。これについては連載の後の方で解説します。
- 外部ジョブの監視
- procmail やcronなど、Hudsonの外部で自動的に実行されるプロセスの実行結果をHudsonで監視する時に使います。自動的に実行されるプログラムは、往々にしてエラーの監視が疎かになりがちです。筆者はよく特定の種類のメールに自動的に応答するデーモンプログラムを書く事がありますが、エラーが起こっているのに気づかないで放置してしまうことがあるのですが、この機能を使うことで、Hudsonから結果の成功・失敗や過去の記録の閲覧をすることができます。これについても、連載の後の方で解説します。
Hudsonを最初に使う場合には、「フリースタイルプロジェクトのビルド」がお勧めです。Hudsonの中で一番古参の機能で枯れている上、魔法が少なくHudsonが何をやっているかわかりやすいという利点もあります。ここでは「フリースタイルプロジェクトのビルド」を選び、適当な名前を入力して次へ進みましょう。
ジョブを設定する
ジョブを作成するとHudsonは設定画面へ移動します。ここでどのようにジョブをHudsonにビルドさせるかを設定します。
「説明」はジョブのトップページに表示されるHTMLを入力する部分です。プロジェクトの数が増えてくると、名前だけでは何をするジョブなのかわからなくなってくるので、そうした場合にこのフィールドを利用しましょう。筆者の環境では、バグトラッカーやソースコードリポジトリブラウザ、プロジェクトのポータルページなど、プロジェクトの他の関連リソースへのリンクを記述しておくことも頻繁に行われます。ジョブが何の目的で使われているのか、誰が責任者なのかといったことも、書かれていると便利です。
ソースコード管理システムの設定
Hudsonは標準でCVSとSubversionをサポートしています。これ以外のソースコード管理システムを使う際には、個別のプラグインをインストールしてください。設定は単純だと思いますが(下図参照)、特筆すべき点がいくつかあります。Hudsonは外部のCVS実行可能ファイルを呼び出してCVSを操作するので、このCVSプログラムがリポジトリアクセスに必要な認証情報を持っている必要があります。通常はこの情報は~/.cvspassに格納されていますが、CVSNTなどWindows用のCVSの一部にはレジストリなど非標準の位置を利用するものがあるので注意が必要です。また、後に HudsonをTomcatなどのコンテナ上で走らせる場合、Hudsonを実行しているユーザーが変化することになるので、正しいユーザーで「cvs login」を実行して認証情報をセットしてください。匿名アクセスが可能なリポジトリの場合にはこのような問題はなく、またSubversionについてはHudson上から認証情報を設定できるので、このような繁雑な問題はありません。
Hudson をcronの置き換えとしてソフトウェアのビルド以外の自動化用途に使う場合、例えば何かのバックアップをとったりとか、定期的なバッチジョブの実行などですが、ソースコード管理を使う必要がないので「なし」を選択しましょう。また、特殊なチェックアウトが必要な場合(例えば複数の種類のリポジトリの混在など)やお使いのソースコード管理システム向けのプラグインがない場合も、ここで「なし」を選択しておいて、シェルスクリプトを使ってチェックアウトをする事になります。
ビルドトリガの設定
ソースコードの次は、いつビルドが行われるのかに関わる「ビルド・トリガ」の設定をします。CIの主眼はソースコードの変更をできるだけ早くビルド・テストすることですから、トリガのタイミングとしては変更がリポジトリにコミットされたらビルドを行うのが普通で、これには大きくわけて2つの方法があります。
1つ目は、ソースコード管理システムをHudsonが定期的にポーリングする方式です。この方法は、ソースコード管理システム側に変更が必要ないので設定が単純だというメリットがありますが、ポーリングの間隔を頻繁にしすぎるとソースコード管理システムによっては大きな負荷がかかり、とはいえ間隔を伸ばしすぎるとコミットをしてからビルドが行われるまでに大きなタイムラグが発生するという問題を生じます。CVSでは、その性質上ポーリングにワークスペースの規模に比例する処理時間がかかるので、頻繁なポーリングは全く現実的ではありません。Subversionでは、ポーリングはワークスペースの規模によらず一定時間で高速に行えるので、ポーリングは現実味のある選択肢です。
いずれにせよ、ポーリングでは、どのように設定してもコミット直後にビルドを開始することができません。ポーリングは最短でも1分間隔なので、全力でポーリングしても平均30秒の待ち時間が発生しますし、ポーリング間隔を現実的に設定すると待ち時間が30分、1時間となるのは普通です。
この問題を解決するには、変更がコミットされた時に、ソースコード管理システム側からHudsonに通知するという方法を使います。具体的な方法はそれぞれに違いますが、例えばCVSではCVSROOT/loginfoを使い、Subversionではリポジトリ上のhooks/post-commitを使うとこういったことができます。これらのスクリプトからリポジトリへの変更を特定し、そこからさらにビルドするべきHudsonのジョブを決定したら、「ビルドの実行」がクリックされた効果をシミュレートするために次のようにすればOKです。お使いの環境での実際のURLを取得するには、ブラウザで「ビルド実行」リンクのアドレスをコピーすればよいでしょう。
CVS の場合、コミットが複数のディレクトリに跨るとあたかも複数のコミットが起こったかのように連続してloginfoが実行されるので、先の例に示したようにdelayパラメータを使って、Hudsonがビルドを開始するまでに数秒の待ち時間を入れましょう。これによって、変更が全て一括してビルドされるようになります。
ソースコードリポジトリの管理がチームの外で行われていて(例えばリポジトリを SourceForgeやjava.netにホストしている場合など)コミットフックを変更することができない場合、コミット通知メールをHudsonが受け取ったタイミングでビルドを行う、というようにすることもできます。実際の方法は使っているメールサーバによって異なりますが、例えばeximならば ~/.forwardを使って、こういった処理を行うことができます。Hudsonを専用ユーザーIDで運用する場合などには、このユーザーの ~/.forwardファイルを利用すればよいでしょう。この方法は初期のセットアップが大変ですが、一度やってしまうと沢山のプロジェクトでほぼ追加コストなしに利用できるので、大規模な環境では向いています。筆者の職場では実際qmailを使って「hudson- xyz@kohsuke.sfbay.sun.com」宛にメールが届くとプロジェクトxyzがビルドされる、という風に運用しています。
このように、ソースコード管理システム側から変更をプッシュする方式は設定が環境依存で繁雑ですが、Hudsonの有用性はビルドの結果を如何に素早く報告できるかで大きく変わってきます。可能であればぜひこのような設定をしたいところです。
定期的に実行
「定期的に実行」はビルドトリガの一つで、ちょうどcronのように予め指定された時刻になると自動でビルドを行う仕組みです。
CIシステムがはやる以前は、プロジェクトの自動ビルドというと、「ナイトリービルド」などの定時実行が主流でした。このため、Hudsonを新規に導入するユーザーは、つい無意識にこの「定期的に実行」を選んでしまいがちです。しかし、Hudsonを導入するメリットの一つは極力早くビルド結果をフィードバックすることにあるので、ソースコードの変更のタイミングとは無関係にビルドをするというこの設定はできるだけ避けるべきです。特に、一日一回しかビルドをしないという貧乏臭い発想は捨てて、コンピュータの代金の元をとってやるという位の気合でできるだけ頻繁にビルドしてみてください。
なお、CI以外の自動化用途にHudsonを使う場合などで、定期的な実行が有用である場合があるのはもちろんの事です。また、cronの文法にはモダンなものを採用しているので、「*/15」で15分おきに、といった便利な記法が色々使えます。ヘルプを参照してください。
ログの保存について
「古いビルドの破棄」に関する設定項目は、ビルドの記録をどの位の期間保存しておくかを指定します。Hudsonを個人的に使っていて最新のビルド結果にしか興味がない場合には、この項目を使って直近の数十程度のビルドだけの記録を保存するようにすれば、ディスク容量の無駄遣いを防ぐことができます。
一方、特にHudsonがチームで使われるようになると、ビルドがおかしな壊れ方をした、重要なバグが修正された、などといったイベントの発生から、そのイベントが別の人に処理されるまでに大きなタイムラグが発生することがあります。このようになってくると、「昔の記録を見ようとしたらもう破棄されてしまっていた」という悲しい出来事が起こる時があります。こういった事を防ぐためには、ビルドの保存期間をそこそこ長めにとっておくのが安全です。現代のコンピュータはビデオや音楽などの用途を想定して、開発用では到底使いきれないほどの容量のHDDが搭載されていることが当たり前になっていますから、やはりここでも富豪的発想をするのが正解です。この富豪アプローチの最たる方法として、「ディスクは安いからそれよりビルドの記録が長く残る方が大事」と考えてビルドの記録を永久に保存するという使いかたをしている人も多いようです。
なお、有限のビルドの保存期間を設定している場合でも、ビルド画面から重要なビルドをその旨マークして特に保存させることができます。これは上述のシナリオのような「後で見る」場合に有効な他、リリースされたバイナリを保存したり、あるいはHudsonのビルドを公式ビルドにしてコンポーネントチーム間でバイナリインテグレーションをするような場合にも有効です。この使いかたについては連載の後の方で解説する予定です。
ビルドの設定
設定画面の「ビルド」セクションは、Hudsonがビルドをどのように実行するべきかを指定する部分です。「ビルド手順の追加」を選んでお好みのビルド方法を指定します。
もっとも単純で汎用的な方法は、バッチコマンドかシェルスクリプトの実行を選択して、コマンドをテキストボックスに記述する方法です。例えば、よくあるパターンとして、環境変数をいくつか設定してからantを呼び出す、などといったビルドはここに記述することになります。なお、今のところHudsonは設定情報をバージョン管理しないので、チーム内の複数の開発者が設定をいじっていると、「どうして環境変数XYZの値がAじゃなくてBなの?」とか、「このパラメータ最近変わった?」などという状態になることがあります。このような状態を避けるためにも、ビルド手順が単純でなくなってきたらスクリプトはソースコード管理システム内において、Hudsonは単にそれを呼び出すだけにするのが望ましいでしょう。
もしもビルド手順がごく単純で、単にAntやMavenを呼び出せばよいというのであれば(すべからくソフトウェアのビルドは単純であるべきなのでこれは大変望ましい事です)、スクリプトによる汎用ビルドを選ぶ代りにAntやMavenなどの特定のビルダーを選択することができます。こうすることで、 Hudsonの管理者がビルドによって必要な何種類かのツールバージョンを用意しておいて利用者がそれらのパスを知らずに適切なバージョンを選択したりできます。また、特にWindows環境下ではビルド中に発生するエラーコードをHudsonへ伝搬するのが必要以上に大変なのですが、これらの特定ビルダーを使うことでこの種の問題を回避できます。
主要な画面の紹介
さて、引き続き「ビルド後の処理」の設定があるのですが、ここまででビルドができる状態に一応なっているはずなので、この最後の部分の説明は後にして、早速幾つかビルドを実行してみましょう。もしソースコード管理システムからのビルドトリガが正しく設定されていれば、幾つか適当なコミットをしてみるとビルドが行われるはずです。画面左側のビルド履歴の部分はAJAXが使われているので、ページリロードなしに新しいビルドの内容が追加されてくるはずです。
ビルドの記録が幾つか溜ってきたところで、Hudsonの主要な画面のいくつかを紹介しましょう。下の画面はジョブのトップページです。左側には直近のビルドへのリンクが数十個表示されます。
ビルド履歴の右肩の「傾向」をクリックするとビルド時間の変遷が表示されます。ビルドの所要時間はフィードバックサイクルの長さに直結しているので、あまり長くなりすぎているようなら何か手を打つことを考えます。
ビルドとビルドの間にソースコードの変更があれば、プロジェクトレベルのページの左から「変更」をクリックすることで変更内容とビルドの対応関係を一覧にする事ができます。チームの他のメンバーの作業がある特定の変更(例えばバグ修正)に依存している場合などに、これを使ってどのビルド以降に必要な変更が取り込まれているのか確認しましょう。
ビルド後の処理の設定
さて、ここまででHudsonがビルドをできるようになったので、このビルド結果を開発者にフィードバックすることでフィードバックループを完結させましょう。開発者にビルド結果を通知する方法は色々あるのですが、まずは筆頭の電子メールによる方法を取り上げます。
設定画面に戻って「E-mail通知」を選びます。宛先アドレスとして、開発チームが既に利用しているメーリングリストがある場合はそれを記入するのが一番手っ取り早い方法です。ビルドが失敗するたびにここにメールが送られます。特にビルドが連続して失敗する場合には、Hudsonは新しい通知メールを以前のメールへの返信として送るので、一連のビルドエラーが一まとまりで表示され、後からビルドの失敗の傾向を分析する一助になります。ビルドの失敗をメーリングリストに送る方法はチームが小さいとよく機能するのですが、大きなチームでは「どうせ誰か別な人が問題を修正してくれるだろう」「きっと一時的な問題だろう」という風に誰もが考えて結局誰もビルドエラーに注意を払わないという問題が起こりがちです。こうした状況が顕著になってきたら、メーリングリストへ送るよりもむしろ、ビルドを壊した個人にメールを送るようにしたほうが責任が明確になるため、効果的になります。電子メールの送りすぎは狼少年と同じでむしろ開発者へのフィードバックを悪化させる事があるので、メールを送り過ぎないように、しかしビルドの問題が短時間で解決されるように、注意してみてください。
電子メール以外に、インスタントメッセンジャーを用いた通知や、タスクトレイからメッセージをポップアップして通知する方法などもプラグインとして利用可能です。また、IDEを常時開いている環境であればIDEにHudsonプラグインをインストールしてIDEから通知を受け取る方法もあります。
テスト結果の集計
素早いフィードバックと並んで重要なのが、プロジェクトの状態の可視化です。この観点から有用なのは、テスト結果の集計です。もしビルドの一部としてテストが自動実行されるならば、Hudsonを設定してテスト結果のレポートを作成しましょう。ディフォルトではJavaのテストフレームワークではデファクトの JUnit XMLフォーマットに対応しており、これでTestNGのレポートなども読み込むことが出来ます。下のスクリーンショットは、この設定がされたプロジェクトのトップページで、テスト結果の履歴が表示されているのが見えます。赤がテストエラーの数で、時々リグレッションが起こっているのもみてとれます。
Hudson上でテスト結果をみる事の主な利点は、時系列データです。Hudsonは過去のテスト結果も記録しているので、それらと比較することによって、新しいリグレッションに注意を集中させたり、長い間壊れっぱなしになっているテストを識別するのが簡単になります(この種のデータマイニングは色々なポテンシャルがありそうなので、作者としては今後発展させていきたい分野の一つです)。下のスクリーンショットは職場のプロジェクトの1つからとったもので、913のテストのうち2つのテストが失敗していることがわかります。+/-0の表示はテストの数にもエラーの数にも増減がないことを表しています。「時期」とあるのは「年齢」の誤訳で、この例では過去59回に渡ってこのテストが失敗しつづけていることがわかります。
また、テストの結果をHudson上に記録することによる可視化効果も無視できません。Hudson上にテスト結果が公開されることで、プロジェクトの状態がプロジェクトに直接携わっていない人にも分かりやすくなります。大きなプロジェクトが小さな部品に分解されてそれぞれ担当チームが分かれているような状況では、他のチームのコードが原因でテストが失敗したりすることもままありますから、どのチームの人間でも他のチームのテスト結果をいつでも見られるということはとても有用です。
おわりに
いわゆるアジャイルな開発では、プログラムが動く状態にある事が非常に重視されます。連載二回目となる今回は、ソースコードに変更が加わってから、それを如何に素早くビルドさせ、結果をチームで共有するか、という点を主眼に解説してきました。プログラムを修正しているとどうしてもバグが混入してしまうのが現実ですが、このようにして問題の発生を素早く検出することで、プログラムの質を高く保つのが容易になります。
さて、次回は視野を広げて、ソフトウェアプロジェクトの開発が複数のチームに分かれている場合に、Hudsonを更に有効活用する方法についてみていきます。