くりにっき

フルスタックキュアエンジニアです

terraform-plan-changes-countを作った

terraform-plan-changes-countについて

github.com

Terraformのplanに含まれるchangesの件数を取得するためのGitHub ActionsのActionです

下記の例が全て

steps:
  - uses: hashicorp/setup-terraform@v3

  - run: terraform plan -out=tfplan

  - name: Run terraform-plan-changes-count
    id: plan-changes
    uses: sue445/terraform-plan-changes-count@v0
    with:
      plan-path: tfplan

  - name: Print outputs
    run: |
      echo "CREATE_COUNT=${CREATE_COUNT}"
      echo "UPDATE_COUNT=${UPDATE_COUNT}"
      echo "DELETE_COUNT=${DELETE_COUNT}"
      echo "TOTAL_COUNT=${TOTAL_COUNT}"
    env:
      CREATE_COUNT: ${{ steps.plan-changes.outputs.create }}
      UPDATE_COUNT: ${{ steps.plan-changes.outputs.update }}
      DELETE_COUNT: ${{ steps.plan-changes.outputs.delete }}
      TOTAL_COUNT:  ${{ steps.plan-changes.outputs.total }}

モチベーション

僕は個人でTerraformのリポジトリを10個以上メンテしています。

Terraformの本体やProviderをバージョンアップするPRは毎月自動で作られるのですが、planの結果を見て1つずつマージしていくのも大変です。

これらのPRの場合基本的にplanのchanges(create, update, delete)の件数が0件なことがほとんどなので、ほとんどのケースで自動マージできます。

そのためGitHub Actions上でplanのchangesの件数を取得しやすくするために作りました。

例:dependabotが作ったPRでplanのchangesの件数が0件だった場合に自動マージする例

jobs:
  terraform:
    permissions:
      contents: write
      pull-requests: write

    steps:
      - name: Run terraform-plan-changes-count
        id: plan-changes
        uses: sue445/terraform-plan-changes-count@v0
        with:
          plan-path: tfplan

      - name: Auto-merge Dependabot PR when there are no plan changes
        run: |
          gh pr review --approve "$PR_URL"
          gh pr merge --auto --merge "$PR_URL"
        if: github.event_name == 'pull_request' && steps.plan-changes.outputs.total == '0' && github.actor == 'dependabot[bot]'
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

元ネタ

GitLabだと下記のような方法でplanのchangesの件数を取得してMergeRequest上で表示することができます。

docs.gitlab.com

ここに書かれてるスクリプトGitHub Actionsでいい感じに使いたくて作りました。

2025年に作ったものまとめ

レギュレーション

  • 既存OSSのバージョンアップを含めたらきりがないので2025年に新しく作ったものだけをカウント

go-gem-wrapper

自分の中で今年のベストオブOSSといったら間違いなくgo-gem-wrapper

github.com

go-gem-wrapperでRubyKaigiにも登壇させてもらったしBundler v4の新機能としても取り込まれた

inside.pixiv.blog

sue445.hatenablog.com

connpass_api_v2-ruby

Connpass API v2が出た直後に作ったやつ

github.com

sue445.hatenablog.com

x_post_sanitizer

個人ツールのために作ったやつ

github.com

sue445.hatenablog.com

sashimi_tanpopo

OSSメンテのために作ったOSS。これのおかげで日々のOSSメンテが割と楽になってる

github.com

sue445.hatenablog.com

sue445/workflows

https://github.com/r7kamura/workflowsインスパイヤされて作った、自分がメンテしてるOSSリポジトリで使ってる汎用workflow集。

github.com

既存リポジトリのworkflow移行は死ぬほどつらかったけど60個近いリポジトリでコピペしまくってたyamlを1箇所に集約できたのは個人的にはかなりの文明開化。

基本的にGitHubメインだけどGitLabにも出してるOSSがあるのでそっちもちょいちょい草が生えています。

https://github.com/sue445

https://gitlab.com/sue445

yardで複数ディレクトリに同名ファイルがある場合にファイル一覧をいい感じにしたい

tl;dr;

ファイルに @title を埋め込むかyard用の中間ファイルを作る

コンテキスト

例えば下記のようなファイル構成があったとします

  • README.md
  • sub-dir/README.md

https://github.com/lsegal/yard でドキュメントを作るとファイル一覧で同じものが並ぶのでなんとかしたかったというのが発端

方法1: ファイルに @title を埋め込む

https://rubydoc.info/gems/yard/file/docs/GettingStarted.md#adding-meta-data-to-extra-files を参照。

これでもいいんだけどGitHubとかで見た時にyardのタグが見えるので見栄えが悪いのがちょっと難点。

方法2: yard用の中間ファイルを作る

.yard/sub-dir-README.md のような名前で sub-dir/README.md をincludeするような中間ファイルを作成。

{include:file:sub-dir/README.md}

.yardoptsなどで下記のように中間ファイルのパスを渡す。

.yard/sub-dir-README.md

こうすることで sub-dir/README.md にyardのタグを書かずにファイル一覧をいい感じにできます。

go-gem-wrapperでこの問題に困ってこっちの方法を採用しました。

github.com

マージした後で気付いたけど .yard/go_gem_README.md@title 書いてもよかったかも。

中間ファイルが増えるのもちょっと微妙だけど自分はこっちの方がまだマシかなという判断。異論は認める

dependabot-auto-mergeを移行した

dependabot-auto-merge(下記で書いたやつ)を新しい仕組みに移行しました。

sue445.hatenablog.com

発端

dependabot-auto-mergeはDependabotの @dependabot merge コマンドに依存してるんですが、2026/1/27に廃止予定なので移行する必要がありました。

github.blog

やったこと

色々調べたんですが以前 id:ohbarye さんが書かれてものが自分のやりたかったことに近かったので参考にさせてもらいました。

blog.smartbank.co.jp

しかし移行予定のリポジトリが20個近くあったため、workflowファイルをコピペしていくとロジックを修正したくなった時に全リポジトリを修正してまわる必要があって大変なのは明らかでした。

そのため、この機会にworkflowの実装を https://github.com/sue445/workflows (自分がメンテしてるリポジトリ全部にいれる汎用workflow集)に移行しました。

最終的に完成した新dependabot-auto-mergeは https://github.com/sue445/workflows/blob/1e4d54c9399e7229b37c60255eb937714481d704/.github/workflows/dependabot-auto-merge.yml

リポジトリに下記のようなworkflowは書いてまわる必要があるものの、workflowの本体は1箇所に集約されてるので便利。

name: dependabot-auto-merge

on:
  pull_request:
    types:
      - opened
      - synchronize # PR branch is rebased

jobs:
  auto-merge:
    uses: sue445/workflows/.github/workflows/dependabot-auto-merge.yml@main
    secrets:
      # TODO: Set secrets to Dependabot secrets
      app-id: ${{ secrets.GH_APP_ID }}
      private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
      slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

基本的に常に最新を使っていいのでmainブランチ指定にしてるんだけど、Require actions to be pinned to a full-length commit SHA *1 が使えなくなるのが難点っすね...

今年買ってよかったもの(2025年版)

今年買ってよかったものを雑にまとめ

前回書いたの2020年か...

sue445.hatenablog.com

日用品

iPhone 17 Pro

www.apple.com

今まで使ってたスマホはコロナ前の2018年に買ったiPhone XS

保証はとっくに切れてたけどスペック的に特に困らなかったのでずっと使ってた。とはいえXSのままだとiOS 26に上げられないので新しくすることにした。

XSに比べてちょっと厚くなったけど大きさはそんなに変わってないのでよき。

大変だったのはコネクタがThunderboltからUSB Type-Cに変わったのでケーブルとかアクセサリもセットで買い直したことくらい。

UGREEN MagFlow

ugreen.jp

iPhone 17の急速充電を活かすワイヤレス充電器が欲しくて色々ググってたら下記エントリでオススメされてたのでポチった

note.com

マグネットがついているのでiPhoneをくっつけてスタンド代わりになって便利。iOSのスタンバイモード(横向きで充電すると時計が出るやつ)とも相性がいい。

マグネットがあるおかげで「ワイヤレス充電器の上に乗せても充電されないから充電されるように位置を微調整」ってことがなくなったのも嬉しい。

漫画

今年になって既刊一気買い、ないしは1巻から買い始めた漫画の中から好きなのをピックアップ

サネカの嫁入り、こないだ完結してしまった(´;ω;`)

わたなれは映画見に行った直後に全巻ポチったw

自分がメンテしてるgemをほぼ全部GitHub Actionsからリリースできるようにした

きっかけ

https://github.com/smartbank-inc/action_ip_filter のソースを見てたら https://github.com/rubygems/release-gem が使われていたのでついカッとなってやりました。

3日間で計50リポジトリくらいで作業してgemをリリースしてまわったと思います。

作業全部終わってから気づいたけどCursorとかにやらせればよかったな...

参考にしたドキュメント

この辺はむっちゃ読みました。

github.com

guides.rubygems.org

guides.rubygems.org

参考にした設定

下記を参考にしました。

tag pushをトリガにしてgemをリリースするか workflow_dispatch を使って手動実行でgemをリリースするかは悩ましかったんですが、 rubygems/release-gem 内で bundle exec rake release を実行している *1ため後者の手動実行を採用しました。( rake release 内のgemのリリースフローでもtagを作ってpushするのだが、同名のtagが存在しているとエラーになって rake release が失敗するため)

実際にやったこと

下記のような作業を50個くらいのリポジトリでやってまわりました。

自分用の作業メモをそのままブログに載せてるので合わないものは適宜変えてください。

.github/workflows/release_gem.yml を追加

リポジトリから手動実行してgemをリリースしてGitHubにReleaseを作るワークフロー。

USER_NAMEREPO_NAMEGEM_NAME を適宜書き換える。

name: Publish gem to rubygems.org

on:
  workflow_dispatch:

jobs:
  release:
    if: github.repository == 'USER_NAME/REPO_NAME'
    runs-on: ubuntu-latest

    environment:
      name: rubygems.org
      url: https://rubygems.org/gems/GEM_NAME

    permissions:
      contents: write
      id-token: write

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
        with:
          egress-policy: audit

      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

      - name: Set up Ruby
        uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
        with:
          bundler-cache: true
          ruby-version: ruby

      - name: Publish to RubyGems
        uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1

      - name: Create GitHub release
        run: |
          tag_name="$(git describe --tags --abbrev=0)"
          gh release create "${tag_name}" --verify-tag --generate-notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

forkされたリポジトリでworkflowを実行できないようにするのを最初見た時 *2 は「なるほど〜」と思いました。

なのでリポジトリ名をハードコーディングしてた方がよさそう。(後述のrubygems.org側のTrusted publishersがあるのでどっちにしろgemリリース時にエラーになるんだけど)

あと、 gh release create でreleaseを作るので .github/release.yml *3を作っておくとリリースノートをいい感じにできそう。

自分のリポジトリで使ってる設定はこれ。 https://github.com/sue445/sashimi_tanpopo/blob/1f3566456f6f39198ed7468653bd52cd17660e8b/.github/release.yml

リポジトリにEnvironmentを追加

Environmentsから rubygems.org を作ります。

複数人でメンテするgemはRequired reviewersがあると、リポジトリへのコミット権は渡したいけどgemのpush権は渡したくような場合に制御できて安心ですね。

基本的に「Protected branch = デフォルトブランチ」になっていると思うので下記のいずれかを設定。

  • Protected branch only
  • デフォルトブランチ(mainブランチなど)を個別に設定する
    • Protected branchが複数あるけどgemのリリースはmainブランチだけで行いたい場合などはこっち

rubygems.orgでTrusted publishersを追加

https://guides.rubygems.org/trusted-publishing/adding-a-publisher/ を参考に設定。

下記を設定します。

  • Workflow Filename: release_gem.yml
  • Environment: rubygems.org

リポジトリ.github/workflows/releasepush を含むyamlがあると補完されてる*4ようなので、workflowのファイル名もそれに合わせておくとよさそう。

gemリリースの流れ

Before

  1. CHANGELOG.md を書く
  2. version.rb を編集
  3. ローカルで bundle exec rake release を実行

After

  1. CHANGELOG.md を書く
  2. version.rb を編集
  3. git push
  4. リポジトリからworkflowを手動実行

rubygems/release-gem を導入できなかったリポジトリ

https://github.com/ruby-go-gem/go-gem-wrapper ではrubygems/release-gemを導入できずに導入後にrevertしました。

リポジトリと同様の手順で導入したら、Gemfile.lockに書かれているgemのバージョンと違うバージョンをbundlerがロードしようとして謎でした...

詳しいログ。

bundler 2.7.2でのエラー

github.com

bundler 4.0.0でのエラー

github.com

2025/12/10 13:14 追記

id:r7kamura さんみたいにworkflow用のリポジトリを作ってそこに集約させるの全然アリだな。この方式パクらせてもらおうw

https://github.com/r7kamura/slimi/blob/08a68e419692a8d681e9e078a38fc40604cff6c1/.github/workflows/release.yml

github.com

2025/12/11 12:51 追記

現状だと無理っぽい...

Bundler v4.0.0でGo gemを作れるようにした

前置き

bundler v4.0.0で bundle gem --ext=go でGoのnative extension gem(以下、Go gem)のスケルトンが作れるようになりました。*1

blog.rubygems.org

[

--ext=go の実装を僕が作ったので宣伝させてください。

github.com

Before my PR(~bundler v2系)

bundle gem--ext はcとrustのみサポートされていました 。

Go gemを作る時は bundle gem <GEM_NAME> --ext=c でCのnative extensionのスケルトンを作った後で https://github.com/ruby-go-gem/go-gem-wrapper/tree/v0.10.0/_tools/patch_for_go_gem のようなスクリプトを実行してパッチをあてる必要がありました。

After my PR(bundler v4系~)

CやRustと同様に bundle gem <GEM_NAME> --ext=go でGo gemのスケルトンが作れるようになりました。やったね!

go-gem-wrapperについて

僕が作ったライブラリです。

github.com

主に下記の2つで構成されています

  • github.com/ruby-go-gem/go-gem-wrapper (Goのmodule)
    • GoからCRubyの関数を呼び出すためのbindingを提供している
  • https://rubygems.org/gems/go_gemRubyのgem)
    • native extensionのビルド時にGoをビルドするための処理を追加
    • go testgo fmt など、Goでよく使うコマンドをRubyから呼び出しやすくするためのrake taskを提供

bundle gem --ext=go した時に作られるスケルトンの中で github.com/ruby-go-gem/go-gem-wrapper やgo_gemが組み込まれています

Go gemやgo-gem-wrapperのもっと詳しい技術的な話について

RubyKaigi 2025 で話したのでそちらの発表資料やアーカイブをご参照ください。

speakerdeck.com

rubykaigi.org

inside.pixiv.blog

余談ですがRubyKaigiの時に喋ったPR *2 がマージされてbundlerに取り込まれたのでKaigi Effect *3 と言えます。

大変だった思い出

だいたいの苦労話はRubyKaigiで話してるので、今回はRubyKaigiで喋っていないbundlerのPRについて書きます

Windowsの時だけなぜか特定のテストがハングする

bundlerはGitHub ActionsのUbuntu, macOS, WindowsのRunnerでそれぞれCIを実行してるんですが、なぜかWindowsの時だけ特定のテストがハングするという現象があってハマりました。(未解決)

https://github.com/ruby/rubygems/pull/8183/commits/44fe3fedef6f8784dbb7e61d8a6cf869d6394d24

Windowsでのビルドが1時間くらいかかる(つらい)

寝る前にpushして、起きてからCIの結果を確認することが多かったです。

https://github.com/ruby/rubygems/actions/runs/19452908845/job/55661461150

【余談1】PRマージ直後の様子

なんやかんやでマージしてもらえるまで1年くらいかかったので喜びもひとしお。

トリアージしてくれたhsbtさんやPRをレビューしてくれた人たちに本当に感謝です...

【余談2】どうでもいい気付き

Bundler v4にGo(5)対応が入るの紛らわしいなw いっそBundler v5合わせでもっと寝かせておくべきだったか