JenkinsでiOSアプリ開発の細々した作業を自動化する(その1 〜 Git → GHUnit → ビルド)
はじめに
サーバーサイドやWeb画面の開発では使われていましたが、ネイティブアプリ開発でJenkinsの導入が無かったため、今更ながら設定してみました。自動化って楽しいです。iOSのネイティブアプリ開発でJenkinsでGitリポジトリから取得し、GHUnit、ビルド、TestFlightで配信、HipChatに通知する環境を構築します。
今回はGitからソースの取得 〜 GHUnitでのUnitTest 〜 アプリのビルドまでです。
ビルドにはXcodeのコマンドラインツールが動作する環境が必要なのでMacが必要です。
流れ
- Gitリポジトリからソースファイルを取得(Jenkins GIT client plugin, Jenkins GIT plugin)
- GHunitでUnitTest(Xcode integration)
- ビルド(Xcode integration)
- TestFlightで配布(Testflight Plugin)
- HipChatで結果を通知(Jenkins HipChat Plugin)
現在の環境
- Mac
- Mini Mid 2010
- OS
- 10.8.3(Mountain Lion)
- Xcode
- 4.6.2
- Jenkins
- 1.517
Jenkins Plugins
- Git Client Plugin
- 1.0.6
- Jenkins GIT plugin
- 1.4.0
- Jenkins HipChat Plugin
- 0.1.4
- Xcode integration
- 1.3.3
- Testflight Plugin
- 1.3.8
各プラグインは Jenkinsの管理 → プラグインの管理 からインストールします
Git周りの設定
ソースコード管理
Git リポジトリの場所と対象のブランチを設定します。
ビルド・トリガ
フックしてビルドしたいところですが、社外Gitリポジトリを参照しているため、1分間に1回のポーリングとします。
GHUnitの設定
コマンドラインからの実行
最終的にJnkinsからShellの実行をするので、まずはコマンドラインからGHUnitを実行できるように設定します。
GHUnit guide_command_line Documentを参考にRunTests.shとRunIPhoneSecurityd.shをxcodeprojのある場所に置きMakefileを作成します。
ここはハマりハマり進んだのですが、そのままの状態だと
Warning: CFFIXED_USER_HOME is not set! It should be set to the simulated home directory.
というWarningが出るので、RunTests.shの11〜16行目をコメントアウトします。
もう一つiphonesimulatorが6.0以上を使用されている場合に
Unknown Device Type. Using UIUserInterfaceIdiomPad based on screen size
というメッセージが出て動作しません。iphonesimulator5.1を指定している場合は動作しますが、デフォルトやiphonesimulator6.0以上を指定している場合はこのメッセージが出てテストが実行されない為、iphonesimulator6.0以上でテストを実行する場合は、以下のようにmain.mを編集することで動作します。
ソースはここから引用しています
// main.m #import <UIKit/UIKit.h> #import "GHUnitIOS/GHUnit.h" @interface MyUIApp : UIApplication @end @implementation MyUIApp - (id)init { self = [super init]; if (self && getenv("GHUNIT_CLI") && [[[UIDevice currentDevice] systemVersion] doubleValue] >= 6.0) { __block BOOL done = NO; NSOperationQueue * queue = [[ NSOperationQueue alloc ] init ]; [queue addOperationWithBlock:^{ int status = [GHTestRunner run]; if (status != 0) { NSString *reason = [NSString stringWithFormat:@"failed to test %d", status]; @throw [NSException exceptionWithName:@"TestFailure" reason:reason userInfo:nil]; } done = YES; }]; while( !done ) { [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 5] ]; } } return self; } @end int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, @"MyUIApp", @"GHUnitIPhoneAppDelegate"); } }
make test
で成功すればコマンドラインからの実行はOKです。
Jenkinsの設定
ビルド - シェルの実行
make clean && WRITE_JUNIT_XML=YES JUNIT_XML_DIR=tmp/test-results make test
clean と build をしてテスト結果を tmp/test-results に吐き出します。
ビルド後の処理 - JUnit テスト結果の集計
テスト結果の場所を設定します。
これで、ビルド実行すれば動作するはずですが、
xcodebuild: error: The workspace 'workspace_name' does not contain a scheme named 'test_target_name'.
とメッセージを出して失敗する場合があります。その場合は以下のようにテストターゲットのSharedのチェックを入れてあげれば解決します。
Xcodeでのビルドの設定
iOSのビルドに関しては↓でまとまっているのでそちらを参照してください。
@IT JenkinsでCIすればiOSアプリのビルドは、もう面倒くさくない (1/2)
設定後のキャプチャだけ貼ります。
まとめ
なんとか環境が作れました。GHunitの導入が現状だと正直テストを最初に作るのも、設定するのも手作業の部分が多くて導入しずらい感じがしています。Jenkins向けの設定は1度作ってしまえばしばらくは使えそうですが、iOSやXcodeのUpdateの時に対応できるのかに不安を感じました。ただ、Git pushでテストしてビルドしてくれるって素敵ですね。
次回はTestFlightとHipChatの設定をします。
参考
mtgto's diary - CocoaPodsでGHUnit + OCMockなiOS開発環境を構築する
guide_command_line-template.markdown - GitHub
Jenkins + GHUnit - launch_msg error - KISS