GitHub＋Maven Centralで自作ライブラリを公開する

今回は、GitHubで開発したライブラリをMaven Central Repositoryで公開するまでの道のりをまとめてみました。
全部無料です！（笑）

## 公開までのプロセス

![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/00_overview.png)

1. JIRAのアカウントを作成する
1. JIRAでIssueを発行し、ライブラリの登録申請をする
1. GitHubでソースコードを開発する
1. GPGで秘密・公開鍵を作成して、公開鍵をKeyServerに登録する
1. GPGの秘密鍵でJarに署名して、OSSRHにリリース（デプロイ）する
1. OSSRHからCentralへ、ライブラリがリリース（ステージング）される

登場人物は以下の通りです。

|name|description|
|:---:|:---:|
|開発者|私、もしくは私たち|
|GitHub|ライブラリのソースコードを管理する場所|
|Maven Central Repository|ライブラリを公開したい場所|
|Sonatype OSSRH|Centralへ公開するために使用するリポジトリホスティングサービス|
|Sonatype JIRA|OSSRHにライブラリを登録するための申請をするサイト|
|Public KeyServer|OSSRHにライブラリを登録する際の署名鍵を管理するサーバ|

以降で、順を追ってプロセスを紹介していきます。

## Step.1 JIRAのアカウントを作成する

何はともあれ、ライブラリ公開の申請をするためにユーザ登録をします。

JIRAで「Sign Up」リンクを押下すると、以下のように登録画面が表示されます。
[JIRA](https://issues.sonatype.org/secure/Signup!default.jspa)のアカウントを作ります。
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/05_signup-sonatype-jira.png)

ここで付与する`Username`はJIRAでしか使わないので、それほど気を使う必要はないと思っています。

## Step.2 JIRAでIssueを発行し、ライブラリの登録申請をする

次に、登録したユーザでライブラリ公開の申請をします。

JIRAにログインして「Create」ボタンを押下すると、以下のようにIssueを作成できます。
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/06_create-sonatype-issue.png)

だいたい見たままですが、必須項目のSummary、GroupId、Project URLとSCM URLを入れればOKです。
ちなみにここで入力するGroupIdはドメインルートで、例えばライブラリに`io.github.yoshikawaa.webapp`みたいなGroupIdを付与していても、`io.github.yoshikawaa`で申請すればOKでした。つまり、一度申請してしまえば、ライブラリごとに申請しなおす必要はないってことですね。（間違ってたら中の人が教えてくれると思いますw）

なお、Issueを発行してから承認されるまで、通常2～3日くらいのようです。

さて、ここで問題は以下になります。

* GroupId（つまりライブラリのルートパッケージ名）を決める必要がある
* 実際に開発しているソースコードのリポジトリが必要である

ということで、実際にIssueを作成するのは、ソースコードを開発してからになります。

## Step.3 GitHubでソースコードを開発する

当たり前ですが、まずは先立つソースコードを開発しましょう。
ソースコードを開発する上でのポイントは以下のとおりです。

* ソースコード品質を確保する
* JavaDoc & ソースコードのJarを作成する
* ドメイン（ルートパッケージ名）を取得する
* 適切なライセンスを付与する
* Centralの要件に合わせて、POMを設定する

### Step.3.1 ソースコード品質を確保する

オープンソースでライブラリを開発して公開する以上、CI（継続的インテグレーション）によりソースコード品質を確保しなければ。ということで、GitHubには連携するCIサービスがいくつもあるので、[Marketplace](https://github.com/marketplace/category/continuous-integration)からテーマごとに適当にピックアップして使います。

ちなみに私は、以下のようなセットを使っています。

|theme|service|
|:---:|:---:|
|回帰テスト|[Travis CI](https://travis-ci.org/)|
|カバレッジ|[Codacy](https://www.codacy.com/)|
|コードレビュー|[Codacy](https://www.codacy.com/)|

### Step.3.2 JavaDoc & ソースコードのJarを作成する

公開するならJavaDocくらい書きましょう！
MavenプラグインでJavaDocとソースコードのJarを作成すれば、一緒にデプロイして公開することができます。
Mavenプラグインを使用するには、POMにちょっとプラグインの設定を足すだけです。

```xml
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>2.10.4</version>
        <configuration>
            <show>protected</show>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>3.0.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>
```

ちなみに私は、ライブラリの拡張ポイントを示すため、`protected`メソッドまでJavaDocに出力しています。

### Step.3.3 ドメイン（ルートパッケージ名）を取得する

ここまで思うまま開発してきましたが、問題が一つ。
ライブラリのGroupIdとライブラリのルートパッケージ名は通常揃えると思いますが、
Javaのパッケージ名のお作法として、サイトのドメインを逆にする（`google.com`なら、`com.google.~`）というのがあります。

残念なことに、私は個人サイトを持っていないし、自分でサーバを借りたりドメインを取得する気もないので、しゃーなし、適当につけるか。。。と思っていたところ、作れます！そう、GitHubならね。
GitHubにはリポジトリからサイトを作成できる[GitHub Pages](https://pages.github.com/)という機能があり、[ユーザ名].github.ioという名前でリポジトリを作成してテーマを選択するだけで、お手軽に自分のサイトが作れます。

[ユーザ名].github.ioリポジトリを作成し、
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/03_create-github-pages.png)

[architectテーマ](https://github.com/pages-themes/architect)を選択すると、こんなデザインのページが作成されました。
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/04_showing-github-pages.png)

写真はある程度コンテンツを書いた後なので、デフォルトページとはちょっと違います。
ちなみにGitHub Pagesではデフォルトで[Jekyll](https://jekyllrb.com/)という静的サイトジェネレータを使用しており、MarkDownで書いたコンテンツを自動的にHTMLに変換してくれます。

ということで、ライブラリのGroupIdは`io.github.[ユーザ名].~`にしました。
※まー、実際には`com.github.[ユーザ名].~`でも良かったんですが…

### Step.3.4 適切なライセンスを付与する

オープンソースで開発する上ではライセンスに気を使う必要があります。
種類ばかり豊富なオープンソースライセンスからどれを選ぶべきかを調べるのは面倒なので、偉大な先駆者の方々の力を借ります。
[@tukiyo3さんの記事](https://qiita.com/tukiyo3/items/58b8b3f51e9dc8e96886)がまとまってて参考になりました。

ライセンスについては、以下の3点の対応をすることにしました。

* リポジトリにライセンス文章のファイルを置いて、トップページからリンクする
* ソースコードにライセンス文章を付与する
* デプロイするJarにライセンス文章のファイルを入れる

まずはGitHubの機能を利用して、ライセンス文章のファイルを置きました。

新規ファイル作成で`LICENSE`という名前をつけると、
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/01_create-license.png)
作成するライセンスの種類を選ぶことができます！
![alt](https://raw.githubusercontent.com/yoshikawaa/images/master/github-maven-central/02_choose-license.png)

なお、今回は後付けでライセンス文章のファイルを作りましたが、リポジトリ作成時に選択することもできます。

次に、[License Maven Plugin](http://code.mycila.com/license-maven-plugin/)を利用して、ソースコードにライセンス文章を入れました。
プラグインの使い方は[@kazuki43zooさんの記事](https://qiita.com/kazuki43zoo/items/4ccad9120778dbf21f5c)が分かりやすいので、ここでは省略します。

最後に、[Maven Resources Plugin](https://maven.apache.org/plugins/maven-resources-plugin/)を利用して、Jarにライセンス文章のファイルを入れました。
※ここまでする必要があるかはさておき…

### Step.3.5 Centralの要件に合わせて、POMを設定する

[Centralのガイド](http://central.sonatype.org/pages/requirements.html#sufficient-metadata)を参考に設定していきます。
`licenses`、`developers`、`scm`あたりを追加する必要がありました。

## Step.4 GPGで秘密・公開鍵を作成して、公開鍵をKeyServerに登録する

OSSRHでは、デプロイ時のユーザ認証に加えて、GPG(GNU Privacy Guard)による署名を利用して、アップロードされたJarの正当性を確認しています。
GPGによる署名を利用するには、

1. GPGで秘密・公開鍵を作成して、公開鍵をKeyServerに登録する
1. GPGの秘密鍵でJarに署名する

というプロセスを踏む必要があります。
KeyServerへの登録まではGPGソフトで行い、Jarへの署名はMavenプラグインで行います。

WindwosでGPGを扱うなら、GUIソフトの[Gpg4win](https://www.gpg4win.org/)が便利だと思いますが、
最終的にMavenプラグインからはコマンドラインでgpg.exeを呼び出す必要があり、Gpg4win（GUI）で作成・管理した鍵がgpg.exe（コマンドライン）に連携されなかったため、結局コマンドラインで鍵を管理しました。

コマンドラインでの鍵の作成・管理とKeyServerへの登録は[@moutendさんの記事](https://qiita.com/moutend/items/5c22d6e57a74845578f6)が分かりやすいので、ここでは省略しますが、登録先はUbuntuのSKS OpenPGP Public Key Server（`keyserver.ubuntu.com`）になります。

## Step.5 GPGの秘密鍵でJarに署名して、OSSRHにリリース（デプロイ）する

ここからはMavenでの作業になります。settings.xmlとPOMに、署名とデプロイのための設定を入れます。

* pom.xml

```xml
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-gpg-plugin</artifactId>
        <version>1.6</version>
        <executions>
            <execution>
                <id>sign-artifacts</id>
                <phase>verify</phase>
                <goals>
                    <goal>sign</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

<distributionManagement>
    <snapshotRepository>
        <id>ossrh</id>
        <name>Sonatype Nexus Snapshots</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </snapshotRepository>
    <repository>
        <id>ossrh</id>
        <name>Sonatype Nexus Releases</name>
        <url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
    </repository>
</distributionManagement>
```

[Maven GPG Plugin](http://maven.apache.org/plugins/maven-gpg-plugin/)を利用して、作成したJarにGPGで署名します。
また、デプロイ先としてOSSRHのスナップショットおよびリリースリポジトリを設定します。

* settings.xml

```xml
<settings>
    <servers>
        <server>
            <id>ossrh</id>
            <username><!-- JIRAのアカウント名 --></username>
            <password><!-- JIRAのパスワード --></password>
        </server>
    </servers>
    <properties>
        <gpg.executable>gpg.exe</gpg.executable>
        <gpg.keyname><!-- キーサーバに登録した鍵名 --></gpg.keyname>
        <gpg.passphrase><!-- 鍵作成時に付与したパスワード --></gpg.passphrase>
    </properties>
</settings>
```

OSSRHのユーザ認証のため、JIRAアカウントの情報を設定します。ここで重要なのは、POMの`distributionManagement`に記載したリポジトリのIDとsettings.xmlに記載する`server`のIDを合わせることです。異なっているとアカウントの情報が連携されません。
また、GPGプラグインで使用するGPGの実行ファイルパス、使用する鍵名およびパスワードを設定します。なお、パスワード以外は省略することもできます。

ここまで設定したら、あとはデプロイするだけです！

```bash
$ mvn clean deploy
```

ちなみに、GitHubからソースコードをCloneしてビルドしたいだけの人が署名エラーになったりするのはウザいので、[プロパティを指定してGPGプラグインの実行をスキップする](http://maven.apache.org/plugins/maven-gpg-plugin/sign-mojo.html#skip)こともできます。

## Step.6 OSSRHからCentralへ、ライブラリがリリース（ステージング）される

基本的には、待っていればOSSRHからCentralにリリースされるらしいです。
待てない人はOSSRHにログインして自分でリリースしたり、[nexus-staging-maven-plugin](https://github.com/sonatype/nexus-maven-plugins/tree/master/staging/maven-plugin)でリリースすることが可能です。

## まとめ

公式リファレンスと先駆者の方々の情報が充実しており、割と楽にOSSRHへのリリースまで進むことができました。

ちなみに、Sonatype JIRAへの登録など面倒だという方は、[GitHubリポジトリをMavenリポジトリにする(@narikeiさんの記事)](https://qiita.com/narikei/items/db064f06e793372e7372)などいくつか方法があるので、模索してみると良いと思います。