カスタムGradleプラグインのartifactIdを明示的に指定する方法、Gradleマルチプロジェクトで

## 解決したい問題

カスタムGradleプラグインの作り方を学ぼうとしました。ひとつ新しくディレクトリを作り、その中で `gradle init` コマンドを実行してGradleプロジェクトを初期化しました。Gradle v8.5を使いました。

```
$ cd ~/tmp
$ mkdir 
$ cd ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify
```

```
$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 4

Select implementation language:
  1: Groovy
  2: Java
  3: Kotlin
Enter selection (default: Java) [1..3] 1

Select build script DSL:
  1: Kotlin
  2: Groovy
Enter selection (default: Groovy) [1..2] 2
```
このあと、入力を求めるプロンプトが何回か続きました。

```
Project name (default: ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to 
```
これに対してはENTERするのみ。

```
Source package (default: artifactid_of_custom_gradle_plugin_in_multiproject_how_
```
これに対しては `com.kazurayam.gradleplugins` を入力した。

```
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) 
```
これに対してはENTERするのみ。

```
> Task :init
For more information, please refer to https://docs.gradle.org/8.5/userguide/custom_plugins.html in the Gradle documentation.

BUILD SUCCESSFUL in 6m 42s
2 actionable tasks: 2 executed
```
無事終了しました。Gradleが下記のようなフォルダ・ツリーを生成しました。

![01](https://kazurayam.github.io/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/images/01_project_in_finder.png)

このフォルダー・ツリーを使うことにしました。`ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify`という長い名前のフォルダのことを以下ではrootと呼ぶことにします。ここで注目してほしいポイントがひとつあります。`gradle init`コマンドはここでGradleの言葉遣いでいうところの「マルチプロジェクト」を生成しました。`plugin`という名前のフォルダが生成されました。

わたしは`plugin`フォルダの中にGroovyコードを配置してカスタムgradleプラグインを実装しました。カスタムgradleプラグインの作り方を解説する記事をネット検索しました。Tom Gregoryの下記の記事を写経することにしました。

- [Introduction to writing Gradle plugins](https://tomgregory.com/gradle/introduction-to-gradle-plugins/)

Tomさんによるサンプル・コードをコピペしました。[Extension class](https://tomgregory.com/gradle/introduction-to-gradle-plugins/#3-extension-class), [Task class](https://tomgregory.com/gradle/introduction-to-gradle-plugins/#4-task-class), [Plugin class](https://tomgregory.com/gradle/introduction-to-gradle-plugins/#5-plugin-class), [Test for the plugin](https://tomgregory.com/gradle/introduction-to-gradle-plugins/#6-adding-a-plugin-integration-test)とか。瑣末な箇所（パッケージ名とか）を改めましたが、基本的にTomさんのコードそのままです。コンパイルが通り、テストもパスしました。

次に `.m2/repository` つまりMavenローカルレポジトリにJARをパブリッシュしようとしました。[`plugins/build.gradle`](https://github.com/kazurayam/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/blob/master/plugin/build.gradle) ファイルの中身は次の通り。

```
plugins {
    id 'java-gradle-plugin'
    id 'groovy'
    id 'maven-publish'
}

group = 'com.kazurayam'
version = '0.1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    // Use the awesome Spock testing and specification framework
    testImplementation libs.spock.core
    // Junit dependencies
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

test {
    useJUnitPlatform()
    testLogging {
        events "started", "passed", "skipped", "failed"
    }
}

gradlePlugin {
    plugins {
        fileDiff {
            id = 'com.kazurayam.file-diff'
            implementationClass = 'com.kazurayam.gradleplugins.filediff.FileDiffPlugin'
        }
    }
}
```

下記のコマンドを実行しました。

```
~/tmp/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify (master)
$ cd plugin
~/tmp/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/plugin (master)
$ gradle publishToMavenLocal
```

このコマンドが成功しました。`~/.m2`ディレクトリの様子を見ました。


![02](https://kazurayam.github.io/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/images/02_artifactId_plugin.png)

問題があります！　`gradle publishToMavenLocal`コマンドは下記２つのディレクトリを生成しました。


- `.m2/repository/com/kazurayam/file-diff`
- `.m2/repository/com/kazurayam/plugin`

一番目のディレクトリは問題ない。二番目のディレクトリの名前 `plugin` が気に入りません。わたしはこれを `file-diff-plugin` ないしは `file-diff-impl` というような名前にしたい。でもどうすればいいのでしょうか？

ここで`plugin`という値が設定された概念のことをGradleのMaven Publishプラグインは「artifactId」という集合名詞で言い表しています。

### わたしの疑問

`gradle init`コマンドによって自動生成されたフォルダ構造とbuild.gradleのままだとgradleプラグインのartifactIdが `plugin` というよろしくない名前になってしまう。それを明示的に指定したい。どうすればいいのか？


## 解決方法

`plugin/build.gradle`ファイルを修正します。下記の行を追加せよ。

```
publishing {
    publications {
        maven(MavenPublication) {
            artifactId = 'file-diff-plugin'
        }
    }
}
```
この修正をした後で `gradle publishToMavenLocal` を再実行すると、下記のようになりました。


![03](https://kazurayam.github.io/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/images/03_artifactId_file-diff-plugin.png)

成功しました。

## 説明

`publishToMavenLocal`タスクがartifactIdを決定します。このタスクを提供するのは `maven-publish` プラグインの働きです。`maven-publish`プラグインの[ドキュメント](https://docs.gradle.org/current/userguide/publishing_maven.html#sec:identity_values_in_the_generated_pom) にこう書いてあります。

>Identity values in the generated POM
> 
>The attributes of the generated POM file will contain identity values derived from the following project properties:
> - groupId - Project.getGroup()
> - artifactId - Project.getName()
> - version - Project.getVersion()

これによると、artifactIdは Project.getName()に基づいている。で、Project.getName()の値はプロジェクトのディレクトリ名に基づいている。artifactIdが `plugin` と設定されたのは、サブプロジェクトのディレクトリ名が `plugin` であったから。

ドキュメントにはこうも書いてあります。

>Overriding the default identity values is easy: simply specify the groupId, artifactId or version attributes when configuring the MavenPublication.

だからわたしは `plugin/build.gradle` ファイルを上記のように修正しました。

## 結論

カスタムGradleプラグインの作り方を解決する記事はネット上にたくさんありますが、わたしの見るところ、それら記事はみなシングルなgradleプロジェクトを素材としていて、マルチ・プロジェクトの事例は見当たらなかった。ところが `gradle init` でプロジェクト・ツリーを初期構築するとマルチ・プロジェクトになる。するとjarファイルの名前が `plugin-0.1.0.jar` という妙な名前になってしまう。これを `file-diff-plugin-0.1.0.jar`というようにわたし好みのartifactIdに改めたい。どうすればいいのか？

その答えをようやく見つけました。Maven publishプラグインのマニュアルを読んで、その通りに設定すればいいだけだった。気づいてしまえば簡単なことだった。しかしこれに気づくまでにえらく時間（たぶん三年）がかかった。ああ！

## 参考

GitHubにコードをホストしています。
- [ArtifactId of customGradle plugin in multiproject, how to specify](https://github.com/kazurayam/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify)

## 補足: "gradle jar"コマンドが生成するjarファイルのartifactIdを明示的に指定する方法

メモを添えておきます。わたしは次のコマンドを実行した。

```
$ cd <root dir>/plugin
$ gradle clean jar
```

すると `plugin/build/libs` ディレクトリの下にJARファイルが出力された。JARのファイル名は `plugin-x.x.x.jar` という形だった。


![11](https://kazurayam.github.io/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/images/11_libs_plugin_jar.png)


このファイル名はいただけない。JARのartifactIdを明示的に指定して `file-diff-plugin-x.x.x.jar` としたい。どうすればできるか？

答え：　`plugin/build.gradle` ファイルを修正すればよい。Gradleを実行したとき `project`オブジェクトが `artifactsBaseName`プロパティを持つ。そのデフォルト値はプロジェクトのディレクトリ名すなわち `plugin` であるが、任意の文字列で置き換えることができる。つまり下記のようにすればいい。


![12](https://kazurayam.github.io/ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify/images/12_libs_controlled_artifactId.png)

Jarタスクのドキュメント[Gradle Jar task](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveBaseName)を参照のこと。