Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Bundler 4.0.0とRubyGems 4.0.0にアップグレードするときの注意点

ruby/rubygems - GitHub

Bundler 4とRubyGems 4は、ユーザービリティ・メンテナンス性・セキュリティを改善するために、非互換な変更を含むさまざまな変更が行われているので、見逃さないために以下を読んでまとめてみました。

参考: Upgrading to RubyGems/Bundler 4 - RubyGems Blog

上の公式ドキュメントに記載されているのは4.0.0の変更だけとは限らず、以前の変更に関連する記述も含まれている点にご注意ください。

利便性のため、上のドキュメントの項目順を重要度の高そうな順に再編成し、可能な限り関連プルリク/コミットも記載しました。

追記

BundlerとRubyGemsのメンテナーであるhsbtさん自らの解説記事が一足先に公開されました↓。こちらもぜひお読みください。不具合があったらRubyGemsのリポジトリまで報告しましょう。

参考: RubyGems/Bundler 4.0 最速解説 - ANDPAD Tech Blog

なお、現在のBundlerはruby/rubygemsのリポジトリ内に統合されています↓(昔は別リポジトリでした)。

参考: rubygems/bundler at master · ruby/rubygems

🔗 最初に: Bundler 4を移行前にシミュレートしよう

Bundler 2.7では、以下の3つの方法のいずれかでシミュレーションできます。これによりBundler 4への移行を予行演習できます。

  1. BUNDLE_SIMULATE_VERSION環境変数に4を設定する
  2. bundle config set --global simulate_version 4を実行する
  3. bundle config set --local simulate_version 4を実行する

hsbtさん記事でもシミュレーションモードでの早期確認を推奨しています

特に、bundle install の挙動変更とGemfileの厳格化は、大規模なRuby/Rails環境において影響が大きいため、早期に Bundler 4シミュレーションモード を活用した移行準備を推奨します。RubyGems と Bundler 4.0 は Ruby 4.0 に同梱される予定です。トリプル 4.0 です。
RubyGems/Bundler 4.0 最速解説 - ANDPAD Tech Blogより

なお、以下のbundle config set例では--global--localの指定を省略しています。

🔗 Bundler 4の注意点

🔗 1: Gemfileのgemが厳格にピニングされるようになった

すべての依存関係についてsourceを明示的に定義する必要があります

  • Gemfileのグローバルなsource文は1個しか書けなくなった(#8968

グローバルなsource文を複数書くとエラーになります。

# 不可
source "https://main_source"
source "https://another_source"

gem "dependency1"
gem "dependency2"

特定のgemのみsourceを変更したい場合は、以下のようにsourceブロックで囲む必要があります。

# 可能
source "https://main_source"

gem "dependency1"

source "https://another_source" do
  gem "dependency2"
end
  • グローバルなpath文やgitは利用できない
# 不可
path "/my/path/with/gems"
git "https://my_git_repo_with_gems"

gem "dependency1"
gem "dependency2"

以下のようにgem文ごとにpathgit引数として指定することは引き続き可能です。

# 可能
gem "dependency1", path: "/my/path/with/gems"
gem "dependency2", git: "https://my_git_repo_with_gems"

または、sourceと同様にpathgitをブロック形式で利用することも可能です。

# 可能
path "/my/path/with/gems" do
  # gem "dependency1"
  # ...
  # gem "dependencyn"
end

git "https://my_git_repo_with_gems" do
  # gem "dependency1"
  # ...
  # gem "dependencyn"
end
  • pathgitで指定したgemは、デフォルトでvendor/cache/*以下にキャッシュされるようになった(#8975

vendor/cache/ディレクトリを作成するとキャッシュがそこに配置され、オフライン状態ではそこからgemの取得を試みるようになります。

🔗 2: Gemfile.lockのRubyバージョンとBundlerバージョンの書式を微修正

Gemfile.lockのRUBY VERSIONセクションとBUNDLED WITHセクションのインデントがスペース3つから2つに変更されました。

bundle platform --rubyで表示されるRubyバージョンからパッチバージョン情報(Rubyのバージョニングポリシーと無関係)が削除されました(#5793

🔗 3: Gemfile.lockにチェックサムが含まれるようになった

Bundler 4からは、新規のGemfile.lockにデフォルトでチェックサムが含まれるようになりました(#8219)。

ただし既存のGemfile.lockにはデフォルトでは追加されません
既存のGemfileにチェックサムを追加するには、プロジェクトディレクトリで以下を明示的に実行する必要があります(#8326)。

bundle lock --add-checksums

自分の環境で実行してみると、以下のようにチェックサムが追加されました。

# Gemfile.lock

# (省略)
CHECKSUMS
  action_text-trix (2.1.15) sha256=4bf9bbd8fa95954de3f0022dae0d927bce22c1bb31d5dc9c3766f8c145c109c1
  actioncable (8.1.1) sha256=7262307e9693f09b299e281590110ce4b6ba7e4e4cee6da4b9d987eaf56f9139
  actionmailbox (8.1.1) sha256=aa99703a9b2fa32c5a4a93bb21fef79e2935d8db4d1fd5ef0772847be5d43205
  actionmailer (8.1.1) sha256=45755d7d4561363490ae82b17a5919bdef4dfe3bb400831819947c3a1d82afdf
  actionpack (8.1.1) sha256=192e27c39a63c7d801ac7b6d50505f265e389516985eed9b2ee364896a6a06d7
  actiontext (8.1.1) sha256=fd8d8da1e6bc0b04ff72fccfd127e78431238a99a82e736c7b52727c576a7640
  actionview (8.1.1) sha256=ca480c8b099dea0862b0934f24182b84c2d29092e7dbf464fb3e6d4eb9b468dc
  activejob (8.1.1) sha256=94f438a9f3b5a6b130fef53d8313f869dbd379309e7d639891bda36b12509383
  activemodel (8.1.1) sha256=8b7e2496b9e333ced06248c16a43217b950192c98e0fe3aa117eee21501c6fbd
  activerecord (8.1.1) sha256=e32c3a03e364fd803498eb4150c21bedc995aa83bc27122a94d480ab1dcb3d17
  activestorage (8.1.1) sha256=bc01d8b4c55e309a0a2e218bfe502c382c9f232e28b1f4b0adc9d8719d2bf28d
  activesupport (8.1.1) sha256=5e92534e8d0c8b8b5e6b16789c69dbea65c1d7b752269f71a39422e9546cea67
# (省略)

追記

bundle update--allオプションを付けないと以下の非推奨警告が表示されます。

$ bundle update
[DEPRECATED] Pass --all to `bundle update` to update everything

🔗 Bundler 4のその他の変更・廃止

🔗 1: 単体のbundlebundle installを実行する振る舞いが非推奨化

従来および現在は、bundleを実行するとbundle installまたはヘルプを表示します。今後は明示的にbundle installを呼ぶことが推奨されます。

以下を実行すると現行の振る舞いを維持できます(現在のデフォルト)(#9136)。

bundle config set default_cli_command install_or_cli_help --global

以下を実行するとbundlebundle installを実行しなくなり、常にヘルプが表示されます。今のうちに設定しておくとよいでしょう。

bundle config set default_cli_command cli_help --global

🔗 2: bundle installの以下のオプションが廃止

  • --clean
  • --deployment
  • --frozen
  • --no-prune
  • --path
  • --shebang
  • --system
  • --without
  • --with

これらのオプションは過去の実行履歴に依存して振る舞いが変わるので、それが混乱の元となっていたためだそうです。

Bundler 4からは上記オプションは廃止されました。

今後は、こうしたオプションはbundle config set --local without development testのようにbundle config setで明示的に設定することになります。

🔗 3: bundle vizコマンドがプラグインに切り出された

bundle vizは、gemとOSの両方に依存する唯一のコマンドであり、これが#8923で削除されたことで、bundler開発時の依存関係が削減されて開発しやすくなります。

今後は以下のbundler-graphプラグインとして利用可能になります。

rubygems/bundler-graph - GitHub

参考: Graphviz

🔗 4: bundle install--binstubsフラグが置き換わった

bundle install --binstubsを実行するとエラーになります(#8978
今後はbundle binstubsコマンドを実行することになります。

従来の--binstubsフラグはプロジェクト内の全てのgemについてbinstubを一律で生成するので非効率でした。

新しいbundle binstubsは個別にgemをbinstub化できますが、従来の振る舞いがどうしても必要な場合はbundle binstubs --allでできます。

🔗 5: bundle injectコマンドが置き換えられた

#8923で削除されました。
今後はbundle addを使うことになります。

🔗 6: gemを取得できない場合にローカルキャッシュからgemの取得を試みるようになった

アドレス解決に失敗した場合は、フェイルオーバーとしてローカルキャッシュで依存解決を試みます。

🔗 7: Bundler 4でBundler.clean_env APIが廃止

以下のAPIが廃止されました(#8924)。

  • Bundler.clean_envおよび依存する以下のAPI
    • Bundler.with_clean_env
    • Bundler.clean_system
    • Bundler.clean_exec

従来は、yieldされるブロック内ではBundler関連の環境変数がBundler.clean_envによってすべて削除されていましたが、現在のbundlerプロセスの開始直前の環境が欲しい場合が多いことがわかったため、以下のAPIが新たに作成されました。

  • Bundler.with_original_envおよび依存する以下のAPI
    • Bundler.original_system
    • Bundler.original_exec

しかし従来の振る舞いが欲しい場合のために、より明確なunbundled_envという名前のAPIが新たに導入されました。

  • Bundler.unbundled_envおよび依存する以下のAPI
    • Bundler.with_unbundled_env
    • Bundler.unbundled_system
    • Bundler.unbundled_exec

🔗 8: Bundler.environmentが廃止(#8924

今後はBundler.loadを使うことになります。

Bundler.environmentでインスタンス化されるBundler::Environmentクラスは、実はBundler::Runtimeと同じであることがわかりました。
そのため、Bundler::Environmentクラスは削除され、Bundler.environmentBundler.load(内部でBundler::Runtimeを参照する)に委譲されました。

🔗 9: Bundler::SpecSetの変更

以下のpublicメソッドは代替なしで削除されました(#9007)。

  • SpecSet#-
  • SpecSet#<<

以下のpublicメソッドは常に暗黙でバリデーションを実行するようになりました。

  • SpecSet#for#9015
    checkパラメータは使われておらず、非推奨化されたのでcheckパラメータを削除すること。

🔗 10: CurrentRuby#maglev?を削除

代替なし。
今後Ruby実装を調べたいときは代わりにRUBY_ENGINE定数をチェックすること。

🔗 11: Bundler.rubygems.all_specsが削除(#9008

今後はBundler.rubygems.installed_specsを代わりに使うこと。

🔗 12: vladcapistrano用のデプロイメントヘルパーが削除(#8957

  • vladはメンテされなくなってから長い
  • capistrano 3はcapistrano-bundler gemとしてBundlerに統合されているので、vladよりこちらを使うべき

capistrano/bundler - GitHub

なお、引き続きcapistrano 2を使っている場合は、bundler 2のlib/bundler/deployment.rbファイルからcapistranoタスクを切り出してアプリに置いて使えるそうです。

🔗 RubyGems 4の注意点

🔗 1: gem queryコマンドが廃止

今後はgem searchgem listを使うことになります。

🔗 2: gem install--defaultが完全に廃止

実装困難のためとのことです。

🔗 3: 以下の非推奨化APIが廃止

以下は代替APIなしで廃止。

  • Gem::Specificationの以下のAPI
    • #has_rdoc
    • #has_rdoc=
    • #has_rdoc?
  • Gem::DependencyInstaller#find_gems_with_sources
  • Gem::Util.silent_system
  • Gem::Specificationの以下のAPI
    • #validate_metadata
    • #validate_dependencies
    • #validate_permissions
  • Gem::Specification#default_executable
  • Gem::Installer#unpack

以下は代替APIありで廃止

  • Gem::Platform.match
    今後はGem::Platform.match_spec?match_gem?を使うこと
  • Gem::BasicSpecification.default_specifications_dir
    今後はGem.default_specifications_dirを使うこと

関連記事

RubyGems 4.0.0とBundler 4.0.0がリリースされました

Ruby: default gemをgemコマンドで更新してもbundlerは元のdefault gemを使う


BPSアドベントカレンダー2025


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。