Xcode Server で iOS アプリの自動ビルド環境を作ってみた

[OS X Server](http://www.apple.com/jp/osx/server/) に含まれてる Xcode Server を使って iOS アプリの自動ビルド環境を作ってみた。

# 概要

- 環境
 - MacBook Pro Mid 2014
 - OS X 10.11.1
 - OS X Server 5.0.15
 - Xcode 7.1.1
 - ビルド対象は、うちの会社で作ってる某 iOS 向けアプリ
- できたこと:
 - GitHub に誰かがコミットをプッシュしたら、自動的にコミットをプルし、アプリをビルドし、アナライズし、インストール済の全てのシミュレーターでそれぞれユニットテストを実行し、アーカイブし、結果 (エラーや警告の件数・内容) をメールで送信する
 - 結果を Xcode 上で確認する
 - Xcode が自動生成するウェブページ上で結果の概要を確認する
- できそうだけど試してないこと:
 - パスフレーズ無しの秘密鍵で認証する SSH 接続以外の方法での GitHub からのプル
 - Git サブモジュールや CocoaPods や Carthage を使っているプロジェクトのビルド
 - 実機での自動テスト
 - ユニットテスト実行時の網羅率の計測

# 設定手順

まずは App Store で OS X Server を購入。2400 円だった。

Xcode と OS X Server をダウンロード・インストールしたら、設定開始。Server アプリを起動して、「この Mac」に接続し、ホスト名とかの基本的な設定を済ませる。

あまり覚えてないけど最初にユーザの設定もした気がする。自分のユーザアカウントをサーバーの管理者として登録しておく。これは Xcode Server に他のマシンからアクセスするときの認証に使う。

<img width="1031" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/918c5886-2565-c732-0b03-32a77dddce5a.png">

(ホスト名とか隠す意味ないと思うけど一応画像を一部加工してます)

また、初期設定時にオレオレ証明書を作らされるが、これはサーバーに HTTPS で接続するとき使う。

## Xcode Server

Xcode 設定画面で右上のスイッチを入にすると裏で Xcode Server が動き出す。

アクセス権・ビルドに使用する Xcode・チームを設定する。

<img width="1032" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/d6426c40-d447-c25f-2661-1be27875b2eb.png">

Xcode Server には Git レポジトリーをホストする機能もあるが、うちでは GitHub を使ってるので無視。

実際にアプリをビルドするための設定はこことは別に行う。

## メールサーバー

ビルド結果をメールで通知するためには、そのマシンからメールを送信できる様にしておかないといけない。OS X Server に入ってるメールサーバー機能を使うのが楽。メール設定画面右上のスイッチを入にすると裏で postfix が動き出す。

<img width="1031" alt="mailsetting.png" src="https://qiita-image-store.s3.amazonaws.com/0/38244/3876b311-3195-ea5e-d656-fea83c69c67e.png">

今回は、社内ネットワークにある別の SMTP サーバーに送信を委譲する。「ISP を経由して送信メールのリレー」設定を有効にして委譲先サーバー名を指定する。

「ドメイン」が一つも指定されてないと適当にそれっぽいドメイン名が仮定されてしまうので、(実際に OS X Server でメールアカウントを提供することはしないにしても) ダミーのドメイン名を入れておく。仮定されたドメイン名がもし実在のドメイン名とかぶると、そのドメインへのメールを OS X Server は自分宛のメールと勘違いしてリレーしなくなってしまうのだ。

## Bot の作成

一つのアプリに対する自動ビルドの設定のことを、Xcode Server では Bot というらしい。

Bot の設定は Server ではなく Xcode から行う。Xcode を使うのは必ずしもサーバーと同じマシンでなくて良い。普段開発作業に使ってるマシンで Xcode を起動し、環境設定を開く。Accounts タブの左下の + を押して、Add Server でサーバーを設定に追加する。

Xcode で普段通りプロジェクトを開いたら、Report navigator を開く (⌘8)。左下の歯車から Create Bot で Bot を作成する。その後は Edit Bot ボタンを押すと Bot の設定を変更できる。

一つの Bot は一つの Scheme に対してビルドやテストやアーカイブを行う。一つのプロジェクトに複数の Scheme があるならその数だけ Bot を作ることになる。

<img width="709" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/eb133ce2-f350-5a40-8d75-246190f68170.png">

ビルドの前後にシェルスクリプトを実行する機能があるが、結局使ってない。
通知メールの送信先として Send to all committers が指定できるのだが、有効な使い道がなさげ。(過去にプロジェクトに関わった全ての人にメールが行くと思われる)

<img width="710" alt="triggerssetting.png" src="https://qiita-image-store.s3.amazonaws.com/0/38244/de7a26f8-ab79-5dc1-92e3-3a6a6e1efac9.png">

(画面に収まらない項目を画像一枚に収めるために画像を加工した。製品名を隠す意味もあまりないと思うが一応隠しておく)

なおビルドが失敗するとテストは実行されないし、テストが失敗するとアーカイブは行われない。

# ビルド結果を見てみる

## Xcode で

Bot が作業を行うと Report navigator の下の方に結果が表示される。ビルド・テスト・アーカイブ等の一連の作業のまとまりは Integrate と呼ばれる。

<img width="279" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/060e3716-5394-fba9-f9c8-246259e99226.png">

Report navigator で Bot を選択すると Integrate 結果の統計がエディタ部分に表示される[^unsound]。

[^unsound]: ご覧の通り、警告出まくり & テスト少なすぎの不健全プロジェクトです……

<img width="920" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/2aeed490-8600-f95d-0bf2-a658d2a3fc1f.png">

特定の Integrate を選択すると、その Integrate に関する詳しい結果がわかる。そこから ipa や xcarchive をダウンロードすることもできる。

<img width="918" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/a216198a-e229-78fe-f0f9-8b52f365068e.png">

テスト結果も表で一目瞭然。なおこの画面内でテストケースを選択するとそのテストケースのコードに飛べる。

<img width="731" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/38244/b1b41d3a-ca97-df80-1269-15e48757110f.png">

網羅率 (coverage) の取得は(まだ)やってない[^coveragecrash]。

[^coveragecrash]: なお Coverage のタブを開こうとすると Xcode が落ちる……

## ブラウザで

実はサーバーマシン上ではいつの間にか HTTP サーバーが起動してて、サーバーにブラウザでアクセスすると Bot のビルド結果が表示される……のだが、HTTPS の使用を強制されるので、アクセスする人全員にサーバーのオレオレ証明書を受け入れるようお願いする必要がある[^certificate]。

[^certificate]: 正式な証明書を設定することもできるけど、たかが社内で使うビルドサーバーにわざわざそこまでしないっしょ

ブラウザ上で見られる情報は Xcode で見られるものよりかなり限られており、警告やテストの件数くらいしかわからない。
あと、ブラウザで ipa や xcarchive をダウンロードすることができる。

全画面表示 ("Big Screen")[^bigscreensupport] にすると警告数等がよりカッコよく表示されるので、余ってるディスプレイがあるなら部屋の中に常時表示させておくと今時のクールな IT 企業の雰囲気を演出できる。

[^bigscreensupport]: Safari と Chrome しかサポートしてない模様

# Tips・所感

xcodebuild の難解なコマンドラインを叩いたり [xcpretty](https://github.com/supermarin/xcpretty) とかで出力を整形したりといった面倒がない点では、[Jenkins](https://jenkins-ci.org/) にジョブを設定するより楽。しかし Xcode (Server) の吐く結果の形式を変更したり他の自動化システムと連携させたりするのは難しそう。

Bot を作るには、アプリをビルドするための Scheme が共有化されてレポジトリーにコミットされてないといけない。開発者間でビルド方法を統一するためにも、(もし Xcode Server を使わないにしても) Scheme は共有化しておいたほうが良いと思う。

全部のシミュレーターに対してまとめてテストを実行できるので便利。しかしシミュレーターを変えるごとにビルドし直しているらしく、割と時間がかかる。ビルド前に毎回クリーンする設定を切るとマシになる。

メインスレッド上で動くユニットテストを実行するといくつかのテストケースが "Stall on main thread" というエラーで失敗することが多かった。`waitForExpectationsWithTimeout:handler:` に指定するタイムアウトを 5 秒から 30 秒に長くしたらおさまった。

On commit でビルドするように設定したまま対象ブランチを GitHub から消すと、延々と Integration が発行され続ける模様。微妙にアホの子やね。

ビルドの前後にトリガーとしてシェルスクリプトを走らせることができるが、Xcode が GitHub からブランチをプルしてくる時に使ったはずの認証情報が使い回せなかったりしてやや不便。なおスクリプトはクローンした Git レポジトリー直下ではなくその一つ外側のディレクトリーから始まるので、最初に `cd` しないといけない。

OS X Server は App Store で購入するが、ソフトウェア使用許諾契約によると 1 ライセンスにつき 1 台の Mac でしか使ってはいけない模様 (一つの OS X Server インスタンスを複数人で共用する場合)。

OS X Server には Xcode の自動ビルド以外にも HTTP サーバーとかディレクトリーサービスとかいろんな機能がくっついてくる。今回は使わなかったけど。

社内ネットワークからインターネットに出るためのプロクシの設定を解除しないと、開発用マシンからサーバーに接続できなかった。ネットワーク環境によってはもっとめんどくさいことになるのかもしれない。

----

この記事は [ACCESS Advent Calendar 2015](http://qiita.com/advent-calendar/2015/access) の 2 日目の記事です。明日は @aKenjiKato さんが GStreamer の話をします。