【gradle】pluginの作り方

# 概要

gradle pluginを作ったのですが、ドキュメントを探しても↓くらいしか見つからず
試行錯誤したのでやったことをメモとして残しておきます

http://gradle.monochromeroad.com/docs/userguide/custom_plugins.html

# なぜ gradle plugin ?

たとえばJavaのコードで複数のアプリケーションで共通のロジックを持っていたらどうするでしょう？
ライブラリを作成し、共通ロジックを一元管理すると思います。

では、Gradleを使っている場合に、build.gradleに同じような記載が必要な場合はどうするでしょう？
こういったときにgradle-pluginで、共通の設定を一元管理できれよいと考え作成を検討しました！

# なぜGroovy？

プラグインの実装をGroovyで行ったのですが、
build.gradleの共通部分の一元管理を目的としているので、
build.gradleに書き方が近い方がメンテナンスがしやすいと判断しました。

# プラグイン作成

それでは簡単なプラグインを作成していきます。

`Hello, gradle plugin`と表示するだけのhelloタスクを追加するプラグインを作ってみたいと思います。

まずはプロジェクトの設定です。

```groovy:build.gradle
plugins {
    id 'groovy' // <1>
    id 'java-gradle-plugin' // <2>
    id 'maven-publish'
}

group 'rhirabay'
version '1.0.0'

gradlePlugin { 
    plugins {
        mySamplePlugin {
            id = 'rhirabay.gradle-plugin' // <3>
            implementationClass = 'rhirabay.HelloPlugin' // <4>
        }
    }
}

repositories {
    mavenCentral()
}

dependencies {
    gradleApi() // <5>
}
```

1. 今回はプラグインをGroovyで実装するので、`groovy`プラグインを適用します。
2. プラグイン開発時に必要なプラグインです
3. 開発したプラグインを利用するときのプラグイン識別子をしていします
4. プラグインの実装クラスをしていします
5. プラグイン開発に必要な最低限の依存ライブラリを取り込んでくれます

次にプラグインの実装です。

```groovy
package rhirabay

import org.gradle.api.Plugin
import org.gradle.api.Project

class HelloPlugin // <1>
        implements Plugin<Project> { // <2>
    
    @Override
    void apply(Project project) { // <3>
        project.tasks.create('hello') {
            doLast {
                println('Hello, gradle plugin')
            }
        }
    }
}
```

1. package・クラス名は、build.graldeの`implementationClass`と対応させる必要があります
2. `Plugin`インターフェースを実装する形で実装します
3. `Project`クラスで、プロジェクトの情報参照やタスクの追加等各種操作が行えます

# ローカルリポジトリにpublish

`publishToMavenLocal`タスクを実行すればOK

```
./gradlew publishToMavenLocal
```

# プラグインの利用方法

maven repository (ローカルや社内リポジトリ含め)にプラグインのjarファイルをアップロードをしている場合、
buildscriptでプラグインの取得元を指定してあげる必要があります。

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

apply plugin: 'rhirabay.gradle-plugin' // <3>
```

1. プラグインのpublish先（今回はローカルリポジトリ）
2. 開発したプラグインの`group`.`project name`.`version`
3. `id`で定義したプラグインの識別子を指定する

これでhelloタスクが追加され、実行すると…

```
> Task :test:hello
Hello, gradle plugin
```

🎉🎉🎉

# How to 〇〇

ここからは、「〇〇したいときはどうする？」をまとめていきます。
試行錯誤してとりあえずこうすれば実現できたという内容をサンプルのみ載せていきます🙇‍♂️

## 独自タスクの追加

`hello`タスクを作成するサンプルです。

```groovy
class HelloPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.tasks.create('hello') {
            doLast {
                // 実行する処理
            }
        }
    }
}
```

## タスクの動作を設定可能に

build.gradleで、以下のように設定すると

```groovy:build.gradle
hello {
    message = 'plugin extention'
}
```

設定したmessageを元にメッセージを出力するようにしてみます。

まずはExtensionを作成します。
読み込ませたい設定をフィールドに持つクラスを作成するだけです！

```groovy
class HelloExtension {
    String message
}
```

次に作成したExtensionをProjectに登録します

```groovy
class HelloPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // extensionを登録
        project.extensions.create("hello", HelloExtension)

        project.tasks.create('hello') {
            doLast {
                // extensionの読み込みは`project.extensions.getByXxxx`を使う
                println("Hello, ${project.extensions.getByType(HelloExtension.class).message}")
            }
        }
    }
}
```

helloタスクを実行してみると

```
> Task :test:hello
Hello, plugin extention
```

## プラグインを複数クラスで管理

以下のような`HelloSubPlugin`があったとします。

```groovy
class HelloSubPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // something
    }
}
```

以下のようにインスタンス化後に`apply`でprojectを渡してあげればOK

```groovy
class HelloPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        new HelloSubPlugin().apply(project)
    }
}
```