理系学生日記

おまえはいつまで学生気分なのか

MavenへのCheckstyleの組み込み

基本的にJavaのエンジニアの多い会社に勤めているはずなのですが、そういえばCheckstyleを自分で設定したことがありませんでした。 Checkstyleは、プロジェクトで定めたコーディング標準に従っているかを機械的にチェックしていくツールですね。

というわけで、今日はMavenからCheckstyleを実行できるようになるまで設定してみます。 Javaを真面目に触るのは本当に久しぶりで、かなりリハビリ期間がかかりそうです。

Maven

まずMavenですが、Mavenにおけるビルトインのライフサイクルとしては以下の3つがあります。

  • clean
  • default (buildとも呼ばれる)
  • site

このうち、Checkstyleを用いるのはdefaultライフサイクル、siteライフサイクルが代表的でしょう。

  • defaultライフサイクル: ソフトウェアをビルドするための標準的なライフサイクル
  • siteライフサイクル: プロジェクトのドキュメントやサイト構築のためのライフサイクル

それぞれのライフサイクルにどのようなフェーズが存在するかについては、Mavenの公式リファレンスで説明がされています。

defaultライフサイクルの、どのフェーズにCheckstyleを組み込むのか

まず最初に必要と考えたのが、Mavenのどのフェーズにcheckstyle:check ゴールを組み込むかです。 checkstyle:checkゴールは、Checkstyleを実行した上でコーディング違反を検知し、必要に応じてビルドを失敗させるという役割を担います。

実際にどのフェーズに組み込むかについては、プロジェクトの開発プロセスに依存するところでしょう。 maven-checkstyle-plugin公式においても、validateフェーズや verifyフェーズに紐づけることを示唆されていますが、決定的な話はありません。

Note that the phase that checkstyle::check is bound to is very important. If bound to the validate phase, it would check the code prior to compiling the code. If the code is invalid, the parsing errors reported by checkstyle may be different than what would be expected from the javac compiler. However, it's guaranteed to run. Another popular option is to bind it to the verify phase which would run much later (and allow the javac compiler to flag invalid code prior to checkstyle). However, if developers generally just use "mvn test" prior to pushing changes, checkstyle would not run as verify occurs after the test phase.

Usage

しかし、コーディング違反があるコードでテストをパスしたとしても、コーディング違反を修正した後で再テストを余儀なくされることが多いはずです。 また、コーディング違反のようなフィードバックは、開発者として速やかに得たいという思いもあります。 そういう意味で、ぼくはvalidateに紐づけるのが良いであろうと考えました。

pom.xmlへの設定

以下のような設定を追加しました。 どうもmaven-checkstyle-plugin v3.1.2は、デフォルトではCheckstyleの8.29を利用するようです。 これは、project.plugins.plugin.dependencies.dependencyで上書きできるため、 現時点でのCheckstyle最新版である10.0を利用するようにしました。

Maven Checkstyle plugin comes with a default Checkstyle version: for maven-checkstyle-plugin 3.1.2, Checkstyle 8.29 is used by default.

Upgrading Checkstyle at Runtime

diff --git a/app/movie-uploader/pom.xml b/app/movie-uploader/pom.xml
index 78a9219..9a57854 100644
--- a/app/movie-uploader/pom.xml
+++ b/app/movie-uploader/pom.xml
@@ -14,9 +14,13 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <java.version>17</java.version>
-
     <maven.compiler.source>17</maven.compiler.source>
     <maven.compiler.target>17</maven.compiler.target>
+    <plugin.checkstyle.version>3.1.2</plugin.checkstyle.version>
+
+    <checkstyle.config.location>kiririmode-checkstyle.xml</checkstyle.config.location>
+    <checkstyle.consoleOutput>true</checkstyle.consoleOutput>
+    <checkstyle.violationSeverity>warning</checkstyle.violationSeverity>
   </properties>

   <dependencyManagement>
@@ -108,5 +112,48 @@
         </plugin>
       </plugins>
     </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${plugin.checkstyle.version}</version>
+        <dependencies>
+          <dependency>
+            <groupId>com.puppycrawl.tools</groupId>
+            <artifactId>checkstyle</artifactId>
+            <version>10.0</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <failsOnError>true</failsOnError>
+        </configuration>
+        <executions>
+          <execution>
+            <id>validate</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
   </build>

Checkstyleの設定ファイル

以前からGoogleのコーディング標準を設定したgoogle_checks.xmlを 使ってみたかったので、これを利用することにしました。google_checks.xmlはCheckstyle本体に組み込まれています。

しかし、この設定は英語が前提となっており、日本語でJavadocを書いていくと以下のようなWarningが検知されてしまいます。

javadocの最初の文に末尾のピリオドがありません。

特定のルールだけ上書きできれば良いのですが、Checkstyleではルールの一部上書きはサポートされていません。

このため、上記のファイルをファイルとしてダウンロードし、必要なところを上書きすることにしました。

diff --git a/app/movie-uploader/kiririmode-checkstyle.xml b/app/movie-uploader/kiririmode-checkstyle.xml
index abda825..71bf73a 100644
--- a/app/movie-uploader/kiririmode-checkstyle.xml
+++ b/app/movie-uploader/kiririmode-checkstyle.xml
@@ -311,6 +311,7 @@
         <module name="SummaryJavadoc">
             <property name="forbiddenSummaryFragments"
                       value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
+            <property name="period" value="。"/>
         </module>
         <module name="JavadocParagraph"/>
         <module name="RequireEmptyLineBeforeBlockTagGroup"/>

siteライフサイクルへの組み込み

siteライフサイクルへの組み込みは、単純にUsageにある以下の設定をいれただけですね。 何のひねりもない。

<project>
  ...
   <reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-checkstyle-plugin</artifactId>
          <version>3.1.2</version>
          <reportSets>
            <reportSet>
              <reports>
                <report>checkstyle</report>
              </reports>
            </reportSet>
          </reportSets>
        </plugin>
      </plugins>
    </reporting>
  ...
</project>

mvn validate

実行すると、想定通りCheckstyleでViolationを検知できています。

$ mvn --version
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: /usr/local/Cellar/maven/3.8.5/libexec
Java version: 17.0.2, vendor: Homebrew, runtime: /usr/local/Cellar/openjdk/17.0.2/libexec/openjdk.jdk/Contents/Home
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "12.2.1", arch: "x86_64", family: "mac"

$ mvn validate
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< de.kiririmo:movieuploader >----------------------
[INFO] Building movieuploader 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-checkstyle-plugin:3.1.2:check (validate) @ movieuploader ---
[INFO] 監査を開始しています...
[WARN] /Users/kiririmode/src/github.com/kiririmode/hobby/app/movie-uploader/src/main/java/de/kiririmo/memory/MovieUploader.java:19:1: Javadoc コメントがありません。 [MissingJavadocType]
[WARN] /Users/kiririmode/src/github.com/kiririmode/hobby/app/movie-uploader/src/main/java/de/kiririmo/memory/MovieUploader.java:29:3: Javadoc コメントがありません。 [MissingJavadocMethod]
[WARN] /Users/kiririmode/src/github.com/kiririmode/hobby/app/movie-uploader/src/main/java/de/kiririmo/memory/MovieUploader.java:35:3: Javadoc コメントがありません。 [MissingJavadocMethod]
[WARN] /Users/kiririmode/src/github.com/kiririmode/hobby/app/movie-uploader/src/main/java/de/kiririmo/memory/MovieUploader.java:47:3: Javadoc コメントがありません。 [MissingJavadocMethod]
監査が完了しました。
[WARNING] src/main/java/de/kiririmo/memory/MovieUploader.java:[19,1] (javadoc) MissingJavadocType: Javadoc コメントがありません。
[WARNING] src/main/java/de/kiririmo/memory/MovieUploader.java:[29,3] (javadoc) MissingJavadocMethod: Javadoc コメントがありません。
[WARNING] src/main/java/de/kiririmo/memory/MovieUploader.java:[35,3] (javadoc) MissingJavadocMethod: Javadoc コメントがありません。
[WARNING] src/main/java/de/kiririmo/memory/MovieUploader.java:[47,3] (javadoc) MissingJavadocMethod: Javadoc コメントがありません。
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.867 s
[INFO] Finished at: 2022-03-20T15:36:05+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.1.2:check (validate) on project movieuploader: You have 4 Checkstyle violations. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException