この記事はScalaプロジェクトをMaven Central Repositoryにリリースして全世界から使えるようにする手順をまとめたものである。作業は大別してSonatype側とビルドツール側とに分かれる。今回はビルドツールとしてMillを利用したが、作業の過半は同じである。数時間でこの作業は終わるし、Sonatype側の作業は一度だけやればよい。
- 用語
- 方針と前提
- Sonatype側の作業(Group IDを作るときに1回だけ必要)
- PGP鍵の準備(こちらも1回だけ作成すればよい)
- Millの場合
- (sbtの場合)
- Nexus Repository Managerで様子を見る
- Nexus Repository Managerで様子を見る代わりに・・・
- 使う
- 参考文献
ScalaはJVM言語だから、もちろん生成したJARファイルをMaven Centralに送って、OSSとして公開できるようになっている。Maven Centralに公開すると、よく見る以下のような形式で自分のソフトウェアをインターネットを介してsbtやMillなどのプロジェクトから使えるようになる:
// sbt "io.github.windymelt" %%% "qw" % "0.0.1" // mill ivy"io.github.windymelt::qw:0.0.1"
現実問題として、制作したScalaのOSSを使ってもらうにはMaven Centralへの公開がほぼ必須事項となる。Maven Centralに頼らない場合、リポジトリサーバを利用者のbuild.sbt
などに記載したり、直接JARファイルをコピペする必要があるからだ。
Maven Centralへの公開手順は比較的簡単になっている。今回自作のOSSqw
を公開したので、その手順を公開する。
用語
混同しないように、登場人物を整理しておこう。
- Maven
- Apache Maven。Javaのためのビルドツール。
- Maven Central
- Mavenがデフォルトでコードリポジトリとして使うリポジトリ。
- Sonatypeが運営している。
- 普通のHTTPプロトコルで配信するため、ブラウザからも様子を見ることができる。
- sbtやmillもここを標準リポジトリとして利用する。
- mvnrepository.com
- Maven Centralを検索できるサービス。
- 個人がメンテしており、Apache財団やSonatype社が管理しているわけではない。
- 非公式なサードパーティのフロントエンドくらいに思っておけばよい。
- central.sonatype.com
- Maven Centralを検索できるサービス。
- こちらはSonatypeが直々に提供している。
- mvnrepository.comと比べるとたいそう遅く、あまり使いものにならない。
- Mill
- Scalaのビルドツール。
- sbtより後発。
- sbt
- Scalaのビルドツール。
- 先発でドキュメントが多い。
方針と前提
以下の方針でMaven Centralにリポジトリを登録する。
- JARファイルにはPGP署名が必須なので、YubiKeyなどの署名用デバイスか鍵を作っている前提とする
- 今回は自分はYubikeyにPGP鍵を登録しています
- ソースコードのリポジトリはGitHubであるものとする
- GitLabなどでもいけるはず。参考文献などを読んでね
- グループIDは
io.github.ユーザ名
とする- こうすることでbotを使った自動ワークフローに乗ることができる
- この形式のグループIDを使う場合、Sonatype側からすればGitHubのオーナーシップだけ確認すればよいので管理が楽。ウィンウィン
- Scalaコード上のパッケージ名もこれに倣って
io.github.windymelt.foobar....
を使う
- アーティファクトのバージョンはGit上のタグを利用する
v0.0.1
というGitタグにバージョン0.0.1
が自動的に対応するようにする
Sonatype側の作業(Group IDを作るときに1回だけ必要)
Maven Centralがどのような形でリリースを制御しているか軽く確認しておこう。Maven Central上ではグループID単位でアップロード権が与えられる、というふうに考えておけばよい。そしてその権限の取得はJIRAにチケット(Issue)を作成して自動化フローに乗ることで行う。
例えば、今回自分はio.github.windymelt
へのリリース権をもらうことになる。すると、io.github.windymelt
以下にアーティファクトをpublishできるようになる。もちろんこれ以外のグループIDにpublishする権限はもらえないが、普通は1つあれば十分だ。
Sonatype JIRAへの登録
Maven CentralはSonatype社が管理しているのだが、Maven Centralへの登録やそのサポートには、JIRAというチケット管理システムを利用する。まずはここのアカウントを作成して、チケット作成の準備をしよう。
Issue作成
次にIssueを作成してグループIDの権限申請を行う。JIRAには新たなプロジェクト作成用のIssueテンプレートが用意されているので、それを使う。
https://issues.sonatype.org/secure/CreateIssue!default.jspa
ログイン後に上掲のページに行く。課題タイプ
がNew Project
になっていることを確認したら、次へを押下する。
次に埋めるべきフォームが登場する。フィールドが多くて面食らうが、埋めなければならない項目は4つだけだ。
要約
にはCreate library for <パッケージ名>
くらいの文言を書いておく。実際はbotが処理するので、あまり内容は気にしなくていいが、一応どのソフトウェアなのか分かるようにしておく。
Group Id
にはio.github.<GitHubのユーザ名>
を記入する。
Project URL
にはGitHub上のリポジトリのURLを記入する。
SCM url
にはGitHubのGitプロトコルのURL(ほとんどの場合リポジトリのURLに.git
をつけたもの)を記入する。
これで作成
を押下する。しばらくするとbotが反応してコメントをするはずだ。しばらく待とう。
ダミーリポジトリ作成
するとSonatypeのbotが、OSSRH-xxxxxx
(xxxxxx
は数字)という名前の空リポジトリをGitHub上に作成するように要求してくるので、その通りの名前で空リポジトリを作成する。これは実際にそのグループIDに対応するGitHubのorganizationのオーナーシップをユーザが持っているかどうか確認するためのものだ。
空リポジトリの作成が完了したら、Waiting for Response
となっている青いボタンをクリックし、オープン
を選択する。これで今度はbotのターンになる。
認証完了
するとbotがオーナーシップの確認を行ってくれてグループIDが発行される。JIRA側の作業はこれで完了だ。同じグループIDを使っている間は、もうIssueを作らなくてよい。ビルドツールがパブリッシュ先に使うためのURLが表示されるので、メモしておこう(たまに変わることがあるらしい)。
同じグループIDで他のリポジトリをpublishするときは、特に申請はいらないみたい。
PGP鍵の準備(こちらも1回だけ作成すればよい)
ここからはローカルの作業だ。
https://www.scala-sbt.org/release/docs/Using-Sonatype.html
Maven Central RepositoryはアーティファクトにPGP署名を付与することを必須としている。したがって、publishするためには自分用のPGP鍵を持っておく必要がある。鍵の作成については割愛する。一般的なRSAやed25519の鍵があれば十分だ。
【令和最新版】PGP鍵の作り方から管理方法、Git Commitへの署名まで - Qiita
手元に作成したPGP公開鍵を、リモートに公開しておく(Sonatypeがサポートしている鍵サーバにアップロードする必要がある):
gpg --keyserver keyserver.ubuntu.com --send-keys 鍵ID
Millの場合
ここからはビルドツール側でpublishのための設定を行い、実際にpublishするという操作になる。今回は設定が簡潔なMillを使った。
Millでは手数が少なく済むかわりに、現在Millは激しく開発されているのでここでの情報が古いものになっている可能性がある。今回はMill v0.11.2を利用した。
以下のような具合で、pomSettings
を定義する:
import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version::0.4.0` // ↑Gitのタグをそのままバージョニングに使うためのプラグイン import mill._, scalalib._ import publish._ object qw extends RootModule with ScalaModule with PublishModule { def scalaVersion = "3.3.0" // ここの名前が "io.github.windymelt" %% "ここ" % "1.2.3" に使われる override def artifactName = "ここにアーティファクト名を入れる" // SonatypeでもらったURLに/service/localをつけたもの override def sonatypeUri = "https://s01.oss.sonatype.org/service/local" // SonatypeでもらったURLに/content/repositories/snapshotsをつけたもの override def sonatypeSnapshotUri = "https://s01.oss.sonatype.org/content/repositories/snapshots" def pomSettings = PomSettings( description = artifactName(), // もらったGroup ID organization = "io.github.windymelt", // プロジェクトURL url = "https://github.com/windymelt/qw.scala", // ライセンス licenses = Seq(License.MIT), // GitHub管理下であることを宣言する versionControl = VersionControl.github("windymelt", "qw.scala"), // 開発者情報 developers = Seq( Developer("windymelt", "windymelt", "https://github.com/windymelt") ) ) // バージョニングはGitのタグからvを取ったものとする(勝手に取ってくれる) override def publishVersion: T[String] = VcsVersion.vcsState().format() }
これでリリース準備が整った。GitHub側でリリースタグを打ち、手元でpull
してそのタグに移動しておく。Gitリポジトリをクリーンな状態にし、自分が正しいタグのコミットを見ていることを確認しよう。
最後にmill publish
を実行するとpublishが行われて仮リリース状態になる。この操作にはSONATYPE_USERNAME
とSONATYPE_PASSWORD
という2つの環境変数が必要である。それぞれSonatypeのユーザ名とパスワードを渡す必要がある。
SONATYPE_USERNAME=windymelt SONATYPE_PASSWORD="..." mill publish
必要に応じてGPGがパスフレーズを要求してくる。
% SONATYPE_USERNAME=windymelt SONATYPE_PASSWORD="xxx" mill publish [64/64] publish Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar.asc Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar.asc.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.jar.asc.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar.asc Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar.asc.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-sources.jar.asc.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar.asc Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar.asc.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3-javadoc.jar.asc.sha1 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom.asc Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom.asc.md5 Uploading io/github/windymelt/qw_3/0.1.3/qw_3-0.1.3.pom.asc.sha1 Published qw_3 to Sonatype
(sbtの場合)
sbtでMaven Central Repositoryにpublishするにはいくつかのプラグインが必要となる。
sbtの場合は上掲の記事に詳しいので参考にしてほしい。Millとやることは本質的には変わりがない。
Nexus Repository Managerで様子を見る
この時点ではアーティファクトは仮リリース状態になっている。全世界に公開するためには、publishしたアーティファクトをcloseし、さらにreleaseする必要がある。もし間違えてpublishした場合はdropする。ちなみに一度releaseするともう二度と削除できなくなるので、失敗しないようにしよう。
https://s01.oss.sonatype.org/ に行ってSonatypeのパスワードでログインする。Staging Repositories
というラベルが画面左にあるので、それを使って先程publishしたアーティファクトを見ることができる。
するとアーティファクトのリストとClose
Release
Drop
というボタンがあるので、リリースして問題なければチェックをつけてClose
を押そう。CloseといってもIssueを閉じるみたいな意味合いではなく、修正をフリーズするくらいの意味合い。
closeすると裏で作業が走るのでしばらく待たされる。のんびり待とう。たまにRefresh
ボタンを押して更新するのを忘れないこと。
しばらくするとRelease
が押せるようになっているはずなので、Release
を押下すると全世界にアーティファクトが公開される。おめでとう。
Nexus Repository Managerで様子を見る代わりに・・・
先程のNexus Repository Manager側の手順は、Millでは以下のように--release true
を渡すことで自動化できる(しばらく時間がかかる点については同じ)。こちらを使ったほうがよいだろう。
SONATYPE_USERNAME="username" SONATYPE_PASSWORD="..." mill publish --release true
使う
検索サービスにインデックスされるまでには時間がかかるし、リポジトリに反映されるのにも1時間ほどかかるようだが、例えばScala Scriptから依存性を定義するとちゃんと使えるようになっているはず。
//> using scala 3.3.0 //> using dep io.github.windymelt::qw::0.1.3 import io.github.windymelt.qw.Syntax.{*, given} println(qw"foo bar buzz")
% scala-cli qw.scala.sc Downloading 2 dependencies Compiling project (Scala 3.3.0, JVM) Compiled project (Scala 3.3.0, JVM) List(foo, bar, buzz)
動いた。
そのうち、Scaladexに登録されるので楽しみに待とう。
それでは良いScalaライフを!