#!/usr/bin/env bash
#
#   npm run deploy:prod      ship the package made by `npm run build:prod`:
#                            upload it, move the server's code to the same
#                            commit, back up the live build, swap, restart pm2,
#                            check the site answers (undone automatically if not)
#   npm run deploy:rollback  swap the server back to the previous release
#
# Nothing is built here - that is build:prod's job - so what ships is exactly
# what was built and tested. Nothing on the server changes until every check
# on this side has passed.
#
# Needs an SSH alias for the server in ~/.ssh/config (see DEPLOY.md).

set -euo pipefail

# Per-app settings - the only lines that differ between the two repos.
APP_DIR="/var/www/html/wedig-strapi"
LOCAL_BRANCH="master"
SERVER_BRANCH="master"
OUT_DIR=".deploy"
DEPLOY_HOST="${DEPLOY_HOST:-wedigtech-prod}"

cd "$(git -C "$(dirname "$0")" rev-parse --show-toplevel)"
step() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
fail() { printf '\n\033[1;31mSTOPPED: %s\033[0m\n' "$*" >&2; exit 1; }

# DEPLOY_HOST=local runs the server half against a folder on this machine -
# how these scripts are tested without touching production.
[[ "$DEPLOY_HOST" == "local" ]] && APP_DIR="${DEPLOY_LOCAL_DIR:?set DEPLOY_LOCAL_DIR}"
remote() {
  if [[ "$DEPLOY_HOST" == "local" ]]; then bash -s -- "$@" < scripts/remote-release.sh
  else ssh "$DEPLOY_HOST" "bash -s -- $(printf '%q ' "$@")" < scripts/remote-release.sh; fi
}
upload() {
  if [[ "$DEPLOY_HOST" == "local" ]]; then cp "$1" "$2"
  else scp -q "$1" "$DEPLOY_HOST:$2"; fi
}

step "Checking the connection to $DEPLOY_HOST"
if [[ "$DEPLOY_HOST" != "local" ]]; then
  ssh -o BatchMode=yes -o ConnectTimeout=10 "$DEPLOY_HOST" true 2>/dev/null \
    || fail "Cannot SSH to '$DEPLOY_HOST'. Set up the alias in ~/.ssh/config (DEPLOY.md, step 1)."
fi

if [[ "${1:-}" == "--rollback" ]]; then
  remote rollback "$APP_DIR" "$SERVER_BRANCH"
  exit 0
fi

step "Checking the package"
[[ -f "$OUT_DIR/release.env" ]] || fail "Nothing built yet. Run: npm run build:prod"
# shellcheck disable=SC1091
source "$OUT_DIR/release.env"
[[ -f "$ARCHIVE" ]] || fail "$ARCHIVE is missing. Run: npm run build:prod"
[[ "$SHA" == "$(git rev-parse HEAD)" ]] \
  || fail "The package was built from ${SHA:0:7}, but you are now on $(git rev-parse --short HEAD). Run: npm run build:prod"
[[ -z "$(git status --porcelain --untracked-files=no)" ]] || fail "Uncommitted changes - commit, build:prod, then deploy."
echo "Package: $(git log --oneline -1 "$SHA")  (built $BUILT_AT)"

step "Checking GitLab"
[[ "$(git branch --show-current)" == "$LOCAL_BRANCH" ]] || fail "Deploy from $LOCAL_BRANCH."
git fetch -q origin "$LOCAL_BRANCH" "$SERVER_BRANCH"
[[ "$SHA" == "$(git rev-parse "origin/$LOCAL_BRANCH")" ]] \
  || fail "This commit is not on GitLab yet (or you are behind it). git push / git pull first - the server pulls the code from GitLab."
if [[ "$(git rev-parse "origin/$SERVER_BRANCH")" != "$SHA" ]]; then
  git merge-base --is-ancestor "origin/$SERVER_BRANCH" "$SHA" \
    || fail "origin/$SERVER_BRANCH has commits that $LOCAL_BRANCH does not. Merge them first."
  echo "Bringing origin/$SERVER_BRANCH up to $LOCAL_BRANCH"
  git push -q origin "$LOCAL_BRANCH:$SERVER_BRANCH"
fi

step "Uploading $(du -h "$ARCHIVE" | cut -f1)"
REMOTE_ARCHIVE="/tmp/$(basename "$ARCHIVE")"
upload "$ARCHIVE" "$REMOTE_ARCHIVE"

step "Releasing on the server"
remote release "$APP_DIR" "$SERVER_BRANCH" "$SHA" "$REMOTE_ARCHIVE"

printf '\n\033[1;32mDone: %s is live.\033[0m  Undo with: npm run deploy:rollback\n' "$(git log --oneline -1)"
