RubyGems/Bundler 4.0 最速解説 – ANDPAD Tech Blog

こんにちは、hsbt です。

相変わらず原神やゼンレスゾーンゼロをプレイしているのですが、Yotei をひと段落したあとにアサシンクリードシャドウズをプレイしてみたら、面白さ再発見という感じで楽しくプレイしています。

今回は、私がメンテナとして開発をしている RubyGems と Bundler のメジャーアップデートである 4.0.0 の重要な変更点と備えについて解説します。特に Bundler 4の変更は、セキュリティの強化 と、長年の混乱の元となっていた暗黙的な挙動の明確化 に焦点を当てています。長年の利用を通じて慣れ親しんだ動作のいくつかがBundler 4でデフォルトから変更されます。

私が書いた上記の2つのエントリにフルバージョンが存在しますが、変更点は大量にあるため、本エントリでは主にユーザーが知るべき振る舞いの変更についてのみ紹介し、メソッドの削除のようなAPIの変更や、新機能の追加などは別の機会に取っておこうと思います。

RubyGems 4 の変更点

RubyGems 4では、いくつかのコマンドラインインターフェース(CLI)の動作が変更されました。

gem query コマンドの削除

gem query コマンドが削除されました。代わりのコマンドとして gem search または gem list を使用してください。私は deprecate フラグがあるコード全てを把握して、実際に gem query コマンドを削除してから、こんなコマンドがあったんだ…というのを知りました。

gem install から --default オプションの削除

gem install --default 機能が完全に削除されました。この --default オプションは、私が Ruby で推進している default gem っぽく gem をインストールする、というオプションでしたが、RubyGemsユーザーにとって混乱を招き、インストールの破損を引き起こす原因となっていました。

例えば、「default gems である openssl の新しいバージョンをインストールするために gem install --default openssl を実行する」という思い込みがユーザーの中でしばしば発生していました。これは良くない CLI やオプションがもたらす悪い例です。

このオプションは何故かライブラリファイルを適切にコピーせずに実行可能ファイルのみを生成するという部分的な実装だったため、結果としてユーザーにとって実際の利益のない複雑な環境を生み出していました。これらの状況を改善するために、完全に空振りするオプションとして機能を変更し、実質削除という形にしました。

Bundler 4への準備とシミュレーション

続いて Bundler の変更点の解説です。まず最初に紹介したいのがシミュレートモードです。

Bundler 4のリリースに備えるため、現在の Bundler 2.7 を Bundler 4とほぼ同じように動作するように簡単に設定できます。 この「Bundler 4 モード」を有効にするには、以下のいずれかの設定を行います。

  1. 環境変数 BUNDLE_SIMULATE_VERSION を 4 に設定する。
  2. bundle config set –global simulate_version 4 を使用してグローバルに設定する。
  3. bundle config set –local simulate_version 4 を使用してローカルに設定する。

これにより、Bundler 4で導入された動作の変更の大半を、Bundler のバージョンを上げる前に既存のプロジェクトでテストできます。

注目すべきデフォルトの変更点

Bundler 4で特に注意が必要な、デフォルトの動作が切り替わる変更点について解説します。

bundle install の実行に bundle 単体での実行が非推奨になった

Bundler 4では、単に bundle を実行した場合、警告が表示されます。bundle というオプションなしでコマンドを実行した際に突然 install が実行されることは、新規ユーザーにとって使いやすい挙動ではないと判断しました。互換性の維持のために install が実行され、Gemfile が存在しないディレクトリでは cli_help が実行されコマンド一覧が表示されます。

長年利用しているユーザーで、引き続き bundle がデフォルトで bundle install になる動作を維持したい場合は、bundle config set default_cli_command install_or_cli_help --global の設定を行う必要があります。一方、すぐに新しい動作(bundle がヘルプのみを表示)を採用したい場合は、bundle config set default_cli_command cli_help --global で設定可能です。このいずれかの設定を行うことで bundle 単体で実行した際の警告は非表示となります。

また、CI で用いるようなスクリプトやドキュメントでは、何が実行されているかを明確にするために、bundle ではなく bundle install を明示的に使用することを推奨します。

bundle install に渡されたフラグが記憶されなくなった

呼び出し間で記憶されることに依存していた bundle install のCLIオプションが削除されます。具体的には、--clean--deployment--frozen--no-prune--path--shebang--system--without、および --with が対象です。

CLIオプションが暗黙的に記憶される動作は、初心者だけでなく経験豊富なユーザーにとっても、歴史的に混乱やバグ報告の原因となってきました。CLIツールは、明示的に設定されない限り、全く同じ呼び出しに対して異なる動作をするべきではない、という設計思想に基づいています。

従来の bundle install --without development:test のように実行し、設定を永続化させるワークフローでは、Bundler 4の設定は毎回消去されます。代わりに、環境変数、アプリケーション設定、またはマシン設定を介して、bundle config set --local without development test などのように明示的に設定を行う必要 があります。

Gemfileでの厳格なソースの固定化がデフォルトで強制されます

Bundler 4では、すべての依存関係のソースが 明確に定義されるようになり、そうでない場合はBundlerは実行を拒否します。この変更に伴い、以下の定義方法がサポートされなくなります。

  • 複数のグローバルなGemfileソースはサポートされなくなります。依存関係ごとにソースを定義するか、ブロック形式を使用して定義する必要があります。
source "https://main_source"
source "https://another_source"

gem "dependency1"
gem "dependency2"

このような Gemfile は以下のように書く必要があります。

source "https://main_source"

gem "dependency1"

source "https://another_source" do
  gem "dependency2"
end
  • グローバルな path および git ソースはサポートされなくなります。これらは、gem メソッドにオプションとして指定するか、path や git をブロック形式で使用して、対象のgemを明示する必要があります。
path "/my/path/with/gems"
git "https://my_git_repo_with_gems"

gem "dependency1"
gem "dependency2"

このような Gemfile は以下のように書くか

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

block を用いて以下のように書く必要があります。

path "/my/path/with/gems" do
  
  
  
end

git "https://my_git_repo_with_gems" do
  
  
  
end

チェックサムによるセキュリティ強化がデフォルトになります

Bundler 4 では 新しいロックファイルを生成する場合に以下のようにチェックサムがデフォルトで含まれます。

  ...
  rake (~> 13.0)
  sass (~> 3.7)

CHECKSUMS
  addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057
  base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
  bigdecimal (3.3.1) sha256=eaa01e228be54c4f9f53bf3cc34fe3d5e845c31963e7fcc5bedb05a4e7d52218
  ...

このチェックサムにより、他のユーザーの環境や本番サーバーなどで bundle install を実行した際に異なるチェックサムが発見された場合は、異常とみなし Bundler は処理を中断します。既存のロックファイルには標準では何もしないため、チェックサムを追加するには、bundle lock --add-checksums を明示的に実行する必要があります。

昨今の supply chain attack に代表されるようなサーバーの偽装によるパッケージ差し替えなどに対する対策のために全てのユーザーに有効にしてもらいたい機能です。特に rubygems.org 以外の private server などを利用している場合は、Bundler 2.7 であってもいますぐに bundle lock --add-checksums を実行してチェックサムを追加することを強くお勧めします。

一部、ネットワークに接続されていない際にチェックサムが作成されない、Bundler.setup 実行時にチェックサムが作成されないなど、いくつか不具合と思われる挙動の報告があるため、まだ完全な機能とは言えません。おかしいと思った挙動があれば rubygems リポジトリ への報告をお願いします。

CLIコマンドの置き換えと削除

コマンドやオプションは以下が削除されます。

  • bundle viz コマンドの削除とプラグイン化: 外部依存関係 (graphviz パッケージなど) を必要とする唯一のコマンドであった bundle viz を削除し、bundle graph という名前の公式メンテナンスプラグイン (bundler-graph) として提供します。
  • --binstubs フラグの削除: bundle install コマンドは --binstubs フラグを受け付けなくなり、このオプションは bundle binstubs コマンドに置き換えられました。今後は、binstubs は 個別 に作成し、バージョン管理にチェックインする必要があります。全ての gem の binstub を作成したい場合は、bundle binstubs --all を使ってください。
  • bundle inject の置き換え: bundle inject コマンドは削除されました。bundle add を使ってください。
  • デプロイメントヘルパーの削除: vlad および capistrano 用のデプロイメントヘルパーを削除しました。capistrano-bundler を明示的に指定して使ってください。

まとめ

Bundler 4は、セキュリティの強化(チェックサムのデフォルト化) と、長年の混乱の元となっていた暗黙的な挙動(bundle install のフラグ保存の無効化やグローバルソースの定義)の明確化に焦点を当てたメジャーアップデートとなります。

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

そのため、12/25 の Ruby 4.0 までに発見し、修正できた不具合は 4.0.1 や 4.0.2 としてリリースした上で Ruby 4.0 に同梱したいと思っています。もし、使ってみて「何かがおかしい」と感じた際は rubygems のリポジトリ まで報告していただけると幸いです。




元の記事を確認する

関連記事