Buildbot による継続的インテグレーション
Python ベースのツールを使った継続的インテグレーションの理論と実践
CI (Continuous Integration: 継続的インテグレーション) は以下の原則を推進するソフトウェア開発プロセスです。
- ソース・リポジトリーを 1 つに維持する
- ビルドを自動化する
- ビルドによって自己テストを行う
- 毎日、全員がコミットする
- コミットするごとに、統合マシンの主系がビルドされるようにする
- ビルドを高速に維持する
- 本番環境のクローンでテストする
- 最新の実行可能ファイルを全員が容易に入手できるようにする
- 何が起きているのかが全員にわかるようにする
- デプロイメントを自動化する
主に Martin Fowler によって広められた CI の基本概念では、ブランチごとに、またコードをトランクにマージするごとに、継続的にテストとビルドを行います。こうすることで、コード・ベース全体としての健全さを高めることができます。また、チーム・メンバー間のコミュニケーションが活発になり、コードの全体的品質に対するフィードバックを得やすくなります。開発者はこのサイクルを利用して、コード・カバレッジ・レポートやその他の統計を生成することがよくあります。
Buildbot は他の CI システムと同様、このチェックアウト、ビルド、テストというサイクルの自動化を支援します。Buildbot スレーブは通常、Win32、Solaris、Intelx64 など、さまざまなプラットフォーム上で実行されます。Buildbot はビルドで障害が起きると E メールで通知し、また実行中のすべてのビルドを追跡します。そのため開発者はプロセス全体の状況を高い視点から把握することができます。また、この自動サイクルを利用して、いつでもソフトウェア品質に関するメトリクスを生成することができます。この記事の最後ではメトリクスを取り上げ、なぜ CI システムの中でメトリクスを実行することに意味があるのかを説明します。
Buildbot の紹介
Buildbot の概要を説明するにあたり、まずは Buildbot のアーキテクチャーを見てみましょう。図 1 に示すように、基本的にビルド・プロセスの上に 3 つのレイヤーがあります。バージョン管理レイヤーは、バージョン管理システムからの通知にフックされます。ビルド・レイヤーは、ビルド・マスターからの通信を受信し、ビルドの結果を返します。最後に、通知レイヤーがあります。通知レイヤーは多くの場合、ビルドが失敗した場合に E メール (つまり IRC メッセージ) を送信するように、またはそれまでに収集したビルドの結果を Web ページに表示するように構成されます。
図 1. Buildbot のアーキテクチャーの概要

これら以外に Buildbot のアーキテクチャーの中心的な特徴の 1 つとして、Python ベースの Twisted ライブラリーを利用してマスター/スレーブ間の非同期通信を処理しています。このコールバック・ベースのアーキテクチャーを使用することで、非常に単純ながら堅牢なマスター/スレーブ型のフィードバック・ループを構成することができます。Twisted の詳細については、この記事の最後に挙げた「参考文献」セクションを参照してください。
今まで Buildbot について聞いたことがなくても、Google で少し検索してみると、大小さまざまなオープンソース・プロジェクトに関連して大量のマスターやスレーブがあることがわかります。スレーブについては先ほど簡単に触れましたが、スレーブというのは文字どおりマスター Buildbot サーバーに制御されるスレーブ・マシンです。通常、1 つのスレーブは、互いに異なるテスト・プラットフォームを実行する何台かのスレーブ群のうちの 1 台です。これは Buildbot サーバーの世界の重要な概念です。例えば、あるオープンソース・プロジェクトのメーリング・リストに皆さんが登録しており、誰かが「Windows スレーブ用の仮想マシンを誰か自発的に提供してくれませんか」と発言するのを聞く、という状況と似ています。
Python 言語プロジェクト自体が大量の Buildbot スレーブを使用し、可能な限り多くのプラットフォーム上で、最新バージョンの Python のビルドとテストを継続的に行っています。図 2 には多種多様なマシンが表示されていますが、これらのマシンは Python トランクに対するスレーブ・ビルドやテストを実行しています。最近の仮想化の進歩により、開発コミュニティーのメンバーに Buildbot スレーブをホストするように依頼したり、あるいは多様なハードウェア構成をエミュレートするために、単に何台かの仮想マシンを実行するように依頼したりすることは、今では一般的になっています。
図 2. Python での Buildbot:

Buildbot のユーザーとしては、Google の Chrome ブラウザー・プロジェクトも有名です。図 3 は大きくカスタマイズしたバージョンの Buildbot です。このバージョンでは Buildbot のユーザー・インターフェースのルック・アンド・フィールが大きく改善されています。幸いなことに、Google はこうした機能強化をオープンソースとして Buildbot に提供しました。また、このカスタマイズ・バージョンのソースとビルドを下記の「参考文献」セクションから入手することができます。
図 3. Google Chrome 用に機能強化された Buildbot:

この記事では、この特定の構成をビルドする方法については省略しますが、皆さん自身で試してみるようお勧めします。今度は Buildbot マスター・サーバーを素早く動作させてみましょう。
Buildbot を 5 分でセットアップする
私は Ubuntu 8.10 で下記のステップを実行しましたが、大部分の Linux ディストリビューションでもステップは同じはずです。
- 下記を実行して ez_setup.py
をダウンロードします。
wget http://peak.telecommunity.com/dist/ez_setup.py
- 下記を実行して easy_install をインストールします。
sudo python ez_setup.py
- 下記を実行して apt-get を使って Python Twisted
パッケージをインストールします。
sudo apt-get install python-Twisted
- 下記を実行して collective.buildbot
の「レシピ」を実行します。
sudo easy_install collective.buildbot
この時点で、大量のパッケージが自動的にダウンロードされてインストールされ、シェルから大量の内容が生成されます。それが終了すると、Buildbot の作成準備は完了です。インストールが適切に終了したら、シェル・プロンプトから下記を入力します。
$ paster create -t buildbot my.project
$ cd my.project
たったこれだけで、ほとんど終わりです。ただし終了する前に、初めて Buildbot を構成する際に間違えやすい点をいくつか指摘しておきましょう。my.project/master.cfg ファイルの中を見ると、下記のようなものがあるはずです。
リスト 1. master.cfg の内容
[buildout] master-parts = master passing.project # uncomment this to enable polling poller [master] recipe = collective.buildbot:master project-name = passing.project project # allow to force build with the web interface allow-force = true # internal port port = 9051 # http port wport = 9081 # buildbot url. change this if you use a virtualhost url = http://localhost:9081/ # static files public-html = ${buildout:directory}/public_html slaves = localhost NaOaPSWb [passing.project] recipe = collective.buildbot:project slave-names = localhost vcs = hg repositories = /home/ngift/myhgrepo # notifications mail-host = localhost email-notification-sender = buildbot@cortese email-notification-recipient = super@example.com # run test each hour periodic-scheduler=60 # cron build cron-scheduler = 0 8 * * * # You can change the sequences to build / test your app # default options should work for most buildout based projects build-sequence = # /usr/bin/python2.5 bootstrap.py -c project.cfg # /usr/bin/python2.5 bin/buildout -c project.cfg test-sequence = nosetests # zope.testing require exit with status # bin/test --exit-with-status [poller] recipe = collective.buildbot:poller # don't forget to check this # since it's generated from the paster template it may be a wrong url repositories = /home/ngift/myhgrepo #user = h4x0r #password = passwd poll-interval = 120
最初にチェックすべき最も重要な事項は、適切なソース管理リポジトリーがあること、最初は build-sequence
を空白にしておくこと、そしてチェックインしたリポジトリーからコードをチェックアウトする際に test-sequence
(この例では「nose」)
がテストにパスすることです。それ以外に質問がある場合には、collective.buildbot のリソース・ガイドを見てください (「参考文献」のリンクを参照)。
構成ファイルを設定できたら、単純に下記の 2 つのコマンドを実行します。
$ python bootstrap.py
$ ./bin/buildout
buildout
コマンドを実行すると、リスト 2 のような出力が大量に生成されます。
リスト 2. buildout コマンドの出力
{673} > ./bin/buildout Unused options for buildout: 'master-parts'. Installing master. New python executable in /home/ngift/my.project Installing setuptools............done. [output suppressed for space]
このコマンドが終了すると、Buildbot のインストールは完了し、起動準備が整ったことになります。シェルから下記のコマンドを実行し、両方の Buildbot デーモンを起動します。
$ ./bin/master start
$ ./bin/yourhostname start
次に、master.cfg ファイルの中で設定した URL (デフォルトは http://localhost:9081/) にブラウザーでアクセスすると、Buildbot が華々しく表示されます。もちろん、この状態では大したことはできません。Buildbot にビルド・スクリプトとテスト・ランナーを指定すると、Buildbot はコードをチェックアウトし、そのコードを自動的にテストします。もちろん、後で構成オプションをいくつか詳細に調べる必要はありますが、面倒な作業は基本的に終わりです。
コードのメトリクス・レポートを生成する
最近、「テストおたく」の間では、ソース・コードに関するメトリクスの生成にも CI サイクルを利用するようになり、知的な進歩を遂げています。最もよく使われる手法は、カバレッジ・オプションと組み合わせて nosetest テスト・コレクターを実行する方法です。例えば「foo」という名前のプロジェクトがあったとすると、通常は下記を実行します。
nosetests --with-coverage --cover-package=example --cover-html \
--cover-html-dir=example_report.html test_example.py
この結果、カバーされなかったコード行すべてを表示する HTML レポートと、下記のような stdout への出力が生成されます。
リスト 3. nosetest からの出力
nglep% nosetests --with-coverage --cover-package=example --cover-html-dir=example_report.html test_example.py . Name Stmts Exec Cover Missing --------------------------------------- example 2 2 100% ---------------------------------------------------------------------- Ran 1 test in 0.004s OK
example.py と test_example.py は「ダウンロード」セクションからダウンロードすることができます。
コードを修正するたびにこのレポートを実行すると、開発者や管理者はコードの中で実際に起きていることに関するメタデータを得ることができます。これは、なぜ CI と同時にメトリクスを実行することがプロジェクトにとって意味があるかを示す完璧な例です。
コードに関するメタデータを得るための、もう 1 つのメトリクス・ツールが PyMetrics の McCabe レーティングです。今をさかのぼる 1970 年代、Thomas McCabe は、コードに関して単純ながら独創的な観察を行い、コードが複雑であればあるほどコードに問題が起こりやすいことに気が付きました。これは当然に思えるかもしれませんが、残念ながら多くの開発者はその関係に気付いていないようです。PyMetrics コマンドライン・ツールを使うことで、関数当たりのブランチの総数を知ることができます。
通常、作成するメソッドや関数それぞれのブランチの総数を 10 未満に維持する必要があります。人間の脳では、一度に 7 つか 8 つを超える事項を筋道立てて考え続けることは困難だからです。比較の参考として、スコアが 50 を超えるコードは基本的にテスト不能で保守不能です。
私は、本番コードで 140 という高いスコアを見たことがあり、そのコードは非常に質の悪いものでした。つまりそのコードは実際に McCabe の理論を実証していました。こうした複雑で脆弱なコードを開発プロセスの初期に見つけ、フラグを立てておけば、たとえすべてのテストにパスしたとしても、そうしたコードが本番コードに入り込むことはありません。
まとめ
CI の主な利点は、ソフトウェアのビルドとテストの自動化や、ソフトウェア・メトリクスを自動生成するオプションなどにより、品質保証サイクルを効率化できることです。プロジェクトの存続中、こうした自動ビルドはソースが変更されるごとにトリガーされ、瞬時にフィードバックとレポートが返されます。実際、CI が適切に構成されると、コードそのものを作成するプロセスの中に CI が組み込まれるだけではなく、コードを make するプロセスにも CI が組み込まれるようになります。
CI テストに使用できるツールは Buildbot のみではありません。Hudson や Bitten も調べてみる必要があります。これらはどれも、Python によるプラグインを使ってカスタマイズすることができます (ただし Hudson は Python で作成されています)。これらのシステムの詳細については「参考文献」セクションの資料を参照してください。
ダウンロード可能なリソース
- このコンテンツのPDF
- Sample Python scripts (example.zip | 1KB)
関連トピック
- CI (継続的インテグレーション) に関する Martin Fowler の論文を読んでください。
- ウィキペディアには CI テストに関する背景情報が解説されています。
- Twisted のコア・ドキュメントには Twisted フレームワークの概要が解説され、またチュートリアルも用意されています。
- Statement coverage for Python では、Python カバレッジ・モジュールの coverage.py を紹介し、解説しています。
- David Stanek が Python の循環的複雑度 (Cyclomatic Complexity) の測定方法について解説しています。
- 「Using Python to create UNIX command line tools」(developerWorks、2008年3月) は管理者や開発者を対象に Python でコマンドライン・ツールを作成する方法を解説しています。
- 「アジャイル・プランニングの実際」(developerWorks、2009年4月) は実際の経験を基に、皆さんの会社でアジャイル開発作業を行うための助言をしています。
- developerWorks の Linux ゾーンには、ハウツー記事やチュートリアル、ダウンロード、ディスカッション・フォーラムその他、Linux 開発者や管理者のためのリソースが豊富に用意されています。
- Twitter で developerWorks をフォローするか、あるいは developerWorks の Linux ツイートのフィードを購読してください。
- Google Chrome Buildbot のソースを入手してください。
- Buildbot に代わるものとして、Hudson と Bitten を調べてみてください。
- nose テスト・フレームワークに関して学んでください。
- collective.buildbot サイトには、Buildbot の「buildout」レシピが集められています。
- PyMetrics は循環的複雑度 (Cyclomatic Complexity) スコアを生成するためのツールです。
- 皆さんの目的に最適な方法で IBM 製品を評価してください。製品の試用版をダウンロードする方法、オンラインで製品を試す方法、クラウド環境で製品を使う方法、あるいは SOA Sandbox で数時間を費やし、サービス指向アーキテクチャーの効率的な実装方法を学ぶ方法などがあります。