AndroidのCI環境をCircleCIからWerckerに移行しました

こんにちは、エンジニアの堀江(@Horie1024)です。先日行われたAndroid Testing Bootcamp #2で「AndroidのCI環境をCircleCIからWerckerにした話」という内容で発表させて頂きました。発表に使用したスライドはこちらになります。

この投稿では、スライドでは単にリンクを貼って終わらせてしまったなど、詳細を紹介しきれなかった点についてご紹介しようと思います。

移行前に利用していたCircleCIによるCI環境について

スライドでも紹介しましたが、iQONの開発では、1年半ほど前からCircleCIを導入していました。導入についての詳細は以下の投稿にまとめてあります。

tech.vasily.jp

CircleCIで行っていたことは以下の通りです。

  • ユニットテスト
  • BetaでのAPK配布
  • Google Playへのアップロード自動化

図にすると以下のようになります。

f:id:vasilyjp:20160614115041p:plain

ユニットテスト

ユニットテストはRobolectricを使いJVM上でのテストを実行しています。使用しているテスティングフレムワークはJUnit、モックライブラリはmockitoです。現状カバレッジは高く無く、モデル部分相当するクラスについて必要に応じて書いています。

UIテスト

AWS DeviceFarmを利用してCalabashで書いたテストを実行していました。

tech.vasily.jp

Calabashを選択した理由は、CucumberがサポートされGherkinでfeature(テストコード)を書くことができるのが理由です。以下は、ログイン後に画面を目的のコンテンツ位置までスクロールし、ログアウトするfeatureです。自然言語に近い文法で書くことができるため理解しやすくなっています。

ただ、コスト的な問題とCloud Test Lab(現Firebase Test Lab)がCalabashでのテストの実行をサポートして無いことから、現在ではEspressoを利用し実機を使用してローカルでテストを実行しています。Espresso Test RecorderがGoogle I/O 2016で発表されていますし、EspressoでのUIテストがより行いやすくなるのを期待しています。

APK配布

APKの配布について当初はDeployGateを利用していましたが、Crashlytics(現Fabric)を利用していたこと、iOSがBetaを採用したこともあり、Betaに変更しています。

Google Playへのアップロード自動化

Google Playへのアップロード自動化については、当初PythonのGoogle APIs Client Libraryを使用する予定でした。

qiita.com

CircleCIでPythonのGoogle APIs Client Libraryを使用するには、各種ライブラリのインストールや依存関係の解決などを行わなければならず、より簡単な方法を探していたところgradle-play-publisherプラグインを発見し、現在でも利用しています。以下のスライドでは、CircleCIでののgradle-play-publisherプラグインの利用方法について言及しています。

Androidのビルド用Dockerイメージの作成

Werckerを利用するには、Dockerイメージが必要になります。Androidプロジェクトをビルド可能なイメージはDockerHubなどで公開されていますが、Android SDKをDockerイメージに含めてpublicで公開すると再配布としてライセンス違反となることと、CIサービス側とローカル環境とのビルド環境のズレを制御するためにイメージを自作しプライベートリポジトリとしてホストしています。SDK VersionやBuild Tools Versionを変更する度Dockerfileを更新する必要がありますが、DockerHubやQuay.ioにはGitHubへのpushをhookしてイメージのビルドを自動的に行うAutomated Buildという機能が用意されているのでメンテナンスコストはほぼ掛かっていません。

qiita.com

ビルドしたイメージは弊社のADサーバーで利用するDockerイメージと同様にQuay.ioにプライベートリポジトリとしてホストしており、プライベートリポジトリの場合wercker.ymlでのboxセクションの書き方が若干変わります。

boxセクションでプライベートリポジトリを指定する方法は、こちらのドキュメントが参考になります。そして、yamlは以下のようになり、idにはリポジトリ名、username、passwordについては、WerckerのWeb UIで入力した環境変数を参照するようにします。

box:
  id: quay.io/knuth/golang
  username: $USERNAME
  password: $PASSWORD
  tag: beta
  registry: quay.io
build:
  steps:
    - script:
      name: echo
      code: echo "hello world!"

また、DockerHubのPrivate Repositoryの場合以下のようなyamlになります。DockerHubの場合registryの指定は不要です。

build:
  box:
    id: guido/python
    username: $USERNAME
    password: $PASSWORD
    tag: latest
  steps:
    - script:
      name: echo "hello world!"

より詳しい内容は以下の記事にまとめてあります。

qiita.com

keystoreや.p12キーファイルの扱い

AndroidアプリのCI/CDをどう行うのかを考えるとkeystoreやkey.p12などのファイルを何処に置くか?が問題になることがあります。今回、keystoreなどのファイルをIP制限をかけたs3のバケットに置き、それをWerckerから取得する方法で解決しました。Werckerが使用するIPアドレスをWhitelistとしてs3バケットのバケットポリシーに追加することで、Werckerからのアクセスのみに制限できます。WerckerのソースIDリストはこちらから確認できますが、予告無しに変更される可能性があるため注意が必要です。

qiita.com

Wercker cache

Werckerでは、Workflowsで繋いだpipeline間で共有出来るディレクトリがあり、キャッシュとして利用できます。キャッシュディレクトリのパスは、環境変数WERCKER_CACHE_DIRを参照することで取得できます。Wercker cacheの詳細は以下のドキュメントをご覧ください。

wercker - docs - Using wercker cache

ビルド速度の改善

WERCKER_CACHE_DIRをGradleのキャッシュディレクトリとして利用することでビルド速度を改善できます。Gradleは実行時に--project-cache-dirを用いることで任意のキャッシュディレクトリを指定できます。詳細は付録D Gradle コマンドラインをご覧ください。したがって、以下のように指定することでWERCKER_CACHE_DIRをキャッシュディレクトリとして利用できます。

$ ./gradlew --project-cache-dir=$WERCKER_CACHE_DIR testDebug

Gradle Wrapperを利用する場合

Gradle Wrapperを利用する場合は、Werckerの環境変数としてGRADLE_USER_HOMEを定義し$WERCKER_CACHE_DIRを指定します。これでWrapperがダウンロードしたGradleを異なるpipeline間で共有でき、pipeline毎にGradleがダウンロードされることが無くなります。

環境変数は「Settings」の「Environment variables」から定義できます。

f:id:vasilyjp:20160614184641p:plain

WERCKER_CACHE_DIRの有効期限

各pipelineは、スタート時にWERCKER_CACHE_DIRにキャッシュをロードします。ロードされるキャッシュは、14日間以内で最後に成功したビルドのもので、キャッシュの容量は1GBまでとなっています。

キャッシュの消去

キャッシュを消去したい場合、「Settings」の「Options」にある「Clear cache」から削除できます。また、Gradle実行時に--recompile-scriptsを付けることでキャッシュが全て破棄され再度コンパイル、保存されます。詳細は「キャッシング」の項目をご覧ください。

f:id:vasilyjp:20160614184916p:plain

まとめ

今回Android Testing Bootcampに参加してみて、様々な取り組みや事例、tipsについて知ることができ非常に勉強になりました。また、発表する機会を頂いたことで自分自身の知識を整理することができ、CI/CDを含めた今後のiQONの開発フローをどのようにしていくのかのヒントを多く得られました。次回のAndroid Testing Bootcampへも是非参加できればと思います。

最後に

VASILYでは一緒にiQONを開発してくれる仲間を募集しています。少しでもご興味のある方は以下のリンク先をご確認ください。

また、VASILYでは今年もエンジニア向けインターンシップを行います。Androidチームでのインターンシップについては、以下の記事で紹介していますので、ご興味のあるかたは是非ご覧ください。

tech.vasily.jp