Monorepo for Aesthetic.Computer aesthetic.computer
at main 107 lines 3.6 kB view raw
1#!/usr/bin/env bash 2set -euo pipefail 3 4# Deploy AT frontend pages to PDS caddy container. 5# Intended for both local use and CI (GitHub Actions). 6# 7# Required env (or defaults): 8# AT_PDS_HOST (default: 165.227.120.137) 9# AT_PDS_USER (default: root) 10# AT_PDS_SSH_KEY_PATH (default: ~/.ssh/aesthetic_pds) 11# AT_PDS_CONTAINER (default: caddy) 12# AT_PDS_CONTAINER_WEBROOT (default: /data/www) 13# AT_FRONTEND_FILE_MAP (default: at/index.html:index.html;at/user-page.html:user.html;at/media-modal.js:media-modal.js;at/media-records.js:media-records.js) 14# 15# AT_FRONTEND_FILE_MAP format: 16# "repo/source/path:container/target/path;repo/source2:path2" 17 18AT_PDS_HOST="${AT_PDS_HOST:-165.227.120.137}" 19AT_PDS_USER="${AT_PDS_USER:-root}" 20AT_PDS_SSH_KEY_PATH="${AT_PDS_SSH_KEY_PATH:-$HOME/.ssh/aesthetic_pds}" 21AT_PDS_CONTAINER="${AT_PDS_CONTAINER:-caddy}" 22AT_PDS_CONTAINER_WEBROOT="${AT_PDS_CONTAINER_WEBROOT:-/data/www}" 23AT_FRONTEND_FILE_MAP="${AT_FRONTEND_FILE_MAP:-at/index.html:index.html;at/user-page.html:user.html;at/media-modal.js:media-modal.js;at/media-records.js:media-records.js}" 24 25SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 26REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" 27 28trim() { 29 local value="$1" 30 value="${value#"${value%%[![:space:]]*}"}" 31 value="${value%"${value##*[![:space:]]}"}" 32 printf "%s" "${value}" 33} 34 35declare -a SOURCE_FILES=() 36declare -a TARGET_FILES=() 37IFS=';' read -r -a FILE_MAP_ENTRIES <<< "$AT_FRONTEND_FILE_MAP" 38for raw_entry in "${FILE_MAP_ENTRIES[@]}"; do 39 entry="$(trim "$raw_entry")" 40 [[ -z "$entry" ]] && continue 41 42 if [[ "$entry" != *:* ]]; then 43 echo "Invalid AT_FRONTEND_FILE_MAP entry: '$entry' (expected source:target)" >&2 44 exit 1 45 fi 46 47 source_path="$(trim "${entry%%:*}")" 48 target_path="$(trim "${entry#*:}")" 49 local_source="$REPO_ROOT/$source_path" 50 51 if [[ -z "$source_path" || -z "$target_path" ]]; then 52 echo "Invalid AT_FRONTEND_FILE_MAP entry: '$entry' (empty source or target)" >&2 53 exit 1 54 fi 55 56 if [[ ! -f "$local_source" ]]; then 57 echo "Missing source file: $local_source" >&2 58 exit 1 59 fi 60 61 SOURCE_FILES+=("$source_path") 62 TARGET_FILES+=("$target_path") 63done 64 65if [[ "${#SOURCE_FILES[@]}" -eq 0 ]]; then 66 echo "No frontend files configured. Set AT_FRONTEND_FILE_MAP." >&2 67 exit 1 68fi 69 70if [[ ! -f "$AT_PDS_SSH_KEY_PATH" ]]; then 71 echo "Missing SSH key: $AT_PDS_SSH_KEY_PATH" >&2 72 exit 1 73fi 74 75SSH_TARGET="$AT_PDS_USER@$AT_PDS_HOST" 76SSH_OPTS=( 77 -i "$AT_PDS_SSH_KEY_PATH" 78 -o StrictHostKeyChecking=no 79 -o UserKnownHostsFile=/dev/null 80) 81 82STAMP="${GITHUB_SHA:-$(date +%Y%m%d%H%M%S)}" 83REMOTE_DIR="/tmp/at-frontend-${STAMP}" 84 85echo "Deploying AT frontend to ${SSH_TARGET}" 86echo "Uploading staging files..." 87ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "mkdir -p '$REMOTE_DIR'" 88 89for i in "${!SOURCE_FILES[@]}"; do 90 source_path="${SOURCE_FILES[$i]}" 91 target_path="${TARGET_FILES[$i]}" 92 local_source="$REPO_ROOT/$source_path" 93 remote_stage="$REMOTE_DIR/${i}-$(basename "$target_path")" 94 target_dir="$(dirname "$target_path")" 95 96 scp "${SSH_OPTS[@]}" "$local_source" "${SSH_TARGET}:${remote_stage}" 97 if [[ "$target_dir" != "." ]]; then 98 ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "docker exec '${AT_PDS_CONTAINER}' mkdir -p '${AT_PDS_CONTAINER_WEBROOT}/$target_dir'" 99 fi 100 ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "docker cp '$remote_stage' '${AT_PDS_CONTAINER}:${AT_PDS_CONTAINER_WEBROOT}/$target_path'" 101done 102 103ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "rm -rf '$REMOTE_DIR'" 104 105echo "Deployment complete." 106echo "Landing: https://at.aesthetic.computer" 107echo "User page: https://jeffrey.at.aesthetic.computer"