Gradle Pluginを作成する

# pluginプロジェクトを作成

[pluginプロジェクトを作成する](https://qiita.com/ykdevs/items/5bcd5140e863c8fefb45#plugin%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B) の手順で作成する。

build.gradleのpluginsにmaven-publishを追加

```gradle:plugin/build.gradle
/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Gradle plugin project to get you started.
 * For more details take a look at the Writing Custom Plugins chapter in the Gradle
 * User Manual available at https://docs.gradle.org/7.5.1/userguide/custom_plugins.html
 */


plugins {
    // Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
    id 'java-gradle-plugin'

    // Apply the Groovy plugin to add support for Groovy
    id 'groovy'

    id 'maven-publish'
}

version = '1.0.0'

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use the awesome Spock testing and specification framework
    testImplementation 'org.spockframework:spock-core:2.1-groovy-3.0'
}

gradlePlugin {
    // Define the plugin
    plugins {
        greeting {
            id = 'plugin.project.greeting'
            implementationClass = 'plugin.project.PluginProjectPlugin'
        }
    }
}

// Add a source set for the functional test suite
sourceSets {
    functionalTest {
    }
}

configurations.functionalTestImplementation.extendsFrom(configurations.testImplementation)

// Add a task to run the functional tests
tasks.register('functionalTest', Test) {
    testClassesDirs = sourceSets.functionalTest.output.classesDirs
    classpath = sourceSets.functionalTest.runtimeClasspath
    useJUnitPlatform()
}

gradlePlugin.testSourceSets(sourceSets.functionalTest)

tasks.named('check') {
    // Run the functional tests as part of `check`
    dependsOn(tasks.functionalTest)
}

tasks.named('test') {
    // Use JUnit Jupiter for unit tests.
    useJUnitPlatform()
}
```

ローカルにpublishする

```shell
% ./gradlew build
```

```shell
% ./gradlew publishToMavenLocal

BUILD SUCCESSFUL in 701ms
9 actionable tasks: 5 executed, 4 up-to-date
```

```shell
% cd ~/.m2/repository/plugin/project/greeting/
% tree .
.
└── plugin.project.greeting.gradle.plugin
    ├── 1.0.0
    │   └── plugin.project.greeting.gradle.plugin-1.0.0.pom
    └── maven-metadata-local.xml

2 directories, 2 files
```

```xml:plugin.project.greeting.gradle.plugin-unspecified.pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>plugin.project.greeting</groupId>
  <artifactId>plugin.project.greeting.gradle.plugin</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <dependencies>
    <dependency>
      <groupId>plugin-project</groupId>
      <artifactId>plugin</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
</project>
```


# pluginを利用するプロジェクトを作成

```shell
% mkdir plugin-use-project
% cd plugin-use-project/
```

```shell
% gradle init

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

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 
Project name (default: plugin-use-project): 

> Task :init
Get more help with your project: Learn more about Gradle by exploring our samples at https://docs.gradle.org/7.5.1/samples

BUILD SUCCESSFUL in 10s
2 actionable tasks: 2 executed
```

build.gradleを編集してPluginを読み込む

```gradle:build.gradle
buildscript {
    repositories {
        mavenLocal() // <1>
    }
    dependencies {
        classpath 'plugin.project.greeting:plugin.project.greeting.gradle.plugin:1.0.0' // <2>
    }
}

apply plugin: 'plugin.project.greeting'
```

Pluginの実行

```
% ./gradlew greeting

> Task :greeting
Hello from plugin 'plugin.project.greeting'

BUILD SUCCESSFUL in 364ms
1 actionable task: 1 executed
```

パッケージ名を変える

```shell
% mv plugin greeting-plugin
```

```gradle:settings.gradle
rootProject.name = 'plugin-project'
include('greeting-plugin')
```

```gradle:greeting-plugin/build.gradle
plugins {
    // Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
    id 'java-gradle-plugin'

    // Apply the Groovy plugin to add support for Groovy
    id 'groovy'

    id 'maven-publish'
}

group = 'com.ykdevs.plugin'
version = '1.0.0'

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use the awesome Spock testing and specification framework
    testImplementation 'org.spockframework:spock-core:2.1-groovy-3.0'
}

gradlePlugin {
    // Define the plugin
    plugins {
        greeting {
            id = 'plugin.project.greeting'
            implementationClass = 'plugin.project.PluginProjectPlugin'
        }
    }
}

// Add a source set for the functional test suite
sourceSets {
    functionalTest {
    }
}

configurations.functionalTestImplementation.extendsFrom(configurations.testImplementation)

// Add a task to run the functional tests
tasks.register('functionalTest', Test) {
    testClassesDirs = sourceSets.functionalTest.output.classesDirs
    classpath = sourceSets.functionalTest.runtimeClasspath
    useJUnitPlatform()
}

gradlePlugin.testSourceSets(sourceSets.functionalTest)

tasks.named('check') {
    // Run the functional tests as part of `check`
    dependsOn(tasks.functionalTest)
}

tasks.named('test') {
    // Use JUnit Jupiter for unit tests.
    useJUnitPlatform()
}
```

```shell
yuzuru[Andy]% ./gradlew build

BUILD SUCCESSFUL in 415ms
10 actionable tasks: 10 up-to-date
yuzuru[Andy]% ./gradlew publishToMavenLocal

BUILD SUCCESSFUL in 399ms
9 actionable tasks: 5 executed, 4 up-to-date
```

```xml:~/.m2/repository/com/ykdevs/plugin/greeting-plugin/1.0.0/greeting-plugin-1.0.0.pom
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!-- This module was also published with a richer model, Gradle metadata,  -->
  <!-- which should be used instead. Do not delete the following line which  -->
  <!-- is to indicate to Gradle or any Gradle module metadata file consumer  -->
  <!-- that they should prefer consuming it instead. -->
  <!-- do_not_remove: published-with-gradle-metadata -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.ykdevs.plugin</groupId>
  <artifactId>greeting-plugin</artifactId>
  <version>1.0.0</version>
</project>
```

呼び出し側のプロジェクトのbuild.gradleを編集

```gradle:build.gradle
buildscript {
    repositories {
        mavenLocal() // <1>
    }
    dependencies {
        classpath 'com.ykdevs.plugin:greeting-plugin:1.0.0' // <2>
    }
}

apply plugin: 'plugin.project.greeting'
```

タスクを実行

```shell
% ./gradlew greeting

> Task :greeting
Hello from plugin 'plugin.project.greeting'

BUILD SUCCESSFUL in 497ms
1 actionable task: 1 executed
```

- groupとversionを指定しておく
- ディレクトリの１階層目がアーティファクト名になる


# 参考
- [【gradle】pluginの作り方](https://qiita.com/rhirabay/items/265f382e74a7fb6829c9)