KotlinのライブラリをMaven Central Repositoryに公開したメモ

自作のライブラリ [twitter4j-v2](https://github.com/takke/twitter4j-v2) をこれまで野良リポジトリ(github)に公開していましたがユーザー環境によっては Maven Central Repository が必須のところもあるようで公開することにしました。

sonatype経由の申請とGPG関連が面倒でしたが、超便利なgradleプラグインがあったのでいつの間にかぬるっと完了しました。

ので備忘録代わりにさらっとメモを書いておきます。


# 参考にした記事

なるべく最近の事例を見て流れをざっくり把握した上で作業を始めました。

- [Android のライブラリプロジェクトを爆速で Maven Central にデプロイする \- Qiita](https://qiita.com/KeithYokoma/items/e9ee24e7f6a62623f2fb)
- [新米エンジニアがMaven Central Repository に自作ライブラリを公開してみた \- Qiita](https://qiita.com/yutwoking/items/199b8a4fbe0c4a384dca)
- [Maven Central Repository に公開手順 \- Qiita](https://qiita.com/RYOOMA/items/a7bda0251790609d2cb4)

# 1. Sonatype の JIRA にサインアップする
https://issues.sonatype.org/secure/Signup!default.jspa


# 2. Sonatype の JIRA にプロジェクト作成のためのIssueを立てる

https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134 からIssueを立てるらしいのでやった。

https://issues.sonatype.org/browse/OSSRH-77407


# 3. GNU PGで鍵を作って公開する

## GNU PG のインストール
- GNU PG というか gpg コマンドは `git for Windows` に含まれてるものを使った。

```bash
$ gpg --version
gpg (GnuPG) 2.2.27-unknown
libgcrypt 1.8.7
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /c/Users/takke/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
```

## GNU PGでKeyを作成する

https://central.sonatype.org/publish/requirements/gpg/ を参考に。

```bash
$ gpg --full-gen-key
gpg (GnuPG) 2.2.27-unknown; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Requested keysize is 3072 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Hiroaki TAKEUCHI
Email address: takke30@gmail.com
Comment:
You selected this USER-ID:
    "Hiroaki TAKEUCHI <takke30@gmail.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key F5B674B1E1E789F8 marked as ultimately trusted
gpg: directory '/c/Users/takke/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/c/Users/takke/.gnupg/openpgp-revocs.d/43193386D26DDDEED7D0CF23F5B674B1E1E789F8.rev'
public and secret key created and signed.

pub   rsa3072 2022-01-19 [SC]
      43193386D26DDDEED7D0CF23F5B674B1E1E789F8
uid                      Hiroaki TAKEUCHI <takke30@gmail.com>
sub   rsa3072 2022-01-19 [E]

$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
/c/Users/takke/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072 2022-01-19 [SC]
      43193386D26DDDEED7D0CF23F5B674B1E1E789F8
uid           [ultimate] Hiroaki TAKEUCHI <takke30@gmail.com>
sub   rsa3072 2022-01-19 [E]
```

- もちろんパスフレーズも設定した。

## GNU PGでKeyを公開する

keyserver が no name とか言われて焦ったけど有効なサーバを指定してあげたら公開できた。

```bash
$ gpg --send-keys 43193386D26DDDEED7D0CF23F5B674B1E1E789F8
gpg: sending key F5B674B1E1E789F8 to hkps://hkps.pool.sks-keyservers.net
gpg: keyserver send failed: No name
gpg: keyserver send failed: No name

$ gpg --keyserver keyserver.ubuntu.com --send-keys 43193386D26DDDEED7D0CF23F5B674B1E1E789F8
gpg: sending key F5B674B1E1E789F8 to hkp://keyserver.ubuntu.com
```


# 4. デプロイの準備

## 秘密鍵の変換
- Gradle プラグイン側でサポートする秘密鍵ファイルが kbx ではなく secring.gpg なので変換する
  - https://gist.github.com/phit/bd3c6d156a2fa5f3b1bc15fa94b3256c を参考に。

```
$ gpg --export-secret-key 43193386D26DDDEED7D0CF23F5B674B1E1E789F8 > ~/.gnupg/exported-secring.gpg
```

## Gradle プラグイン導入

- [PermissionsDispatcher](https://github.com/permissions-dispatcher/PermissionsDispatcher) のやり方を参考にした。

- https://github.com/vanniktech/gradle-maven-publish-plugin を導入した。

- 具体的には下記を記述するだけ。

```gradle:build.gradle
buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0'
  }
}

apply plugin: "com.vanniktech.maven.publish"
```

その他の設定は下記の通り。

## `~/.gradle/gradle.properties` の準備
- `~/.gradle/gradle.properties` に下記を追加。
    - keyId をそのまま指定したらエラーになったので [OSSRHへのアップロードにおけるエラー \(The key ID must be in a valid form \(eg 00B5050F or 0x00B5050F\), given value: ~\) の対応策 \- Qiita](https://qiita.com/Morichan/items/98f74c8d076057235247) を参考に下8桁だけ指定してあげた。

```properties:~/.gradle/gradle.properties
signing.keyId=E1E789F8
signing.password=(パスフレーズ)
signing.secretKeyRingFile=C:\\Users\\takke\\.gnupg\\exported-secring.gpg
mavenCentralUsername=takke
mavenCentralPassword=(JIRAのログインパスワード)
```

## プロジェクトのrootにある`gradle.properties`の準備

- 下記を追記した。

```properties:gradle.properties
# Upload configurations
GROUP                  = io.github.takke
POM_ARTIFACT_ID        = jp.takke.twitter4j-v2
VERSION_NAME           = 1.0.4
POM_NAME               = twitter4j-v2
POM_DESCRIPTION        = A simple wrapper for Twitter API v2 that is designed to be used with Twitter4J.
POM_INCEPTION_YEAR     = 2020
POM_URL                = https://github.com/takke/twitter4j-v2/

POM_LICENSE_NAME       = The Apache Software License, Version 2.0
POM_LICENSE_URL        = https://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENSE_DIST       = repo

POM_SCM_URL            = https://github.com/takke/twitter4j-v2/
POM_SCM_CONNECTION     = scm:git:git://github.com/takke/twitter4j-v2.git
POM_SCM_DEV_CONNECTION = scm:git:ssh://git@github.com/takke/twitter4j-v2.git

POM_DEVELOPER_ID       = takke
POM_DEVELOPER_NAME     = Hiroaki TAKEUCHI
POM_DEVELOPER_URL      = https://github.com/takke/
```

https://github.com/takke/twitter4j-v2/blob/master/gradle.properties




# 4. デプロイする

## オフライン実行してみる

```bash
$ ./gradlew :twitter4j-v2-support:publishToMavenLocal
```

`~/.m2/repository/io/github/takke/jp.takke.twitter4j-v2/` に配布されていることを確認した。


## maven central に上げてみる

```bash
$ ./gradlew :twitter4j-v2-support:publish
The JavaApplication.setMainClassName(String) method has been deprecated. This is scheduled to be removed in Gradle 8.0. Use #getMainClass().set(...) instead. See https://docs.gradle.org/7.3/dsl/org.gradle.api.plugins.JavaApplication.html#org.gradle.api.plugins.JavaApplication:mainClass for more details.
        at build_1f8xxu4am8etkonrhu9idsn8v$_run_closure3.doCall(D:\Src\TwitPane\ext\twitter4j-v2\twitter4j-v2-support-java-example\build.gradle:18)
        (Run with --stacktrace to get the full stack trace of this deprecation warning.)

BUILD SUCCESSFUL in 19s
9 actionable tasks: 3 executed, 6 up-to-date
```

これでステージングサーバに配置されたはず。


# 5. リリース作業をする

- ステージングのリポジトリ https://s01.oss.sonatype.org/ を開き、右上のリンクから「Login」する
    - 左メニューの `Build Promotion` から `Staging Repositories` を選択し、自分のリポジトリを一覧から選択する
    - 内容を確認し、問題なさそうなら Close ボタンを押す => 自動では更新されないので適宜 Refresh ボタンを押す
    - closed になってたら Release ボタンを押す

- しばらく待つ(数分かな？)と https://repo1.maven.org/maven2/io/github/takke/jp.takke.twitter4j-v2/ に公開されていた。


# 6. 使ってみる

下記のimplementationで参照できるようになった。

```gradle
implementation("io.github.takke:jp.takke.twitter4j-v2:1.0.4")
```


# リンク集

- [GitHub上でのGradle Projectの管理状況2021](https://uzzu.co/post/github-gradle-project-2021.html)
- [bintray/JCenter に上げていたJVMライブラリを楽して Maven Central へ移行する](https://zenn.dev/red_fat_daruma/articles/0f3a01a53dc4fd)
- [github/maven\-plugins: Official GitHub Maven Plugins](https://github.com/github/maven-plugins)
- PermissionsDispatcher も Maven Central に移行したのでこの辺りが参考になった⇒ https://github.com/permissions-dispatcher/PermissionsDispatcher/commit/d7e30604ad966cd56195db08e356c464a25daa95