去年の12月頃に Trusted Publishing という機能が RubyGems.org に入った。
これは 「指定した GitHub リポジトリの指定した Workflow に対して、(指定した) gem の push を認可する」機能。これを設定すると、GitHub Actions で Credentials の登録をすることなく gem を push 出来るようになる。
この機能は内部的には、 Open ID Connect (OIDC) を利用していて、これにより short-lived な access token を都度取得出来る。
この方法だと通常は ↑ の記事にあるようなトークンの交換処理を行う必要があるのだが、以下の Custom Action を使うことで、簡単にトークンの交換や gem の release が行える。
この記事では、 release-gem Action を利用して、GitHub Actions から gem のリリース出来るようにする流れを説明する。
1. RubyGems.org 側で Trusted Publishing の設定を行う
(※ https://guides.rubygems.org/trusted-publishing/adding-a-publisher/ の内容とほぼ同じ)
(RubyGems.org にログインした状態で、) 設定を行いたい Gem のページの Link から、 信頼できる発行元
(または Trusted Publishers
) を選択し、遷移先の画面から 作成
(または Create
) を選ぶ。
すると、登録フォームに遷移する。
このフォームで、
- 認可するリポジトリ (Repository Owner / Repository Name の項目)
- 認可する GitHub Workflow のファイル名
- 認可する Environment 名
を入力し、Rubygem Trusted publisher を作成
(または Create Rubygem Trusted publisher
) で登録完了。
Environment は任意だが、実行ブランチの制限や実行時のレビュー必須化など、保護機能が追加で備わっているのでおすすめ。
(新規の gem に対しても似たような手順で設定が行える。詳しくは https://guides.rubygems.org/trusted-publishing/pushing-a-new-gem/ を参照。)
2. release-gem Action を使って Workflow を実装する
(※ https://guides.rubygems.org/trusted-publishing/releasing-gems/ の内容がベース)
https://github.com/marketplace/actions/release-gem を使った、こういう感じの Workflow を実装する。
# ファイル名は、 1. で登録したファイル名にする
name: Release Gem on RubyGems.org
on:
# push でも workflow_dispatch でもどっちでも OK
push:
tags:
- v*
workflow_dispatch:
jobs:
push:
runs-on: ubuntu-latest
# 1. で登録した Environment 名にする必要がある
environment: release
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
# `gem exec` が使えるバージョンの rubygems gem が必要。(後述)
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
ruby-version: ruby
# rubygems: latest
- uses: rubygems/release-gem@v1
release-gem Action が行っていることはざっくり以下の通り。
- OIDC を利用し、RubyGems.org の short-lived な access token を取得
- (内部的には Configure RubyGems Credentials Action を利用)
-
rake release
を実行して gem のリリースを行う- この際に rubygems gem に patch を当てていて、可能なら署名を行いつつ gem を push する
この際に実行している rake release
というのは、Bundler が提供している gem の release 用のタスクで、
- version tag を打って git push
- rubygems への gem の push
を行ってくれる。
(Rakefile 内で require "bundler/gem_tasks"
とすると使える。 bundle gem
とかで gem を作っていると最初から入っている。)
※ rubygems gem のバージョンが古いと gem exec
が実行できずエラーになる
とまあ、便利な release-gem なのだが、 Ruby 3.1.x など、古めの version で動かすと、以下のようなエラーになる。
ERROR: While executing gem ... (Gem::UnknownCommandError)
Unknown command exec
/opt/hostedtoolcache/Ruby/3.1.6/x64/lib/ruby/3.1.0/rubygems/command_manager.rb:198:in `find_command'
/opt/hostedtoolcache/Ruby/3.1.6/x64/lib/ruby/3.1.0/rubygems/command_manager.rb:183:in `process_args'
/opt/hostedtoolcache/Ruby/3.1.6/x64/lib/ruby/3.1.0/rubygems/command_manager.rb:149:in `run'
/opt/hostedtoolcache/Ruby/3.1.6/x64/lib/ruby/3.1.0/rubygems/gem_runner.rb:51:in `run'
/opt/hostedtoolcache/Ruby/3.1.6/x64/bin/gem:21:in `<main>'
これは release-gem が gem exec
(npx, npm exec の ruby 版) という機能を使っていて、 gem exec
が入ったのが rubygems gem 3.4.8 というそこそこ新し目のバージョンのため。
このエラーを回避するには、 setup-ruby 側で rubygems: 3.4.8
を指定するか、rubygems gem のデフォルトバージョンが新しいもの (3.2.6 以降など) を指定すると良い。