| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 | #!/usr/bin/env bash## deploy(1) - Minimalistic shell script to deploy Git repositories.# Released under the MIT License.## https://github.com/visionmedia/deploy#VERSION="0.6.0"CONFIG=./deploy.confLOG=/tmp/pm2-deploy-${USER:-default}.logFORCE=0REF=ENV=## Read PIPED JSON#read conf## 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    -f, --force          skip local change checking  Commands:    setup                run remote setup commands    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 [ref]            deploy [ref]EOF}## Abort with <msg>#abort() {  echo  echo "  $@" 1>&2  echo  exit 1}## Log <msg>.#log() {  echo "  ○ $@"}## Get config value by <key>.#config_get() {    local key=$1    echo $(expr "$conf" : '.*"'$key'":"\([^"]*\)"')}## Output version.#version() {  echo $VERSION}## Return the ssh command to run.#ssh_command() {  local user="`config_get user`"  if test -n "$user"; then      local url="$user@`config_get host`"  else      local url="`config_get host`"  fi  local unexpanded_key="`config_get key`"  local key="${unexpanded_key/#\~/$HOME}"  local forward_agent="`config_get forward-agent`"  local port="`config_get port`"  local needs_tty="`config_get needs_tty`"  local ssh_options="`config_get ssh_options`"  test -n "$forward_agent" && local agent="-A"  test -n "$key" && local identity="-i $key"  test -n "$port" && local port="-p $port"  test -n "$needs_tty" && local tty="-t"  test -n "ssh_options" && local ssh_opts="$ssh_options"  echo "ssh $ssh_opts $tty $agent $port $identity $url"}## Run the given remote <cmd>.#runRemote() {  local shell="`ssh_command`"  echo $shell "\"$@\"" >> $LOG  $shell $@}## Run the given local <cmd>.#runLocal() {  echo "\"$@\"" >> $LOG  /usr/bin/env bash -c "$*"}## Run the given <cmd> either locally or remotely#run() {  local host="`config_get host`"  if [[ $host == localhost ]]  then    runLocal $@  else    runRemote $@  fi}## Output config or [key].#config() {    echo $(expr "$conf" : '.*"$key":"\([^"]*\)"')}## 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}## Pre Setup hook runs on the host before the actual setup runs# multiple commands or a script#hook_pre_setup() {  local cmd=`config_get pre-setup`  if test -n "$cmd"; then    local is_script=($cmd)    if [ -f "${is_script[0]}" ]; then      log "executing pre-setup script \`$cmd\`"      local shell="`ssh_command`"      runLocal "$shell 'bash -s' -- < $cmd"    else      log "executing pre-setup \`$cmd\`"      run "$cmd"    fi    test $? -eq 0  else    log hook pre-setup  fi}## Run setup.#setup() {  local path=`config_get path`  local repo=`config_get repo`  local ref=`config_get ref`  local fetch=`config_get fetch`  local branch=${ref#*/}  hook_pre_setup || abort pre-setup hook failed  run "mkdir -p $path/{shared/{logs,pids},source}"  test $? -eq 0 || abort setup paths failed  log running setup  log cloning $repo  if test "$fetch" != "fast"; then    log "full fetch"    run "git clone --branch $branch $repo $path/source"  else    log "fast fetch"    run "git clone --depth=5 --branch $branch $repo $path/source"  fi  test $? -eq 0 || abort failed to clone  run "ln -sfn $path/source $path/current"  test $? -eq 0 || abort symlink failed  hook post-setup || abort post-setup hook failed  log setup complete}## Deploy [ref].#deploy() {  local ref=$1  local branch=$2  if test -z "$branch"; then    branch=${ref#*/}  fi  local path=`config_get path`  local fetch=`config_get fetch`  log "deploying ${ref}"  # 1- Execute local commands  log executing pre-deploy-local  local pdl=`config_get pre-deploy-local`  runLocal $pdl || abort pre-deploy-local hook failed  # 2- Execute pre deploy commands on remote server  hook pre-deploy || abort pre-deploy hook failed  # 3- Fetch updates  log fetching updates  if test "$fetch" != "fast"; then      log "full fetch"      run "cd $path/source && git fetch --all --tags"  else      log "fast fetch"      run "cd $path/source && git fetch --depth=5 --all --tags"  fi  test $? -eq 0 || abort fetch failed  # 4- If no reference retrieve shorthand name for the remote repo  if test -z "$ref"; then    log fetching latest tag    ref=`run "cd $path/source && git for-each-ref \      --sort=-*authordate \      --format='%(refname)' \      --count=1 | cut -d '/' -f 3"`    test $? -eq 0 || abort failed to determine latest tag  fi  # 5- Reset to ref  log resetting HEAD to $ref  run "cd $path/source && git reset --hard $ref"  test $? -eq 0 || abort git reset failed  # 6- 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 HEAD\` \      >> $path/.deploys"  test $? -eq 0 || abort deploy log append failed  hook post-deploy || abort post-deploy hook failed  # 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 "tac $path/.deploys | awk '{printf \"%d\t%s\n\", NR-1, \$0}'"}## 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"}## Ensure all changes are committed and pushed before deploying.#check_for_local_changes() {  local path=`config_get path`  if [ $FORCE -eq 1 ]  then      return  fi  git --no-pager diff --exit-code --quiet          || abort "commit or stash your changes before deploying"  git --no-pager diff --exit-code --quiet --cached || abort "commit your staged changes before deploying"  [ -z "`git rev-list @{upstream}.. -n 1`" ]       || abort "push your changes before deploying"}# parse argvwhile test $# -ne 0; do  arg=$1; shift  case $arg in    -h|--help) usage; exit ;;    -V|--version) version; exit ;;    -C|--chdir) log cd $1; cd $1; shift ;;    -F|--force) FORCE=1 ;;    run|exec)  run "cd `config_get path`/current && $@"; exit ;;    console)  console; exit ;;    curr|current)  current_commit; exit ;;    prev|previous)  nth_deploy_commit 2; exit ;;    revert)  revert_to ${1-1}; exit ;;    setup)  setup $@; exit ;;    list)  list_deploys; exit ;;    config) config $@; exit ;;    ref) REF=$1; BRANCH=$2 ;;  esacdonecheck_for_local_changesecho# deploydeploy "${REF:-`config_get ref`}" "${BRANCH}"
 |