Jenkins/SonarQubeではじめるお手軽コードレビュー：静的解析

# はじめに
この記事では、グループ内の複数人で行う開発（プログラミング）フェーズ[^1]内でコードの静的解析[^2]を行い、新規に開発した箇所に含まれる問題を早期に取り除くために役立つ方法を紹介します。

[^1]: Javaを用いた[ウォーターフォール・モデル](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A9%E3%83%BC%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A9%E3%83%BC%E3%83%AB%E3%83%BB%E3%83%A2%E3%83%87%E3%83%AB)開発を想定して書いていますが、ウォーターフォール・モデルに限らず適用できると思いますし、SonarQube自体はJava以外の言語にも対応させることが可能です。

[^2]: コンピュータのソフトウェアの解析手法の一種であり、実行ファイルを実行することなく解析を行うこと。([Wikipedia](https://ja.wikipedia.org/wiki/%E9%9D%99%E7%9A%84%E3%82%B3%E3%83%BC%E3%83%89%E8%A7%A3%E6%9E%90)より)

# 前提
- 「masterブランチから開発用ブランチを作成し、開発が終わればそのブランチからdevelopブランチに対してプルリクエストを送る」という開発フローを基本として想定しています。
- reviewerの数がrevieweeに対して多くない状況を想定しています。


# 問題
- reviewerの負担を減らす
 - 同じコーディングルール違反について何度も指摘した経験、ありませんか（ログの使い方、アノテーションの漏れ、etc.）？
 - [SearchBucket](https://github.com/kazuhirokomoda/SearchBucket)で検索した時、同じキーワードで同じような指摘がいくつもヒットしませんか？
- 意図しない不具合がリリースされることを未然に防ぐ
 - メモリリーク、NullPointerException、etc.
- 新規に開発される箇所を対象にする
 - 既存の問題はいったん保留にしたいと思います。

# SonarQube
上の問題の解決を目指して、今回はSonarQubeの導入・活用を試します。
SonarQubeは、一言で説明すれば「コードの品質を継続的に計測・管理するためのOSS」です。

- 決められたコーディングルールに違反している箇所があればそれを洗い出して（解決方針とともに）提示してくれる
- そうした違反箇所などを「技術的負債」として管理し、時系列で推移を記録してくれる

詳細は[公式ドキュメント](https://docs.sonarqube.org/display/SONAR/Documentation)を参照して下さい。
> SonarQube® software (previously called Sonar) is an open source quality management platform, dedicated to continuously analyze and measure technical quality, from project portfolio to method.


## SonarQube Serverのインストール
まず、サーバを構築して、コード品質の計測結果を溜める場所を用意します。
詳細な手順は[公式ドキュメント](https://docs.sonarqube.org/display/SONAR/Installing+the+Server)や[こちらの資料](http://blog.applibot.co.jp/blog/2017/09/14/static-code-analysis-with-sonarqube/)が詳しいです。

## SonarQube Scannerによる静的解析と結果確認
サーバを構築できれば、次はいよいよコードの静的解析です。

### 静的解析: Maven
[Analyzing with SonarQube Scanner for Maven](https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Maven)に従って設定した後、pom.xmlのあるディレクトリで

```
mvn sonar:sonar
```
を実行すると、静的解析が実行されます。

### 結果確認: webコンソール上で
その結果は、

```
sonar.host.url
```
で設定したURL以下で、このような画面として見ることができます。（画像はJavaのコードを対象にしたものではないようですが、参考まで。）

![aMjqj.png](https://qiita-image-store.s3.amazonaws.com/0/32910/3be7148c-a7d2-5802-faea-c076d0b95c51.png)

出典: https://stackoverflow.com/questions/36940993/vs-unit-test-results-file-trx-is-not-displayed-into-sonarqube

検出された問題とその解決方針は、例えばこのように提示されます。

![Selection_964.jpg](https://qiita-image-store.s3.amazonaws.com/0/32910/70b63085-d2a8-dce4-f238-d95ce756c870.jpeg)

出典: https://docs.sonarqube.org/display/SONARQUBE52/Technical+Debt


### 結果確認: IDEで
解析結果をSonarQube Server上に登録していれば、IDE上で確認することも可能です。そのためには、お使いのIDEに合わせて、[SonarLint](https://www.sonarlint.org/)や[radar-netbeans](http://plugins.netbeans.org/plugin/51532/radar-netbeans)をインストールします。
例えばNetBeansにradar-netbeansをインストールすると、このように問題("Issues")が指摘されます。コードの該当箇所と問題の詳細な記述の間を行き来しながらスムーズに修正を行うことができます。

![1463108950_radar-thumbnail-2.PNG](https://qiita-image-store.s3.amazonaws.com/0/32910/de1b1696-4466-e4ef-6bd4-ab1e5442be70.png)


出典: http://plugins.netbeans.org/plugin/51532/radar-netbeans


### メリット・デメリット
実際にSonarQubeを導入して感じたメリットとデメリットを挙げてみます。

- メリット
 - webコンソールやIDE上で開発中に素早く問題点を見つけること（そして修正すること）ができる。 
- デメリット
 - SonarQube Scannerについては、エンジニアがそれぞれインストール・設定をする必要がある。
 - 指摘された問題点を無視しようと思えば無視できる。


# Jenkinsと組み合わせる

> SonarQube Scannerについては、エンジニアがそれぞれインストール・設定をする必要がある。

というデメリットを軽減できるように、グループ共通で使っているJenkinsから手軽に実行できるジョブを作ることを考えてみます。

## スクリプト
開発用ブランチごとに、以下のようにSonarQubeの静的解析を行うためのスクリプト(analyze.sh)を作成します。

- masterブランチに対する解析を（まだ行っていなければ行う）
- 開発用ブランチに対する解析を行う
- sonar.projectKeyは開発用ブランチごとに一意
- sonar.projectVersionはmasterブランチ解析時と開発用ブランチ解析時で変える

```bash:analyze.shの概要
#!/bin/sh -xe

(中略)

SONARQUBE_PROJECT_KEY_FROM_API=`curl -s -X GET "${SONARQUBE_HOST_URL}/api/components/show?key=${SONARQUBE_PROJECT_KEY}" | python [Path to file]/json_value.py component key`

# clone repository
git clone ssh://git@[Bitbucket SSH URL with port]/${BITBUCKET_PROJECT_NAME}/${REPOSITORY_NAME}.git
cd ${REPOSITORY_NAME}; pwd

# if key not exists in SonarQube server
if [ -z ${SONARQUBE_PROJECT_KEY_FROM_API} ]; then
    # (a) mvn clean package (baseline branch)
    git checkout ${GIT_BRANCH_BASELINE}
    ${MAVEN_COMMAND} clean package -Dmaven.test.skip=true

    # (b) run sonar:sonar to ${SONARQUBE_PROJECT_NAME} (baseline branch)
    ${MAVEN_COMMAND} sonar:sonar -Dsonar.projectKey=${SONARQUBE_PROJECT_KEY} -Dsonar.projectName=${SONARQUBE_PROJECT_NAME} -Dsonar.projectVersion=${SONAR_PROJECT_VERSION_BASELINE} -Dsonar.sources=src/main
fi

# (c) mvn clean package (developing branch)
git checkout ${GIT_BRANCH}
${MAVEN_COMMAND} clean package -Dmaven.test.skip=true

# (d) run sonar:sonar to ${SONARQUBE_PROJECT_NAME} (developing branch)
${MAVEN_COMMAND} sonar:sonar -Dsonar.projectKey=${SONARQUBE_PROJECT_KEY} -Dsonar.projectName=${SONARQUBE_PROJECT_NAME} -Dsonar.projectVersion=${SONAR_PROJECT_VERSION} -Dsonar.sources=src/main
```

```python:json_value.py
# encoding: utf-8
import json
import sys

# Get JSON from stdin
dic = json.loads(raw_input())

# get keys from arguents
args = sys.argv
# args[0] is this program name
args.pop(0)

for key in args:
    if isinstance(dic , list): 
        # if current value is list, change key to int
        key=int(key)
    try:
        # set dic[key] as next value (or result)
        dic=dic[key]
    except: 
        # If failed, print empty string and exit. (might be on KeyError and IndexError)
        print ''
        sys.exit()

# print result
print dic
```

## Jenkinsのジョブ設定
Freestyle jobを作成し、"This project is parameterized"にチェックを入れてスクリプトに必要なパラメータを指定できるようにします。

![sonarqube_analyze-setting.JPG](https://qiita-image-store.s3.amazonaws.com/0/32910/f1ed55e9-c560-89fa-4876-90b3aa1fb7e5.jpeg)

## Jenkinsのジョブ実行
ジョブを実行すると、webコンソール上に開発用ブランチに対応するダッシュボードが作成されます（もしまだなければ）。masterブランチと開発用ブランチの差分（新規に開発した箇所）で検出された問題が"New Issues"のところに出てきます。赤丸で囲んでいる部分をクリックすると、問題の詳細を確認できます。

![new_issues.JPG](https://qiita-image-store.s3.amazonaws.com/0/32910/98ebbb56-dea9-8d46-1534-c18a6685a14c.jpeg)


## メリット・デメリット
- メリット
 - 開発中のブランチ名などいくつかの項目を指定するだけで修正すべき問題点を見つけることができる。
- デメリット
 - 指摘された問題点を無視しようと思えば無視できる。

# まとめと今後の課題

「reviewerの負担を減らす」「意図しない不具合がリリースされることを未然に防ぐ」を目的に、Jenkins/SonarQubeを使って、新規に開発した箇所に含まれる問題を早期に取り除くために役立つ方法を紹介しました。

一方で、このような課題も見つかりました。
> 指摘された問題点を無視しようと思えば無視できる。

これはJenkinsやSonarQubeというよりは、むしろグループの事情によるところが大きいと思います。実際にJenkinsのジョブを使ったメンバーに話を聞いたりした上で、以下のような点がネックになりそうだと思っています。

- 静的解析の重要性があまり理解・共有されていない
 - これまでの手動レビューで特に大きな問題はなかった（あるいはトラブルが起こったとしても対応できてきた）。
 - SonarQubeデフォルトのルールに基づく指摘は、必ずしもグループの現状に合っているとは言えない。
- 「（reviewerではなく）revieweeの負担」はむしろ増えている
 - 開発途中に（他にやるべきことが多すぎて）このJenkinsジョブのことを思い出せない。
 - 思い出したとしても、スケジュール・スキル・既存コードとの整合性などの問題で積極的に直すことが難しい。

次回の関連記事では、

- SonarQubeのルール選定
- 自動化

のどちらかについて、改善の目途が立てば共有したいと思います。



# 関連する記事
- [Jenkinsを使ってGitHubのPull Requestが自動でテストできちゃう？](https://qiita.com/kazuhirokomoda/items/9d091a153dda0965c6a7)
 - SonarQubeを使ってはいませんが、「reviewerの負担を減らす」「ミスがリリースに紛れ込む可能性を減らす」という目的意識は一緒です。
- [SonarQubeでテストコードも静的解析するには？](https://qiita.com/kazuhirokomoda/items/86b885f262e63e763e0f)
 - SonarQube Scannerの解析対象を設定する方法を検討しました。