SIerだけど技術やりたいブログ

5年目のSIerのブログです

「mvn clean test」みたいに実行するコマンドと「mvn checkstyle:checkstyle」みたいに実行するコマンドとの差を理解したい

「:」なしで実行できるコマンドと、

mvn clean test 

「:」でつないで実行するコマンドとの差を理解するのが目的です。

mvn checkstyle:checkstyle

動作確認環境

mvn -v
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T20:57:37+09:00)
Maven home: c:\Program Files\apache-maven-3.3.3
Java version: 1.8.0_25, vendor: Oracle Corporation
Java home: c:\Program Files\Java\jdk1.8.0_25\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 8.1", version: "6.3", arch: "amd64", family: "dos"

ライフサイクルとフェーズ

そもそもmavenには、ライフサイクルとフェーズという概念があるらしい。

7. Maven Tips | TECHSCORE(テックスコア)

Maven – Introduction to the Build Lifecycle


ライフサイクルは、フェーズをグループとしてまとめたもので、デフォルトは3つある。

  • default Lifecycle
  • clean Lifecycle
  • site Lifecycle

フェーズは、mavenが用意したライフサイクル中の各ステップ。
https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference

validate validate the project is correct and all necessary information is available.
initialize initialize build state, e.g. set properties or create directories.
generate-sources generate any source code for inclusion in compilation.
process-sources process the source code, for example to filter any values.
generate-resources generate resources for inclusion in the package.
process-resources copy and process the resources into the destination directory, ready for packaging.
compile compile the source code of the project.
process-classes post-process the generated files from compilation, for example to do bytecode enhancement on Java classes.
generate-test-sources generate any test source code for inclusion in compilation.
process-test-sources process the test source code, for example to filter any values.
generate-test-resources create resources for testing.
process-test-resources copy and process the resources into the test destination directory.
test-compile compile the test source code into the test destination directory
process-test-classes post-process the generated files from test compilation, for example to do bytecode enhancement on Java classes. For Maven 2.0.5 and above.
test run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed.
... ...


ポイントは、フェーズ自体は何らかの具体的な処理をするわけではなくて、そういうイベントってみんな共通してあるよね、くらいのものだということ。

それぞれのフェーズにpluginが登録でき、各フェーズで登録されたpluginのゴールを実行することで具体的な処理が実行できるようになる。

とはいえそれだとすぐ使い始められないので、組み込みでいくつかのpluginのゴールがフェーズに割り当てられている。(Built-in Lifecycle Bindings)

process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test


つまり、「mvn test」を実行したら裏で「mvn surefire:test」が実行されていたらしい。
(「mvn test」は指定されたフェーズまでの各フェーズ(compileとかもろもろ)も実行されるので、「mvn test」=「mvn surefire:test」ではない)

雑なたとえ話

フェーズとライフサイクルをカレーに例えると

  • カレーを作るライフサイクル
    • 具材を切るフェーズ
    • 具材を炒めるフェーズ
    • 具材を煮込むフェーズ
    • ルーを入れるフェーズ
    • 皿によそうフェーズ
  • 片づけるライフサイクル
    • 皿を集めるフェーズ
    • 洗うフェーズ

カレーの具材は人によって異なるため「具材を切るフェーズ」には自分で「たまねぎ切るplugin」や「ニンジン切るplugin」を割り当てる。

「ルーを入れるフェーズ」は当然99%の人がジャワカレーを選択するので、mavenが「ジャワカレーplugin」をデフォルトで割り当ててくれている。

具材を炒めるフェーズを実行すると、具材を切るフェーズから実行される。

うーん、あんまりわかりやすくならなかった。

サンプル

プロジェクトを作る。

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false -DgroupId=example.com -DartifactId=sample

echo-maven-pluginというechoするだけのpluginをtestフェーズに割り当てる。

<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>

testフェーズを実行するとecho-maven-pluginも実行されることがわかる。
ついでに、testフェーズまでの各フェーズも実行されている。

$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory c:\Users\pbreh_000\Desktop\study\sample\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sample ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory c:\Users\pbreh_000\Desktop\study\sample\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ sample ---
[INFO] Surefire report directory: c:\Users\pbreh_000\Desktop\study\sample\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.example.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- echo-maven-plugin:0.3.0:echo (default) @ sample ---
[INFO] This is the Test Text
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.049 s
[INFO] Finished at: 2017-07-31T20:24:31+09:00
[INFO] Final Memory: 11M/304M
[INFO] ------------------------------------------------------------------------

実効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の実行をスキップする方法は各pluginごとに用意されている。(例えば、surefire:testだと-Dmaven.test.skip=trueや-DskipTests=trueだったり、install:installだと-Dmaven.install.skip=true)

しかし、フェーズ自体は飛ばせないっぽい。
試しにコマンド打ってみても、echo-maven-pluginは動いてしまう。

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
...

フェーズに割り当てたすべてのpluginをスキップさせるなら、Profileを使えば良さそう。

https://stackoverflow.com/questions/3147714/how-to-skip-install-phase-in-maven-build-if-i-already-have-this-version-installe

ゴール

mavenのpluginは各フェーズに割り当てなくても使える。そのときは以下の形式で実行する。

mvn prefix:goal

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
[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によってはcompileフェーズで生成されたclassesファイルを使うもの(findbugsとか?)もあるので、注意する。


で、このprefix:goalのprefixってなに指定すりゃいいねんと思いながらいつもググってたけど、ちゃんとしたルールがあるらしい。

https://maven.apache.org/guides/introduction/introduction-to-plugin-prefix-mapping.html

またprefix:goalのgoalついても一覧を表示できる。

ググったら詳しいサイトがあったので詳細はこちらを参照。
qiita.com


とりあえず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.
 ...

結論

「mvn clean test」みたいに実行するコマンドと「mvn checkstyle:checkstyle」みたいに実行するコマンドとの差は、「フェーズ」か「ゴール」か。