NaClの前田です。
筆者が開発しているTextbringerというgemのリリースを rake bump
コマンド一発でできるように先日自動化したのですが、少しはまったポイントがあったので記事にまとめます。
Textbringerの開発はGitHubで行っているのですが、Trusted Publishingという仕組みでGitHub Actionsでgemのリリースを行うことができるため、もともとタグをpushした時にリリースできるようにしていました。
ただ、バージョン番号を上げるpull requestを作成して、マージ後にタグを作成してpushをする作業を毎回手でやるのが面倒になってきたため、手元で rake bump
コマンドを実行するだけでバージョンを上げてリリースできるようにしました。
lib/textbringer/version.rbに記載されているTextbringer::VERSIONをインクリメントして、GitHubへのpushとpull requestの作成を行うようにしました。
task :bump do
require_relative "lib/textbringer/version"
version = Textbringer::VERSION.to_i + 1
puts "Bump version to #{version}"
system "git checkout main" or exit(1)
system "git pull" or exit(1)
system "git checkout -b bump_version_to_v#{version}" or exit(1)
File.write("lib/textbringer/version.rb", <<~EOF)
module Textbringer
VERSION = "#{version}"
end
EOF
system "git commit -a -m 'Bump version to #{version}'" or exit(1)
system "git push" or exit(1)
system "gh pr create --title 'Bump version to #{version}' --body ''" or exit(1)
system "git checkout main" or exit(1)
end
version = Textbringer::VERSION.to_i + 1
というコードを見て大丈夫か不安になる方もいるかもしれませんが、TextbringerはLatestVerというバージョニングポリシーを採用しており、バージョン番号は1桁なので問題ありません。
当初は以下のようなワークフロー(.github/workflows/tag_version.yml)を追加し、lib/textbringer/version.rbの変更がmainに入ったら v6
のようなタグを作成するようにしました。
name: Tag version
on:
push:
branches:
- main
paths:
- 'lib/textbringer/version.rb'
permissions:
contents: write
jobs:
tag_version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: k1LoW/github-script-ruby@v2
with:
script: |
require "./lib/textbringer/version"
repo = "#{context.repo.owner}/#{context.repo.repo}"
tag = "v#{Textbringer::VERSION}"
github.create_ref(repo, "refs/tags/#{tag}", context.sha)
しかし、この方法ではタグは作成されるものの、肝心のTrusted Publishingのワークフローが実行されませんでした。
どうもGitHub Actionsではループを避けるためにワークフロー中でリポジトリが変更された場合は他のワークフローがトリガーされないようになっているようです。
personal access tokenを使ったり、GitHub App化すれば他のワークフローをトリガーできるようですが、面倒なので他の方法を取ることにしました。
すべての処理を一つのワークフローで行ってしまえば他のワークフローをトリガーする必要はないので、 bump_version_to_v*
というブランチが作成された時に以下の処理を実行してしまうことにしました。
gh pr merge --merge --auto "$PR_URL"
)git tag "${tag_name}"
)uses: rubygems/release-gem@v1
)1はあらかじめオートマージできるようにリポジトリを設定しておく必要があります。
本当はmainにマージされてからタグを作成してリリースするようにしたかったのですが、1の処理はマージが完了する前に返ってきてしまうので、しかたなくブランチでタグを作成してリリースするようにしました。
version.rbの変更だけでテストが通らなくなることは考えにくいので実用上は問題ないと思います。
修正後のワークフローは以下の通りです。
上記でうまくいったと思ったのですが、pull requestのブランチ上でタグを作成したことで、pull requestのマージ後にブランチが削除されてタグがリポジトリ上のどのブランチにも所属しない状態になり、そのせいかGitHub Releasesのドラフトを作成する時に直前のバージョンからの差分ではなく最後にmainからタグを作成してリリースしたバージョンからの差分になってしまったため、GitHub Actions上でのタグ作成はあきらめてローカルで作成するようにしました。
task :bump do
require_relative "lib/textbringer/version"
version = Textbringer::VERSION.to_i + 1
tag_name = "v#{version}"
puts "Bump version to #{version}"
sh "git checkout main"
sh "git pull"
File.write("lib/textbringer/version.rb", <<~EOF)
module Textbringer
VERSION = "#{version}"
end
EOF
sh "git commit -a -m 'Bump version to #{version}'"
sh "git push"
sh "git tag #{tag_name}"
sh "git push origin #{tag_name}"
end
もともとpull requestにしていたのはオートマージを有効にしてmainへのpushを禁止していたからなのですが、RulesetのBypass listにRepository adminを追加して自分はmainにpushできるようにしてしまいました:(