Skip to content

Instantly share code, notes, and snippets.

@RocketPuppy
Created October 3, 2022 15:50
Show Gist options
  • Save RocketPuppy/a9871835d29e5b30380259744aadaa60 to your computer and use it in GitHub Desktop.
Save RocketPuppy/a9871835d29e5b30380259744aadaa60 to your computer and use it in GitHub Desktop.
Script to auto-update ruby dependencies
#!/usr/bin/env ruby
# You can copy this file and make it executable in your ruby repository.
# Running it will determine which of your top-level gems need updating and will then update them one-by-one.
# It will commit each update separately and push to origin on whatever your current branch is.
require 'bundler'
require 'bundler/cli'
require 'tempfile'
require 'time'
dirroot = `git rev-parse --show-toplevel`.strip!
gemfile_path = "#{dirroot}/Gemfile"
lockfile_path = "#{dirroot}/Gemfile.lock"
# Copy out the Gemfile to a temp location so the matching lockfile can be
# created and manipulated without affecting the master version
tmp_gemfile = Tempfile.create("auto_updater_gemfile_#{Time.now.to_i}")
File.open(gemfile_path, 'r') do |f|
contents = f.read
tmp_gemfile.write(contents)
tmp_gemfile.flush
end
puts "Copied Gemfile to #{tmp_gemfile.path}"
tmp_lockfile = File.open("#{tmp_gemfile.path}.lock", 'w+')
File.open(lockfile_path, 'r') do |f|
contents = f.read
tmp_lockfile.write(contents)
tmp_lockfile.flush
end
puts "Copied Lockfile to #{tmp_lockfile.path}"
# Now the temporary lockfile will be used
old_env_gemfile = ENV["BUNDLE_GEMFILE"]
ENV["BUNDLE_GEMFILE"] = tmp_gemfile.path
puts "Gathering current versions..."
# Get all dependencies and current versions
gemfile = Bundler.definition
# Gemfile deps
deps = gemfile.dependencies
# All deps
specs = gemfile.specs
current_versions = specs.map { |s| [s.name, s.version.version] }.to_h
# Check for updates, will change the temp lockfile locally
puts "Checking for updates..."
Bundler::CLI.start(["lock", "--update"])
gemfile = Bundler.definition
deps = gemfile.dependencies
specs = gemfile.specs
new = specs.map { |s| [s.name, s.version.version] }.to_h
# Updated gems, added gems
updated = new.reject { |k,v| current_versions[k] == v }
# Removed gems
updated.merge!(current_versions.reject { |k,v| new.has_key?(k) })
gems_that_need_updates = deps.map { |d| d.name }.sort.select { |d| updated.has_key?(d) }
puts "Updating the following gems:"
puts gems_that_need_updates
ENV["BUNDLE_GEMFILE"] = old_env_gemfile
gems_that_need_updates.each do |g|
puts "Updating #{g}..."
Bundler::CLI.start(["update", g])
puts "Committing update..."
`git add Gemfile Gemfile.lock`
commit_message = "[gems] Update #{g}: #{current_versions[g]} -> #{updated[g]}"
`git commit -m "#{commit_message}"`
puts "Pushing commit..."
`git push origin`
end
puts "Cleaning up tempfiles..."
File.delete(tmp_gemfile)
File.delete(tmp_lockfile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment