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

## 経緯

[dangerをCircleCI上で使ってAndroidのコードを精査する (FindBugs/Android Lint) - Qiita](http://qiita.com/noboru_i/items/2ad7c07d8b4266c9eb5b) では、CircleCI 1.0を使っていました。
[CircleCI 2.0でAndroidのアプリをビルドしつつ、コードレビューBOTも動かす - Qiita](http://qiita.com/noboru_i/items/780abf904568c664712f) では、CircleCI 2.0でしたが、Saddlerを使っていました。
[DangerでCheckstyleの結果を指摘する - Qiita](http://qiita.com/noboru_i/items/32e4ad1cc2f07184b7e4) では、CircleCI 2.0で[Danger](http://danger.systems/ruby/)を利用しましたが、Checkstyleの結果だけを指摘しました。

その後Gemを更新したりして、 [FindBugs](http://findbugs.sourceforge.net/) / [PMD](https://pmd.github.io/) / [Android Lint](https://developer.android.com/studio/write/lint.html?hl=ja) の結果も通知出来るようになりました。

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

## できるようになること

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

- [checkstyle](http://checkstyle.sourceforge.net/)
- [FindBugs](http://findbugs.sourceforge.net/)
- [PMD](https://pmd.github.io/)
- [Android Lint](https://developer.android.com/studio/write/lint.html?hl=ja)

イメージとしては、下記のような形です。（ [実際のPR](https://github.com/noboru-i/SlideViewer/pull/76) ）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/9060a22d-6526-b0a6-20bf-42f879e9bef9.png)

## 必要なこと

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

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

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

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

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

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

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

```ruby
# 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` を作成し、下記のようにします。

```rb
# 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` を下記のように記述します。

```yaml
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も動かす](http://qiita.com/noboru_i/items/780abf904568c664712f) に書きました。

### 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にしておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/84f55050-5f3d-4ae1-66e9-2774b44d1600.png)


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

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