class Shred::Commands::Deploy
Public Instance Methods
all()
click to toggle source
# File lib/shred/commands/deploy.rb, line 29 def all invoke(:update_code_from_heroku) invoke(:detect_pending_migrations) if migration_count > 0 maintenance_on scale_down end push_code_to_heroku if migration_count > 0 snapshot_db migrate_db scale_up restart_app maintenance_off end send_notifications end
branch()
click to toggle source
# File lib/shred/commands/deploy.rb, line 203 def branch @branch ||= begin br = options[:branch] || cfg("#{environment}.branch", required: false) return br if br console.say_err("Local branch name must be specified, either with --branch or with '#{environment}.branch' config for '#{command_name}' command") end end
detect_pending_migrations()
click to toggle source
# File lib/shred/commands/deploy.rb, line 64 def detect_pending_migrations if migration_count > 1 console.say_ok("#{migration_count} pending database migrations detected") elsif migration_count == 1 console.say_ok("#{migration_count} pending database migration detected") else console.say_ok("No pending database migrations detected") end end
environment()
click to toggle source
# File lib/shred/commands/deploy.rb, line 194 def environment @environment ||= begin env = options[:environment] || cfg('default_environment', required: false) return env if env console.say_err("Deployment environment must be specified, either with --environment or with 'default_environment' config for '#{command_name}' command") exit(1) end end
heroku()
click to toggle source
# File lib/shred/commands/deploy.rb, line 215 def heroku @heroku ||= begin ::Dotenv.load begin PlatformAPI.connect_oauth(ENV['HEROKU_DEPLOY_TOKEN']) rescue Excon::Errors::Unauthorized console.say_err("Access to Heroku is not authorized. Did you set the HEROKU_DEPLOY_TOKEN environment variable?") exit(1) end end end
heroku_app_name()
click to toggle source
# File lib/shred/commands/deploy.rb, line 245 def heroku_app_name @heroku_app_name ||= cfg("#{environment}.heroku.app_name") end
heroku_info()
click to toggle source
# File lib/shred/commands/deploy.rb, line 227 def heroku_info @heroku_info ||= heroku.app.info(heroku_app_name) end
heroku_remote_name()
click to toggle source
# File lib/shred/commands/deploy.rb, line 249 def heroku_remote_name @heroku_remote_name ||= cfg("#{environment}.heroku.remote_name", required: false) || heroku_app_name end
maintenance_off()
click to toggle source
# File lib/shred/commands/deploy.rb, line 176 def maintenance_off heroku.app.update(heroku_app_name, maintenance:false) console.say_ok("Maintenance mode disabled") end
maintenance_on()
click to toggle source
# File lib/shred/commands/deploy.rb, line 75 def maintenance_on heroku.app.update(heroku_app_name, maintenance: true) console.say_ok("Maintenance mode enabled") end
migrate_db()
click to toggle source
# File lib/shred/commands/deploy.rb, line 119 def migrate_db if migration_count > 0 dyno = heroku.dyno.create(heroku_app_name, command: 'rake db:migrate db:seed') poll_one_off_dyno_until_done(dyno) console.say_ok("Pending database migrations applied") else console.say_ok("No pending database migrations to apply") end end
migration_count()
click to toggle source
# File lib/shred/commands/deploy.rb, line 231 def migration_count @migration_count ||= `git diff #{branch} #{heroku_remote_name}/master --name-only -- db | wc -l`.strip!.to_i end
poll_one_off_dyno_until_done(dyno)
click to toggle source
# File lib/shred/commands/deploy.rb, line 253 def poll_one_off_dyno_until_done(dyno) done = false state = 'starting' console.say_trace("Starting process with command `#{dyno['command']}`") while !done do begin dyno = heroku.dyno.info(heroku_app_name, dyno['id']) if dyno['state'] != state console.say_trace("State changed from #{state} to #{dyno['state']}") state = dyno['state'] end sleep 2 rescue Excon::Errors::NotFound done = true console.say_trace("State changed from #{state} to complete") end end end
process_counts()
click to toggle source
# File lib/shred/commands/deploy.rb, line 235 def process_counts @process_counts ||= begin formations = heroku.formation.list(heroku_app_name).each_with_object({}) { |f, m| m[f['type'].to_sym] = f } [:worker, :clock].each_with_object({}) do |process_type, m| quantity = formations.fetch(process_type, {}).fetch('quantity', 0) m[process_type] = quantity if quantity > 0 end end end
push_code_to_heroku()
click to toggle source
# File lib/shred/commands/deploy.rb, line 103 def push_code_to_heroku run_shell_command(ShellCommand.new( command_lines: "git push -f #{heroku_remote_name} #{branch}:master" )) console.say_ok("Pushed code to Heroku") end
restart_app()
click to toggle source
# File lib/shred/commands/deploy.rb, line 161 def restart_app dynos = heroku.dyno.list(heroku_app_name).find_all { |d| d['type'] == 'web' } dynos.each do |dyno| heroku.dyno.restart(heroku_app_name, dyno['id']) end if dynos.count > 1 console.say_ok("Restarted #{dynos.count} web dynos") elsif dynos.count == 1 console.say_ok("Restarted #{dynos.count} web dyno") else console.say_ok("No web dynos to restart") end end
revision()
click to toggle source
# File lib/shred/commands/deploy.rb, line 211 def revision `git rev-parse #{branch}` end
scale_down()
click to toggle source
# File lib/shred/commands/deploy.rb, line 81 def scale_down updates = process_counts.each_with_object([]) do |(process_type, count), m| m << {'process' => process_type.to_s, 'quantity' => 0} if count > 0 end heroku.formation.batch_update(heroku_app_name, 'updates' => updates) updated = process_counts.map do |(process_type, count)| if count > 1 "#{count} #{process_type} processes" elsif count == 1 "#{count} #{process_type} process" else nil end end.compact if updated.any? console.say_ok("Scaled down #{updated.join(', ')}") else console.say_ok("No non-web processes to scale down") end end
scale_up()
click to toggle source
# File lib/shred/commands/deploy.rb, line 132 def scale_up updates = if options[:worker] || options[:clock] [:worker, :clock].each_with_object([]) do |process_type, m| m << {'process' => process_type.to_s, 'quantity' => options[process_type]} end else [:worker, :clock].each_with_object([]) do |process_type, m| count = process_counts[process_type] || 0 m << {'process' => process_type.to_s, 'quantity' => count} if count > 0 end end heroku.formation.batch_update(heroku_app_name, 'updates' => updates) updated = process_counts.map do |(process_type, count)| if count > 1 "#{count} #{process_type} processes" elsif count == 1 "#{count} #{process_type} process" else nil end end.compact if updated.any? console.say_ok("Scaled up #{updated.join(', ')}") else console.say_ok("No non-web processes to scale up") end end
send_notifications()
click to toggle source
# File lib/shred/commands/deploy.rb, line 182 def send_notifications Array(cfg('notifications', required: false)).each do |(service, command)| command. gsub!(%r[{environment}], environment). gsub!(%r[{revision}], revision) dyno = heroku.dyno.create(heroku_app_name, command: command) poll_one_off_dyno_until_done(dyno) console.say_ok("Notification sent to #{service}") end end
snapshot_db()
click to toggle source
# File lib/shred/commands/deploy.rb, line 111 def snapshot_db run_shell_command(ShellCommand.new( command_lines: "heroku pgbackups:capture --expire --app #{heroku_app_name}" )) console.say_ok("Database snapshot captured") end
update_code_from_heroku()
click to toggle source
# File lib/shred/commands/deploy.rb, line 48 def update_code_from_heroku exit_status = run_shell_command(ShellCommand.new( command_lines: "git remote | grep #{heroku_remote_name} > /dev/null" )) unless exit_status.success? run_shell_command(ShellCommand.new( command_lines: "git remote add #{heroku_remote_name} #{heroku_info['git_url']}" )) end run_shell_command(ShellCommand.new( command_lines: "git fetch #{heroku_remote_name}" )) console.say_ok("Updated code from #{heroku_app_name} Heroku app") end