diff hg-web/deploy.sh @ 221:ce7f4400c2de hg-web

[hg-web] Harden forge and add changeset UI
author MrJuneJune <me@mrjunejune.com>
date Sun, 02 Aug 2026 09:01:24 -0700
parents 4de2fb74ce82
children 8bb0ac8f4587
line wrap: on
line diff
--- a/hg-web/deploy.sh	Sun Aug 02 08:34:54 2026 -0700
+++ b/hg-web/deploy.sh	Sun Aug 02 09:01:24 2026 -0700
@@ -1,15 +1,82 @@
-#!/bin/bash
-# sudo groupadd zenbu_team -- already added
-# sudo useradd -r -s /usr/sbin/nologin -G zenbu_team hg_web_server
+#!/usr/bin/env bash
+set -Eeuo pipefail
+
+SERVICE_NAME="${SERVICE_NAME:-hg_web_server.service}"
+RELEASE_ROOT="${RELEASE_ROOT:-/opt/hg_web_server_releases}"
+ACTIVE_PATH="${ACTIVE_PATH:-/opt/hg_web_server_bundle_active}"
+HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:6970/}"
+SERVICE_USER="${SERVICE_USER:-hg_web_server}"
+SERVICE_GROUP="${SERVICE_GROUP:-zenbu_team}"
+
+workspace="$(hg root)"
+cd "$workspace"
+
+revision="$(hg log -r . -T '{node|short}')"
+release_name="${revision}-$(date -u +%Y%m%dT%H%M%SZ)"
+release_dir="${RELEASE_ROOT}/${release_name}"
+staging_dir="${RELEASE_ROOT}/.${release_name}.tmp"
+next_link="${ACTIVE_PATH}.next"
+bundle_dir="bazel-bin/hg-web/hg_web_server_bundle"
+previous_release=""
+promoted=0
+
+health_check() {
+  for _ in $(seq 1 20); do
+    if curl --fail --silent --max-time 3 "$HEALTH_URL" >/dev/null; then
+      return 0
+    fi
+    sleep 1
+  done
+  echo "Health check failed: $HEALTH_URL" >&2
+  return 1
+}
+
+point_active_at() {
+  local target="$1"
+  sudo rm -f "$next_link"
+  sudo ln -s "$target" "$next_link"
+  sudo mv -Tf "$next_link" "$ACTIVE_PATH"
+}
+
+rollback() {
+  trap - ERR
+  if [[ "$promoted" -eq 1 && -n "$previous_release" && -d "$previous_release" ]]; then
+    echo "Deployment failed; rolling back to $previous_release" >&2
+    point_active_at "$previous_release"
+    sudo systemctl restart "$SERVICE_NAME"
+    health_check || echo "Rollback completed, but the health check still fails." >&2
+  else
+    echo "Deployment failed and no previous release is available for rollback." >&2
+  fi
+  sudo rm -rf "$staging_dir"
+  exit 1
+}
+trap rollback ERR
+
 bazel build -c opt //hg-web:hg_web_server_bundle
 
-# Create
-sudo cp -a bazel-bin/hg-web/hg_web_server_bundle /opt/hg_web_server_bundle_new
-sudo chown -R hg_web_server:zenbu_team /opt/hg_web_server_bundle_new
+sudo install -d -o root -g "$SERVICE_GROUP" -m 0755 "$RELEASE_ROOT"
+sudo rm -rf "$staging_dir"
+sudo install -d -o "$SERVICE_USER" -g "$SERVICE_GROUP" -m 0755 "$staging_dir"
+sudo cp -a "${bundle_dir}/." "$staging_dir/"
+sudo chown -R "$SERVICE_USER:$SERVICE_GROUP" "$staging_dir"
+
+sudo test -x "$staging_dir/hg_web_server"
+sudo test -f "$staging_dir/hg-web/src/index.html"
+sudo test -f "$staging_dir/hg-web/src/page.js"
+sudo mv "$staging_dir" "$release_dir"
 
-# Swap
-sudo rm -rf /opt/hg_web_server_bundle_active
-sudo mv /opt/hg_web_server_bundle_new /opt/hg_web_server_bundle_active
+if [[ -L "$ACTIVE_PATH" ]]; then
+  previous_release="$(readlink -f "$ACTIVE_PATH")"
+elif [[ -d "$ACTIVE_PATH" ]]; then
+  previous_release="${RELEASE_ROOT}/legacy-$(date -u +%Y%m%dT%H%M%SZ)"
+  sudo mv "$ACTIVE_PATH" "$previous_release"
+fi
 
-sudo systemctl restart hg_web_server.service
-echo "Deployment complete!"
+point_active_at "$release_dir"
+promoted=1
+sudo systemctl restart "$SERVICE_NAME"
+health_check
+
+trap - ERR
+echo "Deployment complete: $release_dir"