iOSアプリをGitリモートへのプッシュからJenkinsでビルドをしてDeployGateにアップロードをしてSlackに結果を通知してみた！

## はじめに

スマートテック・ベンチャーズ Advent Calendar 23日目担当の @nnsnodnb です。

今回は、ビルド動作を自動化しようというものです。
GitHubにプッシュ操作(masterなどにPRマージなども含む)・Jenkinsなどの設定をしてからの動作です。プッシュは手動でお願いします。

## お品書き

1. Jenkins設定
2. DeployGateアカウント取得・設定
3. Slack設定
4. UltraHook設定
5. GitHub HookにてJenkinsに通知
6. GitHubにプッシュ
7. JenkinsでiOSアプリをビルド・アーカイブ
8. DeployGateにアップロード
9. DeployGateから通知

## 環境

- OSX 10.11.6
- Xcode 8.x
- Jenkins 2.36
- Homebrew 1.1.4

## Jenkins設定

HomebrewからJenkinsおじさんをインストールしていきます。

### Homebrewインストール

```bash
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

### Jenkinsおじさんインストール

```bash
$ brew install jenkins
$ jenkins
```

あとはちょっと他のMac環境が手元にないのでターミナル等の指示に従ってインストールしてくださればと思います。

[CIの勉強始めにMacにJenkinsを導入](http://qiita.com/MilanistaDev/items/900887b256dad1398914)

上記記事がとても詳しく書かれていると思います。

私の場合は、ちょっと前のJenkins環境がなぜか残っていてほげほげしてしまったので、 https://jenkins.io/ からダウンロードしてインストールしました。

http://127.0.0.1:8080 にアクセスしてJenkinsおじさんのセットアップ画面がでてきたらOKです。
プラグイン等は `Install suggested plugins` を選んでおけばOKです。

### プラグインインストール

`Jenkinsの管理`　-> `プラグインの管理` -> `利用可能`

GitHub関連のプラグインをインストール

Xcodeのプラグインもあるんですが、ぶっちゃけ意味ワカンネ状態になってしまったので、今回はパスです。
`Slack Notification Plugin` は入れておきます。

### ジョブの追加

Jenkinsトップ画面の `新規ジョブ作成` 

1. ジョブの名前を入力
2. `フリースタイル・プロジェクトのビルド`
3. OK


![スクリーンショット 2016-12-22 17.14.20.png](https://qiita-image-store.s3.amazonaws.com/0/97280/27fa1f1c-09de-78a8-b047-63d603d703b4.png "スクリーンショット 2016-12-22 17.14.20.png")

次はジョブの設定
今回はSampleとしてジョブを追加しました。

GitHub projectにチェックを入れてリポジトリのURLを入力

![スクリーンショット 2016-12-22 17.16.56.png](https://qiita-image-store.s3.amazonaws.com/0/97280/327bdfc1-7d77-f763-cc11-036dacd2de76.png "スクリーンショット 2016-12-22 17.16.56.png")

`ソースコード管理` まで選ぶ必要はあるかはわかりませんが、とりあえず

![スクリーンショット 2016-12-22 17.18.48.png](https://qiita-image-store.s3.amazonaws.com/0/97280/47d660ca-f9f2-c79b-6860-5bb17c2f2df7.png "スクリーンショット 2016-12-22 17.18.48.png")

プライベートリポジトリの場合は上記2つともで高度な設定や `Credentials` などの設定が必要になります。

`ビルド・トリガ` は今回はmasterにプッシュされたときのみにしておきます。

`Build when a change is pushed to GitHub`

![スクリーンショット 2016-12-22 17.20.37.png](https://qiita-image-store.s3.amazonaws.com/0/97280/cd000aee-6cb9-a713-3c61-01ecd5eef9b0.png "スクリーンショット 2016-12-22 17.20.37.png")

ビルド環境もチェック

![スクリーンショット 2016-12-22 17.21.51.png](https://qiita-image-store.s3.amazonaws.com/0/97280/38f7b924-9bf8-3fbd-7659-6ba35d655d7c.png "スクリーンショット 2016-12-22 17.21.51.png")

今回はビルドするのにシェルスクリプトを実行するのでとりあえずこんな感じDeployGateのAPIキーなどはあとで各自設定お願いします。

![スクリーンショット 2016-12-22 17.26.51.png](https://qiita-image-store.s3.amazonaws.com/0/97280/5155cb87-0623-3ebd-07f6-286dc7e57640.png "スクリーンショット 2016-12-22 17.26.51.png")

```bash
cd ${WORKSPACE}
export DG_USER="username"
export DG_API_KEY="API_KEY"
sh jenkins_build.sh
```

ビルド後の処理は `成果物を保存` 及び `Slack Notifications` を設定しておきます。

![スクリーンショット 2016-12-22 17.29.04.png](https://qiita-image-store.s3.amazonaws.com/0/97280/3c88a662-8beb-4eef-e23f-adeb992f88f7.png "スクリーンショット 2016-12-22 17.29.04.png")

とりあえずJenkins側の操作は一旦終わりです。
まだ行ったり来たりするのでJenkinsは落とさないようにしましょう

## DeployGateアカウント取得・設定

https://deploygate.com/users/signup

ここからサインインしておきましょう！

https://deploygate.com/settings

に行って、下の方に `API key` があるのでコピーしておきます。

![スクリーンショット_2016-12-22_17_32_27.png](https://qiita-image-store.s3.amazonaws.com/0/97280/d680a9df-edbb-b526-1dd6-5727ef4c68c3.png "スクリーンショット_2016-12-22_17_32_27.png")

先程のJenkinsでジョブを設定したときにビルドの設定をした画面を開きます。
シェルスクリプトっぽいやつを書いたところです。
あそこの `DG_USER` と `DG_API_KEY` が埋められます。
DeployGateのユーザ名と先ほどコピーした `API key` を入力します。

## Slack設定

チームは作ってある前提

![スクリーンショット_2016-12-22_17_41_37.png](https://qiita-image-store.s3.amazonaws.com/0/97280/74341d56-d6b3-436e-9d8b-519f0eac223e.png "スクリーンショット_2016-12-22_17_41_37.png")

完全に個人使用のものですが、一応モザイク処理しています。ご了承ください。

![スクリーンショット 2016-12-22 17.43.31.png](https://qiita-image-store.s3.amazonaws.com/0/97280/6eb13d53-4e32-11a3-bf9b-b17f171a6015.png "スクリーンショット 2016-12-22 17.43.31.png")

`Jenkins CI` を選びます。
`Add Configuration` を押すと諸々設定画面がでます。

- Post Channelは各自のSlackのプロジェクトのチャンネル

Slack Notificationsプラグインはすでにさっき入れたのでStep3までスキップします。

Jenkins側で `Jenkinsの管理` -> `システムの設定` -> `Global Slack Notifier Settings` で指示に従ってToken等を入力

![スクリーンショット_2016-12-22_17_47_39.png](https://qiita-image-store.s3.amazonaws.com/0/97280/3c0101e1-7d39-5c31-5b46-45a564871268.png "スクリーンショット_2016-12-22_17_47_39.png")

一応 `Test Connection` をしておくといいかと思います。

![スクリーンショット_2016-12-22_17_49_27.png](https://qiita-image-store.s3.amazonaws.com/0/97280/f49cbe57-cf5f-1091-8392-7570ee759dcd.png "スクリーンショット_2016-12-22_17_49_27.png")

こんな感じに通知が飛んで来るはずです。

## UltraHook設定

今回はローカルで操作しているMacのJenkinsでビルドするためGitHubから http://127.0.0.1:8080 へのHookなどは物理的にも無理ということで `UltraHook` というものを使用します。

http://www.ultrahook.com/

ユーザ登録をするとAPI KEYが発行されます。

![スクリーンショット_2016-12-22_17_52_20.png](https://qiita-image-store.s3.amazonaws.com/0/97280/752f4d40-8321-800b-c444-bf5c9bcf02e8.png "スクリーンショット_2016-12-22_17_52_20.png")

```bash
$ gem install ultrahook
$ ultrahook stripe 8080
```

ちなみに

```bash
curl http://stripe.hoge.ultrahook.com -X POST -d 'key=value'
```

みたいにすると確認ができます。

今回はJenkinsのデフォルトで使用している8080ポートにHookしたいので8080を選択しています。

## GitHub HookにてJenkinsに通知

`GitHubのリポジトリ設定画面` -> `Integration & services` -> `Add service` -> `Jenkins (GitHub plugin)` を選択
先程 `UtlraHook` コマンドを実行してきたときにでてきたURLを設定

![スクリーンショット_2016-12-22_17_58_59.png](https://qiita-image-store.s3.amazonaws.com/0/97280/2bb962e2-fc06-0054-17a3-1274ce32772e.png "スクリーンショット_2016-12-22_17_58_59.png")

## GitHubにプッシュ

masterに向けてプッシュしてみます。

![スクリーンショット_2016-12-22_18_06_47.png](https://qiita-image-store.s3.amazonaws.com/0/97280/e09440e5-6f49-6514-0e4d-a401d256896a.png "スクリーンショット_2016-12-22_18_06_47.png")

こんな感じにHookが来ていることがわかりました。
あとJenkins側も動作していることを確認しましょう！

リポジトリの構成によってはビルドは失敗しているかと思います。仕方ありません。説明していませんもの...

```
├── project
│   ├── project
│   ├── project.xcodeproj
│   ├── project.xcworkspace
│   ├── hogehoge
│   └── Pods
├── .gitignore
├── ProvisioningProfile.mobileprovision
└── jenkins_build.sh
```

## JenkinsでiOSアプリをビルド・アーカイブ
## DeployGateにアップロード

この2つに関しては一気に説明します。
説明というよりシェルスクリプトを置くだけですが...

```bash
#!/bin/sh

#### Set On Jenkins ###

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
WORKSPACE=`pwd`

SCHEME=project
CONFIGURATION=Debug # Debug, Release and so on

PROVISIONING_NAME=ProvisioningProfile
IPA_FILE_NAME=develop-adhoc.ipa
iOS_SDK=iphoneos

# Get the ProvisioningProfile UUID
echo "************** Get the ProvisioningProfile UUID ***************"
KEYCHAIN=${HOME}/Library/Keychains/login.keychain
security cms -D -k ${KEYCHAIN} -i ${PROVISIONING_NAME}.mobileprovision > mobileprovision
plutil -extract 'UUID' xml1 mobileprovision
MPNAME=`/usr/libexec/PlistBuddy -c "Print $UUID" mobileprovision`
rm mobileprovision

# Install ProvisioningProfile
cp ${PROVISIONING_NAME}.mobileprovision ${HOME}/Library/MobileDevice/Provisioning\ Profiles/${MPNAME}.mobileprovision
PROVISIONING_PATH=\"${HOME}/Library/MobileDevice/Provisioning\ Profiles/${MPNAME}.mobileprovision\"
echo $PROVISIONING_PATH

# Unlock keychain
echo "************** Unlock keychain ****************"
/usr/bin/security default-keychain -d user -s ${KEYCHAIN}
/usr/bin/security unlock-keychain -p user ${KEYCHAIN}
/usr/bin/security find-identity -p codesigning -v

# Build project
echo "************** Build project ****************"
BUILD_DIR=${WORKSPACE}/build
/usr/bin/xcodebuild -scheme ${SCHEME} -workspace ${WORKSPACE}/project/project.xcworkspace -sdk ${iOS_SDK} -configuration ${CONFIGURATION} clean build CODE_SIGN_IDENTITY="iPhone Developer" PROVISIONING_PROFILE=${MPNAME} CONFIGURATION_BUILD_DIR=${BUILD_DIR}

# Create ipa
echo "************** Create ipa file ****************"
IPA_FILE=${BUILD_DIR}/${IPA_FILE_NAME}
/usr/bin/xcrun -sdk ${iOS_SDK} PackageApplication -v ${BUILD_DIR}/${SCHEME}.app -o ${IPA_FILE} --embed ${PROVISIONING_PATH}

# Upload to DeployGate
echo "************** Upload ipa to DeployGate ****************"
NOTE="hoge"
MESSAGE=`git log --pretty=format:%x0a%s%x0a%b -1`

curl -F "token=${DG_API_KEY}" \
-F "message=${GIT_BRANCH}-${MESSAGE}" \
-F "distribution_key=${DG_DISTRIBUTION_KEY}" \
-F "release_note=${NOTE}" \
-F "file=@${IPA_FILE}" \
https://deploygate.com/api/users/${DG_USER}/apps
```

`PROVISIONING_NAME` はリポジトリに配置している名前の `.mobileprovision` を取り除いた名前を入力
あとはworkspaceなどのパスは各々変更

## DeployGateから通知

アップロードが完了したらDeployGateのアプリ画面に移動して以下のような設定するところがあるので選択

![スクリーンショット_2016-12-22_18_25_46.png](https://qiita-image-store.s3.amazonaws.com/0/97280/aa68d4d0-13b5-879c-ddb1-be9c6a7fa6ea.png "スクリーンショット_2016-12-22_18_25_46.png")

![スクリーンショット 2016-12-22 18.26.37.png](https://qiita-image-store.s3.amazonaws.com/0/97280/fdac9c25-4465-4b78-97ac-59ce5a24a7e7.png "スクリーンショット 2016-12-22 18.26.37.png")

設定自体は簡単なので特に説明はいらないかと思います。

![スクリーンショット_2016-12-22_18_27_25.png](https://qiita-image-store.s3.amazonaws.com/0/97280/8070f96a-25da-dd96-ef9e-5fd9a983a6ae.png "スクリーンショット_2016-12-22_18_27_25.png")

![スクリーンショット_2016-12-22_18_27_33.png](https://qiita-image-store.s3.amazonaws.com/0/97280/49af620c-ee4a-d30f-87c3-0f9e0dc7415a.png "スクリーンショット_2016-12-22_18_27_33.png")

上記画像のように通知が来るようになります。

## 最後に

GitHubに限らず他のGitサービスなどとも連携ができますが、一番てっとり早くて個人でも使える範囲での説明でした。

何か不備などがありましたらコメント等していただければ幸いです。
DeployGateへのアップロードなどで毎回作業を中断してちょっと不便だなぁって思ったりしている方に少しでも貢献できたらと思います。

----

明日は、 @Nick_paper さんのクリスマスっぽいお話です。