Skip to content

Instantly share code, notes, and snippets.

@tsnow
Created September 30, 2013 15:21
Show Gist options
  • Save tsnow/6765388 to your computer and use it in GitHub Desktop.
Save tsnow/6765388 to your computer and use it in GitHub Desktop.
Bundle Conservative Updating

After reading up on the bundler project about "conservative updating" this, bundle_nice.sh above, appears to be the suggested workflow for updating Just the Gems You Have To:

  • gem list -r --all $X to get the latest version of whatever gem you want.
  • Edit Gemfile to add a new '=' version constraint for that gem.
  • Edit Gemfile.lock to relax the locked constraint for that gem, up to the new version. Dependencies (gem specification $X -v $version) will be updated by bundle install and bundle check in the Gemfile.lock automatically.
  • Run bundle install to conservatively update the dependency graph, and Gemfile.lock.
  • Remove the constraint from the Gemfile, and run bundle check to update the Gemfile.lock with the removed constraint without installing new gems.
  • whew.

Below is a log of those actions, along with git diff interspersed for clarity.

So I wrote a script to do all that. i.e. if you want capistrano upgraded to 2.15.5, with any other gems which MUST be updated to work with that version:

> bundle_nice_update capistrano 2.15.5

(cap_uprade_2_15_5=fcf969) [email protected] ~/dev/tools> git checkout cap_uprade_2_15_5
Already on 'cap_uprade_2_15_5'
(cap_uprade_2_15_5=fcf969) [email protected] ~/dev/tools> git show HEAD | head
commit fcf96939925cbfa7647af586d45bce5986cdc06f
Author: Philip M. Gollucci <[email protected]>
Date:   Tue Aug 13 17:34:21 2013 -0400

    bundle update

diff --git a/Gemfile.lock b/Gemfile.lock
index 26beaac..48cb70c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
(cap_uprade_2_15_5=fcf969) [email protected] ~/dev/tools> git show HEAD | grep -e '^[+-]'
--- a/Gemfile.lock
+++ b/Gemfile.lock
-    capistrano (2.14.2)
+    addressable (2.3.5)
+    capistrano (2.15.5)
-    capistrano-detect-migrations (0.6.2)
+    capistrano-detect-migrations (0.6.3)
-    chef (11.4.0)
+    chef (11.6.0)
-    faraday (0.8.7)
-      multipart-post (~> 1.1)
+    faraday (0.8.8)
+      multipart-post (~> 1.2.0)
-    github_api (0.9.7)
-      faraday (~> 0.8.1)
+    github_api (0.10.2)
+      addressable
+      faraday (~> 0.8.7)
-      nokogiri (~> 1.5.2)
+      nokogiri (~> 1.6.0)
-    github_cli (0.5.9)
-      github_api (~> 0.9)
-    hashie (2.0.3)
-    highline (1.6.18)
-    hipchat (0.4.1)
+    github_cli (0.6.1)
+      github_api (~> 0.10)
+    hashie (2.0.5)
+    highline (1.6.19)
+    hipchat (0.11.0)
-    httparty (0.10.2)
+    httparty (0.11.0)
+    mini_portile (0.5.1)
-    mixlib-shellout (1.1.0)
-    multi_json (1.7.2)
-    multi_xml (0.5.3)
+    mixlib-shellout (1.2.0)
+    multi_json (1.7.9)
+    multi_xml (0.5.5)
-    net-scp (1.1.0)
+    net-scp (1.1.2)
-    net-sftp (2.1.1)
+    net-sftp (2.1.2)
-    net-ssh (2.6.7)
+    net-ssh (2.6.8)
-    nokogiri (1.5.9)
-    oauth2 (0.9.1)
+    nokogiri (1.6.0)
+      mini_portile (~> 0.5.0)
+    oauth2 (0.9.2)
-      httpauth (~> 0.1)
+      httpauth (~> 0.2)
-    ohai (6.16.0)
+    ohai (6.18.0)
(cap_uprade_2_15_5=fcf969) [email protected] ~/dev/tools> VISUAL=cat git revert HEAD
Revert "bundle update"

This reverts commit fcf96939925cbfa7647af586d45bce5986cdc06f.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch cap_uprade_2_15_5
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#modified:   Gemfile.lock
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#Gemfile-e
#Gemfile.lock-e
#config/deploy.rb.orig
#rc_release.sql
#recipes/locking.rb.try
[cap_uprade_2_15_5 a341294] Revert "bundle update"
 1 file changed, 24 insertions(+), 28 deletions(-)
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> sed -i'' -e 's/\("capistrano"\)/\1, "2.15.5"/' Gemfile
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> git diff
diff --git a/Gemfile b/Gemfile
index d7470de..becbfd0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,7 @@ source "https://rubygems.org"
 
 # Capistrano
 gem "chef"
-gem "capistrano"
+gem "capistrano", "2.15.5"
 gem "capistrano_colors"
 gem "capistrano-detect-migrations"
 gem "capistrano-patch"
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> bundle install
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
You have requested:
  capistrano = 2.15.5

The bundle currently has capistrano locked at 2.14.2.
Try running `bundle update capistrano`
7 (cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> grep 2.14.2 Gemfile.lock 
    capistrano (2.14.2)
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> sed -i'' -e 's/capistrano (2.14.2)/capistrano (2.15.5)/' Gemfile.lock
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> git diff
diff --git a/Gemfile b/Gemfile
index d7470de..becbfd0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,7 @@ source "https://rubygems.org"
 
 # Capistrano
 gem "chef"
-gem "capistrano"
+gem "capistrano", "2.15.5"
 gem "capistrano_colors"
 gem "capistrano-detect-migrations"
 gem "capistrano-patch"
diff --git a/Gemfile.lock b/Gemfile.lock
index 26beaac..57175b8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    capistrano (2.14.2)
+    capistrano (2.15.5)
       highline
       net-scp (>= 1.0.0)
       net-sftp (>= 2.0.0)
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> bundle install
Resolving dependencies...
Using highline (1.6.18) 
Using net-ssh (2.6.7) 
Using net-scp (1.1.0) 
Using net-sftp (2.1.1) 
Using net-ssh-gateway (1.2.0) 
Using capistrano (2.15.5) 
Using gdata_19 (1.1.5) 
Using json (1.7.7) 
Using capistrano-calendar (0.1.2) 
Using erubis (2.7.0) 
Using mixlib-log (1.6.0) 
Using mixlib-authentication (1.3.0) 
Using mixlib-cli (1.3.0) 
Using mixlib-config (1.1.2) 
Using mixlib-shellout (1.1.0) 
Using net-ssh-multi (1.1) 
Using ipaddress (0.8.0) 
Using systemu (2.5.2) 
Using yajl-ruby (1.1.0) 
Using ohai (6.16.0) 
Using mime-types (1.23) 
Using rest-client (1.6.7) 
Using chef (11.4.0) 
Using capistrano-chef (0.0.8) 
Using capistrano-ext (1.2.1) 
Using capistrano-deploytags (0.7.0) 
Using capistrano-detect-migrations (0.6.2) 
Using capistrano-log_with_awesome (0.0.2) 
Using capistrano-patch (0.0.2) 
Using capistrano-uptodate (0.0.2) 
Using capistrano_colors (0.5.5) 
Using multipart-post (1.2.0) 
Using faraday (0.8.7) 
Using hashie (2.0.3) 
Using multi_json (1.7.2) 
Using nokogiri (1.5.9) 
Using httpauth (0.2.0) 
Using jwt (0.1.8) 
Using multi_xml (0.5.3) 
Using rack (1.5.2) 
Using oauth2 (0.9.1) 
Using github_api (0.9.7) 
Using github_cli (0.5.9) 
Using httparty (0.10.2) 
Using hipchat (0.4.1) 
Using bundler (1.3.5) 
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> git diff
diff --git a/Gemfile b/Gemfile
index d7470de..becbfd0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,7 @@ source "https://rubygems.org"
 
 # Capistrano
 gem "chef"
-gem "capistrano"
+gem "capistrano", "2.15.5"
 gem "capistrano_colors"
 gem "capistrano-detect-migrations"
 gem "capistrano-patch"
diff --git a/Gemfile.lock b/Gemfile.lock
index 26beaac..350f5ec 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    capistrano (2.14.2)
+    capistrano (2.15.5)
       highline
       net-scp (>= 1.0.0)
       net-sftp (>= 2.0.0)
@@ -115,7 +115,7 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  capistrano
+  capistrano (= 2.15.5)
   capistrano-calendar
   capistrano-chef
   capistrano-detect-migrations
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> sed -i'' -e 's/"capistrano", "2.15.5"/"capistrano"/' Gemfile 
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> git diff
diff --git a/Gemfile.lock b/Gemfile.lock
index 26beaac..350f5ec 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    capistrano (2.14.2)
+    capistrano (2.15.5)
       highline
       net-scp (>= 1.0.0)
       net-sftp (>= 2.0.0)
@@ -115,7 +115,7 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  capistrano
+  capistrano (= 2.15.5)
   capistrano-calendar
   capistrano-chef
   capistrano-detect-migrations
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> bundle check
Resolving dependencies...
The Gemfile's dependencies are satisfied
(cap_uprade_2_15_5=a34129) [email protected] ~/dev/tools> git diff
diff --git a/Gemfile.lock b/Gemfile.lock
index 26beaac..57175b8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    capistrano (2.14.2)
+    capistrano (2.15.5)
       highline
       net-scp (>= 1.0.0)
       net-sftp (>=
function bundle_nice_undo(){
gemname="$1";
desired_version="$2";
## Sweet, it worked. Undo the Gemfile constraint.
sed -i'' -e 's/"'"$gemname"'", "'"$desired_version"'"/"'"$gemname"'"/' Gemfile
## Update the Gemfile.lock with the removed constraint
bundle check
}
function bundle_nice_relax_constraint(){
install_text="$1";
echo "$install_text" | grep -A 1 'You have requested:' | tail -n 1 | read constr_gemname constraint constr_version;
echo "$install_text" | grep 'The bundle currently has' | sed -e 's/The bundle currently has//' -e 's/locked at//' | read locked_gemname locked_version;
#Resolving dependencies...
#You have requested:
# capistrano = 2.15.5
#The bundle currently has capistrano locked at 2.14.2.
#Try running `bundle update capistrano`
if [ "$constraint" -ne "\=" ]; then
echo "only know how to resolve '=' constraints: ";
echo "$install_text";
exit 1;
fi
sed -i'' -e 's/'"$locked_gemname"' ('"$locked_version"')/'"$constr_gemname"' ('"$constr_version"')/' Gemfile.lock
## Retry
next_install_text=`bundle install`;
if [ "$?" == "0" ]; then
bundle_nice_undo "$gemname" "$desired_version"
exit 0;
elif [ "$next_install_text" == "$install_text" ]; then
echo "Please fix this issue:";
echo "$next_install_text";
exit 1;
else
bundle_nice_relax_constraint "$next_install_text"
fi
}
function bundle_nice_update(){
gemname="$1";
desired_version="$2";
## Change it in the Gemfile to the version you want
sed -i'' -e 's/\("'"$gemname"'"\)/\1, "'"$desired_version"'"/' Gemfile
## Pull down all the dependencies and install, if possible. This will break.
install_text="$(bundle install)";
if [ "$?" == "0" ]; then
bundle_nice_undo "$gemname" "$desired_version"
exit 0;
else
bundle_nice_relax_constraint "$install_text"
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment