mavenのビルドで静的解析を実行して、規定のレベルに達していなければfailureを返すための設定
mvn site
で静的解析レポートを出力する例は見かけるが、testと同じようにcheckする設定例をあまり見かけなかったので書いてみた。
静的解析ツール
Jacocoは、OpenCloverとの比較検討のために追加していて、カバレッジのレポート出力(jacoco.exec)だけを実行し、カバレッジ検査は行なっていない。
pom.xmlの設定例
GitHubリポジトリの<build/>
と<reporting/>
を参照
- 静的解析プラグインの
check
ゴールを実行することでビルド時に検査する - 設定例では静的解析の実行フェーズをverifyとしており、
mvn verify
で静的解析を実行してくれる - レポートも出力したい場合は、
mvn site
を実行する。 但し後述のJenkinsのpluginでレポーティングする場合は、checkゴールを実行すれば必要なxmlファイルも出力されるので、mvn site
は必要ない。
静的解析をverifyフェーズで実行している理由
これはOpenCloverのカバレッジ取得の仕組みが原因で、testフェーズ以前だと静的解析でエラーを検出してしまうため。
OpenCloverはテストカバレッジを取得するために clover:setup
ゴールを実行してソースコードを改変する。この改変内容が他の静的解析でエラーで検知されることがある。
回避策としてはsetup
ゴールではなくinstrument
ゴールで実施する。その結果、"正式なプロダクト用"と"カバレッジ取得用"の2回コンパイルが行われるので正式なプログラム用で静的解析が実行できる。 またテストも2回実行する。
但し、instrument
ゴールは、2回目のコンパイルがinstallフェーズの後になってしまう。これを回避するのがinstrument-test
ゴールで、2回目のコンパイルをtestフェーズの後に実施するため、testフェーズより後であれば静的解析も正しくcheckする。 なのでprepare-package
ゴールで実行すれば、静的解析後にパッケージングすることもできる。
つまり、OpenCloverを使わないのであれば、testフェーズで静的解析を実行しても問題ない。
Pluginの設定例
静的解析ツールを実行するためのplugin設定例をpom.xmlから抜粋した。
いずれも<build/>
タグ内の設定内容。
<reporting/>
タグ内には、タグ以外の設定を定義する
Checkstyle
- checkstyle自体は8.17を指定
- Rule Configureは、プラグインが標準で持っている google_checks.xml を定義
- "error"の時のみfailureを出力する
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.17</version>
</dependency>
</dependencies>
<configuration>
<configLocation>google_checks.xml</configLocation>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<violationSeverity>error</violationSeverity>
<consoleOutput>true</consoleOutput>
</configuration>
<executions>
<execution>
<id>checkstyle</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
SpotBugs
- SpotBugs自体は3.1.11を指定
- Defaultレベルを閾値としている
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>3.1.11</version>
<dependencies>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
<version>3.1.11</version>
</dependency>
</dependencies>
<configuration>
<effort>Default</effort>
<threshold>Default</threshold>
<failOnError>true</failOnError>
<trace>true</trace>
<xmlOutput>true</xmlOutput>
</configuration>
<executions>
<execution>
<id>spotbugs</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
PMD
- pmd自体は6.11で解析する
- rulesetは標準のルールを全て定義している
- "[WARNING] Removed misconfigured rule: LoosePackageCoupling cause: No packages or classes specified"という警告が出力されるが、これはDesignルールセット内にあるLoosePackageCouplingが見つからないためである。
- cpdのチェックも一緒に実施する。(cpdはコードの重複をチェックする)
- failurePriorityでエラーとする規定値が変更できる。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.11.0</version>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>6.11.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>6.11.0</version>
</dependency>
</dependencies>
<configuration>
<rulesets>
<ruleset>/category/java/bestpractices.xml</ruleset>
<ruleset>/category/java/codestyle.xml</ruleset>
<ruleset>/category/java/design.xml</ruleset>
<ruleset>/category/java/documentation.xml</ruleset>
<ruleset>/category/java/errorprone.xml</ruleset>
<ruleset>/category/java/multithreading.xml</ruleset>
<ruleset>/category/java/performance.xml</ruleset>
<ruleset>/category/java/security.xml</ruleset>
</rulesets>
<targetJdk>${java.version}</targetJdk>
<failOnViolation>true</failOnViolation>
<failurePriority>0</failurePriority>
<printFailingErrors>true</printFailingErrors>
<verbose>true</verbose>
<analysisCache>true</analysisCache>
</configuration>
<executions>
<execution>
<id>PMD</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
<goal>cpd-check</goal>
</goals>
</execution>
</executions>
</plugin>
OpenClover
- カバレッジの割合を定義してcheckが出来、設定値を下回るとエラーとなる。
- cloverゴールを実行することで、cloverフォルダおよびclover.xmlなどを出力する
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-maven-plugin</artifactId>
<version>4.3.1</version>
<configuration>
<targetPercentage>50%</targetPercentage>
<failOnViolation>true</failOnViolation>
<generateHtml>true</generateHtml>
<generateXml>true</generateXml>
</configuration>
<executions>
<execution>
<id>check</id>
<phase>verify</phase>
<goals>
<goal>instrument-test</goal>
<goal>check</goal>
<goal>clover</goal>
</goals>
</execution>
</executions>
</plugin>
Jacoco
- Testのカバレッジを取得するだけなので、test-compile フェーズで実行する。
- カバレッジの取得時にJVNに渡すjacocoArgsを生成し、maven-surefire-pluginで定義する
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<executions>
<execution>
<id>prepare-agent</id>
<phase>test-compile</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>jacocoArgs</propertyName>
<includes>
<include>*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
# タグにjacocoArgsを定義する
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<argLine>-Xmx256m ${jacocoArgs}</argLine>
</configuration>
</plugin>
Jenkinsの設定例
JenkinsのBuildで静的解析も実行するだけならば、mvn clean varify
とすれば良い。
解析結果をレポートしたい場合mvn site
を実行する必要がなく、verify
で出力されるxmlファイルをPost-Build Actionで指定してあげるだけで良い。
Build
JUnit Test Report
OpenClover coverage report
JaCoCo Coverage report
その他の解析レポートは、Warnings Next Generation Pluginを使う
checkstyle, findbugs, PMDなどの個別のレポートプラグインはEOLになっており、Warning Next Generation Pluginに統合されたので、今回はこちらを使用してみた。
checkstyle
spotbugs
pmd
cmd
感想
検証に使ったソースコードではそれほどテストコードも無いにも関わらず、Jenkinsのビルド時間が7−8分掛かった。
(ローカルPCでJenkinsを動かしていることもあるだろうが)OpenCloverのために2回compileやtestを行なっているのも原因と思う。
OpenCloverの方がJaCoCoに比べ解析できる内容が広いが、OpenCloverを使うことでの副作用を考えるとJaCoCoだけを使った方が用意場合もある。
参考リンク
Apache Maven Plugins
Apache Maven Chackstyle Plugin
SpotBugs Maven Plugin
Apache Maven PMD Plugin
Clover Maven Plugin
OpenCloverでカバレッジを取得する
THE ULTIMATE CODE QUALITY SETUP FOR YOUR AEM PROJECT