Skip to content

Instantly share code, notes, and snippets.

@JonRowe
Created February 8, 2014 01:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JonRowe/8875343 to your computer and use it in GitHub Desktop.
Save JonRowe/8875343 to your computer and use it in GitHub Desktop.
Update heroku apps running old versions of libyaml.
require 'json'
class Shell
def self.heroku_apps
new('heroku apps').cache_at 'heroku_app_cache'
end
def self.ruby_version app
new("heroku run \"ruby -v\" --app #{app}").cache_at "ruby_version_#{app}"
end
def self.yaml_version app
new("heroku run \"ruby -r yaml -e 'puts Psych::LIBYAML_VERSION'\" --app #{app}").cache_at "yaml_version_#{app}"
end
def initialize cmd
@cmd = cmd
end
def cache_at key
from_key(key) || cache(key,from_cmd)
end
private
def json
@json ||=
begin
if File.exist?(file)
JSON.parse(File.read file)
else
{}
end
end
end
def from_key name
json[name]
end
def from_cmd
`#{@cmd}`
end
def cache name, string
json[name] = string
write_cache
string
end
def file
'./heroku_app_info.json'
end
def write_cache
File.open(file,'w+') { |file| file.write JSON.dump json }
end
end
class Heroku
def self.apps
new.apps
end
def self.ruby_version_for name
new.ruby_version_for name
end
def self.yaml_version_for name
new.yaml_version_for name
end
def apps
lines_containing_apps strip_trailing_info parse(Shell.heroku_apps)
end
def ruby_version_for name
RubyVersionString.new parse(Shell.ruby_version name).find { |line| line =~ /ruby\s+\d\.\d\.\d/ }
end
def yaml_version_for name
parse(Shell.yaml_version name).find { |line| line =~ /\d+\.\d+\.\d+/ }
end
private
def parse string
string.split("\n")
end
def strip_trailing_info lines
lines.map { |app| app.gsub(/\s+.*/,'') }
end
def lines_containing_apps lines
lines.select { |app| app =~ /^[\w-]+$/ }
end
end
class NestedHash < Hash
def initialize
super { |hash, key| hash[key] = Hash.new }
end
end
class RubyVersionString
def initialize string
@major, @patch = string.scan(/(\d\.\d\.\d)(?:-?p(\d\d\d))?/).first
end
attr_reader :major
def patch
@patch.to_i
end
end
module Versions
module_function
def for provider
provider.apps.inject(NestedHash.new) do |hash, app|
version = provider.ruby_version_for app
hash[version.major][app] = version.patch
hash
end
end
end
ALLOWED_VERSIONS =
{
'1.9.3' => 484,
'2.0.0' => 353,
}
versions = Heroku.apps.map do |app|
[app, Heroku.ruby_version_for(app), Heroku.yaml_version_for(app)]
end
to_upgrade = versions.select do |app, ruby, version|
if version
major, minor, patch = version.split('.').map &:to_i
major <= 0 && minor <= 1 && patch <= 4
end
end
to_upgrade.each do |app,ruby, version|
puts "App #{app} running old yaml version #{version} (#{ruby.major})"
`heroku git:clone #{app} && cd #{app} && git ci -m "rebuild yaml" --allow-empty && git push heroku master`
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment