web-dev-qa-db-fra.com

Dois-je spécifier des versions exactes dans mon Gemfile?

J'ai remarqué que sur rubygems.org, beaucoup de gemmes vous suggèrent de les spécifier par version principale plutôt que par version exacte. Par exemple...

Le joyau haml-Rails ...

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

Cependant, sur la base des documents Bundler il me semblait qu'il valait mieux définir la version exacte comme celle-ci ...

gem "haml-Rails", "0.3.4"

Il y a donc votre joyau haml-Rails et toutes ses dépendances ne dériveront pas. Si vous extrayez le projet sur une autre machine quelques semaines plus tard et exécutez $ bundle install vous aurez exactement les mêmes versions de tout ce que vous avez spécifié.

J'ai vu des versions ponctuelles casser des trucs et je pensais qu'une partie de l'idée de Bundler était de "Bundle.lock "toutes vos versions de gemmes.

Mais sur rubygems.org, ils utilisent beaucoup "~>" alors peut-être que je manque quelque chose?

Toute clarification me serait très utile pour comprendre Bundler et la gestion des gemmes.

62
Ethan

C'est le but du fichier Gemfile.lock - exécuter bundle install avec un Gemfile.lock présent installe uniquement en utilisant les dépendances qui y sont répertoriées; il ne résout pas le Gemfile. Pour mettre à jour les dépendances/mettre à jour les versions de gem, vous devez alors faire explicitement un bundle update, qui mettra à jour votre fichier Gemfile.lock.

S'il n'y avait pas de Gemfile.lock, le déploiement de code en production serait un problème majeur car, comme vous le mentionnez, les dépendances et les versions de gemmes pourraient changer.

En bref, vous devriez généralement être en sécurité en utilisant l'opérateur de contrainte de version pessimiste (~>) comme le conseille rubygems.org. N'oubliez pas de relancer vos tests après avoir fait un bundle update pour vous assurer que rien ne casse.

Il y a un Nice article par Yehuda Katz qui a un peu plus d'informations sur Gemfile.lock.

55
Abe Voelker

Je dirais certainement utiliser les numéros de version exacts. Vous pouvez probablement toujours le verrouiller dans une version majeure, ou ne jamais spécifier de version, et ça va, mais si vous voulez vraiment ce niveau de contrôle fin et avoir 100% de confiance dans votre programme lorsqu'il est exécuté sur d'autres machines, utilisez les numéros de version exacts.

Je me suis retrouvé dans des situations où le numéro de version exact n'a pas été spécifié et lorsque moi ou quelqu'un d'autre a fait un bundle install, le projet a échoué car il est passé à une version plus récente. Cela peut être particulièrement mauvais lors du déploiement en production.

Bundler ne verrouille les spécifications de votre gem, mais si vous lui dites d'utiliser simplement une version majeure, il verrouille cela. Donc, il sait juste "Oh, la version est verrouillée à> 0.1" ou autre chose, mais pas "Oh, la version est verrouillée spécifiquement à 0.1.2.3".

6
MrDanA

TL; DR

Oui, utilisez verrouillage pessimiste (~>) et spécifiez un version sémantique jusqu'au patch (Major.minor.patch) sur toutes vos gemmes!

Discussion

Je suis surpris par le manque de clarté sur cette question, même des "experts de l'industrie" m'ont dit l'autre jour que Gemfile.lock est là pour maintenir les versions de gemmes. Faux!

Vous souhaitez organiser votre Gemfile de manière à pouvoir exécuter bundle update à tout moment sans risquer de tout casser. Pour y parvenir:

  1. Spécifiez une version au niveau du patch pour toutes vos gemmes avec un verrouillage pessimiste. Cela permettra à bundle update pour vous apporter des correctifs, mais sans interrompre les modifications.

  2. Spécifiez un ref pour les gemmes de git

Le seul inconvénient de cette configuration est que lorsqu'une nouvelle version mineure/majeure pour une gemme sort, vous devez augmenter la version manuellement.

Scénario d'avertissement

Considérez ce qui se passe si vous ne verrouillez pas vos gemmes.
Vous avez déverrouillé un gem "Rails" dans votre gemfile et la version dans Gemfile.lock est 4.1.16. Vous codez le long et à un moment donné vous faites un bundle update. Votre version Rails passe à 5.2.0 (à condition qu'un autre joyau ne l'empêche pas) et tout se casse.
Rendez-vous service et ne le permettez à aucun bijou!

Un exemple de 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

Une concession
.
Cela permettra à la version gem d'augmenter dans la version principale spécifiée, mais jamais dans la suivante.

gem "puma", "~> 3.12"
4
Epigene