Sollte ich in meiner Gemfile genaue Versionen angeben?

75

Ich habe festgestellt, dass auf rubygems.org viele Edelsteine ​​vorschlagen, dass Sie sie eher nach Hauptversion als nach exakter Version angeben. Zum Beispiel...

Das Haml-Rails-Juwel ...

gem "haml-rails", "~> 0.3.4"  # "$ bundle install" will acquire the 
                              # latest version before 1.0.

Basierend auf den Bundler-Dokumenten klang es für mich jedoch so, als wäre es besser, die genaue Version wie diese festzunageln ...

gem "haml-rails", "0.3.4"

Es gibt also Ihren Haml-Rails-Edelstein und all seine Abhängigkeiten werden nicht vorwärts driften. Wenn Sie das Projekt einige Wochen später auf einem anderen Computer auschecken und ausführen $ bundle install, haben Sie genau die gleichen Versionen von allem, was Sie angegeben haben.

Ich habe gesehen, wie Punktveröffentlichungen Sachen kaputt machten, und ich dachte, ein Teil der ganzen Idee von Bundler war es, Bundle.lockalle Ihre Edelsteinversionen zu " " ".

Aber auf rubygems.org verwenden sie häufig "~>", also fehlt mir vielleicht etwas?

Jede Klarstellung wäre für mich sehr hilfreich, um das Bundler- und Edelsteinmanagement zu verstehen.

Ethan
quelle
Ich würde. Je weniger Überraschungen, desto besser. Es dauert nur ein Mal, dass eine Abhängigkeit aktualisiert wird, ohne dass Sie dies absichtlich tun, um Sie stunden- oder tagelang in ein Kaninchenloch zu schicken, damit Sie diese Lektion lernen. Drittanbieter- und Open-Source-Bibliotheken können nicht darauf vertrauen, dass sie die semantische Versionierung strikt befolgen (selbst meine eigenen Bibliotheken). Das Risiko nicht wert.
Joshua Pinter

Antworten:

59

Dies ist der Zweck der Datei Gemfile.lock. Die Ausführung bundle installmit einer vorhandenen Datei Gemfile.lock erfolgt nur unter Verwendung der dort aufgeführten Abhängigkeiten. Das Gemfile wird nicht erneut aufgelöst. Um Abhängigkeiten zu aktualisieren / Gem-Versionen zu aktualisieren, müssen Sie explizit a bundle updateausführen, wodurch Ihre Gemfile.lock-Datei aktualisiert wird.

Wenn es kein Gemfile.lock gäbe, wäre die Bereitstellung von Code für die Produktion ein großes Problem, da sich, wie Sie bereits erwähnt haben, die Abhängigkeiten und Gem-Versionen ändern könnten.

Kurz gesagt, Sie sollten im Allgemeinen sicher sein, wenn Sie den pessimistischen Versionsbeschränkungsoperator ( ~>) verwenden, wie von rubygems.org empfohlen. Stellen Sie einfach sicher, dass Sie Ihre Tests nach dem Ausführen erneut ausführen bundle update, um sicherzustellen, dass nichts kaputt geht.

Es gibt einen schönen Artikel von Yehuda Katz, der ein bisschen mehr Infos zu Gemfile.lock enthält.

Abe Voelker
quelle
1
OK, Edelsteine ​​bleiben also bei ihren in Gemfile.lock aufgezeichneten Versionen. Was ist der Zweck des Hinzufügens von "~>"? Wie ist das vorteilhaft?
Ethan
2
@ethan RubyGems verfügt über ein Dokument , das dies erklärt (siehe Abschnitt "Verhinderung von Versionskatastrophen"). Das Wesentliche dabei ist, dass nur die letzte Ganzzahl in der Versionsnummer erhöht werden kann (z. B. '~> 1.0.5' ermöglicht die Aktualisierung auf Version 1.0.9999, jedoch niemals auf 1.1.x). Der Mechanismus dient dazu, die Aktualisierung von Edelsteinen zuzulassen, ohne jedoch Inkompatibilitäten einzuführen, die zu Problemen führen können (es wird davon ausgegangen, dass Edelsteine ​​der Richtlinie "Rationale Versionierung" folgen, die Konturen verknüpft).
Abe Voelker
3
Ich denke , dass der Kern von dem, was Sie geschrieben haben , ist , dass eine pessimistische Version Einschränkungen in jemandes halten sollte Gemfile so eine kann leicht auf die neueste Version aktualisieren , die Übereinstimmungen sowohl die Haupt- und Nebenversion angegeben. Die Datei Gemfile.lock sollte jedoch auch verwendet und im Quellcode gespeichert werden, damit Upgrades explizit durchgeführt werden müssen, um Auswirkungen auf alle Umgebungen zu haben, in denen Ihr Code bereitgestellt wird.
Kenny Evitt
7

TL; DR

Ja, verwenden Sie pessimistisches Sperren ( ~>) und geben Sie eine semantische Version bis zum Patch ( Major.minor.patch) für alle Ihre Edelsteine ​​an!

Diskussion

Ich bin überrascht über die Unklarheit in dieser Frage, selbst "Branchenexperten" sagten mir neulich, dass Gemfile.lockes Edelsteinversionen gibt. Falsch!

Sie möchten Ihre Gemfileso organisieren , dass Sie jederzeit laufen bundle updatekönnen, ohne das Risiko einzugehen, alles zu beschädigen. Um dies zu erreichen:

  1. Geben Sie eine Patch-Level-Version für alle Ihre Edelsteine ​​mit pessimistischer Sperre an. Auf diese Weise können bundle updateSie Korrekturen vornehmen, aber keine Änderungen vornehmen.

  2. Geben Sie a reffür Edelsteine ​​von git an

Der einzige Nachteil dieses Setups ist, dass Sie die Version manuell hochfahren müssen, wenn eine süße neue Moll- / Dur-Version für einen Edelstein herauskommt.

Warnszenario

Überlegen Sie, was passiert, wenn Sie Ihre Edelsteine ​​nicht sperren.
Sie haben eine freigeschaltete gem "rails"in Ihrer Gemfile und die Version in Gemfile.lockist 4.1.16. Sie codieren mit und irgendwann tun Sie a bundle update. Jetzt springt Ihre Rails-Version zu 5.2.0(vorausgesetzt, ein anderes Juwel verhindert dies nicht) und alles bricht.
Tun Sie sich selbst einen Gefallen und lassen Sie dies für keinen Edelstein zu!

Ein Beispiel Gemfile

# lock that bundler
if (version = Gem::Version.new(Bundler::VERSION)) < Gem::Version.new('1.16.3')
  abort "Bundler version >= 1.16.3 is required. You are running #{version}"
end

source "http://rubygems.org"

# specify explicit ref for git repos
gem "entity_validator",
  git: "https://github.com/plataformatec/devise",
  ref: "acc45c5a44c45b252ccba65fd169a45af73ff369" # "2018-08-02"

# consider hard-lock on gems you do not want to change one bit
gem "rails", "5.1.5"

# pessimistic lock on your common gems
gem "newrelic_rpm", "~> 4.8.0"
gem "puma", "~> 3.12.0"

group :test do
  gem "simplecov", "~> 0.16.1", require: false
end

Eine Konzession
Wenn Sie sicher sind, dass Ihre Tests Fehler erkennen, die durch Änderungen der Edelsteinversion verursacht wurden, können Sie versuchen, Edelsteine ​​mit pessimistischer Sperre in der Nebenversion und nicht im Patch zu verwenden.
Dadurch kann die Edelsteinversion innerhalb der angegebenen Hauptversion erhöht werden, jedoch niemals in die nächste.

gem "puma", "~> 3.12"
Epigen
quelle
1
Dieses Wort pessimistisch ist hier verwirrend (ich verstehe, es ist nur Semantik, aber immer noch). Wenn Sie eine Version mit = festgelegt haben, ist das pessimistisch! Mit ~> können Sie jedoch tatsächlich auf die neueste Nebenversion aktualisieren.
Joel_Blum
2
Du hast geschrieben You want to organize your Gemfile in such a manner that you can run bundle update any time without risking breaking everything. Nein, das ist nicht das Ziel. Es hört sich so an, als ob Sie den Unterschied zwischen bundle updateund möglicherweise nicht verstehen bundle install. update aktualisiert die Gemfile.lockund ändert die von Ihnen verwendeten Versionen. Sie möchten jederzeit laufen bundle installkönnen, ohne das Risiko einzugehen, alles zu beschädigen. So wie es ist, zwingen Sie die, das Gemfilezu tun, was das Gemfile.locktun soll.
Bilderstürmer
2
Und die „Branchenexperten“ korrekt sind: Gemfile.lock nicht in der Tat gem Versionen beibehalten. Bis Sie (natürlich) beschließen, es mit zu überschreibenbundle update (was im Grunde wie gesagt ist bundle overwrite_my_locked_gem_versions).
Bilderstürmer
@iconoclast Wir sind uns nicht einig über die Bedeutung des Wortes "pflegen" dann. Für mich bedeutet dies ein begrenztes Gefühl der Veränderung, um mit der Zeit zu gehen, nicht vollständige Unveränderlichkeit.
Epigene
1
So wie ich es sehe (weshalb ich die Antwort überhaupt geschrieben habe), gibt es ein Missverständnis, dass Gemfile.lockEntwickler , nur weil es eine Datei mit allen genauen Versionen gibt, keine Gem-Versionen angeben müssen Gemfile(die Idee, die sperrt) 'pflegt' Versionen). Das ist falsch. Entwickler 'pflegen' Versionen, indem sie sie angeben Gemfileund gelegentlich bundle updateausführen.
Epigene
6

Ich würde definitiv sagen, verwenden Sie die genauen Versionsnummern. Sie können es wahrscheinlich immer nur auf eine Hauptversion beschränken oder niemals eine Version angeben und in Ordnung sein, aber wenn Sie wirklich diese fein abgestimmte Kontrolle wollen und 100% Vertrauen in Ihr Programm haben möchten, wenn es auf anderen Computern ausgeführt wird, Verwenden Sie die genauen Versionsnummern.

Ich war in Situationen, in denen die genaue Versionsnummer nicht angegeben wurde, und als ich oder jemand anderes eine tat bundle install, brach das Projekt, weil es auf eine neuere Version ging. Dies kann bei der Bereitstellung in der Produktion besonders schlimm sein.

Bündler tut Schloss in Ihrer gem Spezifikation, aber wenn Sie es doch sagen , eine Major - Release nur verwenden, es sperrt dann , dass in. So einfach ist weiß „Oh die Version in bei> 0,1 ist gesperrt“ oder was auch immer, aber nicht „Oh Die Version ist speziell bei 0.1.2.3 "gesperrt.

MrDanA
quelle
10
Wenn Gemfile.lockvorhanden, weiß Bundler tatsächlich, welche spezifische Version installiert werden muss (weshalb Gemfile.locksie neben dem Repo gespeichert werden sollte Gemfile).
Mipadi
3
Ein tun , bundle update <gem>obwohl kann am Ende zu aktualisieren Weg mehr , als Sie gedacht, auch wenn die Gemfile.lockvorhanden ist, und dass eine gefährliche und schwierige Situation sein kann.
MrDanA
1
Ich stimme der Empfehlung von RubyGems selbst zu diesem Thema zu: Verwenden Sie einfach die pessimistische Einschränkung (~>). Dies ermutigt die gesamte Community, sich auf semantische Versionierung zu konzentrieren, was eine gute Sache ist. Zwischen dieser und den integrierten Stabilitätsfunktionen von Gemfile.lock sollten Ihre Basen mehr als abgedeckt sein.
user456584
1
@solidcell Ich glaube nicht, dass ich jedes Mal, wenn ich ein Juwel aktualisiere, die Quelle eingeben muss. Ich bevorzuge es, eine möglichst genaue Version zu verwenden, aber wie bereits erwähnt, können Sie die meiste Zeit oft nur die Einschränkung ~> verwenden. Allerdings hatte ich schon einmal eine neue, fehlerhafte Version von Edelsteinen.
MrDanA
1
Sie müssen (und sollten) keine genauen Versionen in Ihrem verwenden Gemfile. Dies ist der Zweck von Gemfile.lock. Wenn Sie sich Gemfile.lockzur Quellcodeverwaltung verpflichten, bundle installerhält jemand, der dies ausführt und tut , genau die gleichen Versionen von Edelsteinen wie Sie. Das Festlegen einer genauen Version in den verhindert Gemfiledies, bundle update gem_you_want_to_updatewährend Sie mit pessimistischen Versionen ( ~>) oder gar keiner Version bundle update gem_you_want_to_updatedie neueste (kleinere) Version ausführen und
abrufen können