Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 347 lines (286 sloc) 6.443 kB
#!/usr/bin/env bash
VERSION="0.4.0"
CONFIG=./deploy.conf
LOG=/tmp/deploy.log
TEST=1
REF=
ENV=
#
# 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>
console open an ssh session to the host
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 $@
}
#
# Launch an interactive ssh console session.
#
console() {
local url="`config_get user`@`config_get host`"
local key=`config_get key`
if test -n "$key"; then
local shell="ssh -i $key $url"
else
local shell="ssh $url"
fi
echo $shell
exec $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 ;;
console) require_env; console; 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.