exe/deis-rails in deis-rails-1.0.1 vs exe/deis-rails in deis-rails-1.0.3
- old
+ new
@@ -1,348 +1,4 @@
#!/usr/bin/env ruby
-require 'yaml'
-require 'bundler'
-require 'active_support/all'
-require 'pry'
-require 'pty'
-require 'benchmark'
-require 'colorize'
-
-class DeisUtils < Struct.new(:args)
-
- TRUTHY_STRINGS = %w(t true y yes 1).flat_map do |str|
- [str.downcase, str.upcase, str.capitalize]
- end.uniq
-
- FALSEY_STRINGS = %w(f false n no 0).flat_map do |str|
- [str.downcase, str.upcase, str.capitalize]
- end.uniq
-
- NonZeroExitError = Class.new(StandardError)
-
- def run
- command = args.shift
- status = Helpers.run_util(command, *args)
- exit status === false ? 1 : 0
- end
-
- module Helpers
-
- module_function def run_util(name, *args)
- status = false
- time = Benchmark.realtime do
- status = get_runner(name).new(*args).run
- end
- STDOUT.puts "#{$0} #{name} #{args.join ' '}` took #{seconds_to_human time}".light_blue if debug?
- status
- end
-
- module_function def debug?
- ENV['DEBUG'].in? TRUTHY_STRINGS
- end
-
- module_function def get_runner(name)
- DeisUtils.const_get(name.gsub('-', '_').camelize)
- rescue NameError
- STDERR.puts "command `#{name}` does not exist!".red
- exit 1
- end
-
- def app_exists?(app)
- !!deis_command('info', app: app)
- rescue NonZeroExitError
- false
- end
-
- def status(msg)
- msg = "| #{msg} |"
- sep = ''.ljust(msg.size, '-')
- puts "\n\e[0;92;49m#{[sep, msg, sep].join "\n"}\e[0m"
- end
-
- def databases(app)
- databases = deis_command('pg:info', app: app).split('===')
- databases[1..-1].map do |db|
- lines = db.lines
- name = lines[0].split(' ')[0]
- data = lines[1..-1].join
- { 'Name' => name }.merge YAML.load(data)
- end
- end
-
- def info(app)
- cmd_result = deis_command(:info, app: app)
- data = JSON.load cmd_result.match(/Application\r\n(?<json>\{.*\})/m)[:json]
- controller_host = data['url'].split('.').tap { |p| p[p.index app] = 'deis' }.join('.')
- data['git_url'] = "ssh://git@#{controller_host}:2222/#{app}.git"
- data['domains'] = cmd_result.match(/Domains\r\n(?<domains>.*)/m)[:domains].lines.map(&:strip).reject(&:empty?)
- data.sort.to_h
- end
-
- def shell(*commands)
- flags = commands.last.is_a?(Hash) ? commands.pop : {}
- command = commands.join ' '
- flags.each_with_object(command) do |(k, v), c|
- c << case v
- when TrueClass, FalseClass
- v ? " --#{k}" : ''
- when String, Fixnum
- " --#{k} #{v}"
- else
- raise ArgumentError
- end
- end
- result = nil
- time = Benchmark.realtime do
- result = capture_syscall command
- end
- STDOUT.puts "`#{command}` took #{seconds_to_human time}".light_black if debug?
- result
- end
-
- def deis_command(*cmds)
- shell :deis, *cmds
- end
-
- def git_clone(url, flags = {})
- shell "git clone #{url}", flags
- end
-
- def deploy(url, options = {})
- ref = options.delete(:ref) || 'master'
- shell "git push #{url} #{ref}:master", options
- end
-
- def capture_syscall(command)
- puts "\n#{command}".light_yellow if debug?
- String.new.tap do |output|
- threads = []
- PTY.spawn(command) do |p_out, p_in, pid|
- threads << Thread.new { p_in.close }
- threads << Thread.new { output << capture_output(p_out) }
- Process.wait pid
- threads.each(&:join)
- end
- raise NonZeroExitError, output unless $?.exitstatus == 0
- end
- end
-
- def capture_output(io)
- output = ''
- io.each do |line|
- output << line
- STDOUT.puts "#{line.strip}".light_black unless line.nil? || line.strip.empty? if debug?
- end
- ensure
- return output
- end
-
- # Warn Slack for upcoming maintenance mode
- def warn_for_maintenance(app)
- Slacker.message(text: "WARNING: #{app} will go into maintenance mode shortly.",
- username: "Deploy Bot",
- channel: "#pulse-dev",
- color: "warning",
- icon_emoji: ":warning:")
- end
-
- # Enable Maintenance Mode on Heroku
- def enable_maintenance_mode(app)
- get_units!
- status "#{app} is going into maintenance mode!"
- Slacker.message(text: "ALERT: #{app} is going into maintenance mode!",
- username: "Deploy Bot",
- channel: "#pulse-dev",
- color: "danger",
- icon_emoji: ":bangbang:")
- scale app, units.keys.each_with_object({}) { |k, h| h[k] = 0 }
- end
-
- # Disable Maintenance Mode on Heroku
- def disable_maintenance_mode(app)
- scale app, units
- status "#{app} is no longer in maintenance mode!"
- Slacker.message(text: "NOTICE: #{app} is no longer in maintenance mode.",
- username: "Deploy Bot",
- channel: "#pulse-dev",
- color: "good",
- icon_emoji: ":white_check_mark:")
- end
-
- def scale(app, opts={})
- process_string = opts.map { |k, v| "#{k}=#{v}" }.join ' '
- deis_command "scale #{process_string}", app: app
- end
-
- def get_units!
- unit_string = deis_command('ps', app: app)
- shell('foreman check').strip.sub(/.*\((.*)\)/, "\\1").split(', ').each do |unit|
- units[unit] ||= unit_string.lines.select { |l| l.include? "#{unit}." }.count
- end
- end
-
- def units
- @units ||= {}
- end
-
- module_function def seconds_to_human(secs)
- secs = secs.round
- output = ''
- seconds = secs % 60
- minutes = (secs - seconds) / 60
- output << "#{minutes}m" if minutes > 0
- output << "#{seconds}s"
- end
-
- end
-
- class Info < Struct.new :app
- include Helpers
-
- def run
- h = info(app)
- status "`#{app}` Information"
- output_hash h
- end
-
- def output_hash(hash, indent = 0)
- hash.each do |k, v|
- case v
- when Hash
- puts (' ' * indent) + k + ':'
- output_hash(v, indent + 1)
- when Array
- puts (' ' * indent) + k + ':', *v.map { |i| (' ' * (indent + 1)) + i.to_s }
- else
- puts (' ' * indent) + "#{k}: #{v}"
- end
- end
- end
- end
-
- class Exists < Struct.new :app
- include Helpers
-
- def run
- app_exists?(app)
- end
- end
-
- class CopyConfig < Struct.new :source_app, :dest_app
- include Helpers
-
- def run
- system <<-sh
- deis config --app #{source_app} --oneline | xargs deis config:set --app #{dest_app}
- sh
- end
- end
-
- class Disable < Struct.new :app
- include Helpers
-
- def run
- status "Disabling App: #{app}"
- units = shell('foreman check').strip.sub(/.*\((.*)\)/, "\\1").split(', ')
- scale app, units.each_with_object({}) { |k, h| h[k] = 0 }
- end
-
- end
-
- class Enable < Struct.new :app
- include Helpers
-
- def run
- status "Enabling App: #{app}"
- get_units!
- if units.any? { |_, v| v > 0 }
- status "App Already enabled!"
- return
- end
- scale app, units.keys.each_with_object({}) { |k, h| h[k] = 1 }
- status "App enabled!"
- end
-
- end
-
- # 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+(?<migration>[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 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: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
-
-Bundler.with_clean_env do
- DeisUtils.new(ARGV).run
-end
+require 'bundler/setup'
+require_relative '../lib/deis'
+Deis::Runner.new(ARGV).run