FrontPage  Index  Search  Changes  RSS  Login

[CI] CruiseControl.rb

概要

CruiseControl.rb(CC.rb)は、継続的インテグレーションのツールです。

  1. ダウンロードして展開
  2. プロジェクトを登録(cruise add <name> -u <url>)
  3. CI開始(cruise start)

特徴

  • 10分もあればインストールできるよ。
  • Rubyがあれば動かせるよ(いくつかの依存モジュールはあるけれど)。
  • 他のビルドツールにも対応しているよ。非ゼロを返してくれれば失敗と見なすしね。
  • ウェブベースのダッシュボードは便利で役に立つしきれいなんだ。
  • ビルドが壊れたり直ったりすれば、メールとかIMとかCCTrayとかで通知するよ。
  • プロジェクト別にビルド記録のRSSフィードを用意しているよ。
  • ワンクリックで問題のコードにジャンプできるよ。
  • 特別な設定なしにカスタムビルドの結果を表示するよ。
  • ビルダープラグインで拡張したり、ビルドスケジュールを変更したりとか、簡単に色々出来るよ。
  • オープンソースとかRubyとか、ハックにもってこいだよね。
  • タダ酒のごとくタダだよ。

はじめる

~$ cd ~/tmp
~$ wget http://rubyforge.org/frs/download.php/27495/cruisecontrolrb-1.2.1.tgz
~$ tar xvzf cruisecontrolrb-1.2.1.tgz
~$ cd cruisecontrolrb-1.2.1
~$ ./cruise add koshigoe --url <SVN REPO TRUNK> --username <USERNAME> --password <PASSWORD>
~$ ./cruise start
  • http://localhost:3333/
    • 大抵の実アプリではビルドに失敗するはず
      • 大抵はチェックアウト後に何かしらの環境設定が必要
      • DB作成なり、設定ファイル記述なり、、、
    • Build Logを見れば何が原因で失敗しているのか分かる
      • 適宜、色々直してみる

http://w.koshigoe.jp/study/img/ccrb_sample.png

使い方を探る

基礎

CC.rbは、2つのパートから構成されます。

  • Builder
  • Dashboard

Builderは、一定の間隔でリポジトリへのチェックインを監視するデーモンプロセスです。リポジトリにチェックインされた場合に、Builder以下を行います。

  • 気づく
  • プロジェクトのワーキングコピーを更新する
  • ビルド実行
  • ビルド結果を通知対象に通知する

Dashboardは、各プロジェクトのビルド結果表示やトラブルシューティングの助けとなる、ウェブアプリケーションです。

CC.rbは、以下に依存しています。

  • Ruby 1.8.4か1.8.5
    • 注) 2008/02/21現在のドキュメントには、Ruby1.8.6を使う場合に既知の問題があると書かれています
  • Subversion 1.4以降
  • rubyとsvnがコマンドサーチパスに含まれている(環境変数PATH)

CC.rbには以下の制約があります。

  • 対応するバージョン管理システムはSubversionのみ
  • DashboardとBuilderは同一マシンで動作する

マニュアル

ディレクトリ構成

注) ダウンロードしたアーカイブを展開したディレクトリを[cruise]とします。

  • 各プロジェクトが納められるディレクトリ
    • [cruise]/projects/
  • 各プロジェクトのディレクトリ
    • [cruise]/projects/<project_name>
  • ワーキングコピー(ビルド対象)のディレクトリ
    • [cruise]/projects/<project_name>/work/
  • プロジェクト別のBuilder用設定ファイル
    • [cruise]/projects/<project_name>/cruise_config.rb
  • Dashboardと全てのBuilderの設定ファイル
    • [cruise]/config/site_config.rb

サイト設定

CC.rbは標準で、[cruise]/config/site_config.rb_exampleが用意しています。これをsite_config.rbにリネームして使う事になるでしょう。
通常、この設定ファイルは、通知メール用のSMTP設定くらいにしか使われないでしょう。

各プロジェクトのBuilder設定

先述の通り、各プロジェクトのBuilder設定ファイルは、[cruise]/projects/<project_name>/cruise_config.rbに置かれます。この内容は、コメント文を除けば2行から構成されます。

Project.configure do |project|
end

設定ファイルcruise_config.rb[cruise]/projects/<project_name>/work/に移動させる事も出来ます(これは、つまりCIビルド設定をプロジェクトのリポジトリでバージョン管理できる事を意味します)。ここで、標準の位置とwork/以下の両方に設定ファイルがある場合、CC.rbは両方をロードし、前者の内容を後者で上書きします。

設定ファイルはRubyコードで記述されるので、通常のRubyの機能が利用できます。

Project.configure do |project|
  case project.name
  when 'MyProject.Quick' then project.rake_task = 'test:units'
  when 'MyProject.BigBertha' then project.rake_task = 'cruise:all_tests'
  else raise "Don't know what to build for project #{project.name.inspect}" 
  end
end

デフォルト設定でのビルド

標準で、CC.rbはプロジェクトのRakefileを利用してビルドを行おうとします。もし、cruiseタスクがあるなら、CC.rbはcruiseタスクを実行しようとします。

もし、cuiseタスクが無いなら、標準のRailsタスクに従います。

  1. データベース初期化(rake db:migrate)
  2. 自動テスト(rake test)

ビルドが行う事を変更する

cruiseタスクは素早いビルドを想定しています。もし大量のテストを実行したい様な場合は、cruise_config.rbで、project.rake_taskを設定します。

Project.configure do |project|
  ...
  project.rake_task = 'Big_Bertha_build'
  ...
end

Rake以外でのビルドもサポートしています。例えば、my_build_script.shを実行したい場合は、以下の様にします。

Project.configure do |project|
  ...
  project.build_command = 'my_build_script.sh'
  ...
end

project.build_commandがセットされた場合、CC.rbはそのコマンドを実行する為にCWDを変更し、そのexitコードを監視します。exitコードによって成功か失敗かを判断します。

  • project.rake_taskとproject.build_commandは、両方指定する事は出来ません
気になったヒントの適当訳と原文

同じプロジェクトについて2つのビルドが必要で、それらを同じビルドサーバで実行したい場合、それらは異なるRakeタスクとして扱われるはず。少なくとも、これら2つのビルドについてデータベースを分けたいはず。環境の分割とRakefileの中でRAILS_ENVへの設定を行う事で実現できる。config/environments/testconfig/environments/big_bertha.rbにコピーして、その中でENV['RAILS_ENV'] = 'big_bertha'として':Big_Bertha_initタスクを追加し、依存リストの頭に:Big_Bertha_initタスクを追加し、依存リストの頭に:Big_Bertha_build''を入れます。

Hint: When you have two builds for the same projects, and want to run them on the same build server, it actually takes more than just a different Rake task. At the very least, you want to have separate databases for those two builds. You can achieve this by creating a separate environment and setting RAILS_ENV to it in your Rakefile. Copy config/environments/test.rb to config/environments/big_bertha.rb, add a :Big_Bertha_init Rake task with ENV['RAILS_ENV'] = 'big_bertha' in it, and put it in the beginning of :Big_Bertha_build list of depenedencies.

カスタムビルドの結果についてすべき事

プロジェクトによっては、ビルドページで見たり保存しておきたい出力結果を生み出す、特別なタスクを持っているかもしれません。

CC.rbはビルド実行前に、環境変数CC_BUILD_ARTIFACTSをビルド結果を集めるためのディレクトリとしてセットします。プロジェクトの特別なタスクは、アウトプットをそのディレクトリかそのサブディレクトリ以下に書き出す事を、確実に行ってください。

ビルドページは、ビルド結果のディレクトリで見つけたファイルやサブディレクトリへのリンクを含めます。

ビルドのスケジューリング

標準で、Builderは10秒間隔でSubversionの新リビジョンを確認します。この間隔は、cruise_config.rbで変更できます。

Project.configure do |project|
  ...
  project.scheduler.polling_interval = 5.minutes
  ...
end

スケジューラを変更する事も出来ます。

Project.configure do |project|
  ...
  project.scheduler = MyCustomScheduler.new(project)
  ...
end

すべての初期化とプロジェクトのロード(cruise_config.rbの評価を含む)の後で、Builderはproject.scheduler.runを実行します。Builderは、設定の変更やユーザによるビルド要求を検知する事が出来なくてはならないので、カスタムスケジューラーはそのような状況を察知する方法を知っている必要があります。

スケジューラーに関しては、[cruise]/app/models/polling_scheduler.rbを読むと参考になります。

プロジェクトの削除

Builderのプロセスをkillし、そのプロジェクトのディレクトリ([cruise]/projects/<project name>/)を削除してください。

ビルドの連鎖とトリガー

CC.rbは、プロジェクトをビルドするタイミングを伝えるために、トリガーを使います。各プロジェクトは標準でChangeInSourceControlトリガーを持ち、プロジェクトのソース管理の変更を検知したときにビルドの為に伝えます。

もちろん、追加のトリガーや標準トリガーの置き換えが可能です。例えば、SuccessfulBuildTriggerによってビルドの成功を伝える事ができます。

project.triggered_by SuccessfulBuildTrigger.new(project, 'indie')

短くすると、

project.triggered_by 'indie'

あるビルドに別のトリガーとなって欲しいでしょうか?

project.triggered_by = [SuccessfulBuildTrigger.new(project, "fast_build")]

ソースコードの変化によらないトリガーについて。例えば、軽量テストが通ったときに、重量テストを実行する等。

  • {{fontc('この辺よく分からない', red)}}SecurityError (Insecure: can't intern tainted string): inline plugin

環境変数

  • CC_BUILD_REVISION
    • 現在のビルドのリビジョン番号
  • CC_BUILD_LABEL
    • たいていは、CC_BUILD_REVISIONと同じ
    • 特定リビジョンで複数のビルドが有る場合に、".<N>"なサフィックスがつく(Nは整数)
  • CC_BUILD_ARTIFACTS
    • Dashboardが見るディレクトリ
    • Dashboardからファイルをコピーできる

リモートビルド

CC.rbはリモートサーバでのビルド実行が出来ます。

例えば

project.build_command = 'ssh user@server ./run_remotely.sh $CC_BUILD_REVISION'

run_remotely.sh

#/bin/bash
svn up -r$1
rake test:integration

もちろん、最初のビルドの前にリモートサーバ上でコードをチェックアウトする必要があるでしょう。

クリーンチェックアウトの実行

CC.rbはクリーンシェックアウトをサポートしますが、それは標準ではありません。有効にするためには、cruise_config.rbにSubversionのURLを記述し、いつ実行するかも記述します。

project.source_control = Subversion.new(:url => 
                           'svn://rubyforge.org/var/svn/filesandbox/trunk')
project.do_clean_checkout :every => 6.hours
  • :alwaysや'2.days'、'30.minutes'とかも使える

プラグイン

CC.rbのコアを拡張するために、プラグインを利用できます。

インストールとアンインストール

インストール済みのプラグインは、[cruise]/builder_plugins/installed/にあります。インストールする際には、このディレクトリにプラグインを置き、cruiseを再起動させてください。逆にアンインストールする場合は、削除して下さい。

  • [cruise]/builder_plugins/availableに追加プラグインがあります

プラグインを書く

プラグインはイベントベースで動作します。例えば、以下のようなイベントを監視しています。

  • polling_source_control
  • build_requested
  • build_started
  • build_finished
  • build_broken
  • build_fixed
  • build_loop_failed

完全な一覧は、project.rbを読んでください。

既存プラグインのコードを読めば、その仕組みは一目瞭然でしょう。念のため、ここにサンプルを書いておきます。

class MinimalConsoleLogger
  def initialize(project)
  end

  def build_loop_failed(error)
    puts "Build loop failed" 
    puts "#{error.class}: #{error.message}"...
  end
end

Project.plugin :minimal_console_logger

通知あれこれ

通知方法
  • E-mail
  • CCTray (Windows)
  • CCMenu (OSX)
  • ほか

Seleniumとの連携

GUI環境

Seleniumの実行にはウェブブラウザ(GUI環境)が必要です。POSIXを使っている場合は、Xが必要になるでしょう。

Webサーバ

テスト対象のアプリケーションはウェブサーバででホストされる必要があります。ビルドスクリプトで、まずはウェブサーバを起動し、Seleniumテストを実行し、その後にウェブサーバをシャットダウンします。

Railsアプリケーションでは、Seleniumテストは"Selenium on Rails"で書かれるでしょう。CIのビルドでテストを実行する為に、以下が必要です。

  • mongrel_rails start -d -etest
  • rake test:acceptance
  • mongrel_rails stop

mongrelを使わなかったり、Windowsだったり(-dオプション未サポート)、"Selenium on Rails"を使わない場合は、他の方法を自分で見つけてください。

結果の出力先

Seleniumのレポートを結果出力ディレクトリに吐き出せば、Dashboardから見る事が出来る様になります。"Selenium on Rails"は結果を$RAILS_ROOT/log/seleniumに出力します。cruiseタスクを以下の様にして、このログをビルド結果用のディレクトリにコピーする事が出来るでしょう。

task :cruise do
  out = ENV['CC_BUILD_ARTIFACTS']
  system "mv log/selenium/* #{out}/"
end
Last modified:2008/02/26 23:41:06
Keyword(s):[ci] [テスト]
References: