GameWith Engineering Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

AndroidのプロジェクトにCIを導入した話 #GameWith #TechWith

はじめまして、GameWithのエンジニアのソンです。 今回はGameWith本体アプリのAndroidプロジェクトにCIを導入した話をします。

まずはどうしてCIを導入しようと思うのを説明させていただきます。 PullRequestを作る時に、人為的なミスでそもそもBuildやUnitTestが通らないことたまにあります。この問題はCIの導入でReviewする前に必要ない人力が省けます。

また、複数人のプロジェクトにはある程度のCode Styleを制限しないとCodeの可読性がすぐ悪くなります。

 

ゴール

f:id:w_sun:20181204153724p:plain

  1. CircleCI 2を導入
  2. UnitTestを行う
  3. APKをビルド
  4. Danger経由で、GithubにKtlintからのエラーメッセージをコメント
  5. 3.で生成したAPKをDeployGateにアップロード

Circle CI 2を導入

社内のGithubアカウントは既にCircleCiと連携してますので、新しいプロジェクトに導入するのは難しくないです。

導入したいプロジェクトの「Set Up Project」を押すと、そこには簡単なconfig.ymlの例文があります。チュートリアルに沿ってプロジェクトに配置すると、最初の構築が終わります。次はconfig.ymlにどんどんJob(実行させたいタスク)を追加する感じです。

一応CircleCIは複数のJobを同時に実行することができるので、ここはUnitTestBuildKtlintと三つのJobに分けまして、平行で走らせます。

また、各JobでGradleの初期化を行うと時間がかかりますので、CircleCiのworkspaceを使って、初期化したものを各Jobに提供してます。

UnitTestを行う

  unitTest:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Run UnitTest
          command: ./gradlew testProductDebugUnitTest
      - store_artifacts:
          path: app/build/reports
          destination: reports
      - store_test_results:
          path: app/build/test-results

store_artifactsstore_test_resultsはテスト項目の結果を保存するMethodです。Jobが実行した後にArtifactsで見れます。

f:id:w_sun:20181204153805p:plain

APKをビルド

 normalBuild:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Build
          command: ./gradlew assembleQualityAssuranceDebug
      - persist_to_workspace:
          root: ~/
          paths: code/app/build/outputs/apk/qualityAssurance/debug/

最後のpersist_to_workspaceは生成したAPKをDeployGateにアップロードできるように、workspaceに保留する。

ktlintの実行

  ktlint:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run: ./gradlew ktlintProductReleaseCheck
      - persist_to_workspace:
                root: ~/
                paths: code/app/build/reports/ktlint/

ktlintはGradle pluginsのKtlint Gradleを使ってます (https://github.com/JLLeitschuh/ktlint-gradle

OutputはCHECKSTYLEに設定する、この後はDangerから読み込んでGithubにコメントする。

dangerの実行

  danger:
    working_directory: ~/code
    environment:
      - LANG: C.UTF-8
    docker:
      - image: ruby:2.1
    steps:
      - attach_workspace:
          at: ~/
      - run: gem update --system 2.4.8
      - run: gem install bundler
      - restore_cache:
          key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
      - run: bundle install --path vendor/bundle
      - save_cache:
          key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
          paths:
            - vendor/bundle
      - run: bundle exec danger --verbose

DangerはRuby版を使ってます。(https://danger.systems/ruby/)

Dangerfiledanger-checkstyle_formatdanger-lgtmくらい簡単なものしか入れてないです。

  • エラーになる時

f:id:w_sun:20181204160901p:plain

  • 成功する時

f:id:w_sun:20181204160913p:plain

DeployGateにアップロード

 deploy:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Deploy APK
          command: curl -F "token=${DEPLOY_GATE_API_KEY}" -F "file=app-qualityAssurance-debug.apk" -F "message=$(git log --oneline -1)" https://deploygate.com/api/users/

リリースする前にQA版のAPKを使って自動テストを実行してるので、そこの手動生成の手間が省略できます。

以上で簡単なCI導入の手順でした。導入してよかったと思ったところがいくつあります。

  1. Ktlintの導入によって、書き方のミスが防げるようになりました。基本的に人工でチェックするのは不可能ので、非常に助かります。
  2. QAテスト向けのAPKを手動でビルドして、DeployGateにアップロードする手間も省略できました。
  3. 開発する時にDebugBuildすることは多いですが、実際ReleaseBuildの時にBuildが通らないこともたまにあります、これもCIによって事前にわかります。

また、この記事を書いてる途中で気づきましたけど、DangerさんがKtlintを対応してくれました。また試してみます。 :thinking_face:

終わりに

GameWith は、ゲームの楽しさをもっと世界に伝えていきたいエンジニアを大募集中です。 Wantedly でもよいので是非お気軽にお声がけください!

www.wantedly.com