class Deploku::Remote

Attributes

force[R]
maintenance[R]
remote[R]

Public Class Methods

new(remote) click to toggle source
# File lib/deploku/remote.rb, line 8
def initialize(remote)
  @remote = remote
end

Public Instance Methods

add_migration(hash) click to toggle source
# File lib/deploku/remote.rb, line 168
def add_migration(hash)
  @migrations ||= []
  migration = @migrations.detect {|m| m.version == hash[:version] } || Deploku::Migration.new(version: hash[:version])
  if hash[:location] == :local
    migration.local_status = hash[:status]
  else
    migration.remote_status = hash[:status]
  end
  @migrations << migration
end
ahead() click to toggle source
# File lib/deploku/remote.rb, line 37
def ahead
  @ahead ||= count_rev_list("..#{remote_commit}")
end
app_name() click to toggle source
# File lib/deploku/remote.rb, line 12
def app_name
  @app_name ||= begin
    output = run_command("git remote -v | grep #{remote} | grep push")
    if output =~ /git@/
      output.match(/heroku[^:]*:(.*)\.git/)[1]
    else
      output.match(/\/\/[^\/]+\/(.*)\.git/)[1]
    end
  end
end
behind() click to toggle source
# File lib/deploku/remote.rb, line 33
def behind
  @behind ||= count_rev_list("#{remote_commit}..")
end
count_rev_list(range) click to toggle source
# File lib/deploku/remote.rb, line 41
def count_rev_list(range)
  run_command("git rev-list #{range}").split("\n").size
end
database_configured?() click to toggle source
# File lib/deploku/remote.rb, line 28
def database_configured?
  return @database_configured if defined? @database_configured
  @database_configured = test_command("bundle exec rake db:migrate:status")
end
deploy(args) click to toggle source
# File lib/deploku/remote.rb, line 84
def deploy(args)
  status(args)
  @force = !!args.delete("force")
  if args.delete("maintenance")
    @maintenance = :use
  elsif args.delete("maintenance:skip")
    @maintenance = :skip
  end
  if args.any?
    puts "Unknown argument(s): #{args.join(", ")}"
    exit 1
  end
  puts "The following command#{'s' if deploy_commands.size > 1} will be run:"
  puts
  deploy_commands.each_with_index do |command, index|
    puts "  #{index + 1}. #{command}"
  end
  repeat = true
  while repeat
    repeat = false
    print "\nChoose:\nD = deploy, or\nL = list commits to deploy, or\nanything else to abort: "
    proceed = STDIN.getch.upcase
    puts proceed
    if proceed == "D"
      puts ""
      deploy_commands.each_with_index do |command, index|
        puts "  #{index + 1}. #{command} ..."
        run_command command
      end
      puts
    elsif proceed == "L"
      puts "\nList of commits between #{remote_commit.slice(0, 7)} and local branch\n"
      run_command "git log --oneline #{remote_commit}..", :echo
      repeat = true
    else
      puts "Abort"
    end
  end
end
deploy_commands() click to toggle source
# File lib/deploku/remote.rb, line 124
def deploy_commands
  return @deploy_commands if @deploy_commands
  maintenance_mode = false
  list = []
  if migration_required?
    case maintenance
    when :use
      maintenance_mode = true
    when :skip
      # OK, nothing to do
    else
      puts "There are migrations to run. Please either choose maintenance or maintenance:skip"
      exit 1
    end
  end
  list << "heroku maintenance:on --app #{app_name}" if maintenance_mode
  list << "git push#{force ? " --force" : ""} #{remote} #{local_branch}:master"
  list << "heroku run rake db:migrate --app #{app_name}" if migration_required?
  list << "heroku restart --app #{app_name}" if migration_required?
  list << "heroku maintenance:off --app #{app_name}" if maintenance_mode
  @deploy_commands = list
end
extract_migrations(output, location) click to toggle source
# File lib/deploku/remote.rb, line 187
def extract_migrations(output, location)
  output.split("\n").
    select {|line|
      line =~ /^\s*(up|down)/
    }.map {|line|
      values = line.split(" ")
      add_migration(
        location: location,
        version: values[1],
        status: values[0],
      )
    }
end
local_branch() click to toggle source
# File lib/deploku/remote.rb, line 151
def local_branch
  @local_branch ||= run_command("git symbolic-ref HEAD").chomp.sub(/^\/?refs\/heads\//, '')
end
local_migrations() click to toggle source
# File lib/deploku/remote.rb, line 179
def local_migrations
  @local_migrations ||= extract_migrations(run_command("bundle exec rake db:migrate:status"), :local)
end
migration_required?() click to toggle source
# File lib/deploku/remote.rb, line 147
def migration_required?
  database_configured? && pending_migration_count > 0
end
migrations() click to toggle source
# File lib/deploku/remote.rb, line 159
def migrations
  local_migrations && remote_migrations # Triggers building of @migrations
  @migrations.sort_by(&:version)
end
pending_migration_count() click to toggle source
# File lib/deploku/remote.rb, line 155
def pending_migration_count
  pending_migrations.size
end
pending_migrations() click to toggle source
# File lib/deploku/remote.rb, line 164
def pending_migrations
  migrations.select(&:pending?)
end
remote_commit() click to toggle source
# File lib/deploku/remote.rb, line 45
def remote_commit
  @remote_commit ||= run_command("git ls-remote #{remote} 2> /dev/null").chomp.split(' ').first
end
remote_commit_exists_locally?() click to toggle source
# File lib/deploku/remote.rb, line 23
def remote_commit_exists_locally?
  return @remote_commit_exists_locally if defined? @remote_commit_exists_locally
  @remote_commit_exists_locally = test_command("git show #{remote_commit}")
end
remote_migrations() click to toggle source
# File lib/deploku/remote.rb, line 183
def remote_migrations
  @remote_migrations ||= extract_migrations(run_command("heroku run rake db:migrate:status --app #{app_name}"), :remote)
end
status(args) click to toggle source
# File lib/deploku/remote.rb, line 49
def status(args)
  puts "Looking up current status for #{remote}"
  puts "Heroku app #{app_name} is running commit #{remote_commit.slice(0, 7)}"
  if remote_commit_exists_locally?
    if behind == 0 && ahead == 0
      puts "It is up to date"
    else
      if ahead == 0
        puts "It is #{behind} commit#{"s" if behind > 1} behind your local #{local_branch} branch"
      elsif behind == 0
        puts "It is #{ahead} commit#{"s" if ahead > 1} ahead of your local #{local_branch} branch"
      else
        puts "It is #{behind} commit#{"s" if behind > 1} behind and #{ahead} commit#{"s" if ahead > 1} ahead of your local #{local_branch} branch"
      end
    end
  else
    puts "Warning! The commit #{remote_commit.slice(0, 7)} is not present in the local repo. Why?"
  end
  if database_configured?
    case pending_migration_count
    when 0
      puts "There are no pending migrations"
    when 1
      puts "There is 1 pending migration"
    else
      puts "There are #{pending_migration_count} pending migrations"
    end
    if pending_migration_count > 0
      pending_migrations.each do |migration|
        puts migration
      end
    end
  end
end