Mavenのビルドライフサイクル

# はじめに
Mavenのビルドのライフサイクルについてまとめました。
基礎的な部分しか書いてないです。

# 3つのビルドライフサイクル
mavenには3つのビルドライフサイクルがあります。

- clean: ビルドした成果物を削除する
- default: デプロイまでを行う
- site: サイトドキュメントを生成する

それぞれのライフサイクルは複数のフェーズで構成されています。
フェーズとはライフサイクルを構成するステップのことで、それぞれのフェーズで行う内容が異なります。

- https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference

## clean
ビルドした成果物を削除するライフサイクル。
`target`ディレクトリを削除すると思っておけばOK。

|Phase|内容|
|:-:|:-:|
|pre-clean|cleanの前処理|
|clean|ビルドで生成した全ファイルを削除する|
|post-clean|cleanの後処理|

## default
コンパイル、テスト、パッケージング、デプロイなどを行うライフサイクル。
以下のフェーズで構成されています。

|phase|内容|
|:-:|:-:|
|validate|プロジェクトの正当性や必要な情報が揃っているかを検証する|
|initialize|初期化を行う（プロパティのセット、ディレクトリの生成など）|
|generate-sources|コンパイルに含むソースコードを生成する|
|process-sources|ソースコードに対して処理を行う（フィルタリングなど）|
|generate-resources|パッケージに含むリソースを生成する|
|process-resources|リソースを配布用ディレクトリにコピーする|
|compile|ソースコードのコンパイルを行う|
|process-classes|コンパイルで生成したファイルに対して後処理を行う（バイトコードの拡張など）|
|generate-test-sources|コンパイルに含むテストソースコードを生成する|
|process-test-sources|テストソースコードに対して処理を行う（フィルタリングなど）|
|generate-test-resources|テスト用リソースを生成する|
|process-test-resources|リソースをテスト用ディレクトリにコピーする|
|test-compile|テストソースコードをコンパイルする|
|process-test-classes|コンパイルで生成したテスト用ファイルに対して後処理を行う（バイトコードの拡張など）|
|test|ユニットテストを行う|
|prepare-package|パッケージングの前段階の処理で、ここではパッケージングはされない|
|package|コンパイルコードのパッケージング(jarなど)を行う|
|pre-integration-test|統合テストの前処理で、必要な環境のセットアップなどを行う|
|integration-test|統合テストを行う|
|post-integration-test|統合テストの後処理で、環境のクリーンなどを行う|
|verify|パッケージが有効であること、品質基準を満たしていることをチェックする|
|install|ローカルリポジトリにインストールする|
|deploy|リモートリポジトリにデプロイする|

## site
プロジェクトのサイトドキュメントを生成するライフサイクル。
このようなドキュメントが作成されます↓
<img width="1274" alt="スクリーンショット 2019-01-12 12.55.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/89007/29663fbd-b154-fd5f-3034-fc4b3a96f394.png">


|Phase|内容|
|:-:|:-:|
|pre-site|siteの前処理|
|site|サイトドキュメントを生成する|
|post-site|siteの後処理、site-deployの準備を行う|
|site-deploy|生成したサイトドキュメントをwebサーバにデプロイする|

# プラグイン
mavenでは全ての処理がプラグインによって実現されています。←これ重要
ライフサイクルの各フェーズで行われる処理は実際はプラグインが持つ処理が実行されています。
mavenではフェーズとプラグインが持つ処理(ゴール)を紐付けることにより、フェーズを指定するだけで処理が実行される仕組みになっています。

# ゴール
ゴールはプラグインが持つ特定の処理のことです。
プラグインは複数のゴールを持っており、同じプラグインでも指定するゴールによって実行する処理内容は異なります。

## ゴールの実行
ゴールの実行は

1. フェーズを指定する
2. ゴールを直接指定する

の2通りあります。

### フェーズを指定する
フェーズを指定して実行する場合は`mvn <phase>`のように指定します。
フェーズを指定して実行すると最初のフェーズから指定したフェーズまで順番に呼び出され、呼び出されたそれぞれのフェーズに紐付いているゴールが順次実行されます。
例えば以下のように指定して実行すると、validateからcompileフェーズが順次呼び出され、それぞれが紐付いているゴールが実行されます。

```shell
# validate, initialize, ..., compileフェーズに紐づくゴールが順次実行される
mvn compile
```

### ゴールを直接指定する
直接ゴールを指定して実行する場合は`mvn <plugin>:<goal>`という形で指定します。
特定のゴールだけを実行したい場合などはこの方法で実行します。
例えば以下のように指定して実行するとcompilerプラグインのcompileゴールが実行されます。

```shell
# compilerプラグインのcompileゴールを実行する
mvn compiler:compile
```

# フェーズとゴールの紐づけ
上記で説明したように、フェーズとゴールを紐付けることでフェーズを指定するだけでゴールが実行されます。
mavenではそれぞれのライフサイクルのいくつかのフェーズはあらかじめゴールが紐付けられています。

- https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings

## clean
cleanフェーズのみにゴールが紐付けられます。

|Phase|plugin:goal|
|:-:|:-:|
|clean|clean:clean|

## default
defaultライフサイクルではpom.xmlの`<packaging>`要素によってフェーズとゴールの紐づけが異なります。
例えば`<packaging>`にjarを指定した場合、以下のフェーズにゴールが紐付けられるようになります。

|Phase|plugin:goal|
|:-:|:-:|
|process-resources|resources:resources|
|compile|compiler:compile|
|process-test-resources|resources:testResources|
|test-compile|compiler:testCompile|
|test|surefire:test|
|package|jar:jar|
|install|install:install|
|deploy|deploy:deploy|

packagingタイプによってどのフェーズでどのゴールが実行されるかは以下リンクを参照。

- https://maven.apache.org/ref/3.6.0/maven-core/default-bindings.html

## site
以下のフェーズがゴールに紐付けられます。

|Phase|plugin:goal|
|:-:|:-:|
|site|site:site|
|site-deploy|site:deploy|

## 自由にフェーズとゴールを紐付ける
自由にフェーズとゴールを紐づけたい場合はpom.xmlのpluginタグ内をいじります。
具体的には`<executions>`内の`<execution>`内に`<phase>`と`<goal>`を指定します。

```xml:pom.xml
    ...
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <!-- packageフェーズにrepackageゴールを実行する -->
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        ...
        </plugins>
    </build>
    ...
```

# 実際に実行してみる
上記で説明してきたことを踏まえて、packagingをjarにして`mvn deploy`してみます。

## POM
jarを生成するように`<packaging>`にjarを指定します。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8" ?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hoge.fuga</groupId>
    <artifactId>piyo-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!-- jarを指定 -->
    <packaging>jar</packaging>
    <name>piyo-app</name>
    ...
```

## plugin
次の2つのプラグインを追加し、以下のフェーズとゴールをそれぞれ指定します。

|plugin|phase|goal|
|:-:|:-:|:-:|
|spring-boot-maven-plugin|package|repackage|
|kotlin-maven-plugin|compile<br>test-compile|compile<br>test-compile|

```xml:pom.xml
    ...
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.1.1.RELEASE</version>
                <executions>
                    <execution>
                        <!-- packageフェーズにrepackageゴールを実行する -->
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>compile</id>
                        <!-- compileフェーズにcompileゴールを実行する -->
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <!-- test-compileフェーズにtest-compileゴールを実行する -->
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
    </build>
    ...
```

## 結果
実際に実行してみると、あらかじめ紐付けられているゴールと自分で紐づけたゴールがそれぞれのフェーズで実行される様子がわかります。

```
$ mvn deploy

[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< com.hoge.fuga:piyo-app >---------------
[INFO] Building piyo-app 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:resources (default-resources) @ piyo-app ---
...
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ piyo-app ---
...
[INFO] --- kotlin-maven-plugin:1.3.10:compile (compile) @ piyo-app ---
...
[INFO] --- maven-resources-plugin:3.0.1:testResources (default-testResources) @ piyo-app ---
...
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ piyo-app ---
...
[INFO] --- kotlin-maven-plugin:1.3.10:test-compile (test-compile) @ piyo-app ---
...
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ piyo-app ---
...
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ piyo-app ---
...
[INFO] --- spring-boot-maven-plugin:2.0.3.RELEASE:repackage (default) @ piyo-app ---
...
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ piyo-app ---
...
[INFO] --- maven-deploy-plugin:2.8.2:deploy (default-deploy) @ piyo-app ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 36.815 s
[INFO] Finished at: 2019-01-02T20:59:50+09:00
[INFO] ------------------------------------------------------------------------
```


# 参考
- [Maven – Introduction to the Build Lifecycle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
- [7. Maven Tips | TECHSCORE(テックスコア)](http://www.techscore.com/tech/Java/ApacheJakarta/Maven/7/)