Es war Weihnachtszeit, und die Versionen sprangen: Nicht nur hat Ruby selbst es auf die Version 4.0 geschafft (was allemal einen eigenen Blogbeitrag wert ist), auch eines der Workhorses im Ruby-Ökosystem trägt seit kurzem eine neue major version. Bundler hatte bereits im Sommer das last release before Bundler 4 angekündigt, und Anfang Dezember war es dann soweit. Auf die Version 2.7 folgte direkt 4.0, womit sich Bundler an die Versionsnummern von RubyGems angleicht. Inhaltlich will das Team hinter Bundler in der neuen major version “bisher unveröffentlichte bedeutende Änderungen, die seit einer Dekade anstanden” konsolidieren.
.bundle pro Projekt
Standardmäßig installiert Bundler die Gems aus dem Gemfile nun in ein Verzeichnis .bundle im root des Projekts. Damit sollen die Abhängigkeiten eines Projekts besser isoliert werden, indem nicht mehr alle Gems aller Projekte in das Verzeichnis der Ruby-Version installiert werden. In der Praxis hat sich aber gezeigt, dass der neue Standard nicht immer angewendet wird, etwa wenn parallel noch andere Tools wie ein Versionsmanager (rbenv, rmv etc.) ins Spiel kommen. Dann kann es notwendig sein, den path ausdrücklich zu setzen:
bundle config set --local path .bundle
Man kann aber auch festlegen, dass man das alte Verhalten gerne beibehalten möchte:
bundle config set --local path.system true
Um zu vermeiden, dass dasselbe Gem für mehrere Projekte mehrfach heruntergeladen oder eine Erweiterung mehrfach kompiliert wird, verwendet Bundler einen globalen Cache. Der lässt sich bei Bedarf ebenfalls abschalten:
bundle config set --local global_gem_cache false
Außerdem räumt Bundler standardmäßig auf und entfernt nicht (mehr) verwendete Gems aus .bundle, wenn das Bundle installiert wird. Möchte man dieses neue Verhalten abschalten, geht das mit
bundle config set --local clean false
Nicht mehr übergreifend
Einige Kommandozeilen-Flags von bundle install können bisher über mehrere Aufrufe hinweg ihre Wirkung entfalten. Beispielsweise verhindert bundle install --frozen Veränderungen an Gemfile.lock ab dem folgenden Aufruf. Versucht man es trotzdem, schlägt bundle mit einem non-zero response code fehl. Mit bundle install --shebang jruby kann man festlegen, dass Skripte mit binstubs mit dem angegebenen Ruby (hier JRuby) gestartet werden sollen, auch in der Zukunft.
Dieses Verhalten hat nach Ansicht des Bundler-Teams häufig zu Verwirrung geführt. Deshalb sind diese Optionen nun deprecated und sollen in einer zukünftigen Version entfernt werden. Die Funktionalität bleibt dabei erhalten und ist nun über bundle config erreichbar. Entsprechend kann man, was bisher zum Beispiel bundle install --without development:test getan hat, mit bundle config set --local without development test erreichen.
Diese Änderung betrifft die folgenden Flags:
--clean--deployment--frozen--no-prune--path--shebang--system--without--with
Checksummen
Vom nächsten neuen Feature möchte man idealerweise nie etwas bemerken: Schon seit einiger Zeit kann Bundler für jedes installierte Gem eine Checksumme in Gemfile.lock verzeichnen. Soll dann bei bundle install mit diesem Lockfile ein Gem installiert werden, das zu einer anderen Checksumme als der hinterlegten führt, schlägt Bundler Alarm.
Damit sollen Supply Chain-Angriffe abgefangen werden. Denn wenn versucht wird, eine andere Fassung eines Gems einzuschleusen als die, für die die Checksumme ermittelt wurde, fällt das dank dieser Funktion auf. Implementiert ist diese Absicherung schon länger, seit Bundler 2.6 kann man sie auf Wunsch dazuschalten, ab Bundler 4 ist sie standardmäßig aktiviert.
Eindeutig woher
In der neuen Version akzeptiert Bundler keine nicht eindeutigen Quellen für Gems. Versucht man etwas wie
source "https://main.source.tld"
source "https://another.source.tld"
gem "gem1"
gem "gem2"
ist nicht klar, aus welcher der beiden definierten Quellen jedes der beiden Gems geholt werden soll. Dieses Gemfile wird Bundler also nicht akzeptieren. Man muss entsprechend festlegen, was woher genau kommen soll, beispielsweise in Form von
source "https://main.source.tld"
gem "gem1"
source "https://another.source.tld" do
gem "gem2"
end
Globale path oder git-Quellen werden ebenfalls nicht mehr akzeptiert. Nun muss sie pro Gem oder als Block angeben, also in der Art
gem "gem1", path: "/path/to/the/gems"
gem "gem2", git: "https://the.repository.tld"
path "/path/to/the/gems" do
gem "gem1"
end
git "https://the.repository.tld" do
gem "gem2"
end
Neben diesen “großen” Neuerungen bringt Bundler 4 noch eine ganze Reihe weiterer, im Vergleich “kleinere” Änderungen. Eine Übersicht gibt es in der Dokumentation.