sbtプラグインを自作してBintrayで公開する

sbt公式ドキュメントの[Bintray For Plugins](https://www.scala-sbt.org/1.x/docs/Bintray-For-Plugins.html) にしたがって、自作した [sbt](https://www.scala-sbt.org/index.html)プラグインを[Bintray](https://bintray.com/)（開発したライブラリを公開するリポジトリサービス）で公開する手順です。

* ここではプラグインを sbt 1.x と 0.13.x の両方から利用できるように公開します。
* 2018/3時点では [Bintray For Plugins](https://www.scala-sbt.org/1.x/docs/Bintray-For-Plugins.html) に **This is currently in Beta mode.** と書かれていることから、今後手順が変わる可能性があるかもしれません。
* この手順では *Bintray* に自分用のリポジトリを作成して公開する形になる（公のリポジトリに公開されるわけではない）ようです。
そのため、プラグインを利用する際には `Resolver` にリポジトリを追加する必要があります。
  * でもそのほうが気楽に公開できていいのかも...

## プラグインプロジェクトの作成

### giter8によるプロジェクトの生成

sbtプラグインを作成するためのsbtプロジェクトは [giter8テンプレート](https://github.com/sbt/sbt-autoplugin.g8) から作るのが良いと思います。
（作成したsbtプラグインを *Bintray* に公開するために必要な[sbt-bintray](https://github.com/sbt/sbt-bintray)プラグインも自動的に導入済みになります）

```sh
$ sbt new sbt/sbt-autoplugin.g8
```

コマンドを実行すると、作成するプラグインの名前などを聞いてくるので応答します。

が、これがいきなりなかなかの曲者です。
sbt公式ドキュメントで [Plugins Best Practices](https://www.scala-sbt.org/1.x/docs/Plugins-Best-Practices.html) が公開されており、その中でプラグインの命名ルールについても記載があります。

> Follow the naming conventions 
> Use the sbt-$projectname scheme to name your library and artifact. A plugin ecosystem with a consistent naming convention makes it easier for users to tell whether a project or dependency is an SBT plugin.
> 
> If the project’s name is foobar the following holds:
> 
> BAD: foobar
> BAD: foobar-sbt
> BAD: sbt-foobar-plugin
> GOOD: sbt-foobar
> 
> If your plugin provides an obvious “main” task, consider naming it foobar or foobar... to make it more intuitive to explore the capabilities of your plugin within the sbt shell and tab-completion.

sbtプラグインのアーティファクト名（=jarファイル名）は `sbt-****` にすべし、とのことですが、*giter8* が入力を求めてくるときのデフォルト値に倣って命名すると、このベストプラクティスの通りになりません。

たとえば `sbt-foobar` プラグインを作成したい場合は、以下のように応答するとベストプラクティス通りになります。

```sh
[info] Set current project to github (in build file:/Users/****/****/)

sbt AutoPlugin seed

name [sbt AutoPlugin]: sbt foobar
organization [org.example]: com.example
package [org.example.sbt]: com.example.sbt
purpose [An sbt AutoPlugin]: An sbt FooBar plugin

Template applied in ./sbt-foobar
```
* *name* は `sbt 名前` で応答します。
  * `sbt` の後に半角スペースを入れます。（半角スペースがハイフンに置き換わります）
  * 名前は キャメルケースは使わずに英小文字、数字、ハイフン で命名するのが良いと思います。
  * `-plugin` のような接尾辞はつけません。
* *purpose* は README 冒頭の概要になるだけなので、あまり気にしなくていいです。

これでプロジェクト `sbt-foobar` が作成され、ビルドすると `com.example.sbt-foobar-0.1-SNAPSHOT.jar` が生成されます。

## 生成されたプロジェクトの調整

### build.sbtの調整

*giter8* が生成した `build.sbt` には、いくつか設定が足りないので追記します。

* 作成したプラグインを sbt 1.x と 0.13.x 両方で使えるようにクロスビルドできるようにします。
* 作成したプラグインの（お好みの）ライセンスを明示します。
* 作成したプラグインを *Bintray* に公開するための設定を追加します。

```scala:build.sbt
crossSbtVersions  := Seq("0.13.6", "1.0.0")

licenses += ("MIT", url("https://opensource.org/licenses/mit-license.php"))

publishMavenStyle := false
bintrayRepository := "sbt-plugins"
bintrayOrganization in bintray := None
```

### プラグインコードの調整

*giter8* がプラグインのコード（Ex. `src/main/scala/com/example/sbt/SbtFoobarPlugin.scala`） を生成しますが、これの接頭辞 `Sbt` が余計なので `FoobarPlugin` にリネームしておきます。
（プラグインの利用側で `enablePlugins()` するときの名前になりますが、`Sbt`なんて接頭辞が付いているプラグインは見かけないので）

## プラグインの実装

[Plugins Best Practices](https://www.scala-sbt.org/1.x/docs/Plugins-Best-Practices.html) にそってプラグインを実装します。

こちらの記事 [SBT Pluginの作り方](https://qiita.com/yoskhdia/items/9f2ed8ae738b8efc8c05) も参考になると思います。

## プラグインの公開

プラグインの実装ができたら、[Bintray For Plugins](https://www.scala-sbt.org/1.x/docs/Bintray-For-Plugins.html) に沿って *Bintray* に公開します。

### Bintrayにアカウントとリポジトリを作る

* [Bintray](https://bintray.com/signup/oss) にアクセスしてアカウントを作ります。

* アカウントを作成してサインインしたら、*Add new repository* からプラグイン公開用のリポジトリを作成します。

|設定項目|設定値|
|----|----|
|Name|`sbt-plugins` にしろ、とのこと|
|Type|`Generic`|
|Desc|任意の説明|
|Tags|`sbt`|

### Bintrayへのプラグインの公開

* `build.sbt` の `version` をリリースバージョン（接尾辞 `-SNAPSHOT`が付かない任意のバージョン）に変更します。
  * *Bintray* にはスナップショットバージョンでは公開できないようなので注意。

* sbtで *bintrayChangeCredentials* を実行し、*Bintray* に公開するための認証情報を設定します。
  * *Bintray* のユーザー名 と API Key（Bintrayの管理画面 > Edit Plugin > API Key から取得できます）を入力します。

```shell
$ sbt
sbt:sbt-foobar> bintrayChangeCredentials
Enter bintray username : **************
Enter bintray API key : *************
```

* sbtで `^` をつけて *publish* します。
  * `^` をつけないとクロスビルドされず、sbt 0.13.x向けのプラグインが作成されません。

```shell
$ sbt
sbt:sbt-foobar> ^ publish
```

なお、間違って公開してしまったりした場合は、*Bintray* の管理画面からいつでも削除できるので安心です。

## プラグインの利用

利用するsbtプロジェクトの `project/plugins.sbt`（あるいは `project/foobar.sbt`を作成して）に以下を追記することで、公開したプラグインを利用できるようになります。

* `Resolver.ivyStylePatterns` を指定しないと、*Maven*スタイルのリポジトリとして解決しようするため、プラグインがダウンロードされません。

```scala:project/plugins.sbt
resolvers += Resolver.url("example Plugin Repository", url("https://dl.bintray.com/Bintrayユーザー名/sbt-plugins/"))(Resolver.ivyStylePatterns)

addSbtPlugin("com.example" % "sbt-foobar" % "0.1")
```

# おわりに

上記手順で sbtプラグイン [sbt-fileupload](https://github.com/crossroad0201/sbt-fileupload) を開発していますので、具体的なサンプルとして参考にしてください。