Plugin Portalへ公開できるPrecompiled script pluginsの作り方

## はじめに
ちょっとしたものをプラグインとするのであればさっと書きやすいので、Precompiled script pluginsで作成したが何点か公開するには詰まったところがあった。それらを含めた備忘録をまとめる。

## Precompiled script plugins とは
gradleファイルで書いたものをそのままプラグインにできる。
Precompiledが指す通りあらかじめコンパイルされる。そのため、完成物はバイナリプラグインでありjarができあがる。
使う上ではスタンドアロンプラグインと変わりない。

## 作り方

Precompiled script pluginsの場合、居たるところでplugin IDが影響するため、一番最初にIDを決める手順としている。

1. [IDを決める][1]
1. [build.gradleを作る][2]
1. [プラグインファイルを作る][3]

[1]:#1idを決める
### 1.IDを決める
[ポータル][portal]の```Plugin IDs should trace back to the author```の見出しに書いてある。

ここでは見出し同様にGitHubをソースレポジトリとして公開する前提で話を進める。```io.github.【ユーザーID】.【プラグイン名】```という規則性で決まる。
また、プラグイン名は英数と一部の記号という制約があるので[リファレンス](https://docs.gradle.org/current/userguide/custom_plugins.html#sec:creating_a_plugin_id)を読んでそれらを満たすようにすること

例えば、GitHubのユーザーが```johndoe```で、プラグイン名が```myplugin```とする。その時のplugin IDは```io.github.johndoe.myplugin```となる。

※ドメインを所持していればそれでも公開できるようだが、DNSレコードをいじったり何なりしないとできないらしい。

[2]:#2buildgradleを作る
### 2.build.gradleを作る

```gradle:build.gradle
plugins {
	id 'java-gradle-plugin'
	id 'groovy-gradle-plugin'
	id 'com.gradle.plugin-publish' version '0.16.0'
}

group = '【プラグインID】'
version = '0.1'

tasks.whenTaskAdded { task ->
	if(!'extractPluginRequests'.equals(task.name))return
	gradlePlugin.plugins {
		named('【プラグインID】') {
			displayName = ''
			description = ''
		}
	}
}

pluginBundle {
	website = '【ソースURL】'
	vcsUrl  = '【ソースURL】'
}

```

#### 置き換え文字
* 【プラグインID】
    * [1][1]で決めたIDと置き換える
* 【ソースURL】
    * このプラグインのために作ったGitHubのレポジトリURL

#### plugins

Precompiled script pluginsを作るときの中心となるのが```groovy-gradle-plugin```です。これがバイナリプラグインを生成してくれます。
そして公開には```com.gradle.plugin-publish```が必要です。この点はスタンドアロンプラグインと変わりません。

※ローカルで試す際には一時的に```maven-publish```を入れるのも手です。
※```groovy-gradle-plugin```の裏側では```java-gradle-plugin```が動くようなので一応書いていますが不要かも知れません。

#### gradlePlugin.plugins
本来であれば、build.gradle直下に以下のように書くものです。

```gradle:build.gradle
gradlePlugin {
    plugins {
        //plugin parameters
    }
```

位置は変わりますが、```named('【プラグインID】')```の中へ書くことで同等の効果となり書き方も同様です。この際、IDは生成済みとなるため上書きしないでください。
プラグイン固有のdisplayNameやdescriptionを設定してください。

##### 説明
Precompiled script pluginsは、各プラグイン定義がされるのが各種gradleコマンドを実行する際に動的に行われます。そのため起動直後には各プラグイン用の定義がありません。
逆に```gradlePlugin.plugins```を書いてしまうと動的に行われる設定と二重定義になり落ちます。
その対策として、各プラグイン用の定義が生成された上で、それらへの修正として定義を混ぜ込みます。
具体的にはextractPluginRequestsの実行後に定義が完了しているため、蒸気のような記述となります。

#### pluginBundle
スタンドアロンプラグインと同様です。

[3]:#3プラグインファイルを作る
### 3.プラグインファイルを作る
[リファレンス][precompiled_plugins]の3段落目```To apply ~~```に書いてある。
ディレクトリは```src/main/groovy```
ファイル名は```【プラグインID】.gradle```

例えば、plugin IDが```my.java-library-convention```だと、ファイル名は```my.java-library-convention.gradle```になる。
同様に「IDを決める」のところの例で出した```io.github.johndoe.myplugin```だと```io.github.johndoe.myplugin.gradle```になる。


## 参考先
* [リファレンス][precompiled_plugins]
    * 主にPrecompiled script pluginsのセクションを読むが、plugin idなどの命名規則などはスタンドアロンに準ずるためすべて目を通す必要あり
* [ポータルへの公開方法その1](https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html)
    * gradleのユーザーガイド内のドキュメント
* [ポータルへの公開方法その2][portal]
    * こっちはポータルで記載されてるドキュメント
    * ↑2つは矛盾はないが載ってる内容が微妙に違うのでそれぞれから拾ってくる必要があった
* [Gradle のプラグインの作り方メモ](https://qiita.com/opengl-8080/items/fcf60ba5daf658f39951)
    * こちらの記事はスタンドアロンプラグイン
* [&#91;isssue&#93;Docs for Publishing precompiled plugins](https://github.com/gradle/gradle/issues/16273)
    * 設定注入の参考元

[precompiled_plugins]:https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins
[portal]:https://plugins.gradle.org/docs/publish-plugin