class Bard::CLI

Public Class Methods

new(*args, **kwargs, &block) click to toggle source
Calls superclass method
# File lib/bard.rb, line 11
def initialize(*args, **kwargs, &block)
  super
  @config = Config.new(project_name, "bard.rb")
end

Public Instance Methods

ci(branch=Git.current_branch) click to toggle source
# File lib/bard.rb, line 89
def ci branch=Git.current_branch
  ci = CI.new(project_name, `git rev-parse #{branch}`.chomp, local: options["local-ci"])
  if ci.exists?
    puts "Continuous integration: starting build on #{branch}..."

    success = ci.run do |elapsed_time, last_time|
      if last_time
        percentage = (elapsed_time.to_f / last_time.to_f * 100).to_i
        output = "  Estimated completion: #{percentage}%"
      else
        output = "  No estimated completion time. Elapsed time: #{elapsed_time} sec"
      end
      print "\x08" * output.length
      print output
      $stdout.flush
    end

    if success
      puts
      puts "Continuous integration: success!"
      if !options["local-ci"] && File.exist?("coverage")
        puts "Downloading test coverage from CI..."
        download_ci_test_coverage
      end
      puts "Deploying..."
    else
      puts
      puts ci.last_response
      puts ci.console
      puts red("Automated tests failed!")
      exit 1
    end

  else
    puts red("No CI found for #{project_name}!")
    puts "Re-run with --skip-ci to bypass CI, if you absolutely must, and know what you're doing."
    exit 1
  end
end
data(from=nil, to="local") click to toggle source
# File lib/bard.rb, line 17
def data(from=nil, to="local")
  from ||= @config.servers.key?(:production) ? "production" : "staging"
  Data.new(self, from, to).call
end
deploy(to=nil) click to toggle source
# File lib/bard.rb, line 39
def deploy to=nil
  branch = Git.current_branch

  if branch == "master"
    run_crucial "git push origin master:master"
    invoke :ci, [branch], options.slice("local-ci") unless options["skip-ci"]

  else
    run_crucial "git fetch origin master:master"

    unless Git.fast_forward_merge?("origin/master", branch)
      puts "The master branch has advanced. Attempting rebase..."
      run_crucial "git rebase origin/master"
    end

    run_crucial "git push -f origin #{branch}:#{branch}"

    invoke :ci, [branch], options.slice("local-ci") unless options["skip-ci"]

    run_crucial "git push origin #{branch}:master"
    run_crucial "git fetch origin master:master"
  end

  if `git remote` =~ /\bgithub\b/
    run_crucial "git push github"
  end

  to ||= @config.servers.key?(:production) ? :production : :staging

  command = "git pull origin master && bin/setup"
  run_crucial ssh_command(to, command)

  puts green("Deploy Succeeded")

  if branch != "master"
    puts "Deleting branch: #{branch}"
    run_crucial "git push --delete origin #{branch}"

    if branch == Git.current_branch
      run_crucial "git checkout master"
    end

    run_crucial "git branch -D #{branch}"
  end

  ping to
end
download_ci_test_coverage() click to toggle source
# File lib/bard.rb, line 197
def download_ci_test_coverage
  rsync :from, :ci, "coverage"
end
hurt(*args) click to toggle source
# File lib/bard.rb, line 137
def hurt *args
  1.upto(Float::INFINITY) do |count|
    puts "Running attempt #{count}"
    system *args
    unless $?.success?
      puts "Ran #{count-1} times before failing"
      break
    end
  end
end
install() click to toggle source
# File lib/bard.rb, line 162
def install
  install_files_path = File.expand_path(File.join(__dir__, "../install_files/*"))
  system "cp #{install_files_path} bin/"
end
master_key(from="production", to="local") click to toggle source
# File lib/bard.rb, line 187
def master_key from="production", to="local"
  if to == "local"
    copy :from, from, "config/master.key"
  end
  if from == "local"
    copy :to, to, "config/master.key"
  end
end
open(server=nil) click to toggle source
# File lib/bard.rb, line 130
def open server=nil
  server ||= @config.servers.key?(:production) ? :production : :staging
  server = @config.servers[server.to_sym]
  exec "xdg-open #{server.default_ping}"
end
ping(server=:production) click to toggle source
# File lib/bard.rb, line 168
def ping server=:production
  server = @config.servers[server.to_sym]
  return false if server.ping == false

  url = server.default_ping
  if server.ping =~ %r{^/}
    url += server.ping
  elsif server.ping.to_s.length > 0
    url = server.ping
  end

  command = "curl -sfL #{url} 2>&1 1>/dev/null"
  unless system command
    puts "#{server.key.to_s.capitalize} is down!"
    exit 1
  end
end
ssh(to=:production) click to toggle source
# File lib/bard.rb, line 150
def ssh to=:production
  command = "exec $SHELL -l"
  if to == "gubs" && !options["home"]
    server = @config.servers[:gubs]
    command = %(bash -lic "exec ./vagrant \\"cd #{server.path} && #{command}\\"")
    exec ssh_command(to, command, home: true)
  else
    exec ssh_command(to, command, home: options["home"])
  end
end
stage(branch=Git.current_branch) click to toggle source
# File lib/bard.rb, line 24
def stage branch=Git.current_branch
  unless @config.servers.key?(:production)
    raise Thor::Error.new("`bard stage` is disabled until a production server is defined. Until then, please use `bard deploy` to deploy to the staging server.")
  end

  run_crucial "git push -u origin #{branch}", true
  command = "git fetch && git checkout -f origin/#{branch} && bin/setup"
  run_crucial ssh_command(:staging, command)
  puts green("Stage Succeeded")

  ping :staging
end
vim() click to toggle source
# File lib/bard.rb, line 202
def vim
  exec "vim -p `git diff master --name-only | grep -v sass$ | tac`"
end

Private Instance Methods

copy(direction, server, path) click to toggle source
# File lib/bard/base.rb, line 40
def copy direction, server, path
  server = @config.servers[server.to_sym]

  uri = URI.parse("ssh://#{server.gateway}")
  port = uri.port ? "-p#{uri.port}" : ""
  gateway = server.gateway ? "-oProxyCommand='ssh #{port} #{uri.user}@#{uri.host} -W %h:%p'" : ""

  uri = URI.parse("ssh://#{server.ssh}")
  port = uri.port ? "-P#{uri.port}" : ""
  from_and_to = [path, "#{uri.user}@#{uri.host}:#{server.path}/#{path}"]

  from_and_to.reverse! if direction == :from
  command = "scp #{gateway} #{port} #{from_and_to.join(" ")}"

  run_crucial command
end
project_name() click to toggle source
# File lib/bard/base.rb, line 24
def project_name
  @project_name ||= File.expand_path(".").split("/").last
end
rsync(direction, server, path) click to toggle source
# File lib/bard/base.rb, line 57
def rsync direction, server, path
  server = @config.servers[server.to_sym]

  uri = URI.parse("ssh://#{server.gateway}")
  port = uri.port ? "-p#{uri.port}" : ""
  gateway = server.gateway ? "-oProxyCommand=\"ssh #{port} #{uri.user}@#{uri.host} -W %h:%p\"" : ""

  uri = URI.parse("ssh://#{server.ssh}")
  port = uri.port ? "-p#{uri.port}" : ""
  ssh = "-e'ssh #{port} #{gateway}'"

  dest_path = path.dup
  dest_path = "./#{dest_path}"
  from_and_to = [dest_path, "#{uri.user}@#{uri.host}:#{server.path}/#{path}"]
  from_and_to.reverse! if direction == :from
  from_and_to[-1].sub! %r(/[^/]+$), '/'

  command = "rsync #{ssh} --delete -avz #{from_and_to.join(" ")}"

  run_crucial command
end
run_crucial(command, verbose = false) click to toggle source
# File lib/bard/base.rb, line 10
def run_crucial(command, verbose = false)
  stdout, stderr, status = Open3.capture3(command)
  failed = status.to_i.nonzero?
  if verbose || failed
    $stdout.puts stdout
    $stderr.puts stderr
  end
  if failed
    puts red("!!! ") + "Running command failed: #{yellow(command)}"
    exit 1
  end
  stdout.chomp
end
ssh_command(server, command, home: false) click to toggle source
# File lib/bard/base.rb, line 28
def ssh_command server, command, home: false
  server = @config.servers[server.to_sym]
  uri = URI.parse("ssh://#{server.ssh}")
  command = "cd #{server.path} && #{command}" unless home
  command = "ssh -tt #{"-p#{uri.port} " if uri.port}#{uri.user}@#{uri.host} '#{command}'"
  if server.gateway
    uri = URI.parse("ssh://#{server.gateway}")
    command = "ssh -tt #{" -p#{uri.port} " if uri.port}#{uri.user}@#{uri.host} \"#{command}\""
  end
  command
end