[GitLab CI] Merge Request 時に静的コード解析のレポートを確認する


## 背景

* GitLab CI にて、静的コード解析が自動実行されるようにしてみたが、解析結果を今ひとつ活用できていない
* プロジェクトが佳境に入ったタイミングで導入されたため、大量の静的解析指摘を修正するのは別の不具合を生むリスクがある


## やりたいこと

* 全ての静的解析指摘を一度に修正するのは困難なので、コード変更・修正をしながら少しずつ静的解析指摘を修正したい
* 今後のコード変更・修正によって、新たな静的解析指摘を増やさないようにしたい

⇒ コード変更・修正する毎に、静的解析指数の増減を確認できるようにしたい


## 方針

* GitLab CI にて、静的コード解析のレポートを自動でコミットできるようにする

⇒ Merge Request 時、コード差分と共に静的コード解析結果の差分も確認できるようになる


## やってみた

今回は、Android プロジェクトに対して Android Lint と FindBugs でやってみた。

Android Lint は Android 特有のバグを検出するのに優れるらしい。

FindBugs はソースコードではなくバイナリを解析するため、実際の動作で不具合となりうるバグを検出するのに優れるらしい。

### CI Configuration

```.gitlab-ci.yml
variables:
  ANDROID_COMPILE_SDK: "25"
  ANDROID_BUILD_TOOLS: "26.0.2"
  GIT_CI_USER_EMAIL:   "admin@example.com"  # CI がコミットする際のユーザー情報
  GIT_CI_USER_NAME:    "GitLab CI"          # CI がコミットする際のユーザー情報
  GITLAB_HOST_NAME:    "10.0.1.23"          # GitLab のホスト名

stages:
  - build-and-analysis  # ビルド & 静的コード解析
  - deploy

# Android Lint を実行し、レポート(XML)をコミットする
# Merge request 時、レポート内容をコード差分と共に確認できる
# 事前準備 1: GitLab Runner マシンの SSH key を、GitLab 上の適当なユーザに追加しておくこと
# 事前準備 2: GitLab Runner マシンから GitLab へ push できることを確認しておくこと
lint:
  stage: build-and-analysis
  before_script:
    - git checkout -b $CI_JOB_ID
  script:
    - ./gradlew lint
    - mv app/build/reports/lint-results.xml app/lint-results.xml
  after_script:
    - git add app/lint-results.xml
    - git config --global user.email "$GIT_CI_USER_EMAIL"
    - git config --global user.name "$GIT_CI_USER_NAME"
    - git commit -m "Generate Lint Report [ci skip]" # このコミットでは CI を実行させない（無限ループするため）
    - git pull origin $CI_COMMIT_REF_NAME
    - git remote remove origin
    - git remote add origin git@$GITLAB_HOST_NAME:$CI_PROJECT_PATH.git
    - git push origin $CI_JOB_ID:$CI_COMMIT_REF_NAME

# デバッグビルドと FindBugs を実行する
# FindBugs はバイナリに対する解析ツールであるため、ビルド後に実行する
# ビルド成功なら apk を GitLab からダウンロードできるようにする
# FindBugs のレポート(XML)をコミットする
# Merge request 時、レポート内容をコード差分と共に確認できる
assembleDebugAndFindbugs:
  stage: build-and-analysis
  before_script:
    - git checkout -b $CI_JOB_ID
  script:
    - ./gradlew assembleDebug
    - ./gradlew findbugs
    - mv app/build/reports/findbugs/findbugs.xml app/findbugs.xml
  after_script:
    - git add app/findbugs.xml
    - git config --global user.email "$GIT_CI_USER_EMAIL"
    - git config --global user.name "$GIT_CI_USER_NAME"
    - git commit -m "Generate FindBugs Report [ci skip]" # このコミットでは CI を実行させない（無限ループするため）
    - git pull origin $CI_COMMIT_REF_NAME
    - git remote remove origin
    - git remote add origin git@$GITLAB_HOST_NAME:$CI_PROJECT_PATH.git
    - git push origin $CI_JOB_ID:$CI_COMMIT_REF_NAME
  artifacts:
    name: "apk"
    when: on_success
    paths:
    - app/build/outputs/apk

javadoc:
  stage: deploy
  only:
    - tags
    - web
  script:
    - rm -rf doc
    - javadoc -private -d doc -sourcepath app/src/main/java -subpackages com.greysonparrelli.gitlabciandroid -Xdoclint:none -link http://docs.oracle.com/javase/8/docs/api -windowtitle "JavaDoc 出力テスト" -doctitle "JavaDoc 出力テスト" -header "JavaDoc 出力テスト" -linksource
  artifacts:
    name: "javadoc"
    when: on_success
    paths:
    - doc
```

### Lint による静的コード解析のスクリーンショット

activity_main.xml ファイルにテキストのハードコーディングをしたため、 lint-results.xml ファイルに issue 要素が追加される。

Lint による静的解析指摘が増えたことがわかる。

![Screenshot-Lint.png](https://qiita-image-store.s3.amazonaws.com/0/40619/150cf5f0-1c1f-3e0e-5b8e-fe1b9a798295.png "Screenshot-Lint.png")


### FindBugs による静的コード解析のスクリーンショット

MainActivity クラスから不要な変数 data を削除したため、 findbugs.xml ファイルから BugInstance 要素が削除される。

FindBugs による静的解析指摘が減ったことがわかる。

![Screenshot-FindBugs.png](https://qiita-image-store.s3.amazonaws.com/0/40619/037a75da-d122-ed87-3638-5bd566c89c2f.png "Screenshot-FindBugs.png")


## 導入によって期待したいこと

* 解析結果を活用できるようにしたことで、コードの品質が向上する
* 静的解析指数の増減を見えるようになったことで、開発メンバーのより良いコードを書く意識が向上する


## 改善点

* findbugs.xml はコード変更・修正が無い場合でもタイムスタンプ等の差分があるため、一見しただけでは静的解析指数の増減が確認できない。

⇒ レポート(XML)をそのままコミットするのではなく、 issue 要素や BugInstance 要素のみを切り出した結果をコミットできるようにしたい。

* 重大な静的解析指摘がある場合には、コードレビューの実施以前に突き返したい。

⇒ レポート(XML)をさらに解析して、重大な静的解析指摘を検出した場合にはエラー出力することで GitLab CI の実行結果を Failed にしたい。

* Merge Request を承認する際、レポート(XML)の差分が原因でコンフリクトすることがある。

⇒ 検討中…。