dangerをCircleCI上で使ってAndroidのコードを精査する (FindBugs/Android Lint)

[前回](http://qiita.com/noboru_i/items/011fd5ef1808bea3d6ba)は、PR自体の属性（milestoneとかassignee）に対してのチェックを行いました。

今回は、[FindBugs](http://findbugs.sourceforge.net/)とAndroid Lintの結果を通知してみます。

最終的な差分は [こちら](https://github.com/noboru-i/SlideViewer/pull/63) のようになりました。

## 手順

### Dangerfileの修正

http://techlife.cookpad.com/entry/2017/06/28/190000 を参考に、下記のような処理を追加しました。

```rb
# Findbugs
findbugs.gradle_task = "app:findbugs"
findbugs.report_file = "app/build/reports/findbugs/findbugs.xml"
findbugs.report(true)

# Android Lint
android_lint.gradle_task = "app:lint"
android_lint.report_file = "app/build/reports/lint-results.xml"
android_lint.filtering = true
android_lint.lint(inline_mode: true)
```

今回、対象となるモジュールは "app"という名前だったので、上記のような形になります。

この状態でPUSHし、PRを作成、CircleCI上で実行してみた結果としては、下記のようになりました。

https://circleci.com/gh/noboru-i/SlideViewer/153

```
Danger::DSLError: 
[!] Invalid `Dangerfile` file: undefined local variable or method `findbugs' for #<Danger::Dangerfile:0x007f0e42481dc0>.
```

ということで、gemを追加します。

### Gemfileの更新

下記のように、`danger-findbugs`などを追加します。

```rb
gem 'danger'
gem 'danger-findbugs'
gem 'danger-android_lint'
```

そして、 `bundle install` すると、インストールされ、Gemfile.lockにも追記されます。

インストールできたので、 `bundle exec danger pr https://github.com/noboru-i/SlideViewer/pull/63` をしてみました。（これで合ってるか不安ですが。。）

すると、2つのエラーが出ました。

```
* What went wrong:
Task 'findbugs' not found in project ':app'.
```

```
* What went wrong:
Execution failed for task ':app:lint'.
> Lint found errors in the project; aborting build.

  Fix the issues identified by lint, or add the following to your build script to proceed with errors:
  ...
  android {
      lintOptions {
          abortOnError false
      }
  }
  ...
```

ということで、解消します。

### app/build.gradleの編集

まずは、findbugsというタスクがないということですが、 https://github.com/monstar-lab/gradle-android-ci-check を使います。
（詳しくは、 `ci.gradle` の中身を見ていただければと思います。）

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

次に、lintのエラーのときにabortしてしまっているのをやめさせます。

```groovy
android {
    // ...
    lintOptions {
        abortOnError false
    }
}
```

この状態で、再度 `bundle exec danger pr https://github.com/noboru-i/SlideViewer/pull/63` を実行します。

今度は上手く実行されたようです。
ただ、Dangerfileに `github.dismiss_out_of_range_messages` を書いていることもあり、差分以外のチェック結果についてはGitHub上で表示されません。
全体のチェック結果を確認できるようにしておきます。

### Artifactsへの保存

結果のxmlなどを、CircleCI上のArtifactsに保存しておきます。
circle.ymlを下記のように書き換えます。

```yaml
test:
  override:
    - bundle exec danger
    - cp app/build/reports/findbugs/findbugs.xml $CIRCLE_ARTIFACTS || true
    - cp app/build/reports/lint-results.xml $CIRCLE_ARTIFACTS || true
```

※07/09追記： `|| true`が無いと、PRが存在しないmasterブランチのCIなどでエラーになったので追記。

これにより、CircleCIの画面上より、対象のxmlを見ることができます。

https://circleci.com/gh/noboru-i/SlideViewer/154#artifacts/containers/0
![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/9739b44a-5c62-6e39-778c-782dad0eaef7.png)

## 試してみる

まずは、それぞれのエラーを仕込んでみます。

```java
Integer i = null;
i.toString();

SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.commit();
```

明らかにNull Pointer Exceptionが起こるということで、FindBugsのチェックに引っかかります。
http://findbugs.sourceforge.net/bugDescriptions.html#NP_ALWAYS_NULL

また、SharedPreferencesはcommitではなくapplyを使いましょうという、Android Lintの ApplySharedPref というルールに引っかかります。
http://tools.android.com/tips/lint-checks

この状態でコミットし、CircleCIにてdangerを実行しました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/87fefed7-5857-b2ee-ca55-1715adf9f871.png)

ちゃんと出てますね。

では、これらを修正してみます。

```java
Integer i = 1;
i.toString();

SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.apply();
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/8fbed202-a466-3a48-d39f-f070acb80022.png)

見事に消えました。

## まとめ

dangerプラグインが用意されているお陰で、FindBugsとAndroid Lintの結果をGitHubのPRコメントに追記するのは簡単にできました。

また、修正されたものについては、PRコメントからも消えるのが良いですね。

ただ、個人的には、 `NP_ALWAYS_NULL`だったり、`ApplySharedPref`のような、それぞれのチェックに対応するキーが表示されたほうがありがたいなーと思いました。
実際に作業していくにあたっては、Artifactsとして保存したxmlを見る必要も出てきそうな気がします。

あとは、Checkstyleの結果も出力したいですね。誰か、dangerプラグイン作ってるかな？