ほぼ初めてAndroid向けのCI環境をセットアップしたので、試行錯誤した作業手順を書いておこうと思う。
今回セットしたCIの内容は、JVMテストとカバレッジの計測で作業手順は以下のようになった。
- DockerfileでCI環境を定義
- Dockerfileとcloudbuild.yamlを含むレポジトリをgithubに作成
- Google Container Registory(GCR)にプロジェクトを作成
- レポジトリにpushするとGCR上でビルド&ホストされる
- wercker.ymlをライブラリのレポジトリに追加
- werckerにプロジェクトを作成
- pushすると自動でCIが走るようになる
- jacocoをセットアップ
- coverallsにプロジェクトを作成
- coveralls-gradle-pluginを導入し、coverallsのAPIキーをwerckerに設定
- wercker.ymlを編集しカバレッジをcoverallsに送信する
(本エントリのはAutomation with Wercker and Container Builderを元にして書かれています。 Keishin Yokomakuさんありがとうございました)
DockerfileでCI環境を定義する
AndroidのプロジェクトはCI as a Serviceが提供する環境を利用するのは難しい。理由はSDKに含まれるライブラリ/ツールの更新があった場合、CIサービス側のサポートを待つ必要が生まれるためだ。
その為Dockerの実行をサポートするCIサービスを使って、自分で定義した環境でCIを動かす選択肢を選んだ。
Dockerfileを一から書くのは大変なのでYokomakuさんが公開されているDockerfileをforkした。
Dockerは基本的にはshell scriptなので、すこし書き換えるくらいならDocker知らなくてもどうにかなる。
Dockerfileとcloudbuild.yamlを含むレポジトリを作成
先程作ったDockerfileとGCRの設定ファイル(cloudbuild.yaml)を含めたレポジトリを作る。cloudbuild.yamlはなくても動くのだけど、ほぼ確実にtimeout(default:10min)に引っかかる。
timeout: 40m steps: - name: 'gcr.io/cloud-builders/docker' args: ['build', '--tag=gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA', '.'] images: ['gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA']
参考: github.com
GCRにプロジェクトを作成
Google Cloud Platform(GCP)のコンソールを開き、新規プロジェクトを作成する。
プロジェクトを作ったらサイドメニューからContainer Registoryを選択する。初回は「Container Registry は有効でありません」と出るので有効にする。
トリガーを作成を選択 -> ソースを選択[github.com] -> 認証 -> レポジトリを選択[先程作ったレポジトリ] -> トリガー設定を行う。
トリガーを作成したら、試しに動かしてイメージが正常に作成されるか確認する。
(余談: Dockerのビルドは手元でやる選択もありますが、普段使わないのに手元にDocker環境をセットアップしたくない、適切にクリーンしないとストレージが圧迫されて辛い。などの理由でリモートビルドしています。)
wercker.yamlをレポジトリに追加する
以下を参考にwercker.yamlを作成する。
build: box: id: gcr.io/{your_project}/{your_repository} username: _json_key password: $GCR_JSON_KEY_FILE registry: gcr.io tag: {your_container_hash} steps: - script: name: run test code: | ./gradlew --project-cache-dir=$WERCKER_CACHE_DIR {library_module}:testDebugUnitTest -PdisablePreDex
idやtagは、GCRのビルド履歴画面を参考に埋めることが出来る。(id: イメージ ターゲット, tag: イメージタグ)
DockerイメージをprivateにしているのでJSON_ファイルを利用した認証を行う。高度な認証方式 を参考にサービスアカウントからJSONキーを発行する。
JSONファイルを手に入れたら、wercker側の環境変数に追加する。
Werckerのプロジェクトを作成
werckerのトップから Create->Applicationを選択する。Werckerのプロジェクト作成は驚くほど簡単なので詳細な説明は省略するが、ポチポチしてれば勝手にhookが設定され自動でCIが走るようになる。
jacocoをセットアップする
jacocoはJavaのコードカバレッジツールの一つで、唯一Java8のコードがまともに計測できる。
Androidで使う場合にはけっこう大変だったが、Droidkaigiのconference-app-2017レポジトリが参考になった。
私がハマった点は、testCoverageEnabled true
を忘れていた点とRobolectricを利用している場合古いjacocoを利用する必要がある点だった。これらを忘れるとカバレッジ0%でずっと悩み続けることになる。
参考までに対応した際のcommitを貼っておく。 kazy1991/PrefKit -Setting jacoco
coveralls-gradle-pluginのセットアップ
coverallsはカバレッジ結果をwebUIで可視化してくれるサービスである。jacocoにも対応しているので生成したxmlをcoverallsに送る手順を追加する。
coveralls側でプロジェクトを作成するとAPIキーが手に入るので、werckerの環境変数に追加しておく。
プロジェクト直下のbuild.gradleにcoveralls-gradle-plugin
を追加する。
dependencies { //.. classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.8.1' }
ライブラリ側のbuild.gradleでxmlの場所を指定する。
coveralls { jacocoReportPath = "{your_xml_path}/{file_name}.xml" // jacocoReportPath = "build/reports/jacoco/xml/prefkit.xml" }
wercker.ymlを編集して、カバレッジを送るようにする。
- ./gradlew --project-cache-dir=$WERCKER_CACHE_DIR {library_module}:testDebugUnitTest -PdisablePreDex + ./gradlew --project-cache-dir=$WERCKER_CACHE_DIR {library_module}:jacoco {library_module}:coveralls -PdisablePreDex
coveralls-gradle-pluginは、xmlファイルが見つからなくてもエラーにはならない。coveralls側に反映されないときはwerckerのログを読んでみると良いと思う。
このブログを書いていて気づいたが、coverallsよりcodecov.ioのほうがモダンな見た目なのでこっちに乗り換えるかもしれない
[追記]
codecovに乗り換えた。ハマリポイントとしてはcodecovが認識できるファイル名が-name 'jacoco*.xml'
なのでファイル名をデフォルトから変更している場合はちゅういがひつようだった。対応PRはこちら。
Use codecov by kazy1991 · Pull Request #5 · kazy1991/PrefKit · GitHub
まとめ
AndroidのCI環境のセットアップはとにかく手順が多く、そんなに頻繁にはやる作業でもないので忘れてないうちにブログにまとめた。 環境に作ったことに満足してしまってまだテストは一つも書いてない。