class HerokuRailsDeploy::Deployer
Constants
- PRODUCTION
- PRODUCTION_BRANCH_REGEX
Attributes
args[R]
config_file[R]
Public Class Methods
new(config_file, args)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 25 def initialize(config_file, args) raise "Missing config file #{config_file}" unless File.file?(config_file) @app_registry = YAML.load(File.read(config_file)) @config_file = config_file @args = args @options = parse_options end
Public Instance Methods
production?()
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 72 def production? options.try(:environment) == PRODUCTION end
run()
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 33 def run return unless options app_name = app_registry.fetch(options.environment) do raise OptionParser::InvalidArgument.new("Invalid environment '#{options.environment}'. " \ "Must be in #{app_registry.keys.join(', ')}") end raise 'Only master, release or hotfix branches can be deployed to production' if production? && !production_branch?(options.revision) no_uncommitted_changes! puts "Deploying to Heroku app #{app_name} for environment #{options.environment}" if !options.skip_avro_schemas && (production? || options.register_avro_schemas) puts 'Checking for pending Avro schemas' pending_schemas = list_pending_schemas(app_name) if pending_schemas.any? puts 'Registering Avro schemas' register_avro_schemas!(registry_url(app_name), pending_schemas) else puts 'No pending Avro schemas' end end puts 'Pushing code' push_code(app_name, options.revision) puts 'Checking for pending migrations' if pending_migrations?(app_name) puts 'Running migrations' run_migrations(app_name) puts 'Restarting dynos' restart_dynos(app_name) else puts 'No migrations required' end end
Private Instance Methods
app_remote(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 188 def app_remote(app_name) "https://git.heroku.com/#{app_name}.git" end
changed_files(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 176 def changed_files(app_name) run_command("git diff --name-only #{remote_commit(app_name)}..#{current_commit}", quiet: true).split("\n").map(&:strip) end
current_commit()
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 180 def current_commit run_command!("git log --pretty=format:'%H' -n 1", quiet: true) end
git_branch_name(revision)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 125 def git_branch_name(revision) run_command!("git rev-parse --abbrev-ref #{Shellwords.escape(revision)}", quiet: true).strip rescue raise "Unable to get branch for #{revision}" end
list_pending_schemas(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 172 def list_pending_schemas(app_name) changed_files(app_name).select { |filename| /\.avsc$/ =~ filename } end
no_uncommitted_changes!()
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 116 def no_uncommitted_changes! uncommitted_changes = run_command!('git status --porcelain', quiet: true) raise "There are uncommitted changes:\n#{uncommitted_changes}" unless uncommitted_changes.blank? end
parse_options()
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 78 def parse_options options = Options.create_default(app_registry) OptionParser.new do |parser| parser.on_tail('-h', '--help', 'Show this message') do puts parser # rubocop:disable Lint/NonLocalExitFromIterator return # rubocop:enable Lint/NonLocalExitFromIterator end parser.on('-e', '--environment ENVIRONMENT', "The environment to deploy to. Must be in #{app_registry.keys.join(', ')} (default #{app_registry.keys.first})") do |environment| options.environment = environment end parser.on('-r', '--revision REVISION', 'The git revision to push. (default HEAD)') do |revision| options.revision = revision end parser.on('--register-avro-schemas', 'Force the registration of Avro schemas when deploying to a non-production environment.') do |register_avro_schemas| options.register_avro_schemas = register_avro_schemas end parser.on('--skip-avro-schemas', 'Skip the registration of Avro schemas when deploying to production.') do |skip_avro_schemas| options.skip_avro_schemas = skip_avro_schemas end end.parse!(args) options end
pending_migrations?(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 139 def pending_migrations?(app_name) !run_heroku_command(app_name, 'run rake db:abort_if_pending_migrations') end
production_branch?(revision)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 112 def production_branch?(revision) git_branch_name(revision).match(PRODUCTION_BRANCH_REGEX) end
push_code(app_name, revision)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 121 def push_code(app_name, revision) run_command!("git push --force #{app_remote(app_name)} #{revision}:master") end
register_avro_schemas!(registry_url, schemas)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 167 def register_avro_schemas!(registry_url, schemas) cmd = "rake avro:register_schemas schemas=#{schemas.join(',')}" run_command!("DEPLOYMENT_SCHEMA_REGISTRY_URL=#{registry_url} #{cmd}", print_command: cmd) end
registry_url(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 162 def registry_url(app_name) result = run_command!("heroku config -a #{app_name} | grep AVRO_SCHEMA_REGISTRY_URL:", quiet: true) result.split.last end
remote_commit(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 184 def remote_commit(app_name) run_command!("git ls-remote --heads #{app_remote(app_name)} master", quiet: true).split.first end
restart_dynos(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 135 def restart_dynos(app_name) run_heroku_command!(app_name, 'ps:restart') end
run_command(command, print_command: nil, validate: nil, quiet: false, display_output: false)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 196 def run_command(command, print_command: nil, validate: nil, quiet: false, display_output: false) printed_command = print_command || command puts printed_command unless quiet if display_output Bundler.with_clean_env { system(command) } else output = Bundler.with_clean_env { `#{command}` } end success = $CHILD_STATUS.success? raise "Command '#{printed_command}' failed#{output && output.strip != '' ? ", output: #{output}" : ''}" if validate && !success display_output ? success : output end
run_command!(command, print_command: nil, quiet: false, display_output: false)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 192 def run_command!(command, print_command: nil, quiet: false, display_output: false) run_command(command, print_command: print_command, quiet: quiet, display_output: display_output, validate: true) end
run_heroku_command(app_name, command, validate: nil)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 149 def run_heroku_command(app_name, command, validate: nil) cli_command = "heroku #{command} --app #{app_name}" if command.start_with?('run ') # If we're running a shell command, return the underlying # shell command exit code cli_command << ' --exit-code' display_output = true else display_output = false end run_command(cli_command, validate: validate, display_output: display_output) end
run_heroku_command!(app_name, command)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 143 def run_heroku_command!(app_name, command) run_heroku_command(app_name, command, validate: true) rescue raise "Heroku command '#{command}' failed" end
run_migrations(app_name)
click to toggle source
# File lib/heroku_rails_deploy/deployer.rb, line 131 def run_migrations(app_name) run_heroku_command!(app_name, 'run rake db:migrate') end