Posted at

CircleCI 2.0でAndroid関連の静的解析結果をPullRequestで指摘する

More than 1 year has passed since last update.


経緯

dangerをCircleCI上で使ってAndroidのコードを精査する (FindBugs/Android Lint) - Qiita では、CircleCI 1.0を使っていました。

CircleCI 2.0でAndroidのアプリをビルドしつつ、コードレビューBOTも動かす - Qiita では、CircleCI 2.0でしたが、Saddlerを使っていました。

DangerでCheckstyleの結果を指摘する - Qiita では、CircleCI 2.0でDangerを利用しましたが、Checkstyleの結果だけを指摘しました。

その後Gemを更新したりして、 FindBugs / PMD / Android Lint の結果も通知出来るようになりました。

今回は、そのあたりのコードをまとめて貼っていきます。


できるようになること

CircleCI 2.0を動作させ、Dangerを経由して、下記のチェック結果をPull Requestにコメントする。

イメージとしては、下記のような形です。( 実際のPR


必要なこと


build.gradleにて、各チェックが実行されるようにする

app/build.gradle の任意の箇所に、下記のように追加します。

apply from: "https://raw.githubusercontent.com/monstar-lab/gradle-android-ci-check/1.3.1/ci.gradle"

詳細は monstar-lab/gradle-android-ci-check を見ていただき、不要な部分などあれば、独自に記述してください。

これにより、 ./gradlew :app:check -x test とやることで、各種のチェックが実行され、xmlが出力されるようになります。


Gemfileを記述し、Gemfile.lockを生成する

Dangerやその他必要なものをinstall出来るように、Gemfile を記述していきます。

# frozen_string_literal: true

source "https://rubygems.org"

gem 'danger'
gem 'danger-checkstyle_format'

gem 'android_lint_translate_checkstyle_format'
gem 'findbugs_translate_checkstyle_format'
gem 'pmd_translate_checkstyle_format'

その後、ローカルで bundle install しておき、生成されるGemfile.lockもrepositoryに追加しておきます。

(個人的には、プロジェクトごとにGemを管理したいので、 bundle install --path vendor/bundleを実行してます。)


Dangerfileを記述する

Dangerfile を作成し、下記のようにします。

# github comment settings

github.dismiss_out_of_range_messages

checkstyle_format.base_path = Dir.pwd

# checkstyle
checkstyle_format.report 'app/build/reports/checkstyle/checkstyle.xml'

# Findbugs
require 'findbugs_translate_checkstyle_format'
findbugs_xml = ::FindbugsTranslateCheckstyleFormat::Script.translate(File.read('app/build/reports/findbugs/findbugs.xml'))
checkstyle_format.report_by_text findbugs_xml

# PMD
require 'pmd_translate_checkstyle_format'
pmd_xml = ::PmdTranslateCheckstyleFormat::Script.translate(File.read('app/build/reports/pmd/pmd.xml'))
checkstyle_format.report_by_text pmd_xml

# PMD-CPD
require 'pmd_translate_checkstyle_format'
pmd_cpd_xml = ::PmdTranslateCheckstyleFormat::Script.translate_cpd(File.read('app/build/reports/pmd/cpd.xml'))
checkstyle_format.report_by_text pmd_cpd_xml

# # Android Lint
require 'android_lint_translate_checkstyle_format'
android_lint_xml = ::AndroidLintTranslateCheckstyleFormat::Script.translate(File.read('app/build/reports/lint-results.xml'))
checkstyle_format.report_by_text android_lint_xml


CircleCI 2.0の設定を記述する

.circleci/config.yml を下記のように記述します。

version: 2

defaults: &defaults
working_directory: ~/code
docker:
- image: circleci/android:api-26-alpha
environment:
JVM_OPTS: -Xmx3200m

jobs:
build:
<<: *defaults
steps:
- checkout
- restore_cache:
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
- run:
name: Download Dependencies
command: ./gradlew androidDependencies
- save_cache:
paths:
- ~/.gradle
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
- run:
name: Check lint
command: ./gradlew :app:check -x test
- run:
name: Build apk
command: ./gradlew :app:assembleDebug
- store_artifacts:
path: app/build/outputs/apk/app-debug.apk
destination: app-debug.apk
- store_test_results:
path: app/build/test-results
- persist_to_workspace:
root: ~/code
paths:
- .

check:
working_directory: ~/code
docker:
- image: circleci/ruby:2.4.1
steps:
- attach_workspace:
at: ~/code
- restore_cache:
key: gems-{{ checksum "Gemfile.lock" }}
- run: bundle install --path vendor/bundle
- run:
name: Run danger
command: bundle exec danger
- run:
name: Move artifacts
command: |
ARTIFACTS="/tmp/circle_artifacts"
mkdir -p "$ARTIFACTS"
cp -v "app/build/reports/checkstyle/checkstyle.xml" "$ARTIFACTS/"
cp -v "app/build/reports/findbugs/findbugs.xml" "$ARTIFACTS/"
cp -v "app/build/reports/pmd/pmd.xml" "$ARTIFACTS/"
cp -v "app/build/reports/pmd/cpd.xml" "$ARTIFACTS/"
cp -v "app/build/reports/lint-results.xml" "$ARTIFACTS/"
- save_cache:
paths:
- vendor/bundle
key: gems-{{ checksum "Gemfile.lock" }}
- store_artifacts:
path: "/tmp/circle_artifacts"

deploy:
<<: *defaults
steps:
- attach_workspace:
at: ~/code
- run:
name: Build apk
command: ./gradlew :app:assembleRelease
- store_artifacts:
path: app/build/outputs/apk/app-release.apk
destination: app-release.apk
- store_artifacts:
path: app/build/outputs/mapping/release/dump.txt
destination: dump.txt
workflows:
version: 2
build_and_deploy:
jobs:
- build
- check:
requires:
- build
- deploy:
requires:
- build
- check
filters:
branches:
only: master

check jobだけDockerのイメージが切り替わっていたり面倒なことになっていますが、その理由などは、 CircleCI 2.0でAndroidのアプリをビルドしつつ、コードレビューBOTも動かす に書きました。


CircleCI側の設定

Dangerでは、DANGER_GITHUB_API_TOKENという環境変数を利用します。

GitHub側でPersonal access tokenを作成し、CircleCIの設定画面の"Environment Variables"に設定しておきます。

BOTアカウントを作っておき、そのtokenを使用すると、BOTに指摘されたように見えていい感じです。

また、必須ではないですが、CircleCI側で、「PRが作成されたときだけCIを実行する」としておいた方が良いかと思います。

プロジェクトの設定画面から、"Advanced Settings"にある、"Only build pull requests"をONにしておきます。

あとはGitHubにPUSHしPRを作成すると、CircleCIがビルドを行い、変更箇所にwarningなどがあれば、PRのコメントとして指摘が付きます。

(最終的な設定イメージ: https://github.com/noboru-i/SlideViewer/tree/bc86f226b943aeedb58b74b50784f7de8835346e