Mavenのversionに日付とその日のビルド番号を自動的に付与する

Mavenプロジェクトのversionは、基本的に`pom.xml`に書いておきますが、~~基本的に手動でバージョンを上げなければなりません。~~

**追記2020/04/03**
releaseプラグインを使えば、x.y.zのzは自動的にインクリメントしてくれるそうです。

でも、日付やタイムスタンプ、ビルド番号を付与したいって言われたら？

`pom.xml`をshスクリプトとかで書き換える？マルチモジュールのとき、大変すぎない？
`mvn versions:set -DnewVersion=whatever`で毎回一斉に書き換える?
手間が増えるよね？結局ビルドにスクリプトが必要になっちゃう?

JenkinsとかCIツールだったらプラグインで出来るみたいだけど・・・

なお、ここでやりたいのは、Arfictの生成物であるファイル名をどうにかしたいのではなく、Artifactのバージョンそのものを付ける方法の話です。

# Goal

`mvn install`などで、モジュールの`version`に自動的に日付とビルド番号を付与する。
例)`0.0.1.20200401-2`

自前でスクリプトなどを書かずに実現すること。

なお、一部にCIの機能を使うことは許容する。
・・・どういうことかというと、とりあえず`version`のテンプレートなどが定義できていて、一部の値をCIツールからビルドコマンドで渡せればOK、という意味です。

# 環境

|ツールなど|バージョンなど|
|:--|:--|
| MacbookPro |macOS Mojave 10.14.5|
|IntelliJ IDEA |Ultimate 2019.3.3|
|Java |AdoptOpenJDK 11|
|apache maven |3.6.3|
|Spring Framework|5.2.4.RELEASE|
|JUnit|5.6.0|
|Tomcat|apache-tomcat-8.5.51|

# 実現方法

結論から言うと、**一部にCIの機能を使うことは許容する**ことで、日付とビルド番号を付与できます。
なお、このプロジェクトは、マルチモジュール構成となっていて、すべてのモジュールが親のバージョンを使い完全にバージョンを一致させる運用としています。
簡単に言うと、サブモジュールでは

```xml:pom.xml
	<artifactId>some-api</artifactId>
	<packaging>war</packaging>
```

とだけして、`version`タグを入れません。ルートの`pom.xml`にだけ、入れておきます。
そうすると、サブモジュールもすべて同じバージョンになります。

## 1.ルートpomへの`<version>`の設定

```xml:root/pom.xml
    <version>0.0.1.${buildDate}-${revision}</version>
```

## 2.ルートpomへの`<properties>`の設定

```xml:root/pom.xml
    <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- バージョニングに使う日付 -->
        <buildDate>${maven.build.timestamp}</buildDate>
        <!-- バージョニングに使う日付のフォーマット -->
        <timestamp>${maven.build.timestamp}</timestamp>
        <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>

        <!-- バージョニングに使うリビジョン番号。
        CI/CDツールにて -Drevision=buildNumber で上書きする -->
        <revision>SNAPSHOT</revision>
    </properties>
```

コメントにある通り、`<revision>`はコマンドラインから指定可能です。省略すると、`SNAPSHOT`が付くことになります。

## 3.サブモジュールの`<parent>`の`<version>`も変更する

```xml:submodule/pom.xml
	<parent>
		<groupId>jp.example.myapp</groupId>
		<artifactId>testsample</artifactId>
		<version>0.0.1.${buildDate}-${revision}</version>
	</parent>
```

すべてのサブモジュールに対して行うのを忘れないように。

## 4.ビルド

`mvn clean install`と、`mvn install -Drevision=2`としてビルドしてみてください。
各モジュールの`target`フォルダの`pom.properties`や、生成された`jar`/`war`ファイルのファイル名で確認できます。(`<build>/<finalName>`で上書きしていない場合)

### (1)revision指定なし

```console
$ mvn clean install
$ ls -la **/target/*.?ar
17:02 submodule/target/submodule-0.0.1.20200402-SNAPSHOT.war
17:02 core/target/core-0.0.1.20200402-SNAPSHOT.jar
```

```submodule/target/maven-archiver/pom.properties 
#Generated by Maven
#Thu Apr 02 17:02:10 JST 2020
groupId=jp.example.myapp
artifactId=testsample
version=0.0.1.20200402-SNAPSHOT
```

### (2)revision指定あり

```console
$ mvn clean install -Drevision=2
$ ls -la **/target/*.?ar
17:29 submodule/target/some-api-0.0.1.20200402-2.war
17:29 core/target/some-core-0.0.1.20200402-2.jar
```

```submodule/target/maven-archiver/pom.properties 
#Generated by Maven
#Thu Apr 02 17:29:47 JST 2020
groupId=jp.example.myapp
artifactId=testsample
version=0.0.1.20200402-2
```

## 5.CIでビルド番号を付与する

CIでの実行コマンドで、`mvn install`などしていると思うので、そこに`-Drevision=`オプションを追加すればよいですね。
「その日のビルド番号」は、CIツールでそれぞれ取り方があると思うので、そちらを参照してください。

とりあえず、Jenkinsだと[Version Number](https://plugins.jenkins.io/versionnumber/)というプラグインを使うと、`BUILDS_TODAY`というのが使えそうです。(ただ、リセットされるタイムゾーンは不明ですが・・・)

Azure Pipelinesだと、[Configure run or build numbers](https://docs.microsoft.com/ja-jp/azure/devops/pipelines/process/run-number?view=tfs-2017&tabs=yaml)のページによれば、`$(Rev:r)`を使えば行けそうです。


# 参考

`-Dreivision`のやり方の参考になりました。
https://stackoverflow.com/questions/18456111/what-is-the-maven-way-for-automatic-project-versions-when-doing-continuous-deliv

マルチモジュールでのバージョニング管理について参考になりました。
https://qiita.com/ms0_mtRiver/items/85593b17d6ebb8fb2cfd