Bundler 4とRubyGems 4は、ユーザービリティ・メンテナンス性・セキュリティを改善するために、非互換な変更を含むさまざまな変更が行われているので、見逃さないために以下を読んでまとめてみました。
参考: Upgrading to RubyGems/Bundler 4 - RubyGems Blog
上の公式ドキュメントに記載されているのは4.0.0の変更だけとは限らず、以前の変更に関連する記述も含まれている点にご注意ください。
利便性のため、上のドキュメントの項目順を重要度の高そうな順に再編成し、可能な限り関連プルリク/コミットも記載しました。
なお、現在のBundlerはruby/rubygemsのリポジトリ内に統合されています↓(昔は別リポジトリでした)。
参考: rubygems/bundler at master · ruby/rubygems
🔗 最初に: Bundler 4を移行前にシミュレートしよう
Bundler 2.7では、以下の3つの方法のいずれかでシミュレーションできます。これによりBundler 4への移行を予行演習できます。
BUNDLE_SIMULATE_VERSION環境変数に4を設定するbundle config set --global simulate_version 4を実行する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文ごとにpathやgit引数として指定することは引き続き可能です。
# 可能
gem "dependency1", path: "/my/path/with/gems"
gem "dependency2", git: "https://my_git_repo_with_gems"
または、sourceと同様にpathやgitをブロック形式で利用することも可能です。
# 可能
path "/my/path/with/gems" do
# gem "dependency1"
# ...
# gem "dependencyn"
end
git "https://my_git_repo_with_gems" do
# gem "dependency1"
# ...
# gem "dependencyn"
end
pathやgitで指定した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: 単体のbundleでbundle installを実行する振る舞いが非推奨化
従来および現在は、bundleを実行するとbundle installまたはヘルプを表示します。今後は明示的にbundle installを呼ぶことが推奨されます。
以下を実行すると現行の振る舞いを維持できます(現在のデフォルト)(#9136)。
bundle config set default_cli_command install_or_cli_help --global
以下を実行するとbundleでbundle 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プラグインとして利用可能になります。
参考: 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および依存する以下のAPIBundler.with_clean_envBundler.clean_systemBundler.clean_exec
従来は、yieldされるブロック内ではBundler関連の環境変数がBundler.clean_envによってすべて削除されていましたが、現在のbundlerプロセスの開始直前の環境が欲しい場合が多いことがわかったため、以下のAPIが新たに作成されました。
Bundler.with_original_envおよび依存する以下のAPIBundler.original_systemBundler.original_exec
しかし従来の振る舞いが欲しい場合のために、より明確なunbundled_envという名前のAPIが新たに導入されました。
Bundler.unbundled_envおよび依存する以下のAPIBundler.with_unbundled_envBundler.unbundled_systemBundler.unbundled_exec
🔗 8: Bundler.environmentが廃止(#8924)
今後はBundler.loadを使うことになります。
Bundler.environmentでインスタンス化されるBundler::Environmentクラスは、実はBundler::Runtimeと同じであることがわかりました。
そのため、Bundler::Environmentクラスは削除され、Bundler.environmentはBundler.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: vladとcapistrano用のデプロイメントヘルパーが削除(#8957)
vladはメンテされなくなってから長い- capistrano 3はcapistrano-bundler gemとしてBundlerに統合されているので、
vladよりこちらを使うべき
なお、引き続きcapistrano 2を使っている場合は、bundler 2のlib/bundler/deployment.rbファイルからcapistranoタスクを切り出してアプリに置いて使えるそうです。
🔗 RubyGems 4の注意点
🔗 1: gem queryコマンドが廃止
今後はgem searchかgem listを使うことになります。
🔗 2: gem installの--defaultが完全に廃止
実装困難のためとのことです。
🔗 3: 以下の非推奨化APIが廃止
以下は代替APIなしで廃止。
Gem::Specificationの以下のAPI#has_rdoc#has_rdoc=#has_rdoc?
Gem::DependencyInstallerの#find_gems_with_sourcesGem::Util.silent_systemGem::Specificationの以下のAPI#validate_metadata#validate_dependencies#validate_permissions
Gem::Specificationの#default_executableGem::Installerの#unpack
以下は代替APIありで廃止
Gem::Platform.match
今後はGem::Platform.match_spec?かmatch_gem?を使うことGem::BasicSpecification.default_specifications_dir
今後はGem.default_specifications_dirを使うこと

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