今時CI回してないとかやばくない?ってとある方に言われました
今回はTravis上でのビルドとテストの実行、fastlaneを使ってデプロイするところまでできたので、わかったことをつらつら書いていきます
とある理由でTravisが途中で使えなくなってしまって、中途半端なところで終わってしまっていますが、Travisが復活したら続きを書きます
わからないながら調べ調べやっているので、間違い等あるやもしれませんが、そのときは指摘・アドバイス等いただけたらと思います
なぜTravisとfastlane?
CIに関しては、自前でサーバを管理したくなかった、iOS/Android/Webがビルドできる、安いプランでも制限が少ないという理由でTravisにしました。
他のサービスとの比較は以下の記事に書きましたので、良かったら読んで下さい。
iOSアプリでCIを始めようとサービスを調べた
fastlaneに関しては、CIに依存しすぎないために使うことにしました。今後CIサービスが変わったり、CIサービスを使うのをやめた場合でも、fastlane単体でビルド・テスト・デプロイができるからです。
Travisの設定
ここでは.travis.ymlについて書きます。設定画面での設定については以下の素晴らしい記事を参考にしてください。
Travis CI と GitHub を連携して iOS アプリをテストする
Travis-CI上でiOS アプリをビルドしてdeploygateで配布する
.travis.ymlについても、公式のドキュメントが充実しているので、それ読めばいいって話ですが、書くことなくなっちゃうので自分がやったことを書いていきます。
Getting started
Customizing the Build
今回は以下のようなファイルを用意しました。これをプロジェクトのルートディレクトリに配置します。
language: objective-c
osx_image: xcode8.3
notifications:
slack: 【slackのAPIキー】
install:
- bundle install
- bundle update fastlane
script:
- bundle exec fastlane test
after_success:
- test $TRAVIS_BRANCH == develop && bundle exec fastlane adhoc
- test $TRAVIS_BRANCH == master && bundle exec fastlane release
それぞれ要素を見ていきます。
language: objective-c
osx_image: xcode8.3
まずは使用する言語とxcodeのバージョンを指定します。
言語はswiftの場合でもobjective-cと指定するようです。
Xcodeのバージョンは、執筆時点ではデフォルトで7.3.1とちょっと古いので、ビルドしたいバージョンを指定します。
Building an Objective-C or Swift Project
notifications:
slack: 【slackのAPIトークン】
今回は通知にslackを使用するので、slackの設定をしておきます。これでビルド結果がslackに流れるようになります。
通知はslackの他にも、メール、IRC、Webhookなどを設定できますので、お好みのものを使ってください。
Configuring Build Notifications
リポジトリがプライベートなので、まあいっかってことでAPIトークンを直書きしちゃっていますが、暗号化しておいた方がいいみたいです。そこら辺も上記のページにちゃんと書いてあるので、参考にしてください。
install:
- bundle install
- bundle update fastlane
fastlaneをbundlerで実行したいのでそのための準備をします。
Configuring Build Notifications#Dependency-Management
上記ページに書いてありますが、TravisはルートディレクトリにPodfileがある場合、自動でpod install
を実行してくれます。Gemfileがある場合は自動でbundle exec pod install
を実行してくれます。
ですが、今回はfastlane内でそれをやらせたいので、Travisにやってほしくありません。そんなときは、上記のようにinstall:
を定義しておけば良いみたいです。
script:
- bundle exec fastlane test
fastlaneのtestというlaneを実行します。中身については後述しますが、ビルドとテストをしています。
after_success:
- test $TRAVIS_BRANCH == develop && bundle exec fastlane adhoc
- test $TRAVIS_BRANCH == master && bundle exec fastlane release
動作未確認
Travisが途中で使えなくなってしまったため、実行できてないです。こうすれば上手く行くんじゃないかなーというのを書いています。
script:
が成功したら、さらにlaneを実行します。デプロイをするのですが、ブランチによってデプロイ先を変えます。
TRAVIS_BRANCHはTravisが用意してくれる環境変数で、ブランチの名前が入っています。
Environment Variables
fastlaneの設定
インストールに関してはこちらで。
Getting started with fastlane for iOS
bundlerを使うのでGemfileをルートディレクトリに配置します。cocoapodsもbundlerでインストール・実行するので、Gemfileに書いておきます。
source "https://rubygems.org"
gem "fastlane"
gem "cocoapods"
Appfile
アカウント情報などをここに記載します。laneごとに使う情報を変えることができます。
Appfile
今回はリリースとそれ以外でバンドルIDとアカウントを、アドホックと開発でチームを変えたかったので以下のように書きました。
app_identifier "【開発用バンドルID】"
apple_id "【開発用アカウントID】"
team_id "【開発用チームID】"
for_platform :ios do
for_lane :release do
app_identifier "【リリース用バンドルID】"
apple_id "【リリース用アカウントID】"
team_id "【リリース用チームID】"
end
for_lane :adhoc do
team_id "【アドホック用チームID】"
end
end
Fastfile
fastlaneに実行させる内容を記載します。laneという単位でタスクを定義するとこができ、関数のようにlaneから別のlaneを呼び出すこともできます。
ビルドする、テストする、デプロイするといった処理は予めactionとして用意されており、オプションをいくらか加えるだけで簡単に実行できるようになっています。
fastlane actions
今回は以下のように書きました。releaseに関しては未実装です。
fastlane_version "2.50.1"
default_platform :ios
platform :ios do
before_all do
ENV["SLACK_URL"] = "【URL】"
cocoapods
ENV["KEYCHAIN_NAME"] = "【適当な名前】"
ENV["KEYCHAIN_PASSWORD"] = "【適当なパスワード】"
end
desc "Runs all the tests"
lane :test do
scan(
workspace: "【ワークスペース】",
scheme: "【対象スキーム】"
)
slack(
message: "Test succeeded"
)
end
desc "create ipa and deploy via deploygate"
lane :adhoc do
import_adhoc_certificate if is_ci?
sigh(
app_identifier: "【アドホック用バンドルID】",
adhoc: true,
provisioning_name: "【アドホック用プロビジョニングファイル名】",
)
gym(
workspace: "【ワークスペース】",
scheme: "【対象スキーム】",
output_name: "【ipaファイル名】"
)
deploygate(
api_token: "【トークン】",
user: "【ユーザ名】",
message: "Fastlane build",
)
slack(
message: "Successfully deployed to deploygate"
)
end
desc "Deploy a new version to the App Store"
lane :release do
# TODO
end
desc "Import certificate for adhoc"
lane :import_adhoc_certificate do
create_keychain(
name: ENV["KEYCHAIN_NAME"],
default_keychain: true,
unlock: true,
timeout: 3600,
lock_when_sleeps: true,
password: ENV["PASSWORD"]
)
import_certificate(
keychain_name: ENV["KEYCHAIN_NAME"],
certificate_path: "【開発者証明書のパス】",
certificate_password: ENV["KEYCHAIN_PASSWORD"]
)
end
error do |lane, exception|
slack(
message: exception.message,
success: false
)
end
end
それぞれ要素を見ていきます。
fastlane_version "2.50.1"
default_platform :ios
platform :ios do
...
end
これはおまじないだと思っています。
before_all do
ENV["SLACK_URL"] = "【URL】"
cocoapods
ENV["KEYCHAIN_NAME"] = "【適当な名前】"
ENV["KEYCHAIN_PASSWORD"] = "【適当なパスワード】"
end
laneが実行される前に実行されるブロックです。cocoapodsによる依存フレームワークのインストールと、環境変数のセットをしています。
cocoapodsは基本的にpod install
を実行しますが、ルートディレクトリにGemfileがある場合、自動でbundle exec pod install
に切り替えてくれるみたいです。
その他オプションについては公式ドキュメント#cocoapodsをどうぞ。
環境変数に関しては、ファイル内に書くよりCIの方で設定しておいたほうが良いみたいです。
desc "Runs all the tests"
lane :test do
scan(
workspace: "【ワークスペース】",
scheme: "【対象スキーム】"
)
slack(
message: "Test succeeded"
)
end
scanを使ってビルド・テストを実行し、成功したらslackで通知します。
scanについて
注意としては、スキームをsharedにするのと、ワークスペースを使用する場合containerはワークスペースにしないとエラーが出ました。
desc "Import certificate for adhoc"
lane :import_adhoc_certificate do
create_keychain(
name: ENV["KEYCHAIN_NAME"],
default_keychain: true,
unlock: true,
timeout: 3600,
lock_when_sleeps: true,
password: ENV["PASSWORD"]
)
import_certificate(
keychain_name: ENV["KEYCHAIN_NAME"],
certificate_path: "【開発者証明書のパス】",
certificate_password: ENV["KEYCHAIN_PASSWORD"]
)
end
順番が前後しますが、先にこちらを。キーチェーンを作り、開発者証明書を登録します。
今回の場合、開発者証明書はp12で書き出しておいてリポジトリに含めておきます。
certを使えばそこもfastlaneでできる?
証明書を専用のリポジトリで管理するmatchという方法もあるみたいです。詳しいことは調べてないので、今後の課題ということで。
Codesigning concepts
desc "create ipa and deploy via deploygate"
lane :adhoc do
import_adhoc_certificate if is_ci?
sigh(
app_identifier: "【アドホック用バンドルID】",
adhoc: true,
provisioning_name: "【アドホック用プロビジョニングファイル名】",
)
gym(
workspace: "【ワークスペース】",
scheme: "【対象スキーム】",
output_name: "【ipaファイル名】"
)
deploygate(
api_token: "【トークン】",
user: "【ユーザ名】",
message: "Fastlane build",
)
slack(
message: "Successfully deployed to deploygate"
)
end
CIで実行されているなら開発者証明書を登録し、sighでプロビジョニングファイルを生成、gymでipaを作成、deploygateでデプロイ、成功すればslackで通知します。
is_ciもactionの一つで、手動実行か自動実行か判別してくれるものみたいです。
各actionのオプションについては公式ドキュメントを。。。
error do |lane, exception|
slack(
message: exception.message,
success: false
)
end
各actionで正常終了しなかった時に呼ばれます。ここではslackで何かしらに失敗したことを通知します。
おわりに
Travisとfastlaneをなんとかかんとか使ってみたという記事でした
一応自分のやろうとしていることは実現できているのですが、ちゃんと挙動を分かっていないものが多いので、今後きっちり調べて理解しようと思っています
この記事を書いている途中でTravisを再び使えるようになったので、今度はiTunesConnectへアップロードするところまでやってみて、また記事にまとめます