Xcode Server を導入してみた


# はじめに

Xcode9 から Xcode の標準機能として Xcode Server が導入され、
Xcode 上で CI 環境の構築ができるようになったみたいなので、
Xcode Server を動かせるようになるまでの流れを備忘録として記録しておきます

※以前は [MacOS Server](https://www.apple.com/jp/macos/server/) というアプリと連携して Xcode Server を動かす必要があったようですが
MacOS Server 5.7.1 のリリースに伴い、Xcode 単体で Xcode Server を動かすことができるようになったようです

※どのような処理を行なっているか曖昧なところもあるので、参考にされる際は自己責任でお願いいたします
（証明書関係の設定が変更される場合があります）

# 開発環境
Xcode: 10.1
CocoaPods: 1.5.3

# 導入方法

### Server を起動

1. メニューバーから Xcode -> Preference -> Server & Bots を開く


2. 画面右上のスイッチをクリック
<img width="810" alt="スクリーンショット 2019-01-03 13.58.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/b7956269-4cc2-5c66-42c1-6a7e9341c726.png">


3. Xcode Server を起動するホストを聞かれるので、動かしたいホストを選択
<img width="807" alt="スクリーンショット 2019-01-03 13.58.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/034ee8c3-555b-aea2-86f1-e76a025e40c1.png">



以下のような表示になったら Xcode Server の起動が完了
<img width="809" alt="スクリーンショット 2019-01-03 14.05.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/10c85406-e988-294f-d216-45bd91582d13.png">




### Xcode Server アカウントを追加

1. メニューバーから Xcode -> Preference -> Accounts を開く

2. 左下の + ボタンから Xcode Server を選択
<img width="813" alt="スクリーンショット 2019-01-03 14.13.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/1051dc42-2d14-1837-dd7f-b2499b74aa85.png">


3. Xcode Server を起動する端末を選択
<img width="809" alt="スクリーンショット 2019-01-03 14.13.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/82d2080d-53ac-a83b-9cd7-73be06f7fbd1.png">

4. 端末へログインするためのアカウント名、パスワードを入力
<img width="810" alt="スクリーンショット 2019-01-03 14.13.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/817a3938-9ef9-7dc0-58bd-884a7667aea8.png">


5. Server の追加が完了すると、Accounts ページに Xcode Server 用のアカウントが追加される
<img width="806" alt="スクリーンショット 2019-01-03 14.14.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/ada6f6d8-edf3-df59-4e03-662a5238291f.png">



### Bot を追加
1. メニューバーから Product -> Create Bot を開く
2. Bot 名と Bot を動かすサーバを聞かれるので、1つ上の手順で作成した Xcode Server アカウントを指定
<img width="737" alt="スクリーンショット 2019-01-03 14.31.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/fe4d00a1-57db-5797-f06a-118812753866.png">

3. Git との連携を行う
<img width="738" alt="スクリーンショット 2019-01-03 14.40.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/41b35ea1-35d0-aa7f-b7af-c4d011ff0e11.png">
この画面で `Sign in` と表示されている場合は Git との連携が完了していないので、
`Sign in` をクリックし、Git との連携を行なってください

4. Bot の処理を設定
<img width="739" alt="スクリーンショット 2019-01-03 14.35.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/d1e633a6-d1f1-ba0a-b33f-a321057fe7b8.png">
今回はテストコードを動かすことが目的なので、 `Test` の部分のみチェックを入れています
`Test` のところの `Language` 、 `Region` を設定することで、ビルド時のローカライズ言語等を設定できるようです

5. Bot を動かすタイミングを設定
<img width="736" alt="スクリーンショット 2019-01-03 14.35.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/00735a1a-8862-76d1-89be-c271f885df9d.png">
 - Integrate: どのタイミングで Bot を動かすか
 - Clean: 過去のビルド情報をどれぐらいの期間で削除するか

※ちなみに、`On Commit` を選択すると、リモートの `master` ブランチにコミットされたタイミングで Bot が動き出すようになります
`master` ブランチへのコミットが Bot の動き出すトリガーになっている要因は、手順3のところで `master` ブランチをターゲットに指定していることっぽいです<br><br>
6. テストをする環境を選択
<img width="735" alt="スクリーンショット 2019-01-03 14.36.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/3368b936-3673-68be-fe06-94b29c3e97a8.png">
`All iOS Devices and All Simulators` や `All iOS Devices` 等を選択できますが、ここでは `Specific iOS Devices and Simulators` を選択しています
これを選択することで、特定のバージョン、端末を指定してのテストが可能です<br><br>
7. Provisioning を設定
<img width="739" alt="スクリーンショット 2019-01-03 14.36.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/0aaa9419-fd21-ffa0-afcb-e0402b8ce7ac.png"><br>
8. 環境変数を設定
<img width="738" alt="スクリーンショット 2019-01-03 14.36.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/80ae92a8-6b13-25a4-ae67-f14cd46820b6.png">
アプリをビルドするために環境変数を使用する必要がある場合はこちらに定義を追加してください<br><br>
9. Bot の実行前、実行後等のタイミングで行いたい処理を設定
<img width="737" alt="スクリーンショット 2019-01-03 14.36.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/3173abb6-5202-c513-092c-251a1a1bb963.png">
この部分は比較的使用頻度が高そうな印象です
Bot が動く前、動いた後に実行したいシェルスクリプトを追加することができます
新しいエラーが発生した場合にメールで通知してくれるような機能があるのですが、その送信先もここから設定可能です
Xcode Server を動かすだけなら、ひとまず何も設定しなくて大丈夫です


# 動かし方
上記の手順9で `Create` をクリック後に自動で Bot が動き、テストを行ってくれるかと思います

手動で実行したい場合は以下ので順で実行できます
 1. ナビゲーターバーのレポートナビゲータを選択
 2. Bot を選択
 3. 右上の `Integrate` をクリック
<img width="1017" alt="スクリーンショット 2019-01-03 15.20.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/535a1a6b-6799-b5cf-af7b-6d8f84c89d26.png">



Bot の設定を変更したい場合は、先ほどの `Integrate` ボタン横の `Edit Bot` から編集可能です
<img width="1017" alt="スクリーンショット 2019-01-03 15.20.19 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/1ad02243-98bd-02da-cb96-3599836f8b92.png">



# つまずいたところ

Xcode Server 導入時に個人的につまずいたところも記載しておきます

## 1, エラー内容の詳細を確認したい！
Bot 実行時にエラー内容が表示されるのですが、その内容が切れてしまっていたり、どんなエラーなのかわからなかったりして詳細を確認したい場合があります

その場合は、以下のような手順でログを確認できます
1. エラー内容を確認したい `Integrate` を選択
2. 上バーの `Integrate()` をクリック
3. 表示されるメニューから `Logs` をクリック
<img width="1096" alt="スクリーンショット 2019-01-03 15.29.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/a4430071-e15f-230c-53e7-e702e8ecf750.png">
4. 確認したいログを選択する
<img width="754" alt="スクリーンショット 2019-01-03 15.30.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/8bd50712-c324-44ec-5d0c-8658f6c33a1f.png">



また、 `Configure bot trigger` に追加したシェルスクリプトのログを確認したい場合、上記の手順4に `Pre-Integration Script` 等の項目が追加されているので、そこから確認可能です



## 2, 後から CocoaPods を導入し、Xcode Server を動かすとエラーが表示される！
初めは ライブラリ等を使用せずに実装しており、後から CocoaPods を導入し、ライブラリを使用し始めた際に Bot がこけてしまっていました

ビルド対象が `.xcworkspace` ではなく、 `.xcodeproj` になってしまっていることが原因だったようです

1. Bot を動かしたいプロジェクトを `.xcworkspace` で開き、Bot を選択する
2. `Edit bot` を選択
3. アラートが表示されるが、`edit` を選択
<img width="1013" alt="スクリーンショット 2019-01-03 15.49.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/2289f366-52f4-3ed2-f79a-95f7ce064e07.png">
4. `Repository` タブを開き、`Replace Workspace and Repositories` をクリック
<img width="737" alt="スクリーンショット 2019-01-03 15.47.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/c07cbe1f-efe8-17d6-24f7-2bb4c46ac5d4.png">
5. `.xcodeproj` になっていた部分が `.xcworkspace` に置き換わったら完了
<img width="740" alt="スクリーンショット 2019-01-03 15.53.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/42cba3d9-141f-1297-5de2-14913b25c1c6.png">




## 3, CocoaPods を使用したプロジェクトで Xcode Server を動かすとエラーが表示される！
この部分が一番悩みました
エラー内容は以下です

```
Bot Issue for TestXcodeServer Bot (error)
Integration #2 of TestXcodeServer Bot on [サーバ名]
Open Integration in Xcode: xcbot://[ユーザ名]/botID/78652e5d0a874216b90ff4a0ed000d64/integrationID/78652e5d0a874216b90ff4a0ed006924
Error: /Users/[ユーザ名]/Library/Caches/XCSBuilder/Bots/78652e5d0a874216b90ff4a0ed000d64/Source/TestXcodeServer/Pods/Target Support Files/Pods-TestXcodeServer/Pods-TestXcodeServer.debug.xcconfig: unable to open file (in target "TestXcodeServer" in project "TestXcodeServer") (in target 'TestXcodeServer')
```

私は CocoaPods の `Pod` ディレクトリを Git の管理下に設定しておらず、 `git clone` をした人が自分で `pod install` をする想定の作りをしていました
そのため、Bot が動く前のタイミングで `pod install` を呼ぶようなシェルスクリプトを追加する必要があるようです

1. `Edit bot` をクリック
2. `Triggers` タブを開く
3. 左下の + ボタンから `Pre-Integration Script` を選択
<img width="737" alt="スクリーンショット 2019-01-03 16.00.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/97c70a9f-ab40-0f8f-39a6-6e9133a8e90b.png">

4. 適当な名前を付け、以下のようにスクリプトを追記

```sh
#!/bin/sh
export LANG=en_US.UTF-8

cd "${XCS_PRIMARY_REPO_DIR}"

/usr/local/bin/pod install
```
 - `export LANG=en_US.UTF-8` を入れているのは、文字コードの指定を促すようなアラートがログに表示されていたため追加しています
 - `/usr/local/bin/pod install` とフルパスで記述しているのは、`pod install` だけだと `command not found` と表示されてしまい、`pod install` が実行できなかったのでフルパスで記述しています

※このシェルスクリプトのログは `Pre-Integration Triggers` を追加した場合は項目が増えているので、そこから確認可能です
<img width="745" alt="スクリーンショット 2019-01-03 16.11.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/53717/9225f222-92b0-b6b8-2283-1975faaaba98.png">


これで Bot が動き出す前に `pod install` を実行できるようになり、CocoaPods を使用したプロジェクトも Bot を動かすことができるようになりました！

## 4, リモートに Push しても自動で Bot が動いてくれない！

Bot が動くタイミングを OnCommit にしていたのですが、リモートブランチに Push したにも関わらず、Bot が動いてくれなくて悩みました

この原因は、Bot で設定しているターゲットブランチと最後に Integrate したブランチが異なっているためだと思われます
Bot の Repositories を変更した場合は一度手動で Integrate を実行してあげることで、ターゲットブランチへの Commit を検知して自動で Bot が動いてくれるようになるかと思います！




# 終わりに
現在はテストコードの実行ぐらいで終わってしまっているので、今後は「テストコードが通ったらアーカイブして配布」ぐらいにまで発展していく予定です


# 参考
- [Xcode 9の Bot で pod install する方法](https://qiita.com/da1ssk/items/4def67c09b5d15692dee)
- [Xcode Server で iOS アプリの自動ビルド環境を作ってみた](https://qiita.com/magicant/items/e63e67f40a089d049ef5)