Android
CircleCI
PMD
FindBugs
lint

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

image.png

必要なこと

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

image.png

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

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