class Shuttle::Strategy

Public Instance Methods

changes_at?(path) click to toggle source
# File lib/shuttle/strategy.rb, line 296
def changes_at?(path)
  result = ssh.run(%{diff -r #{current_path}/#{path} #{release_path}/#{path} 2>/dev/null})
  result.success? ? false : true
end
checkout_code(path=nil) click to toggle source
# File lib/shuttle/strategy.rb, line 150
def checkout_code(path=nil)
  # Trigger hook before checking out code
  execute_hook(:before_checkout_code)

  checkout_path = [release_path, path].compact.join('/')
  res = ssh.run("cp -a #{scm_path} #{checkout_path}")
  
  if res.failure?
    error "Failed to checkout code. Reason: #{res.output}"
  else
    ssh.run("cd #{release_path} && rm -rf $(find . -name .git)")
    ssh.run("cd #{release_path} && rm -rf $(find . -name .svn)")
  end

  # Trigger hook after checking out code
  execute_hook(:after_checkout_code)
end
cleanup_release() click to toggle source

Delete current session release

# File lib/shuttle/strategy.rb, line 208
def cleanup_release
  if ssh.directory_exists?(release_path)
    ssh.run("rm -rf #{release_path}")
  end
end
cleanup_releases() click to toggle source
# File lib/shuttle/strategy.rb, line 214
def cleanup_releases
  ssh.run("cd #{deploy_path('releases')}")
  ssh.run("count=`ls -1d [0-9]* | sort -rn | wc -l`")

  count = ssh.capture("echo $count")

  unless count.empty?
    num = Integer(count) - Integer(keep_releases)

    if num > 0
      log "Cleaning up old releases: #{num}" if num > 1

      ssh.run("remove=$((count > #{keep_releases} ? count - #{keep_releases} : 0))")
      ssh.run("ls -1d [0-9]* | sort -rn | tail -n $remove | xargs rm -rf {}")
    end
  end
end
connect() click to toggle source
# File lib/shuttle/strategy.rb, line 288
def connect
  exec("ssh #{target.user}@#{target.host}")
end
debug?() click to toggle source
# File lib/shuttle/strategy.rb, line 305
def debug?
  ENV["SHUTTLE_DEBUG"] ? true : false
end
deploy() click to toggle source
# File lib/shuttle/strategy.rb, line 20
def deploy
  setup
  update_code
  checkout_code
  link_release
  cleanup_releases
end
deploy_running?() click to toggle source
# File lib/shuttle/strategy.rb, line 284
def deploy_running?
  ssh.file_exists?("#{deploy_path}/.lock")
end
disable_history() click to toggle source
# File lib/shuttle/strategy.rb, line 252
def disable_history
  ssh.run("set +o history")
end
execute_commands(commands = [], allow_failures = false) click to toggle source
# File lib/shuttle/strategy.rb, line 301
def execute_commands(commands = [], allow_failures = false)
  Shuttle::Hook.new(self).run(commands, allow_failures)
end
execute_hook(name, allow_failures = false) click to toggle source
# File lib/shuttle/strategy.rb, line 278
def execute_hook(name, allow_failures = false)
  if config.hooks && config.hooks[name]
    execute_commands(config.hooks[name], allow_failures)
  end
end
export_environment() click to toggle source
# File lib/shuttle/strategy.rb, line 256
def export_environment
  ssh.export_hash(
    'DEPLOY_APP'          => config.app.name,
    'DEPLOY_APPLICATION'  => config.app.name,
    'DEPLOY_USER'         => target.user,
    'DEPLOY_PATH'         => deploy_path,
    'DEPLOY_RELEASE'      => version,
    'DEPLOY_RELEASE_PATH' => release_path,
    'DEPLOY_CURRENT_PATH' => current_path,
    'DEPLOY_SHARED_PATH'  => shared_path,
    'DEPLOY_SCM_PATH'     => scm_path
  )

  if config.env?
    log "Exporting environment variables"

    config.env.each_pair do |k, v|
      ssh.export(k, v)
    end
  end
end
keep_releases() click to toggle source
# File lib/shuttle/strategy.rb, line 292
def keep_releases
  config.app.keep_releases || 10
end
release_lock() click to toggle source
# File lib/shuttle/strategy.rb, line 203
def release_lock
  ssh.run("rm #{deploy_path}/.lock")
end
rollback() click to toggle source
# File lib/shuttle/strategy.rb, line 28
def rollback
  execute_hook(:before_rollback)

  if last_version == 0
    error "There are no releases to rollback to"
  end

  release = available_releases.select { |v| v == last_version-1 }.first

  if release
    if ssh.run("unlink #{current_path}").failure?
      ssh.run("rm -rf #{current_path}")
    end

    if ssh.run("ln -s #{deploy_path}/releases/#{release} #{current_path}").failure?
      error "Unable to create symlink to current path"
    end

    ssh.run("echo #{release} > #{version_path}")
    ssh.run("rm -rf #{deploy_path}/releases/#{last_version}")

    log "Rolled back to release v#{release}"
  else
    error "There are no older releases"
  end

  execute_hook(:after_rollback)
end
setup() click to toggle source
# File lib/shuttle/strategy.rb, line 5
def setup
  log "Preparing application structure"

  execute_hook(:before_setup)

  ssh.run "mkdir -p #{deploy_path}"
  ssh.run "mkdir -p #{deploy_path('releases')}"
  ssh.run "mkdir -p #{deploy_path('shared')}"
  ssh.run "mkdir -p #{shared_path('tmp')}"
  ssh.run "mkdir -p #{shared_path('pids')}"
  ssh.run "mkdir -p #{shared_path('log')}"

  execute_hook(:after_setup)
end
update_code() click to toggle source
# File lib/shuttle/strategy.rb, line 57
def update_code
  if config.app.svn
    return update_code_svn
  end

  error "Git is not installed" if !git_installed?
  error "Git source url is not defined. Please define :git option first" if config.app.git.nil?

  branch = config.app.branch || 'master'

  if ssh.directory_exists?(scm_path)
    # Check if git remote has changed
    current_remote = git_remote
    
    if current_remote != config.app.git
      log("Git remote change detected. Using #{config.app.git}", 'warning')

      res = ssh.run("cd #{scm_path} && git remote rm origin && git remote add origin #{config.app.git}")
      if res.failure?
        error("Failed to change git remote: #{res.output}")
      end
    end

    log "Fetching latest code"
    res = ssh.run "cd #{scm_path} && git pull origin #{branch}"

    if res.failure?
      error "Unable to fetch latest code: #{res.output}"
    end
  else
    log "Cloning repository #{config.app.git}"
    res = ssh.run "cd #{deploy_path} && git clone --depth 25 --recursive --quiet #{config.app.git} scm"

    if res.failure?
      error "Failed to clone repository: #{res.output}"
    end
  end

  ssh.run("cd #{scm_path} && git fetch")

  # Make sure to pull changes from current non-master branch
  if branch != 'master'
    ssh.run("cd #{scm_path} && git pull origin #{branch}")
  end

  log "Using branch '#{branch}'"
  result = ssh.run("cd #{scm_path} && git checkout -m #{branch}")

  if result.failure?
    error "Failed to checkout #{branch}: #{result.output}"
  end

  if ssh.file_exists?("#{scm_path}/.gitmodules")
    log "Updating git submodules"
    result = ssh.run("cd #{scm_path} && git submodule update --init --recursive")

    if result.failure?
      error "Failed to update submodules: #{result.output}"
    end
  end
end
update_code_svn() click to toggle source
# File lib/shuttle/strategy.rb, line 119
def update_code_svn
  error "Subversion is not installed" if !svn_installed?
  error "Subversion source is not defined. Please define :svn option first" if config.app.svn.nil?

  url = URI.parse(config.app.svn)
  repo_url = "#{url.scheme}://#{url.host}#{url.path}"

  opts = ["--non-interactive", "--quiet"]

  if url.user
    opts << "--username #{url.user}"
    opts << "--password #{url.password}" if url.password
  end

  if ssh.directory_exists?(scm_path)
    log "Fetching latest code"

    res = ssh.run("cd #{scm_path} && svn up #{opts.join(' ')}")
    if res.failure?
      error "Unable to fetch latest code: #{res.output}"
    end
  else
    log "Cloning repository #{config.app.svn}"
    res = ssh.run("cd #{deploy_path} && svn checkout #{opts.join(' ')} #{repo_url} scm")

    if res.failure?
      error "Failed to clone repository: #{res.output}"
    end
  end
end
write_lock() click to toggle source
# File lib/shuttle/strategy.rb, line 199
def write_lock
  ssh.run(%{echo #{deployer_hostname} > #{deploy_path}/.lock})
end
write_release() click to toggle source
# File lib/shuttle/strategy.rb, line 248
def write_release
  ssh.run("echo #{version} > #{release_path}/RELEASE")
end
write_revision() click to toggle source
# File lib/shuttle/strategy.rb, line 232
def write_revision
  if ssh.directory_exists?(deploy_path('scm'))
    command = nil

    if config.app.git
      command = "git log --format='%H' -n 1"
    elsif config.app.svn
      command = "svn info |grep Revision: |cut -c11-"
    end

    if command
      ssh.run("cd #{scm_path} && #{command} > #{release_path}/REVISION")
    end
  end
end