プルリクをトリガーにjenkinsで自動テスト＆静的解析

自分のプロダクトでは若手も多いということで、最低限のレビューをjenkinsにやらせるようにしました。
（Androidメインの記事ですが、似たようなことはiosでもできます）

#findBugs/PMD/CheckStyleの導入

##設定ファイルの追加
任意の場所に各ツールの設定ファイルを配置してください。
ここではプロジェクトのルートにconfigフォルダを用意して配置しました。
(ファイル名はcheckstyle-config.xml、android-exclude-filter.xml、pmd-ruleset.xmlとしました)
※具体的な設定ファイルは省略します

##graldeの修正
今回のツール用のgradleをconfigフォルダ内に新規作成します

```xml:quality.gradle 
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'

dependencies {
    checkstyle 'com.puppycrawl.tools:checkstyle:8.1'
}

def qualityConfigDir = "$project.rootDir/config"
def reportsDir = "$project.rootDir/build/reports" // 解析結果の出力パス

check.dependsOn 'checkstyle', 'findbugs', 'pmd'

task checkstyle(type: Checkstyle) {
    group = "quality"
    ignoreFailures = true
    configFile file("$qualityConfigDir/checkstyle-config.xml")
    source 'src'
    include '**/*.java'

    reports {
        xml.enabled = true
        html.enabled = true
        xml {
            destination "$reportsDir/checkstyle.xml"
        }
        html {
            destination "$reportsDir/checkstyle.html"
        }
    }

    classpath = files()
}

task findbugs(type: FindBugs) {
    group = "quality"
    ignoreFailures = true
    effort = "max"
    reportLevel = "high" // どのレベルの報告まで対応するかで変更
    excludeFilter = new File("$qualityConfigDir/android-exclude-filter.xml")
    classes = files("build/intermediates/classes/")
    source 'src/main'
    include '**/*.java'
    exclude '**/gen/**'
    reports {
        xml.enabled = true
        html.enabled = false
        xml {
            destination "$reportsDir/findbugs_report.xml"
        }
        html {
            destination "$reportsDir/findbugs_report.html"
        }
    }
    classpath = files()
}

task pmd(type: Pmd) {
    group = "quality"
    ruleSetFiles = files("$qualityConfigDir/pmd-ruleset.xml")
    ignoreFailures = true
    ruleSets = []

    source 'src'
    include '**/*.java'
    exclude '**/gen/**'

    reports {
        xml.enabled = true
        html.enabled = true
        xml {
            destination "$reportsDir/pmd.xml"
        }
        html {
            destination "$reportsDir/pmd.html"
        }
    }
}
```

プロジェクトのgradleに下記を追加します

```xml:build.gradle
buildscript {
    dependencies {
        classpath 'io.fabric.tools:gradle:1.+'
    }
}
apply plugin: 'com.android.application'
apply from: '../config/quality.gradle' // ここを追加
...
```

#bitbucketの設定
プロジェクトの設定＞フック
ポストレシーブ（Bitbucket Server Webhook to Jenkins）の設定
jenkins URLにjenkinsサーバーのURLを設定（jenkins本体のURLで、jobのパスは不要）

#jenkinsの設定

##ソースコード管理(git)
![git設定.png](https://qiita-image-store.s3.amazonaws.com/0/202533/15cb66bb-dbd0-6edd-18fe-38f2745213f2.png)
「高度な設定」を選択すると、上記のような画面になります。
名称は空欄でOK、Refspecとブランチ指定子は公式にあるように下記の文字列を入力してください。

```xml:Refspec
+refs/pull-requests/*:refs/remotes/origin/pr/*
```

```xml:ブランチ指定子
origin/pr/${pullRequestId}/merge
``` 

##ビルドトリガ
![ビルドトリガー.png](https://qiita-image-store.s3.amazonaws.com/0/202533/90c4bce1-0618-1eaf-b2ca-8bf530ad9528.png)
「SCMをポーリング」にチェックを入れ、スケジュールは空欄にしてください。
「post-commitフックを無視」は環境に異なるとかいう噂ですので、動かなかったらON/OFFを切り替えて試してみてください…

###Stash Pull Requests Builder
![PRビルダー.png](https://qiita-image-store.s3.amazonaws.com/0/202533/5fd2c72a-fee8-4e00-8bd9-1cf205bde361.png)
Cronには「* * * * *」、stash hostにはstashのURLを指定してください。
Project,RepositoryNameは監視するプロジェクト/リポジトリ名を設定してください。

##ビルド後の処理
###CheckStyle/FindBugsの集計
プラグインで下記のようにしておくと見やすいです。
![集計.png](https://qiita-image-store.s3.amazonaws.com/0/202533/9cf74db0-8375-d18c-96ee-34d769c77605.png)

###Notify Stash Instance
Commit SHA-1には以下のように入力してください
（「高度な設定」内にあります）

```xml:CommitSHA-1
${sourceCommitHash}
```

![スクリーンショット 2017-10-26 13.28.01.png](https://qiita-image-store.s3.amazonaws.com/0/202533/aab31bca-5c49-f009-2c39-a07c78a11106.png)


#結果
こんな感じで見えます
![result.png](https://qiita-image-store.s3.amazonaws.com/0/202533/6c5944c9-7732-d561-2953-c5880f173d6d.png)


#カスタムコメント
プルリクに記載されるコメントはカスタマイズ可能です。
私は上記キャプチャのように、各ツールの警告数をコメントで出力するようにしています。
![スクリーンショット 2017-10-26 13.52.59.png](https://qiita-image-store.s3.amazonaws.com/0/202533/f28b4d7a-de43-a1e7-1961-19c2bf1dc496.png)

###計測結果数の環境変数化
ここで、PMD_RESULEやFB_RESULTS は環境変数なのですが、計測結果数を環境変数として保存して実現しています。やり方はこちらに書きましたので、ご参照ください。
https://qiita.com/mkosuke/items/ef55ae48b2064873ba2b

###計測結果数の集計
解析結果ファイルをスクリプトで地道に解析しています。
ちなみにスクリプトは苦手なのでもっと賢いやり方はあるのだと思います…

```js:CheckStyle
CS_TERM=\<td\>[0-9]*\<\/td\>\<td\>[0-9]*\<\/td\>
CS_RESULT=$(grep $CS_TERM ./build/reports/checkstyle.html | sed -r "s/[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+/\2/")
echo -e "CS_RESULTS=$CS_RESULT" >> analytics_result.txt
```

```js:FindBugs
FB_TERM=\<BugInstance
FB_RESULT=$(grep -c $FB_TERM ./build/reports/findbugs_report.xml)
echo -e "FB_RESULTS=$FB_RESULT" >> analytics_result.txt
```

```js:PMD
PMD_TERM=var/lib/jenkins/jobs/BUS_BUILD_CHECKER/workspace/
PMD_RESULT=$(grep -c $PMD_TERM ./build/reports/pmd.html)
echo -e "PMD_RESULTS=$PMD_RESULT" >> analytics_result.txt
```
例では解析結果をanalytics_result.txtというテキストファイルに出力していますので、環境変数のインジェクトでanalytics_result.txtを読み込んであげればカスタムコメントにも使えるようになります。