Skip to content

Instantly share code, notes, and snippets.

@milyoni
Created June 24, 2011 20:50
Show Gist options
  • Save milyoni/1045661 to your computer and use it in GitHub Desktop.
Save milyoni/1045661 to your computer and use it in GitHub Desktop.
heroku autotag deploy scripts
require 'rake'
['sandbox', 'staging', 'production'].each do |env|
desc "Deploy the given git tag and tag to #{env}"
task "#{env}:deploy", :tag do |_, args|
CodePusher.new(env, args[:tag]).deploy!
end
desc "Rollback #{env} to tag"
task "#{env}:rollback", :tag do |_, args|
CodePusher.new(env, args[:tag]).rollback!
end
end
class CodePusher
HEROKU_APP_PREFIX="your_heroku_app_name"
def initialize(environment_name, tag)
@env = environment_name
@tag = tag || previous_deploy
@heroku_app_name = "#{HEROKU_APP_PREFIX}-#{@env}"
end
def deploy!
puts green("DEPLOYING TAG: = #{@tag} = to heroku app #{@heroku_app_name}")
push! && tag_ref_with(@env) && migrate_and_restart
puts green("Win!")
end
def rollback!
puts green("Rolling back #{@heroku_app_name} to #{@tag}")
stop_the_presses!
enter_maintenance!
target_migration = `git checkout #{@tag} && ls db/migrate/ | tail -n1`.match(/(\d+)_.*/)[1]
migrate_down!(target_migration)
push!(:force => true)
tag_ref_with(@env)
tag_ref_with("#{@env}-rollback")
migrate_and_restart
exit_maintenance!
`git checkout master`
puts yellow("Rollback successful, make sure you are working on the right branch, currently master")
end
protected
def previous_deploy
last_two_revisions = `autotag list #{@env} | tail -n2 | awk {'print $1'}`
previous_deploy = last_two_revisions.split(' ').to_a[0]
end
def tag_ref_with(env_name)
timestamp = AutoTagger::Base.new({}).send(:timestamp)
new_tag = "#{env_name}/#{timestamp}"
command = [%{git fetch origin refs/tags/*:refs/tags/*},
%{git update-ref refs/tags/#{new_tag} #{@tag}},
%{git push origin refs/tags/*:refs/tags/*}].join(" && ")
system(command) || raise("failed to tag")
end
def push!(opts={})
puts green("Pushing #{@tag} to #{@heroku_app_name}")
system("git push #{"--force" if opts[:force]} #{@env} +#{@tag}:master") || raise("failed to push to heroku")
end
def migrate_and_restart
system(%{heroku rake db:migrate --app #{@heroku_app_name}}) || raise("migration failed")
system(%{heroku restart --app #{@heroku_app_name}}) || raise("restarting heroku app failed")
end
def stop_the_presses!
file_name = "stop_the_presses_#{Time.now.to_i}_spec.rb"
system(%{cp script/support/stop_the_presses_spec.rb spec/lib/#{file_name}}) || raise("couldn't copy stop the presses")
system(%{git add spec/lib/#{file_name}}) || raise("couldn't git add stop the presses")
system(%{git ci -m "Stop the presses! ! We are rolling back. Add a failing test to prevent futher auto deploys until reolved." }) || raise("couldn't commit stop the presses")
system(%{git push origin master}) || raise("couldn't push stop the presses")
end
def enter_maintenance!
puts green('Entering Maintenance Mode on heroku')
system("heroku maintenance:on --app #{@heroku_app_name}") || raise("failed to turn maintenance mode on")
end
def exit_maintenance!
puts green("Turning the app back on, everything should be happy :)")
system "heroku maintenance:off --app #{@heroku_app_name}" || raise("failed to turn maintenance mode off")
end
def migrate_down!(target_migration)
puts green("Migrating down to #{target_migration}")
system("heroku rake db:migrate:down VERSION=#{target_migration} --app #{@heroku_app_name}") || raise("failed to migrate database down")
end
def colorize(text, color_code)
"\e[#{color_code}m#{text}\e[0m"
end
def green(text)
colorize(text, 32)
end
def yellow(text)
colorize(text, 33)
end
end
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment