Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 329 lines (270 sloc) 6.081 kb
#!/usr/bin/env bash
VERSION="0.3.2"
CONFIG=./deploy.conf
LOG=/tmp/deploy.log
TEST=1
REF=
ENV=production
#
# 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
-T, --no-tests ignore test hook
-V, --version output program version
-h, --help output help information
Commands:
setup run remote setup commands
update update deploy to the latest release
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
[ref] deploy to [ref], the 'ref' setting, or latest tag
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-999
}
#
# Output version.
#
version() {
echo $VERSION
}
#
# Run the given remote <cmd>.
#
run() {
local url="`config_get user`@`config_get host`"
local key=`config_get key`
if test -n "$key"; then
local shell="ssh -A -i $key $url"
else
local shell="ssh -A $url"
fi
echo $shell "\"$@\"" >> $LOG
$shell $@
}
#
# Output config or [key].
#
config() {
if test $# -eq 0; then
cat $CONFIG
else
config_get $1
fi
}
#
# Execute hook <name> relative to the path configured.
#
hook() {
test -n "$1" || abort hook name required
local hook=$1
local path=`config_get path`
local cmd=`config_get $hook`
if test -n "$cmd"; then
log "executing $hook \`$cmd\`"
run "cd $path/current; \
SHARED=\"$path/shared\" \
$cmd 2>&1 | tee -a $LOG; \
exit \${PIPESTATUS[0]}"
test $? -eq 0
else
log hook $hook
fi
}
#
# Run setup.
#
setup() {
local path=`config_get path`
local repo=`config_get repo`
run "mkdir -p $path/{shared/{logs,pids},source}"
test $? -eq 0 || abort setup paths failed
log running setup
log cloning $repo
run "git clone $repo $path/source"
test $? -eq 0 || abort failed to clone
log setup complete
}
#
# Deploy [ref].
#
deploy() {
local ref=$1
local path=`config_get path`
log deploying
hook pre-deploy || abort pre-deploy hook failed
# fetch source
log fetching updates
run "cd $path/source && git fetch --all"
test $? -eq 0 || abort fetch failed
# latest tag
if test -z "$ref"; then
log fetching latest tag
ref=`run "cd $path/source && git for-each-ref refs/tags \
--sort=-authordate \
--format='%(refname)' \
--count=1 | cut -d '/' -f 3"`
test $? -eq 0 || abort failed to determine latest tag
fi
# reset HEAD
log resetting HEAD to $ref
run "cd $path/source && git reset --hard $ref"
test $? -eq 0 || abort git reset failed
# link current
run "ln -sfn $path/source $path/current"
test $? -eq 0 || abort symlink failed
# deploy log
run "cd $path/source && \
echo \`git rev-parse --short HEAD\` \
>> $path/.deploys"
test $? -eq 0 || abort deploy log append failed
hook post-deploy || abort post-deploy hook failed
if test $TEST -eq 1; then
hook test
if test $? -ne 0; then
log tests failed, reverting deploy
quickly_revert_to 1 && log "revert complete" && exit
fi
else
log ignoring tests
fi
# done
log successfully deployed $ref
}
#
# 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, ignoring tests.
#
quickly_revert_to() {
local n=$1
log "quickly reverting $n deploy(s)"
local commit=`nth_deploy_commit $((n + 1))`
TEST=0 deploy "$commit"
}
#
# Revert to the <n>th last deployment.
#
revert_to() {
local n=$1
log "reverting $n deploy(s)"
local commit=`nth_deploy_commit $((n + 1))`
deploy "$commit"
}
#
# Require environment arg.
#
require_env() {
config_section $ENV || abort "[$ENV] config section not defined"
test -z "$ENV" && abort "<env> required"
}
#
# Update deploy.
#
update() {
log "updating deploy(1)"
rm -fr /tmp/deploy
git clone git://github.com/visionmedia/deploy.git \
--depth 0 \
/tmp/deploy \
&> /tmp/deploy.log \
&& cd /tmp/deploy \
&& make install \
&& log "updated $VERSION -> `./bin/deploy --version`"
}
# 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; shift ;;
-C|--chdir) log cd $1; cd $1; shift ;;
-T|--no-tests) TEST=0 ;;
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-1}; exit ;;
setup) require_env; setup $@; exit ;;
list) require_env; list_deploys; exit ;;
update) update; exit ;;
config) config $@; exit ;;
*)
if test -z "$ENV"; then
ENV=$arg;
else
REF="$REF $arg";
fi
;;
esac
done
require_env
# deploy
deploy "${REF:-`config_get ref`}"
Jump to Line
Something went wrong with that request. Please try again.