Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Way to bundle update conservatively a single gem #2016

Closed
marcandre opened this issue Jul 5, 2012 · 33 comments
Closed

Way to bundle update conservatively a single gem #2016

marcandre opened this issue Jul 5, 2012 · 33 comments

Comments

@marcandre
Copy link

If some_gem is already installed, and I want the latest version of it, bundle install will not do anything and bundle update some_gem will update some_gem (yay!) but also any of its dependency (not what I want). I'd rather not update my rails version just because I'm also updating a minor gem that has rails as a dependency.

Only current way is to go in the Gemfile and manually state that we want a version >= current_version, and now bundle install will update it.

It would be awesome to be able to update some_gem and be conservative for the rest, without having to state an actual version in the Gemfile.

BTW, I don't understand the reason behind the decision that bundle update foo is not conservative; this won't happen when I bundle install and have added some_gem line in my Gemfile, or increased the minimum version for that gem. In any case, a --conservative or something would be greatly appreciated.

This is a repost of #2011

@indirect
Copy link
Member

indirect commented Jul 5, 2012

Rails (the gem) does not conform to Semantic Versioning, and therefore the best practice is to explicitly state which version of Rails your application is compatible with in your Gemfile. Bundler will honor explicit versions set in the Gemfile, even while you run bundle update some_gem.

In the case of gems other than Rails, we strongly recommend that you update a gem's dependencies when you update that gem, which is why the update command functions the way it does. If you need to update just one gem to a specific version, that is when you should edit your Gemfile and then run bundle install (which will re-resolve your Gemfile in the most conservative mode).

Thanks for the suggestion, and I hope that the explanation of locking Rails via a version in the Gemfile addresses your issue.

@indirect indirect closed this as completed Jul 5, 2012
@likethesky
Copy link

+1 for "bundle update [some gem] [--conservative]" (where '--conservative' can only be added when a gem name is specified on the bundle update command).

I think this is a reasonable feature request by @marcandre This would simply be a time-saving bit of sugar, to be able to conservatively update a particular gem, without having to edit the Gemfile, bundle install, then undo the edits to the Gemfile. Or worse, result in devs fiddling with their Gemfile.lock (see Options 1 & 3 in this post). Regardless of whether this is rails, or any other gem.

Use case: My company's internal gem works with any version of rails, and any version of many other gems it depends on. But when my team updates to the latest version of my internal (company specific, private) gem, they don't always want to change any other code in related gems, but just get my internal gem updates. This would allow them to do this in the most conservative way possible, and make it easier than the process described, which works of course, but is a bit of a pain, particularly when working with internal gems which are updated often to get company specific business logic/functionality. Thanks for listening!

@byrnejb
Copy link

byrnejb commented Nov 18, 2013

There is reputedly a way to do this in bundler via the --source option:

bundle update --source=some_gem  

I say reputedly because I am unable to get it to work for the xpath gem but this problem may be specific to that gem.

@likethesky
Copy link

My understanding is that --source is simply for specifying the source (URL or local filesystem) location where any needed gems can be found. @byrnejb : Do you have a link to a blog post or other explaining how --source can be used to conservatively update only one (or several) gems at a time, changing no other gems that the ones specified on the bundle update command line? Thanks.

@byrnejb
Copy link

byrnejb commented Nov 19, 2013

P.S. If you run bundle update --source gem_name and gem_name is not updated then gem_name has other dependencies which differ from those already locked. You will have to discover which of these dependencies must be updated to allow gem_name to update as well. it is quite possible to get into a vicious cycle where one cannot update a particular gem because its dependency versions conflict with those required by a different gem that one does not wish to update.

@jbodah
Copy link
Contributor

jbodah commented Oct 17, 2014

For anyone who runs into this, updating in my Gemfile (in my case from a branch to merged master) and bundle install worked great for a conservative upgrade

@likethesky
Copy link

I'll just put in another plug for adding a '--conservative' option for bundler when updating single gems. Anytime you have users having to edit a file, re-run a command, then revert changes to the edits, seems like a slam dunk for a nice convenient command line option. Anyway, that's imo of course.

@indirect
Copy link
Member

So help me understand exactly what you want, then, I guess? You want to be able to run bundle update --only foo or something like that, and update to the newest version of foo that doesn't require changing the version of any other gem in your Bundle?

Could this instead be solved by interactive update mode, like https://github.com/wireframe/bundler-updater?

@marcandre
Copy link
Author

You want to be able to run bundle update --only foo and update to the newest version of foo that doesn't require changing the version of any other gem in your Bundle?

No, not quite. It has to update to the latest foo, even if that requires changing other versions. Problem is, currently, bundler changes versions it doesn't have to.

Update foo to the latest available version, and update other gems only if required. In particular, if the requirements of foo haven't changed, then only foo would be updated.

Other way to say this: equivalent of bundle install, but as if the Gemfile had been modified with gem 'foo', 'the.latest.version'.

If you want a concrete example:

  • my gem scheherazade has a single dependency on Rails >= 3.0.
  • imagine a Gemfile with a single entry: gem 'scheherazade'
  • imagine that bundle install settles on scheherazade v0.1.0 and rails v3.2.18 because that's what is available at a given time.
  • a year later, say, there's a bugfix release of scherazade v0.1.1. Its requirements are still Rails >= 3.0.

I'd like a single command line call that will change the Gemfile.lock's version of scheherazade from 0.1.0 to v0.1.1 but will not change rails' version.

I consider it a bug that bundle update scheherazade will change Rails' version, but if it's not a bug, then can we have an option that will not change Rails's version in this example?

(I've taken an example with Rails, but this has nothing to do with Rails)

@segiddins
Copy link
Member

If you care about the versions of implicit dependencies, you should make those dependencies explicit in your own Gemfile.

@marcandre
Copy link
Author

If you care about the versions of implicit dependencies, you should make those dependencies explicit in your own Gemfile.

That won't fix it. Even if the dependency is explicit, say in my example above I have a gem 'rails', ~> '3.0' in my Gemfile, this might still change the Rails version. I don't want that to change at this point! Imagine I don't trust 100% my integrations specs. If I update only foo, then I can concentrate manual tests on areas that use that gem. If other gems have changed too, then I might have to manually double check everything...

@indirect
Copy link
Member

I see what you're saying now. Conservative update for all child dependencies, along with aggressive update for the top level dependency, sounds like the way to go. That also sounds very, very hard to get right. :)

On Oct 19, 2014, at 12:35 PM, Marc-André Lafortune notifications@github.com wrote:

If you care about the versions of implicit dependencies, you should make those dependencies explicit in your own Gemfile.

That won't fix it. Even if the dependency is explicit, say in my example above I have a gem 'rails', ~> '3.0' in my Gemfile, this might still change the Rails version. I don't want that to change at this point!

There are two very distinct situations when I want to change versions of gems I'm using:

I need a new updated foo gem while coding.
I do gem update foo --conservative or whatever. I can assume that risks of regressions are extremely minimal because only foo changes (or maybe some of the small dependencies from foo's author, say). I don't bother the QA team for anything that's not related to my new feature.

Periodical update
Every so often, gem update to update all gems with the latests bugs fixes and all for everything I'm using. Even assuming a perfectly setup Gemfile, and all gems using semantic versioning, there are still regressions possible and I will have my QA team go over everything (say I don't have complete integration specs, I'm not perfect you know).


Reply to this email directly or view it on GitHub.

@marcandre
Copy link
Author

I see what you're saying now.

😄

That also sounds very, very hard to get right

I haven't looked at the code, but I'm surprised this looks hard to get right.
Wouldn't the following work?

  • Check the Gemfile.lock for requirements about foo in DEPENDENCY or in one of the specs (on the second level).
  • Check the source gem repo for the highest version that matches the found requirements (if any)
  • Run bundle install with a temporary requirement gem 'foo', 'max.version.found'.

@jonswar
Copy link

jonswar commented Mar 4, 2015

+1 for this request. We do very conservative gem updates in our environment so it's always a surprise when bundler updates dependencies unnecessarily!

@vassilevsky
Copy link
Contributor

--conservative: update to the latest version; update dependencies only if necessary

--ultra-conservative: update to the maximum possible version still satisfied by current dependencies

@drewbug
Copy link

drewbug commented May 8, 2015

👍

@gerrywastaken
Copy link

That also sounds very, very hard to get right. :)

@indirect What are the difficult parts with @marcandre's suggestion? Where bundle update 'foo' is really:

Run bundle install with a temporary requirement gem 'foo', 'max.version.found'

@pjscopeland
Copy link

@indirect, 6 Jul 2012

If you need to update just one gem to a specific version, that is when you should edit your Gemfile and then run bundle install (which will re-resolve your Gemfile in the most conservative mode).

Er... no. I am updating rails from 4.2.0 to 4.2.5, and test_after_commit from 0.4.0 to 0.4.2. Here are the changes to my Gemfile (minimised a bit):

$ git diff
-gem 'rails', '4.2.0'
+gem 'rails', '4.2.5'
-gem 'test_after_commit', '0.4.0'
+gem 'test_after_commit', '0.4.2'

And then, according to your instructions, I'm supposed to run:

$ bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching version metadata from https://rubygems.org/...
Fetching dependency metadata from https://rubygems.org/..
You have requested:
  rails = 4.2.5

The bundle currently has rails locked at 4.2.0.
Try running `bundle update rails`

So that doesn't work. If I do bundle update rails test_after_commit, the following gems are the ones that get upgraded. However, only the bold changes are actually needed to satisfy my new requirements:

  • actionmailer (4.2.5)
  • actionpack (4.2.5)
  • actionview (4.2.5)
  • activejob (4.2.5)
  • activemodel (4.2.5)
  • activerecord (4.2.5)
  • activesupport (4.2.5)
  • arel (6.0.3)
  • globalid (0.3.6)
  • loofah (2.0.3)
  • mime-types (2.99)
  • mini_portile2 (2.0.0)
  • minitest (5.8.3)
  • nokogiri (1.6.7)
  • rails (4.2.5)
  • rails-dom-testing (1.0.7)
  • railties (4.2.5)
  • sprockets (3.4.1)
  • sprockets-rails (2.3.3)
  • test_after_commit (0.4.2)

I don't want all the rest! I had to manually figure out in each case whether the change was actually needed, and then revert parts of my Gemfile.lock. It would be so much easier if I could just run bundle update rails --conservative! (--minimal was the word I thought of.)

@indirect
Copy link
Member

indirect commented Dec 6, 2015

@pjscopeland you should be able to get that exact behavior today by running bundle install --source rails. It's a bug, but it's a useful big, and we'll make sure it keeps working until we replace it with a feature with the same behavior.

@hashar
Copy link

hashar commented Jan 27, 2016

Well --source does not work at all:

$ bundle --version
Bundler version 1.11.2
$ bundle install --source foo
Unknown switches '--source'

And bundle update --source foo still updates dependencies of foo even when the ones in the .lock file match...

@indirect
Copy link
Member

Sorry, it's update --source foo.

@indirect
Copy link
Member

Here's an explanation of how --source updating works: http://ilikestuffblog.com/2012/07/01/you-should-update-one-gem-at-a-time-with-bundler-heres-how/

@hashar
Copy link

hashar commented Jan 28, 2016

Yup found that. Though bundle update --source foo still have the dependencies of foo re-resolved even when matched which is not that conservative. That is a different story though. Thank you for the tip about --source.

chrismo added a commit to chrismo/bundler-fixture that referenced this issue Mar 14, 2016
Found a place the faked source was being merged with the one read from
the lockfile, so now tests that want to simulate that case will work.

This also adds a spec that demonstrates how `bundle update foo` will
also grab an update to any gems `foo` depends on, even though we didn't
request that. This refers to the conservative idea that has been floated
around the 'net.

rubygems/bundler#2016
http://makandracards.com/makandra/13885-how-to-update-a-single-gem-conservatively
@chrismo
Copy link
Contributor

chrismo commented Apr 28, 2016

I've been messing around with this for a while, just released 0.7.0 of a gem today, would love feedback: https://github.com/livingsocial/bundler-patch

@jrochkind
Copy link
Contributor

An old ticket, but a ways back @indirect says:

If you need to update just one gem to a specific version, that is when you should edit your Gemfile and then run bundle install (which will re-resolve your Gemfile in the most conservative mode).

That's how I thought it worked, and I swear it's worked this way for me before (maybe back in 2012), but today it does not seem to. I edit my Gemfile changing a Rails dependency from ~> 4.1 to ~> 4.2, then run bundle install, and get:

You have requested:
  rails ~> 4.2

The bundle currently has rails locked at 4.1.14.1.
Try running `bundle update rails`

This surprised me. Of course, if I run bundle update rails, potentially more things then I want will be updated. Are things still supposed to work like @indirect says?

Of course, this case may be complicated by the fact that "rails" has it's own dependencies, on activerecord etc, that of course will need to be updated too to get a resolution. But I thought this had worked for me before.

Anyone know what's up?

@chrismo
Copy link
Contributor

chrismo commented May 18, 2016

@jrochkind I couldn't recreate with just a simple Gemfile with just gem 'rails' in it ... but that's not valid, the regular Gemfile would need to be considered. Anything you can link to in a gist?

@chrismo
Copy link
Contributor

chrismo commented Aug 23, 2016

Bundler now has some new flags for conservative updates, would love y'alls feedback: rubygems/bundler-features#122

@jrochkind
Copy link
Contributor

jrochkind commented Aug 23, 2016

@chrismo I don't have a simple repro, sorry, these things tend to occur in complicated gem files. And I think I've lost the gemfile/gemfile.lock that happened in, don't remember what project of mine anymore either.

But I have had this problem fairly regularly. Next time it happens, is it useful if I file a fresh issue, with the complete Gemfile/Gemfile.lock even if it's complicated?

What keeps me from filing in the past is not even being sure if what I'm seeing is somehow expected behavior (in the past, there have been things I was sure were rubygems bugs, that I was told was not a bug upon reporting), or not having any idea if such reports are welcome and will get any attention at all.

@chrismo
Copy link
Contributor

chrismo commented Aug 23, 2016

Yeah, definitely. Happy to try and diagnose a weird case. 👻

@jrochkind
Copy link
Contributor

@chrismo Okay if it happens again, I'll file an issue! So long as we are agreed that the expected/intended behavior is:

If you need to update just one gem to a specific version, that is when you should edit your Gemfile and then run bundle install (which will re-resolve your Gemfile in the most conservative mode).

I have to admit I don't understand what the docs at rubygems/bundler-features#122 are describing, and I'm not sure if it's what others (and me) were actually wanting? Am I just not following the docs, or is it intended to be something differnet from what this issue is asking for?

What this issue is asking for is related to the quote above, originally from indirect.

Consider a Gemfile with lots of things in it, including 'widget', '~> 4.3'. But let's say there's a Widget 5.2.0 out. If I manually update my Gemfile to 'widget', '~> 5.2' and then run bundle install then what happens (or at least what we think is supposed to happen), is widget is updated to latest 5.2.0, but widgets dependencies are only updated as neccesary to be compatible with 5.2.0. Other widget dependencies whose Gemfile.lock versions are still compatible with the new 5.2.0 are not updated. (This is very different than what happens when you run bundle update widget, where all dependencies of widget are updated to latest possible version).

What this issue is asking for is something similar, but without having to manually update the Gemfile. perhaps bundle update --conservative widget would find the most recent version of widget that exists, then resolve the rest of the dependencies as if that version had been specified in the Gemfile (it is not though). Since bundler can already do that (sans bugs) with a manual update of Gemfile and bundle install, it seems like the logic already exists?

Of course it gets more complicated if more than one gem is involved bundle update --conservative widget gadget. But I could spec out what I'd want that to do too.

But it's not clear to me that rubygems/bundler-features#122 is describing anything like this at all. It appears to be something different, involving minor/patch restrictions, which is not what this issue was asking for, and is not something that to me is obviously useful for my workflow anyway.

@chrismo
Copy link
Contributor

chrismo commented Aug 24, 2016

Thx for the feedback, it's exactly the sort of stuff I was hoping we could flush out at this stage. "Conservative updates" appears to have varying meaning to folks and your reply plus the comments on 122 from yesterday are already drawing out some additional use cases that weren't at the forefront of my mind when I wrote what I did.

If you're cool with it, I'd like to move this discussion over to that issue, so we can try to accumulate discussion there. I'm also curious if the existing comments there overlap with how you'd like things to work. In particular, this case: rubygems/bundler-features#122 (comment)

@codyrobbins
Copy link

I just ran into the exact problem that the original comments on this thread were describing: I had a very old project that needed a single gem updated to its latest version to pull in a fix for a bug in that gem, but every combination of bundle install and bundle update gem-name-here I tried resulted in almost every gem in the project getting updated. The gem that needed to be updated had no dependencies and for the sake of maintaining the status quo I did not want any other gems updated since they didn’t need to be. I just tried the --minor option to bundle update described in rubygems/bundler-features#122 and it worked perfectly and did exactly what I needed! Thank you for implementing this!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests