module Deis module Commands # Deploy a deis repo class Deploy < Struct.new(:app, :ref) include Helpers LAST_MIGRATION_CMD = %{bundle exec rake db:migrate:status} MIGRATION_REGEX = /up\s+(?[0-9]{8}[0-9])+/ attr_reader :worker_count attr_reader :web_count def run status "Deploying `#{ref}` to `#{app}` on Deis" precheck_migrations! output = deploy info['git_url'], ref: ref if output.include? 'Another git push is ongoing' sleep 60 # one minute return run_util 'deploy', app, ref end run_migrations! if needs_migrations? rescue NonZeroExitError => e raise e unless e.message.include? 'Another git push is ongoing' remove_instance_variable :@needs_migrations sleep 60 retry end private def debug? true end def info @info ||= super(app) end def run_migrations! # Todo: put the site in a readonly state but NEVER in maintenance mode status 'Running Migrations' deis_command(:run, 'rake "db:create"', app: app) deis_command(:run, 'rake "db:migrate"', app: app) end def precheck_migrations! needs_migrations? end def needs_migrations? return false if TRUTHY_STRINGS.include? ENV['SKIP_MIGRATIONS'] return true if TRUTHY_STRINGS.include? ENV['FORCE_MIGRATIONS'] @needs_migrations ||= begin status 'Checking Migration Status' (local_migration != remote_migration).tap do |val| if val puts 'Database out of date, Migrations are Required' else puts 'Database is up to date' end end end end def remote_migration @remote_migration ||= sha_from_migration_status deis_command("run #{LAST_MIGRATION_CMD}", app: app) rescue NonZeroExitError 'error' end def local_migration @local_migration ||= sha_from_migration_status shell(LAST_MIGRATION_CMD) rescue NonZeroExitError 'error' end def sha_from_migration_status(result) lines = result.lines.reject { |line| line.include? '**** NO FILE ****' } migration_lines = lines.map(&:strip).select { |line| line =~ MIGRATION_REGEX } Digest::SHA2.hexdigest migration_lines.join end end end end