Maven 「mvn checkstyle:checkstyle」みたいなコマンドと「mvn test」みたいなコマンドのちがい

疑問点

「:」でつないで実行するコマンドと、

$ mvn checkstyle:checkstyle

「:」なしで実行できるコマンドがある。

$ mvn test

この差は何か?

結論

  • 「mvn checkstyle:checkstyle」は「ゴール
  • 「mvn test」は「フェーズ

ゴールとは?

mavenのpluginそれぞれが提供する具体的な機能

以下の形式で実行する。

$ mvn prefix:goal

例えば、echo-maven-pluginの場合、

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example.com</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>sample</name>
  <url>http://maven.apache.org</url>

  <build>
    <plugins>
      <plugin>
        <groupId>com.soebes.maven.plugins</groupId>
        <artifactId>echo-maven-plugin</artifactId>
        <version>0.3.0</version>
        <configuration>
          <echos>
            <echo>This is the Test Text </echo>
          </echos>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

以下の形式で、echo-maven-pluginが提供する機能を利用する。

$ mvn echo:echo
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- echo-maven-plugin:0.3.0:echo (default-cli) @ sample ---
[INFO] This is the Test Text // <-ここがecho plugin の実行結果
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.147 s
[INFO] Finished at: 2017-07-31T20:48:17+09:00
[INFO] Final Memory: 8M/304M
[INFO] ------------------------------------------------------------------------

テストやビルドの具体的な処理も、全てpluginが提供している。

注意点

ゴールは指定したゴールしか実行できない。pluginによっては別のpluginの実行結果やコンパイル結果(classesファイル)が存在することを前提としたものがある(findbugsとか)。そのため、ゴール単体で利用するときは、実行順序に注意が必要。 後述するフェーズを利用すれば、この問題を解消できる。

フェーズとは?

mavenが用意している、ライフサイクル中の各ステップ。

validate - validate the project is correct and all necessary information is available compile - compile the source code of the project test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed package - take the compiled code and package it in its distributable format, such as a JAR. verify - run any checks on results of integration tests to ensure quality criteria are met install - install the package into the local repository, for use as a dependency in other projects locally deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.

参考 Introduction to the Build Lifecycle

フェーズ自体は具体的な処理をせず、フェーズに登録されたpluginのゴールを呼びだすだけ。もし複数のpluginのゴールが登録されていれば、複数のpluginのゴールを呼びだす。

したがってMavenを利用してビルドやテストをするためには、各フェーズにpluginを登録する必要がある。が、Mavenは親切なので、デフォルトでいくつかのpluginのゴールが登録されている。

Lifecycle 説明
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test

参考 Built-in Lifecycle Bindings

例えば、「mvn test」を実行したら「mvn surefire:test」が実行されることになる。

注意点

フェーズは、指定されたフェーズまでの各フェーズも実行される。したがって、「mvn test」=「mvn surefire:test」ではなく、「mvn test」∋「mvn surefire:test」。

ライフサイクルとは?

ライフサイクルは、フェーズをグループとしてまとめたもの。

デフォルトは以下の3つ。

  • default Lifecycle
  • clean Lifecycle
  • site Lifecycle

参考 Introduction to the Build Lifecycle

Tips

pluginのprefix

prefix:goal のprefixには、以下のルールがある。

  • maven-${prefix}-plugin
  • ${prefix}-maven-plugin

参考 Specifying a Plugin's Prefix

pluginのgoal

prefix:goalのgoalは、helpゴールを利用すると一覧が表示できる。

$ mvn echo:help
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- echo-maven-plugin:0.3.0:help (default-cli) @ sample ---
[INFO] Maven Echo Plugin 0.3.0
  The Echo Maven Plugin is intended to print out messages during the build.

This plugin has 3 goals:

echo:echo

echo:format

echo:help
  Display help information on echo-maven-plugin.
  Call mvn echo:help -Ddetail=true -Dgoal=<goal-name> to display parameter
  details.
 ...

参考 Maven で Plugin の usage を確認する

各フェーズのpluginを調べる

実効pomを表示すれば、各フェーズで実行されるpluginが調べられる。

$ mvn help:effective-pom
...

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.4</version>
        <executions>
          <execution>
            <id>default-test</id>
            <phase>test</phase>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
...

フェーズにpluginのゴールを登録する

<executions>タグ内で<phase><goal>を定義する。 たいていはpluginのサイトに例が載っているのでそれを参考にしたほうが良い。

  <build>
    <plugins>
      <plugin>
        <groupId>com.soebes.maven.plugins</groupId>
        <artifactId>echo-maven-plugin</artifactId>
        <version>0.3.0</version>
        <executions> 
          <execution>
            <phase>test</phase>
            <goals>
              <goal>echo</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <echos>
            <echo>This is the Test Text </echo>
          </echos>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

参考 Plugins

フェーズをスキップする

フェーズはスキップできない。ただし、フェーズに登録されたpluginをスキップする方法は、各pluginごとに用意されている。例えば、surefire:testだと-Dmaven.test.skip=true-DskipTests=true。 install:installだと-Dmaven.install.skip=true

試しにsurefire:testをスキップするコマンドを打つと、testフェーズに登録していたecho-maven-pluginが動いてしまう。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example.com</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>sample</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>com.soebes.maven.plugins</groupId>
        <artifactId>echo-maven-plugin</artifactId>
        <version>0.3.0</version>
        <executions>
          <execution>
            <phase>test</phase>
            <goals>
              <goal>echo</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <echos>
            <echo>This is the Test Text </echo>
          </echos>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>
$ mvn clean package -Dmaven.test.skip=true
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ sample ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- echo-maven-plugin:0.3.0:echo (default) @ sample ---
[INFO] This is the Test Text
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ sample ---
[INFO] Building jar: c:\Users\pbreh_000\Desktop\study\sample\target\sample-1.0-SNAPSHOT.jar
...

フェーズをスキップさせるのを疑似るなら、mavenのProfileを使えば良いっぽい。
参考 stack overflow