115 lines
3.7 KiB
Bash
115 lines
3.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
|
||
|
|
set -Eeuo pipefail
|
||
|
|
|
||
|
|
REMOTE="${BLISS_DEPLOY_REMOTE:-root@134.122.14.193}"
|
||
|
|
APP_DIR="${BLISS_DEPLOY_APP_DIR:-/home/nodejs/bliss2}"
|
||
|
|
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
|
|
LOCAL_BRANCH="${BLISS_DEPLOY_BRANCH:-main}"
|
||
|
|
TRANSFER_DIR="$(mktemp -d)"
|
||
|
|
CONTROL_SOCKET="$TRANSFER_DIR/ssh-control"
|
||
|
|
LOCAL_BUNDLE="$TRANSFER_DIR/bliss.bundle"
|
||
|
|
|
||
|
|
cleanup() {
|
||
|
|
ssh -S "$CONTROL_SOCKET" -O exit "$REMOTE" >/dev/null 2>&1 || true
|
||
|
|
rm -rf "$TRANSFER_DIR"
|
||
|
|
}
|
||
|
|
trap cleanup EXIT
|
||
|
|
|
||
|
|
echo "Updating $REMOTE:$APP_DIR"
|
||
|
|
echo "You may be prompted for the droplet passcode."
|
||
|
|
|
||
|
|
git -C "$ROOT_DIR" rev-parse --verify "$LOCAL_BRANCH" >/dev/null
|
||
|
|
echo "Bundling committed local branch $LOCAL_BRANCH..."
|
||
|
|
git -C "$ROOT_DIR" bundle create "$LOCAL_BUNDLE" "$LOCAL_BRANCH"
|
||
|
|
|
||
|
|
ssh -M -S "$CONTROL_SOCKET" -o ControlPersist=60 -o ConnectTimeout=15 -fnNT "$REMOTE"
|
||
|
|
REMOTE_BUNDLE="$(ssh -S "$CONTROL_SOCKET" "$REMOTE" mktemp /tmp/bliss-deploy.XXXXXX.bundle)"
|
||
|
|
scp -q -o ControlPath="$CONTROL_SOCKET" "$LOCAL_BUNDLE" "$REMOTE:$REMOTE_BUNDLE"
|
||
|
|
|
||
|
|
ssh -S "$CONTROL_SOCKET" "$REMOTE" bash -s -- "$APP_DIR" "$REMOTE_BUNDLE" "$LOCAL_BRANCH" <<'REMOTE_SCRIPT'
|
||
|
|
set -Eeuo pipefail
|
||
|
|
|
||
|
|
APP_DIR="$1"
|
||
|
|
DEPLOY_BUNDLE="$2"
|
||
|
|
DEPLOY_BRANCH="$3"
|
||
|
|
cleanup_bundle() {
|
||
|
|
rm -f "$DEPLOY_BUNDLE"
|
||
|
|
}
|
||
|
|
trap cleanup_bundle EXIT
|
||
|
|
|
||
|
|
cd "$APP_DIR"
|
||
|
|
|
||
|
|
test -f package.json || { echo "No package.json in $APP_DIR" >&2; exit 1; }
|
||
|
|
test -d .git || { echo "$APP_DIR is not a Git checkout" >&2; exit 1; }
|
||
|
|
|
||
|
|
if [[ -n "$(git status --porcelain --untracked-files=no)" ]]; then
|
||
|
|
echo "Refusing to pull: the deployed checkout has uncommitted tracked changes:" >&2
|
||
|
|
git status --short --untracked-files=no >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
OLD_HEAD="$(git rev-parse HEAD)"
|
||
|
|
OLD_LOCK="$(sha256sum package-lock.json 2>/dev/null | awk '{print $1}' || true)"
|
||
|
|
|
||
|
|
echo "Pulling Git changes..."
|
||
|
|
git fetch "$DEPLOY_BUNDLE" "$DEPLOY_BRANCH"
|
||
|
|
git merge --ff-only FETCH_HEAD
|
||
|
|
|
||
|
|
NEW_HEAD="$(git rev-parse HEAD)"
|
||
|
|
NEW_LOCK="$(sha256sum package-lock.json 2>/dev/null | awk '{print $1}' || true)"
|
||
|
|
|
||
|
|
if [[ ! -d node_modules || "$OLD_LOCK" != "$NEW_LOCK" ]]; then
|
||
|
|
echo "Installing production dependencies..."
|
||
|
|
if [[ -f package-lock.json ]]; then
|
||
|
|
npm ci --omit=dev
|
||
|
|
else
|
||
|
|
npm install --omit=dev
|
||
|
|
fi
|
||
|
|
else
|
||
|
|
echo "Dependencies unchanged; skipping npm install."
|
||
|
|
fi
|
||
|
|
|
||
|
|
mapfile -t APP_PIDS < <(
|
||
|
|
for process_dir in /proc/[0-9]*; do
|
||
|
|
[[ "$(readlink "$process_dir/cwd" 2>/dev/null || true)" == "$APP_DIR" ]] || continue
|
||
|
|
[[ "$(cat "$process_dir/comm" 2>/dev/null || true)" == "node" ]] || continue
|
||
|
|
basename "$process_dir"
|
||
|
|
done
|
||
|
|
)
|
||
|
|
|
||
|
|
if [[ "${#APP_PIDS[@]}" -eq 0 ]]; then
|
||
|
|
echo "No running Node process found for $APP_DIR; refusing to guess how to start it." >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
APP_PID="${APP_PIDS[0]}"
|
||
|
|
SERVICE=""
|
||
|
|
|
||
|
|
while IFS= read -r unit; do
|
||
|
|
[[ -n "$unit" ]] || continue
|
||
|
|
if [[ "$(systemctl show -p MainPID --value "$unit" 2>/dev/null || true)" == "$APP_PID" ]]; then
|
||
|
|
SERVICE="$unit"
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
done < <(systemctl list-units --type=service --all --no-legend --plain 2>/dev/null | awk '{print $1}')
|
||
|
|
|
||
|
|
if [[ -n "$SERVICE" ]]; then
|
||
|
|
echo "Restarting systemd service $SERVICE..."
|
||
|
|
systemctl restart "$SERVICE"
|
||
|
|
systemctl is-active --quiet "$SERVICE"
|
||
|
|
systemctl --no-pager --full status "$SERVICE" | sed -n '1,12p'
|
||
|
|
elif command -v pm2 >/dev/null 2>&1 && pm2 pid all 2>/dev/null | grep -qx "$APP_PID"; then
|
||
|
|
echo "Restarting PM2 process $APP_PID..."
|
||
|
|
pm2 restart "$APP_PID" --update-env
|
||
|
|
pm2 show "$APP_PID"
|
||
|
|
else
|
||
|
|
echo "Found Node PID $APP_PID, but it is not managed by systemd or PM2." >&2
|
||
|
|
echo "The code was updated from $OLD_HEAD to $NEW_HEAD, but the process was not restarted." >&2
|
||
|
|
echo "Refusing to kill it without knowing the correct startup mechanism." >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "Deployment updated successfully: $OLD_HEAD -> $NEW_HEAD"
|
||
|
|
REMOTE_SCRIPT
|