Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

AndroidのCI環境を移行しました!

こんにちは、Androidチームの若宮(id:D_R_1009)です。

2019年5月よりAndroidチームのCI環境をBitriseからCircleCIに移行いたしました。 今回は移行の経緯や結果などをまとめたいと思います。

CI環境変更経緯

昨年の6月ごろからBitriseを利用していました。 それ以前はWorckerを使っていたようです。

tech.studyplus.co.jp

BitriseはGUIによって容易にステップの追加/削除が可能なため、自動化したい処理の管理が非常に簡単です。 ステップにはコミュニティ主導で作られているものもあり、機能追加やメンテナンスが活発に行われています。 弊社のアプリに関して言えば、build.gradleファイルの整理時にgradle-play-publisherをBitriseのステップに置き換えるなどの様々な試作を行うことができました。

これらのことから、Bitriseを利用することになんら不満はありませんでした。一方で弊社全体のCI環境を見ると、少し違和感のある状況になっていました。

チーム 環境
Android(Kotlin/Java) Bitrise
iOS(Swift/Obj-C) CircleCI
Server(Ruby) CircleCI

上記の通りCI環境がチームによって分断されているため、CI環境に対する投資とそのリターンの効率が悪くなっています。 また、CI環境構築や改善についての知見がそれぞれのチームに偏ってしまうため、CI構築のノウハウが育ちにくい状況になっていました。

これらの状況を踏まえ、AndroidチームもCircleCIを利用することを決めた次第です。

CI移行ステップ

Androidのビルドについて立ち止まって考えてみると、一般的なCIサービスで利用できないものは特にないことに気づきます。

そのため何らかの方針を決めてCIで自動化する処理を決める必要があると考えました。 今回の移行ではCIで実行したいことは何かを整理すること、CIでは何をシェルスクリプトで書くべき何かを整理すること、この2点を重視しています。

なおCIについて何を考えていくかについては、darumaさんのLTを参考に考えていきました。

おすすめです。

スタディプラスAndroidチームのCI方針

"Ruby"を活用していく点がポイントだと考え、fastlaneによるビルド環境構築を選択しました。

fastlane.tools

fastlaneはiOSアプリの様々な自動化においてデファクトスタンダードとなっているツールです。 Androidではあまりなじみはありませんが、様々な対応がなされています。

実際にステップ構築にあたり考えた方針は下記の通りです。

  • fastlaneで可能なことは、全てfastlaneで実行する
  • fastlaneで実行できないがGradleプラグインで実行できるものは、Gradleプラグインで実行する
  • fastlaneとGradleプラグインで実行できないことだけ、シェルで実行する

出来上がったconfigファイルを見返してみるとCrashlytics Beta用NoteにGit logを記載する箇所だけシェルによる実行となっており、この方針は満たせているかなと感じています。

BitriseからCircleCIに移行で苦労した点

CircleCI上に各リリース用のkeyを設定する以外には、特にありませんでした。 というのも、CircleCI 2.1のconfiguration機能を使うことで、CircleCIの各処理を小さくまとめて記載することができたためです。

たとえば、Dangerを走らせる場合には

commands:
  setup_bundle:
    steps:
      - restore_cache:
          key: v1-danger-cache-{{ checksum "Gemfile.lock" }}
      - run:
          name: Bundle install
          command: bundle check --path ./vendor/bundle || bundle install --jobs=4 --retry=3 --path ./vendor/bundle --clean
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-danger-cache-{{ checksum "Gemfile.lock" }}
  run_danger:
    steps:
      - run:
          name: Run danger
          command: bundle exec fastlane android check_pull_request

とcommandsを定義します。これを

jobs:
  check_pull_request:
    executor:
      name: android_defaults
    steps:
      - checkout
      - setup_android
      - setup_bundle
      - run_danger

のようにjobとすることで、Bitriseと同じようにステップとして扱うことができます。

移行を始めた当初は書き慣れないYAMLファイルやRubyの環境構築(Bundlerとは、Gemfileとはなど)に手間取りました。 しかし学習が進むについれ、手元の環境で構文チェックをしながら構築することができ、生産性が加速度的に高まっていったように感じます。

CircleCI上にAndroidリリース用のファイルを設定する方法は、下記ブログが一番実用的だと感じました。

medium.com

弊社の状況に合わせて試行錯誤した結果、ほぼ同一の対応をすることになっていました。 一度このブログの手順に合わせて構築し、各環境に合わせてカスタマイズすると良いのではないかと感じています。

移行結果

移行した結果、実行時間の削減が見られました。 以下の2ファイルはキャッシュがない状態で、ほぼ同一の処理を行っています。

CircleCI Bitrise
f:id:D_R_1009:20190524162647p:plain
CircleCI stageビルド
f:id:D_R_1009:20190524162341p:plain
Bitirise stageビルド

2019年6月現在ではdebug/stage/releaseの全てのビルドをCircleCIに移行していますが、ほぼ同じか半分程度の実行時間になっています。 Bitriseではビルド待ちの問題が発生しなかった点を差し引く必要がありますが、概ね実行時間は短縮されたと言えます。

まとめ

BitriseとCircleCI、どちらも利便性に優れたCI環境です。 特にCIで実行するステップの管理に対して、アプローチは異なりますがどちらも簡潔だなと感じました。 簡潔な処理を適切に組み合わせることとなるので、だんだんとステップを編集するコストを軽く感じるようになりました。

一部キャッシュの扱いについて違いがあるため個別のCIについての学習は発生しますが、利用しながら改善していけば十分な範疇だと思います。 なんらかの事情において移行したいケースや、別のCI環境も利用してみたいと感じるようであれば、気軽に試してみても良いのではないでしょうか。

よりよいCI環境について知見のあるエンジニアの方がいましたら、ぜひこちらからご連絡いただければと思います。 一緒に最高のDXを作り上げましょう!