public
Last active

  • Download Gist
1 hello.md
Markdown

Deployer thing

Super cheapo Capistrano replacement. Inspired by github.com/cyx/tell.
This is more of a proof-of-concept than production-grade code... be sure you scrutinize it before you use it.

Contents:

  • deploy.yml (the config file)
  • deploy.rb (the deployer itself)

Usage

./deploy.rb production    # Deploys to production servers

Example output

$ ./deploy.rb production

server1.myapp.com$ git pull
  ...done.

server1.myapp.com$ rake cdn:propogate
  Sending new assets to Akamai...
  done.

server1.myapp.com$ thin restart
  Restarting thin.

server2.myapp.com$ git pull
  ...
  ...
  ...etc
2 deploy.yml
YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
# This is the config file describing the servers.
#
# This describes a cluster that looks like this:
#
# - 3 production servers (server1.myapp.com ... server3.myapp.com)
# - 1 development server (dev.myapp.com)
# - 1 test server (test.myapp.com)
#
# With this setup, you can:
#
# ./deploy.rb production # Deploys to server1 to server3.myapp.com
# ./deploy.rb test # Deploys to test.myapp.com
#
production.1: &production
host: server1.myapp.com
deploy:
- "git pull"
- "rake cdn:propogate"
- "sudo thin restart"
 
# Notice how these take advantage of YAML's inheritance
production.2:
<<: *production
host: server2.myapp.com
 
production.3:
<<: *production
host: server2.myapp.com
 
development: &dev
host: dev.myapp.com
deploy:
- "git pull"
- "touch tmp/restart.txt"
 
test:
<<: *dev
host: test.myapp.com
identity: id_rsa.pub
login: rsc
# ^-- not supported, but support for these can easily be added in as
# an exercise to the reader.
3 deploy.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#!/usr/bin/env ruby
 
# The deployer class.
#
# Basic usage:
#
# d = Deployer.new yaml_filename
# d.run!('production') # deploys to servers matching production*
#
class Deployer
include Process
 
def initialize(file='deploy.yml')
require 'yaml'
@data = YAML::load_file(file)
end
 
# Deploys to given hosts matching /to/.
def run!(to, options={})
select(to).each do |(key, data)|
host = data['host'] || key
fork?(options[:fork]) {
data['deploy'].each { |cmd| tell host, cmd }
}
end
 
wait if options[:fork]
end
 
# Forks if the given parameter is truthy; else, runs as is.
def fork?(fork_it)
fork_it ? fork { yield } : yield
end
 
# Tells a server `host` to do a command `cmd`.
def tell(host, cmd)
log host, cmd
system "ssh #{host} -- #{cmd}"
end
 
# Logs something to stdout.
def log(host, cmd)
c1 = "\033[0;30m"
c2 = "\033[0m"
puts "\n#{c1}%s$#{c2} %s" % [ host, cmd ]
end
 
# Returns servers matching the spec given in `to`.
def select(to)
@data.select { |(key, data)| key.match(/^#{to}/) }
end
end
 
if $0 == __FILE__
if ARGV.size < 0
$stderr << "Usage: $0 <to>\n"
exit
end
 
Deployer.new.run! ARGV[0]
 
# Yes if you've noticed: you can add `, :fork => true` to the end of
# the previous line to do the deployments in parallel.
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.