🟨

Gem を省いた Ruby のバージョンのみを Renovate で更新する

2024/12/02に公開

現在自分が携わっている Rails のプロジェクトでは、使用している Gem のバージョンアップデートに関して Dependabot で自動で PR(Pull Request) を作成し管理しています。
ただ Ruby そのもののバージョンに関しては、過去の PR を参考に手動で作成していました。
そんな中 Ruby 3.3.4 のリリースで今後は遅くとも2ヶ月おきに新しいバージョンがリリースされるということが発表されました。
Ruby の更新頻度が多くなり Gem だけでなく Ruby そのものについてもバージョンの記載などの基本的な箇所は自動で PR を作成していきたいという話になりました。

今回は依存関係の自動更新を行うためのオープンソースである Renovate を使って Gem を省いた Ruby のバージョンのみを更新する方法について書きます。

Renovate の導入

Renovate アプリを使用した導入の流れは以下のようになります。

  1. GitHub 上で Renovate アプリを設定する
  2. PR「Configure Renovate」が作成されるのでマージする

これだけで Renovate によって更新可能なバージョンが検出され PR が作成されるようになります。(参考: Installing & Onboarding

例えば、以下のバージョンを使用している Rails プロジェクトに Renovate を導入します。

  • ruby 3.3.4
  • rails 7.2.0

2024年12月1日時点では ruby は 3.3.6、 rails は 8.0.0 までリリースされているため、Renovate を導入すると以下のような PR が作成されます。


Renovate の設定ファイルは初期状態で以下のようになっています。

renovate.json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended"
  ]
}

$schema はエディタの補完をサポートするための記述です。
extends は様々な設定のプリセットの指定できます。デフォルトで指定されている config:recommended は、ほとんどのユーザーに勧められる設定が含まれているようです。(参考: Full Config Presets

ただ、いずれも Ruby や Rails といった言語やライブラリを指定しているわけではありません。
つまり、設定として指定されたうえでその言語やライブラリが更新対象になるわけではなく、 Renovate がサポートしている言語やライブラリは元からすべて更新対象であり、プロジェクト内の更新可能なものはすべて PR を作成しようとする動きをすることがわかります。

そのため、今回のケースでは Gem については更新対象とせず Ruby のバージョンのみを対象とするため Gem を更新対象から外す設定を加える必要がありそうです。

Gem を更新対象から外す

Gem を更新対象から外すには Renovate に用意されているモジュールの中の Datasource の設定を加える必要があります。

Datasource は利用可能なバージョンをレジストリから探し出してくるモジュールです。
そのままでは Renovate がサポートしているレジストリすべてが検索されてしまうため RubyGems からは取得しないよう以下の設定を加えます。

renovate.json
{
  ...
  "packageRules": [
    {
      "matchDatasources": ["rubygems"],
      "enabled": false
    }
  ]
}

ちなみに、混同しやすいモジュールとして Manager がありますが、こちらはプロジェクトに含まれる依存関係を抽出する役割を担うため、ファイル単位で更新対象を修正する場合などで使用します。この後の章では使用しています。

なお、この章でも Manager 等の設定を使った方法を検討しましたが、うまくいきませんでした。

Manager 等の設定を使った方法での検討

まず Manager に関する設定を使う場合 Gemfile を更新対象にした bundler という Manager を無効化する方法が浮かびます。

しかし、Gemfile では Gem を含める Ruby のバージョンを記載しているため Gemfile 自体は更新対象から外すことはできません。

そこでファイル名ではなくパッケージ名を更新対象から外す設定を使うことを考えました。
例えば、"rails" を更新対象から外す場合、以下のようにします。

renovate.json
{
  ...
  "packageRules": [
    {
      "matchPackageNames": ["rails"],
      "enabled": false
    }
  ]
}

パッケージ名を指定する matchPackageNames には正規表現も使うこともできるので、ここで 「"ruby" 以外」を指定できれば良さそうです。

"ruby" 以外」は否定の先読みを使い以下のように書けます。

renovate.json
{
  ...
  "packageRules": [
    {
      "matchPackageNames": ["^(?!ruby$).+$"],
      "enabled": false
    }
  ]
}

しかしこれはうまくいきませんでした。
理由は Renovate が使用している正規表現のパッケージである RE2 が否定の先読みを禁止しているためです。否定の先読みはパフォーマンスの低下を引き起こしうる記述方法の一つのようです。

https://docs.renovatebot.com/modules/manager/regex/#online-regex-testing-tool-tips

The regex manager uses RE2 which does not support backreferences and lookahead assertions.

https://github.com/uhop/node-re2?tab=readme-ov-file#limitations-things-re2-does-not-support

RE2 doesn't support lookahead assertions, which are ways to allow a matching dependent on subsequent contents.

正規表現にマッチする箇所を更新対象に加える

上記までで Gem を更新対象から外すことができました。
これで終わりと思いきや、実は Dockerfile にも Ruby のバージョンが記載されていましたが、PR の差分には現れませんでした。
こういった .ruby-version Gemfile 以外に Ruby のバージョンが記載されている場合も合わせて修正したいです。
このような場合はカスタムの Manager を用意し正規表現で対象のファイルや修正箇所を検出することができます。

例えば Dockerfile で Ruby のバージョンが以下のように記載されているとします。

ARG RUBY_VERSION=3.3.4

これに対し、以下の設定を追加します。

renovate.json
{
  ...
  "customManagers": [
    {
      "customType": "regex",
      "fileMatch": ["^Dockerfile$"],
      "matchStrings": ["RUBY_VERSION=(?<currentValue>.*?)\\n"],
      "depNameTemplate": "ruby",
      "datasourceTemplate": "ruby-version"
    }
  ]
}

それぞれの項目が表す内容は以下です。

  • fileMatch: 更新対象のファイル名
  • matchStrings: ファイル内の更新部分
  • depNameTemplate Datasource 内の対象のパッケージ名
  • datasourceTemplate 対象の Datasource

カスタムの Manager の指定方法は他にも複数あるため詳しくは公式ドキュメントを見てみてください。(参考: Custom Manager Support using Regex

これにより Dockerfile にある Ruby のバージョンも更新対象に含まれます。

おわりに

Gem を省いた Ruby のバージョンのみを Renovate で更新する方法について説明しました。
はじめから Gem も含めて全部 Renovate に任せればよいのではという声も聞こえてきそうですが、現状 Dependabot でそこまで困っているわけでもないため、無理に移行するよりかは一旦はこれで良さそうに思います。
今回の対応で Renovate の知見を得る機会になり個人的にもよかったです。

SocialPLUS Tech Blog

Discussion