Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

2024年版: Scala+sbtで新Maven Centralにパブリッシュする

新しくなったMaven CentralにScalaプロジェクトをパブリッシュできたのでその手順をまとめた。

背景

2024年より、Maven Centralはパブリッシュ用のAPIを変更した上、新サイトからしかアカウントを作成できなくなった。Mavenなどはこれに適合しているが、Scala + sbtのデファクトパブリッシングプラグインであるsbt-sonatypeは何の告知も受けられなかったのか突然新システムでは利用不能な状態になってしまった(以前に旧システムに登録した人はそのまま使えているはず)。さいわいコントリビューターの手によってワークアラウンド用のPRが提供され、いまだ正式なリリースはされていないものの手元でビルドすることで対応可能な状態になっているので、これを利用してテスト用リポジトリをpublishしてみる。

旧手順はこちら。

blog.3qe.us

ちなみに一度パブリッシュしたアーティファクトは二度と消せなくなるので、くれぐれもヘンなデータには注意しよう。今回はただのHello, Worldをパブリッシュする。

パブリッシュとは

Publish。自作のアプリケーションやライブラリをJARファイルにコンパイル・バンドルし、Maven Centralにアップロードして誰でも利用できるようにすること。パブリッシュするにはアカウントの登録と、JARファイルに署名を行う必要がある。Maven Central以外のリポジトリも存在しており、そちらに登録することも一般にパブリッシュと言うが、大抵の場合はMaven Centralにパブリッシュする。 他の言語でいうところのnpmやgemに登録するのと同じである。

おおまかな流れ

新Maven CentralはAPIやブラウザ上のUIだけが異なるので、本質的にはあまり手順の変更はない。

  • sbt-sonatypeのパッチ版をダウンロードしてビルドする
  • Scalaのサンプルプロジェクトを作成し、パブリッシュに必要なプロジェクト設定を行う
  • サンプルプロジェクトが、前述のプラグインを使うようにする
  • プロジェクト用のGPG鍵を作成する
  • サンプルプロジェクトをビルドし、署名付きJARを生成する
  • 署名付きJARをMaven Centralにパブリッシュする

事前に準備するもの

  • Scalaの開発環境
  • Maven Centralのアカウント(GitHubでログインするとよい)
  • Maven Central上のnamespace(Group IDに相当する部分の権限)
    • GitHubログインするとio.github.{GitHubユーザ名}というnamespaceがもらえる
    • ドメインを持っている場合はそれを認証することでnamespaceにできる
    • 今のところ、通常の方法でアカウント作成した後でGitHubでログインしてもアカウント統合が行われないので注意すること
    • パブリッシュする前に設定しておく必要がある
  • gpgコマンド(アーティファクトの署名に必要)
  • csコマンド(あると動作確認できて便利)

csコマンド(Couriser)については以下の記事で扱っている。

blog.3qe.us

ユーザ登録に関しては、Gradle版の記事が参考になるかもしれない:

zenn.dev

準備ができたらはじめよう。

Maven Centralのページからnamespaceを取っておく

namespaceはここで確認できる:

central.sonatype.com

namespaceを取るには、GitHubログインしてio.github.{GitHubユーザ名}を自動的に付与してもらうか、独自ドメインを利用してDNSの設定でそのドメインをnamespaceとして使えるようにするかのどちらかとなる。

今回はdev.capslockを持っているので、これを利用する。namespaceは後程build.sbtに書き込む。

テスト用リポジトリを作る

まずはパブリッシュ対象となるダミーコードをGitHubに作る。

github.com

これはsbt new scala/scala3.g8で作っただけの、hello worldが出るだけのコードから始める。

まずはパブリッシュするときに必須となるパッケージ名などを設定しておく。

// build.sbt
val scala3Version = "3.3.3" // Scala 3.3系はLTSなので、ライブラリをパブリッシュするときは3.3にしておくとよい

lazy val root = project
 .in(file("."))
 .settings(
   organization := "dev.capslock", // ここに取得済みのnamespaceを入力する
   organizationName := "capslock.dev", // organizationの名前はわかりやすければなんでもいい
   startYear := Some(2024), // 作った年
    // ライセンスを指定する。License.以下に定番のライセンスが用意されているが、それに無い場合は(名前, そのライセンスのURL)のタプルを渡す
   licenses += License.MIT,
   homepage := Some( // そのプロジェクトのホームページを指定する。GitHubの場合はそのプロジェクトページでよい
     url(
       "https://github.com/windymelt/scala-new-maven-central-exercise"
     )
   ),
   scmInfo := Some(
     ScmInfo( // ソースコード管理システムの情報を与える。1つめはURL、2つめはgit cloneするときの文字列を与える
       url("https://github.com/windymelt/scala-new-maven-central-exercise"),
       "https://github.com/windymelt/scala-new-maven-central-exercise.git"
     )
   ),
   developers += Developer( // 開発者情報。ID、名前、メール、ホムペの順
     "windymelt",
     "windymelt",
     "windymelt@3qe.us",
     url("https://www.3qe.us/")
   ),
   name := "scala-new-maven-central-exercise",
   version := "0.0.1", // バージョンを指定する。semantic versioningするとよい
   scalaVersion := scala3Version,
   libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test
 )

sbt-sonatypeの最新版を手でビルドする

sbt-sonatypeはまだ新Maven Central向けのリリースを出していないが、既にPull-Reqが作成されており、パブリッシュ可能な状態になっている。よってこれを利用するための手順を行う。

github.com

具体的にはこれを行う。対応版のフォークブランチでsbt-sonatypeをビルドしてローカルで利用できるようにする。

% git clone git@github.com:Andrapyre/sbt-sonatype.git
% cd sbt-sonatype
% git switch adding-sonatype-central-client
% git pull
% sbt "compile; publishLocal"
[info]  published ivy to /home/windymelt/.ivy2/local/org.xerial.sbt/sbt-sonatype/scala_2.12/sbt_1.0/0.0.0-734-5b5db727/ivys/ivy.xml

するとこの通りxmlファイル出したと言われるのでそれを見にいく。中にrevisionがあるのでこれをコピーする。

<info organisation="org.xerial.sbt" module="sbt-sonatype" revision="0.0.0-734-5b5db727" status="integration" publication="20240323224111" e:sbtVersion="1.0" e:scalaVersion="2.12">

この場合は0.0.0-734-5b5db727をコピーしておく。

sbt再設定

プラグインがローカルで使えるようになったので、パブリッシュしたいリポジトリのproject/plugins.sbtにこれを追加する:

addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.0.0-734-5b5db727") // ここに指定する
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")

このように書くことで、sbtはローカルにあるビルド済みのプラグインを利用してくれるようになる。

build.sbtには以下を追加する:

import xerial.sbt.Sonatype.sonatypeCentralHost

// パブリッシュ先はMaven Centralであることを指定している
ThisBuild / publishTo := sonatypePublishToBundle.value
ThisBuild / sonatypeCredentialHost := sonatypeCentralHost

クレデンシャル準備

sbt-sonatypeは環境変数からMaven Centralへのログインに必要な情報を読み取るので、環境変数でsonatypeのクレデンシャルを設定する。 これは直接ユーザ/パスワードではなく、ユーザ画面からトークンを作っておくとよい。

このへんはopコマンドで1Passwordと連携してもいいと思う。

% export SONATYPE_USERNAME="<sonatype_username>"
% export SONATYPE_PASSWORD="<sonatype_password>"

署名用GPG鍵準備

Maven Centralは、JARファイルがGPGで署名されていることを要求しているので、GPG鍵の設定もやっておく。鍵は開発者のをそのまま使うのではなく、プロジェクトごとに1つ作るのがよい。

手順は以下の項目に準じている。

github.com

% gpg --gen-key
Real name: {プロジェクト名 bot}
Email address: {ここは自分のメールアドレスにする}
You selected this USER-ID:
    "scala-new-maven-central-exercise bot <windymelt@3qe.us>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? o # これでいいのでoを押す
# パスワードを訊かれるので、1Passowrdとかで生成して保存する

% LONG_ID=DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF # 生成したPGP鍵の長いIDを環境変数に入れる
# 公開鍵を公開する(Linuxの場合)
% gpg --keyserver hkp://keyserver.ubuntu.com --send-key $LONG_ID && \
gpg --keyserver hkp://pgp.mit.edu --send-key $LONG_ID && \
gpg --keyserver hkp://pool.sks-keyservers.net --send-key $LONG_ID

プロジェクトのビルド

ついに準備ができたので署名付きJARを生成する。

% sbt "publishSigned" 

途中で署名のためにPGP鍵のパスワードを訊かれるので入力する。

最後にMaven Centralにパブリッシュする。

% sbt "sonatypeBundleRelease"

ちなみにコケるとその旨出力されるし、ブラウザからもわかるような通知が出る。

PublishコーナーのDeploymentsに行くと理由が出てるので、これを直す。

ちなみにコケたときはその都度sbtでcleancleanIvyすると成果物が綺麗になるのでヘンなトラブルを回避できる。

うまくいくとこういう出力が出てくる:

2024-03-23 23:27:00.383+0900  info [SonatypeCentralClient] Uploading bundle /home/windymelt/src/github.com/windymelt/scala-new-maven-central-exercise/target/sonatype-staging/0.1.0-SNAPSHOT-bundle/bundle.zip to Sonatype Cent
ral  - (SonatypeCentralClient.scala:72)
2024-03-23 23:27:02.930+0900  info [SonatypeCentralService] Checking if deployment succeeded for deployment id: 45ea0223-28b8-4a3c-8557-2fe9e2954bef...  - (SonatypeCentralService.scala:27)
2024-03-23 23:34:12.115+0900  info [SonatypeCentralClient] Deployment succeeded for deployment id: 45ea0223-28b8-4a3c-8557-2fe9e2954bef. Current deployment state: PUBLISHED  - (SonatypeCentralClient.scala:107)

パブリッシュに成功した場合、csコマンドから直接起動できるようになるので確認するとよい:

% cs launch dev.capslock::scala-new-maven-central-exercise:0.0.1
Hello world!
I was compiled by Scala 3. :)

Further Reading

tarao.hatenablog.com

より本格的なリリースを行うときはここの記述を参考にするとよい。リリース手順だけ手で行うようにすれば、正式にsbt-sonatypeが新Maven Centralに対応するまでのつなぎにできる。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?