解決したい問題
カスタム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が下記のようなフォルダ・ツリーを生成しました。
このフォルダー・ツリーを使うことにしました。ArtifactId_of_custom_Gradle_plugin_in_multiproject_how_to_specify
という長い名前のフォルダのことを以下ではrootと呼ぶことにします。ここで注目してほしいポイントがひとつあります。gradle init
コマンドはここでGradleの言葉遣いでいうところの「マルチプロジェクト」を生成しました。plugin
という名前のフォルダが生成されました。
わたしはplugin
フォルダの中にGroovyコードを配置してカスタムgradleプラグインを実装しました。カスタムgradleプラグインの作り方を解説する記事をネット検索しました。Tom Gregoryの下記の記事を写経することにしました。
Tomさんによるサンプル・コードをコピペしました。Extension class, Task class, Plugin class, Test for the pluginとか。瑣末な箇所(パッケージ名とか)を改めましたが、基本的にTomさんのコードそのままです。コンパイルが通り、テストもパスしました。
次に .m2/repository
つまりMavenローカルレポジトリにJARをパブリッシュしようとしました。plugins/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
ディレクトリの様子を見ました。
問題があります! gradle publishToMavenLocal
コマンドは下記2つのディレクトリを生成しました。
.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
を再実行すると、下記のようになりました。
成功しました。
説明
publishToMavenLocal
タスクがartifactIdを決定します。このタスクを提供するのは maven-publish
プラグインの働きです。maven-publish
プラグインのドキュメント にこう書いてあります。
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にコードをホストしています。
補足: "gradle jar"コマンドが生成するjarファイルのartifactIdを明示的に指定する方法
メモを添えておきます。わたしは次のコマンドを実行した。
$ cd <root dir>/plugin
$ gradle clean jar
すると plugin/build/libs
ディレクトリの下にJARファイルが出力された。JARのファイル名は plugin-x.x.x.jar
という形だった。
このファイル名はいただけない。JARのartifactIdを明示的に指定して file-diff-plugin-x.x.x.jar
としたい。どうすればできるか?
答え: plugin/build.gradle
ファイルを修正すればよい。Gradleを実行したとき project
オブジェクトが artifactsBaseName
プロパティを持つ。そのデフォルト値はプロジェクトのディレクトリ名すなわち plugin
であるが、任意の文字列で置き換えることができる。つまり下記のようにすればいい。
JarタスクのドキュメントGradle Jar taskを参照のこと。