Bundler: How to check if Gems are up to date - ruby

Using Bundler, is there a way to check if there are newer gems available than the versions specified in the Gemfile? In other words, is there a way to check if my gems are up to date without actually updating?

List installed gems with newer versions available
$ bundle outdated [GEM] [--local] [--pre] [--source]
Options:
--local: Do not attempt to fetch gems remotely and use the gem cache instead
--pre: Check for newer pre-release gems
--source: Check against a specific source
Source: http://bundler.io/v1.3/bundle_outdated.html

If you mean just see if an update is necessary (w/o actually updating), you might have to specify in your Gemfile to use some repo source for comparison, like:
gem "rails", :git => "git://github.com/rails/rails.git"
or specify a specific version to compare against with :version => ...
Then run bundle check and it'll list all gems that are out of date.
EDIT - I guess it depends on what's meant by up to date.

Related

Ruby Bundler - Multiple Ruby versions in the same gemfile

I am using rbenv and bundler on macos.
I need to maintain multiple versions of Ruby for my application. Specifically 2.2.4 and 2.5.5. Different users will have different versions.
Currently I am only working with 2.2.4 so I do the following. My gemfile looks like this
source "https://rubygems.org"
ruby '2.2.4'
gem "net-ssh", "4.1.0"
gem "net-scp", "2.0.0"
.....
To install I run bundle install and then to deploy with my application I run
bundle install --deployment --path src/mct-tools/ext/gems
This generates a folder src/mct-tools/ext/gems/ruby/2.2.0 in my application that I then distribute.
Now I would like to add ruby 2.5.5 with updated gems so I was wondering whether it would be acceptable to have a gemfile looking like this one
source "https://rubygems.org"
ruby '2.2.4'
gem "net-ssh", "4.1.0"
gem "net-scp", "2.0.0"
.....
ruby '2.5.5'
gem "net-ssh", "6.1.0"
gem "net-scp", "3.0.0"
.....
so that when I deploy with bundle install --deployment --path src/mct-tools/ext/gems the two versions are added to the gems folder.
Is this the correct approach? An alternative would be to specify two different gemfiles for each version and then switch between them.
Gemfiles Declare Dependencies
A Gemfile declares a dependency on a Ruby version, with or without semantic versioning constraints. It is not meant to control multiple build targets for your application. It simply enforces that the Ruby version available to your app/gem is whatever you've defined. For example:
# Will fail if run with a different RUBY_VERSION.
ruby '2.2.4'
# Allows RUBY_VERSION >= 2.2.4, but <= 2.3.
ruby '~> 2.2.4'
# Allows either Ruby 2.2.4+ or 2.5.5+, with
# a minimum (but no maximum) patch version.
ruby '~> 2.2.4', '~> 2.5.5'
However, it won't install a given Ruby, nor do anything other than raise an error and a non-zero exit status when running bundler install. You need to take a different approach to test multiple targets.
Changing Build Targets with Continuous Integration (CI) Tools
If you're using an external CI like TravisCI, you can create a build matrix that targets multiple Ruby versions to test against. Whether you remove the Ruby version constraint altogether, or specify a supported range, is up to you. Leveraging your CI tool to build against the versions of Ruby you plan to support is really the best approach, though, whether or not you constrain your Ruby runtime in a Gemfile.
For example, you might use a matrix in your travis.yml like so:
language: ruby
rvm:
- 2.2.4
- 2.5.5
Switching Gemfiles
If you insist on doing it the way you're doing it, with a singular Ruby version allowed in your Gemfile, then you might consider having two separate gemfiles with different names in your source tree, such as Gemfile-2.2.4 and Gemfile-2.5.5. You can then specify which Gemfile to use with Bundler's --gemfile flag , or by symlinking a custom Gemfile to the canonical Gemfile for your project.
Here are some examples to consider:
# Resolve against a specific Gemfile with
# hard-coded Ruby version.
$ ls Gemfile*
Gemfile-2.2.4 Gemfile-2.5.5
$ bundle install --gemfile="Gemfile-2.2.4"
# Resolve against whatever custom file is
# symlinked to your ./Gemfile.
$ ln -sf Gemfile{-2.5.5,}
$ ls -F Gemfile*
Gemfile# Gemfile-2.2.4 Gemfile-2.5.5
$ bundle install
Both approaches work, but the former is more flexible at the cost of needing to specify your chosen Gemfile each time, while the latter can help when you have a development/testing workflow that doesn't support Bundler's --gemfile flag.
Changing Rubies with Ruby Managers
If you have multiple Ruby versions in development, best practice is to use a version manager such as rvm, rbenv, or chruby. You can use your version manager to change rubies back and forth manually as needed.
You might also check whether your version manager supports auto-switching on .ruby-version or other configuration files. You'd still have to update that file each time you want to build or test against a different Ruby, but you wouldn't have to keep changing your Gemfile contents, re-pointing the Gemfile symlink, or updating a flag on each call to Bundler.
Whether or not any given approach is better than others will depend on your workflow. No technical solution will fit all circumstances, so your mileage may legitimately vary.

Force Bundler to Use my Gem Source

I am running my own gem server with geminabox. This gem server hosts private forks of several public gems, as well as my own gems. I have a Gemfile with the sources listed like so:
source https://rubygems.org
source http://my/gem/server
When Bundler installs a bundle, I would like it to always use the version available on my gem server if it exists and satisfies the version requirements. I can't get this to work. Instead, bundler seems to pull from rubygems unless it can't find a gem with the same name there. This may be because the versions on rubygems are higher. However, bundler's documentation makes no mention of version numbers. This is how it describes source priority:
SOURCE PRIORITY
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
The source explicitly attached to the gem (using :path or :git)
For implicit gems (dependencies of explicit gems), any git or path repository otherwise declared. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from rubygems.org
The sources specified via source, searching each source in your Gemfile from last added to first added.
Also, I know it is possible to explicitly list a source for each gem in the Gemfile. I would prefer to avoid this, since I have many of my own gems, and it is annoying to make explicit entries in the Gemfile for dependencies of dependencies (which you have to do, because bundler will not read the Gemfile of dependencies).
How can I achieve my goal?

why is gem still outdated after bundle update

I am working on a gem and it's on github.
When I include the gem in an application, do a capistrano deploy, and (on the server) run:
bundle outdated
I see:
* authengine (0.0.1 d8baa49 > 0.0.1 de43dfa)
which tells me that a more recent commit is available. Why doesn't the bundle update (part of capistrano deploy) pull the more recent version? There is no version constraint in the Gemfile of the host application, and anyway they have the same version number, just different commits.
Even if I log into the server and run
bundle update authengine
I get the same "outdated" result afterwards.
What am I missing here?
One thing I've found that can cause this is if other gems in the bundle make requirements on gems by version that are incompatible. Bundler tries to reconcile these by selecting versions of gems such that their requirements can all be satisfied. The result is that it quietly refuses to update gems.
The way to check this is to set an explicit version requirement in your Gemfile. Something like
gem "authengine", "> 0.0.2" #(you'll need to bump the version to make this work)
#or
gem "authengine", :ref => "d8baa49"
Then run
bundle update authengine
You should see something like (this is taken from my particular case):
Bundler could not find compatible versions for gem "json": In
Gemfile:
chef (> 10.8) ruby depends on
json (<= 1.6.1, >= 1.4.4) ruby
logical-construct (>= 0) ruby depends on
json (1.7.5)
So, in my case it's a problem with explicitly requiring a newer version of json.
The author, André Arko, stated in 2014 that:
The Bundler resolver is definitely a work in progress, and we adjust
the tradeoffs between specific versions and resolving quickly based on
user feedback.
Bundler has consistently not provided the newest possible version of
every gem for the entirety of its existence, and it does result in a
lot of tickets being opened. In most cases, it turns out to be the
result of Bundler having to pick between the newest version of one gem
or a different gem, and Bundler picks the gem the user doesn’t care
about having the newest version of. That’s why it’s so important to
make your Gemfile version requirements accurately reflect your actual
requirements.
I recognize that your assumption that Bundler would give you the
newest possible version seemed valid at the time, but the docs only
say that you will get a version that meets your requirements, not the
latest. Is there anywhere we could expand the docs to make it clearer
that the newest versions of everything simply isn’t feasible?
What is the output returned when you run bundle update authengine? Does it actually say it updated the gem? Or does it ignore the gem?
You can try using the --source parameter to specifically tell Bundler to use the git repository. That, or your
bundle update authengine --source https://github.com/mustardseeddatabase/authengine.git
Also, when unexpected things like this happen, I like to clean up my gemlist in general. It could be that you still have older versions of the gem laying around, not using in bundler.
So you could do:
gem list
gem check
gem cleanup
Or do a complete reinstall
gem uninstall authengine
bundle install

Bundler: always use latest revision of git branch in Gemfile

I have a Gemfile with a private git repo in the following format:
gem 'magic_beans', :git => "git#git.example.com:magic_beans.git', :branch => 'super_beans'
When I bundle install, the Gemfile.lock locks it to a specific SHA revision.
Can I get bundler to always check and use the latest SHA commit and/or update the Gemfile.lock? Notice that when I push updates to the super_beans branch I am not modifying the gem version.
Ideally, every time I run bundle it would check upstream git repo for a newer SHA revision of the branch.
This isn't how bundler works.
The point is to allow seamless versioning of dependencies.
(particularly so you know exactly what version of the code is deployed at any given time).
If want the latest version, you should just run.
bundle update magic_beans
This is exactly the same functionality as if you just say
gem "rails"
I'd suggest though, if you have a range of specific things you want to update
then add a custom binary (say an executable file named bundle_update)
#!/usr/bin/env bash
bundle install
bundle update magic_beans
Then just do a ./bundle_update when you want to update these things.
You can run bundle update to update all or specific gems to their latest available version, as stated in the docs.
Would that help?
After searching through the documents I finally found the magic way to do this:
bundle update magic_beans --source magic_beans
That is to update the magic_beans gem only, but not to touch other locked gems. The doc about this is: http://bundler.io/man/bundle-update.1.html
delete .gemlock is what worked for me :/

Installing a gem from Github with Bundler

I am trying to use the instructions here to install a pre-released version of a gem with bundler.
The "bundle install" output lists the gem as getting installed, but "gem list" fails to find it.
My Gemfile:
source :gemcutter
gem 'sinatra', '1.1.0', :git => 'http://github.com/sinatra/sinatra.git'
gem 'RedCloth', '4.2.3'
Here is a gist with the rest of my sample code.
Has anyone gotten this scenario to work?
NOTE: I am also using RVM (on OS X). bundle show does list the gem (and dependencies) as existing, but I am not able to properly resolve them.
Thanks.
I would look at the load paths, and further debug from there, example:
...(master) $ irb
irb(main):001:0> $LOAD_PATH.count
=> 8
irb(main):004:0> require 'bundler/setup'
=> true
irb(main):005:0> $LOAD_PATH.count
=> 112
irb(main):006:0>
Bundler configures the load path for you, this means not all the gems are included on your load path by default.
Additionally, from the bundler git help:
Because Rubygems lacks the ability to handle gems from git, any gems installed from a git repository will not show up in gem list. They will, however, be available after running Bundler.setup.
Best regards, hope this helps
ED
Bundler might have installed it locally to your app. This could vary wildly, depending on OS and whether you are using RVM.
What is the output of bundle show sinatra?
In my case, sinatra was installed here:
/home/marshall/.rvm/gems/ruby-1.8.7-p302#3846859/bundler/gems/sinatra-9cfa74a7f352
Sinatra doesn't show in the gems list, but the server launches correctly if I execute rackup.
Gems installed via bundler on Engine Yard go to a different folder to isolate them.
it's usually /data/APP_NAME/shared/bundled_gems
To be sure, check your .bundle/config file on your APP folder at Engine Yard
It looks like there is an issue using Shotgun and Bundler (git repositories only).
If I use rackup to start up my app, all is well. I am going to investigate a little more and then file a bug with one (or both) of the projects.

Resources