Skip to content

Instantly share code, notes, and snippets.

@tj
Created May 24, 2011 22:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tj/989926 to your computer and use it in GitHub Desktop.
Save tj/989926 to your computer and use it in GitHub Desktop.
start of deployment script
key /path/to/whatever.pem
user deployer-of-doom
addr n.n.n.n
repo git@github.com:visionmedia/express.git
path /path/to/www/whatever
branch origin/master
command /path/to/www/whatever/restart
#!/usr/bin/env bash
VERSION="0.0.1"
CONFIG=./deploy.conf
LOG=/tmp/deploy.log
ENV=
WD=.
#
# Output usage information.
#
usage() {
cat <<-EOF
Usage: deploy [options] <env> [command]
Options:
-C, --chdir <path> change the working directory to <path>
-c, --config <path> set config path defaults to ./deploy.conf
-V, --version output program version
-h, --help output help information
Commands:
setup run remote setup commands
deploy [rev] deploy to [rev] or HEAD
revert [n] revert to [n]th last deployment or 1
config [key] output config file or [key]
curr[ent] output current release commit
prev[ious] output previous release commit
exec|run <cmd> execute the given <cmd>
list list previous deploy commits
EOF
}
#
# Abort with <msg>
#
abort() {
echo
echo " $@" 1>&2
echo
exit 1
}
#
# Log <msg>.
#
log() {
echo "... $@"
}
#
# Set configuration file <path>.
#
set_config_path() {
test -f $1 || abort 'invalid --config path'
CONFIG=$1
}
#
# Check if config <section> exists.
#
config_section() {
grep "^\[$1" $CONFIG &> /dev/null
}
#
# Get config value by <key>.
#
config_get() {
local key=$1
test -n "$key" \
&& grep "^\[$ENV" -A 20 $CONFIG \
| grep "^$key" \
| head -n 1 \
| cut -d ' ' -f 2
}
#
# Output version.
#
version() {
echo $VERSION
}
#
# Run the given remote <cmd>.
#
run() {
local url="`config_get user`@`config_get addr`"
local key=`config_get key`
if test -n "$key"; then
local shell="ssh -i $key $url"
else
local shell="ssh $url"
fi
echo $shell $@ >> $LOG
$shell $@
}
#
# Output config or [key].
#
config() {
if test $# -eq 0; then
cat $CONFIG
else
config_get $1
fi
}
#
# Run setup.
#
setup() {
local path=`config_get path`
local repo=`config_get repo`
local branch=`config_get branch`
run "mkdir -p $path/{shared/{logs,pids},source}"
log running setup
log cloning $repo
run "git clone $repo $path/source"
log setup complete
}
#
# Deploy <ref>.
#
deploy() {
local ref=$1
local path=`config_get path`
log deploying $ref
# fetch source
run "cd $path/source && git fetch origin && git reset --hard $ref"
# link current
run "ln -sf $path/source $path/current"
# deploy log
run "cd $path/source && \
echo \`git rev-parse --short HEAD\` \
>> $path/.deploys"
# command
local cmd=`config_get command`
if test -n "$cmd"; then
log "executing $ $cmd"
run "cd $path/current && $cmd"
fi
# done
log deploy complete
}
#
# Get current commit.
#
current_commit() {
local path=`config_get path`
run "cd $path/source && \
git rev-parse --short HEAD"
}
#
# Get <n>th deploy commit.
#
nth_deploy_commit() {
local n=$1
local path=`config_get path`
run "cat $path/.deploys | tail -n $n | head -n 1 | cut -d ' ' -f 1"
}
#
# List deploys.
#
list_deploys() {
local path=`config_get path`
run "cat $path/.deploys"
}
#
# Revert to the <n>th last deployment.
#
revert_to() {
local n=$1
log "reverting $((n - 1)) deploy(s)"
local commit=`nth_deploy_commit $n`
deploy $commit
}
#
# Require environment arg.
#
require_env() {
config_section $ENV || abort "[$ENV] config section not defined"
test -z "$ENV" && abort "<env> required"
}
# parse argv
while test $# -ne 0; do
arg=$1; shift
case $arg in
-h|--help) usage; exit ;;
-V|--version) version; exit ;;
-c|--config) set_config_path $1 ;;
-C|--chdir) WD=$1; CONFIG=$WD/deploy.conf ;;
run|exec) require_env; run "cd `config_get path` && $@"; exit ;;
curr|current) require_env; current_commit; exit ;;
prev|previous) require_env; nth_deploy_commit 2; exit ;;
revert) require_env; revert_to ${1-2}; exit ;;
setup) require_env; setup $@; exit ;;
list) require_env; list_deploys; exit ;;
config) config $@; exit ;;
*) ENV=$arg ;;
esac
done
require_env
# chdir
test "$WD" != "." && cd $WD && log cd $WD
# deploy
deploy `config_get branch`
@tj
Copy link
Author

tj commented May 25, 2011

todo

  • use bash script instead of lame field cutting for config
  • defaults for branch
  • optional pk

@indexzero
Copy link

Why not use haibu? Just sayin' is all.

@tj
Copy link
Author

tj commented May 25, 2011

haibu is more for the entire "cloud" no? we still will be using cluster still etc

@tj
Copy link
Author

tj commented May 25, 2011

I've wanted something like for a while, back from when I did ruby stuff with capistrano, there's no reason at all for it to be ruby when a simple shell script will do. it's like using cake instead of make, or rake (pukeee)

@indexzero
Copy link

@visionmedia That's the awesome thing about haibu, it's designed to be a "cloud" of any size (i.e. works well on just one server). Haibu is definitely tailored to node.js applications since it uses the package.json specification, but check out this deployment sample:

On the server
npm install haibu
forever start haibu-server

On the client
https://github.com/nodejitsu/haibu/blob/master/examples/hello-spawn.js

There is a CLI tool coming in the next couple of weeks focused on making haibu as easy as jitsu. Would love your feedback.

@indexzero
Copy link

Oh, also. Cluster and haibu are complementary tools. I'm actually looking for someone to write a cluster plugin for haibu. Happy to give you details if you're interested in checking it out: https://github.com/nodejitsu/haibu/issues/9

@tj
Copy link
Author

tj commented May 25, 2011

i'll have to take a better look at it and see if it would work out :D

@indexzero
Copy link

Cool! Come hang out in #nodejitsu sometime, we've got a small army of developers who are working on it if you want to command them :-D

@tj
Copy link
Author

tj commented May 25, 2011

cool man, I'll check it out sometime soon when i have a minute. so it's not coupled with the load balancer etc?

@rainerborene
Copy link

Most beautiful code in shell script I ever seen. I was searching for something like this these last days. Thanks!

@tj
Copy link
Author

tj commented May 25, 2011

haha thanks man

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment