Mercurial
view hg-web/deploy.sh @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | c5129452493e |
| children |
line wrap: on
line source
#!/usr/bin/env bash set -Eeuo pipefail SERVICE_NAME="${SERVICE_NAME:-hg_web_server.service}" SERVICE_USER="${SERVICE_USER:-hg_web_server}" SERVICE_GROUP="${SERVICE_GROUP:-zenbu_team}" DEPLOY_ROOT="${DEPLOY_ROOT:-/opt/hg_web_server}" ACTIVE_PATH="${ACTIVE_PATH:-${DEPLOY_ROOT}/active}" NEW_PATH="${NEW_PATH:-${DEPLOY_ROOT}/new}" BACKUP_PATH="${BACKUP_PATH:-${DEPLOY_ROOT}/previous}" REPOSITORY_PATH="${REPOSITORY_PATH:-${DEPLOY_ROOT}/repository}" REPOSITORY_NEW_PATH="${REPOSITORY_NEW_PATH:-${DEPLOY_ROOT}/repository-new}" HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:6970/}" HG_ALLOW_PUSH="${HG_ALLOW_PUSH:-false}" MANAGE_NGINX="${MANAGE_NGINX:-auto}" NGINX_SERVER_NAME="${NGINX_SERVER_NAME:-zenbu.babocoder.com}" NGINX_SITE_NAME="${NGINX_SITE_NAME:-hg-web}" NGINX_SITE_AVAILABLE="${NGINX_SITE_AVAILABLE:-/etc/nginx/sites-available/${NGINX_SITE_NAME}}" NGINX_SITE_ENABLED="${NGINX_SITE_ENABLED:-/etc/nginx/sites-enabled/${NGINX_SITE_NAME}}" workspace="${BUILD_WORKSPACE_DIRECTORY:-$(cd "$(dirname "$0")/.." && pwd)}" cd "$workspace" if [[ ! -d "$workspace/.hg" ]]; then echo "Run deployment from a Zenbu Mercurial workspace." >&2 exit 1 fi DEPLOY_ROOT="$(realpath -m "$DEPLOY_ROOT")" ACTIVE_PATH="$(realpath -m "$ACTIVE_PATH")" NEW_PATH="$(realpath -m "$NEW_PATH")" BACKUP_PATH="$(realpath -m "$BACKUP_PATH")" REPOSITORY_PATH="$(realpath -m "$REPOSITORY_PATH")" REPOSITORY_NEW_PATH="$(realpath -m "$REPOSITORY_NEW_PATH")" if [[ ! "$DEPLOY_ROOT" =~ ^/opt/[A-Za-z0-9._/-]+$ ]]; then echo "DEPLOY_ROOT must be a dedicated directory below /opt." >&2 exit 1 fi declare -A deployment_paths=() for path in \ "$ACTIVE_PATH" \ "$NEW_PATH" \ "$BACKUP_PATH" \ "$REPOSITORY_PATH" \ "$REPOSITORY_NEW_PATH"; do if [[ "$path" != "$DEPLOY_ROOT/"* ]]; then echo "Deployment path escapes DEPLOY_ROOT: $path" >&2 exit 1 fi if [[ -n "${deployment_paths[$path]:-}" ]]; then echo "Deployment paths must be distinct: $path" >&2 exit 1 fi deployment_paths["$path"]=1 done if [[ ! "$SERVICE_USER" =~ ^[A-Za-z0-9._-]+$ || ! "$SERVICE_GROUP" =~ ^[A-Za-z0-9._-]+$ || ! "$SERVICE_NAME" =~ ^[A-Za-z0-9._@-]+$ || ! "$HG_ALLOW_PUSH" =~ ^(true|false)$ ]]; then echo "Invalid systemd deployment setting." >&2 exit 1 fi if [[ -n "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then if [[ -n "${RUNFILES_DIR:-}" ]]; then source "$RUNFILES_DIR/bazel_tools/tools/bash/runfiles/runfiles.bash" elif [[ -n "${RUNFILES_MANIFEST_FILE:-}" ]]; then runfiles_library="$( grep -sm1 '^bazel_tools/tools/bash/runfiles/runfiles.bash ' \ "$RUNFILES_MANIFEST_FILE" | cut -d' ' -f2- )" source "$runfiles_library" elif [[ -d "$0.runfiles" ]]; then RUNFILES_DIR="$0.runfiles" export RUNFILES_DIR source "$RUNFILES_DIR/bazel_tools/tools/bash/runfiles/runfiles.bash" elif [[ -f "$0.runfiles_manifest" ]]; then RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" export RUNFILES_MANIFEST_FILE runfiles_library="$( grep -sm1 '^bazel_tools/tools/bash/runfiles/runfiles.bash ' \ "$RUNFILES_MANIFEST_FILE" | cut -d' ' -f2- )" source "$runfiles_library" else echo "Bazel runfiles are unavailable." >&2 exit 1 fi bundle_dir="$(rlocation _main/hg-web/hg_web_server_bundle)" nginx_template="$(rlocation _main/hg-web/nginx/hg-web.conf.template)" service_template="$(rlocation _main/hg-web/systemd/hg-web.service.template)" else bazel build -c opt //hg-web:hg_web_server_bundle bundle_dir="bazel-bin/hg-web/hg_web_server_bundle" nginx_template="hg-web/nginx/hg-web.conf.template" service_template="hg-web/systemd/hg-web.service.template" fi NGINX_SITE_TEMPLATE="${NGINX_SITE_TEMPLATE:-$nginx_template}" rendered_nginx="$(mktemp)" rendered_service="$(mktemp)" service_backup="$(mktemp)" repository_bundle="$(mktemp)" release_id="$(date -u +%Y%m%dT%H%M%SZ)-$$" promotion_prepared=0 service_changed=0 service_had_previous=0 service_was_enabled=0 nginx_site_created=0 nginx_link_created=0 lock_acquired=0 cleanup() { rm -f \ "$rendered_nginx" \ "$rendered_service" \ "$service_backup" \ "$repository_bundle" } 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 return 1 } restore_host_configuration() { local restore_failed=0 if [[ "$nginx_link_created" -eq 1 ]]; then sudo rm -f "$NGINX_SITE_ENABLED" || restore_failed=1 fi if [[ "$nginx_site_created" -eq 1 ]]; then sudo rm -f "$NGINX_SITE_AVAILABLE" || restore_failed=1 fi if [[ "$nginx_link_created" -eq 1 || "$nginx_site_created" -eq 1 ]]; then if sudo nginx -t; then sudo systemctl reload nginx || restore_failed=1 else restore_failed=1 fi fi if [[ "$service_changed" -eq 1 ]]; then if [[ "$service_had_previous" -eq 1 ]]; then sudo install -o root -g root -m 0644 \ "$service_backup" "/etc/systemd/system/$SERVICE_NAME" || restore_failed=1 else sudo rm -f "/etc/systemd/system/$SERVICE_NAME" || restore_failed=1 fi sudo systemctl daemon-reload || restore_failed=1 if [[ "$service_was_enabled" -eq 1 ]]; then sudo systemctl enable "$SERVICE_NAME" >/dev/null || restore_failed=1 else sudo systemctl disable "$SERVICE_NAME" >/dev/null 2>&1 || true fi fi if [[ "$restore_failed" -ne 0 ]]; then echo "Host configuration rollback needs manual attention." >&2 fi return 0 } rollback() { trap - ERR INT TERM EXIT if [[ "$lock_acquired" -eq 1 ]]; then restore_host_configuration if [[ "$promotion_prepared" -eq 1 ]]; then if [[ -d "$BACKUP_PATH" ]]; then sudo rm -rf "$ACTIVE_PATH" sudo mv "$BACKUP_PATH" "$ACTIVE_PATH" sudo systemctl restart "$SERVICE_NAME" || true elif sudo test -f "$ACTIVE_PATH/.hg-web-release" && [[ "$(sudo cat "$ACTIVE_PATH/.hg-web-release")" == "$release_id" ]]; then sudo rm -rf "$ACTIVE_PATH" sudo systemctl stop "$SERVICE_NAME" || true fi fi sudo rm -rf "$NEW_PATH" sudo rm -rf "$REPOSITORY_NEW_PATH" fi cleanup exit 1 } trap rollback ERR INT TERM trap cleanup EXIT deploy_user="$(id -un)" sudo install -d -o "$deploy_user" -g "$SERVICE_GROUP" -m 0755 "$DEPLOY_ROOT" exec 9>"$DEPLOY_ROOT/deploy.lock" if ! flock -n 9; then echo "Another hg-web deployment is already running." >&2 exit 1 fi lock_acquired=1 sudo rm -rf "$NEW_PATH" sudo cp -a "$bundle_dir" "$NEW_PATH" sudo chown -R "$deploy_user:$SERVICE_GROUP" "$NEW_PATH" printf '%s\n' "$release_id" > "$NEW_PATH/.hg-web-release" bundled_hg="$NEW_PATH/third_party/mercurial/runtime/bin/hg" test -x "$NEW_PATH/hg_web_server" test -x "$NEW_PATH/hg-web/run_hg_web" test -x "$bundled_hg" if [[ -e "$REPOSITORY_PATH" && ! -d "$REPOSITORY_PATH/.hg" ]]; then echo "REPOSITORY_PATH exists but is not a Mercurial repository." >&2 exit 1 fi if [[ ! -d "$REPOSITORY_PATH/.hg" ]]; then sudo rm -rf "$REPOSITORY_NEW_PATH" HGRCPATH= "$bundled_hg" clone \ --noupdate --pull "$workspace" "$REPOSITORY_NEW_PATH" sudo chown -R "$SERVICE_USER:$SERVICE_GROUP" "$REPOSITORY_NEW_PATH" sudo mv "$REPOSITORY_NEW_PATH" "$REPOSITORY_PATH" else HGRCPATH= "$bundled_hg" --repository "$workspace" \ bundle --all "$repository_bundle" sudo chown "$deploy_user:$SERVICE_GROUP" "$repository_bundle" chmod 0640 "$repository_bundle" sudo -u "$SERVICE_USER" env HGRCPATH= \ "$bundled_hg" --repository "$REPOSITORY_PATH" \ pull "$repository_bundle" fi sudo -u "$SERVICE_USER" env HGRCPATH= \ "$bundled_hg" --repository "$REPOSITORY_PATH" verify sudo chown -R "$SERVICE_USER:$SERVICE_GROUP" "$NEW_PATH" sed \ -e "s|__SERVICE_USER__|${SERVICE_USER}|g" \ -e "s|__SERVICE_GROUP__|${SERVICE_GROUP}|g" \ -e "s|__ACTIVE_PATH__|${ACTIVE_PATH}|g" \ -e "s|__HG_ALLOW_PUSH__|${HG_ALLOW_PUSH}|g" \ -e "s|__REPOSITORY_PATH__|${REPOSITORY_PATH}|g" \ "$service_template" > "$rendered_service" if sudo test -f "/etc/systemd/system/$SERVICE_NAME"; then sudo cat "/etc/systemd/system/$SERVICE_NAME" > "$service_backup" chmod 0600 "$service_backup" service_had_previous=1 fi if sudo systemctl is-enabled --quiet "$SERVICE_NAME"; then service_was_enabled=1 fi service_changed=1 sudo install -o root -g root -m 0644 \ "$rendered_service" "/etc/systemd/system/$SERVICE_NAME" sudo systemctl daemon-reload manage_nginx=0 case "$MANAGE_NGINX" in 1|true|yes) manage_nginx=1 ;; 0|false|no) ;; auto) if command -v nginx >/dev/null 2>&1 && [[ -d /etc/nginx/sites-available && -d /etc/nginx/sites-enabled ]]; then manage_nginx=1 fi ;; *) echo "MANAGE_NGINX must be auto, true, or false." >&2 exit 1 ;; esac if [[ "$manage_nginx" -eq 1 && ! -e "$NGINX_SITE_AVAILABLE" && ! -L "$NGINX_SITE_AVAILABLE" ]]; then if [[ ! "$NGINX_SERVER_NAME" =~ ^[A-Za-z0-9.-]+$ ]]; then echo "Invalid NGINX_SERVER_NAME: $NGINX_SERVER_NAME" >&2 exit 1 fi if [[ ! -f "$NGINX_SITE_TEMPLATE" ]]; then echo "Nginx template not found: $NGINX_SITE_TEMPLATE" >&2 exit 1 fi sed "s/__SERVER_NAME__/${NGINX_SERVER_NAME}/g" \ "$NGINX_SITE_TEMPLATE" > "$rendered_nginx" sudo install -D -o root -g root -m 0644 \ "$rendered_nginx" "$NGINX_SITE_AVAILABLE" nginx_site_created=1 sudo ln -s "$NGINX_SITE_AVAILABLE" "$NGINX_SITE_ENABLED" nginx_link_created=1 sudo nginx -t sudo systemctl reload nginx elif [[ "$manage_nginx" -eq 1 && ! -e "$NGINX_SITE_ENABLED" && ! -L "$NGINX_SITE_ENABLED" ]]; then sudo ln -s "$NGINX_SITE_AVAILABLE" "$NGINX_SITE_ENABLED" nginx_link_created=1 sudo nginx -t sudo systemctl reload nginx elif [[ "$manage_nginx" -eq 1 ]]; then echo "Nginx site already exists; leaving it unchanged." fi sudo rm -rf "$BACKUP_PATH" promotion_prepared=1 if [[ -e "$ACTIVE_PATH" || -L "$ACTIVE_PATH" ]]; then sudo mv "$ACTIVE_PATH" "$BACKUP_PATH" fi sudo mv "$NEW_PATH" "$ACTIVE_PATH" sudo systemctl enable "$SERVICE_NAME" >/dev/null sudo systemctl restart "$SERVICE_NAME" if ! health_check; then echo "hg-web health check failed." >&2 rollback fi sudo rm -rf "$BACKUP_PATH" trap - ERR INT TERM EXIT cleanup echo "Deployment complete: $ACTIVE_PATH"