Publish deployment and backup scripts

This commit is contained in:
2026-04-11 00:21:08 +02:00
parent 86204e0836
commit 9de9acec48
27 changed files with 3709 additions and 206 deletions

199
deploy Executable file
View File

@@ -0,0 +1,199 @@
#!/usr/bin/env bash
# ==============================================================================
# Unified Deploy Wrapper
# ==============================================================================
# Auto-discovers deploy-{docker,local}-*.sh scripts in the same directory and
# dispatches to them with a shorter CLI interface.
#
# Usage:
# deploy.sh # List available services
# deploy.sh mattermost # Deploy via docker (default)
# deploy.sh -l paperclip # Deploy via local (bare-metal)
# deploy.sh --local hermes --domain h.an2.io # Local deploy with flags
# deploy.sh -r mattermost # --remove
# deploy.sh -r -p mattermost # --remove --purge
# deploy.sh -r -p -y mattermost # --remove --purge --yes
# deploy.sh web --domain w.an2.io --dir acme # Pass-through flags
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
# ── Discover available deploy scripts ────────────────────────────────────────
# Builds two associative arrays:
# DOCKER_SCRIPTS[service] = script_path
# LOCAL_SCRIPTS[service] = script_path
# And a sorted list of unique service names.
declare -A DOCKER_SCRIPTS=()
declare -A LOCAL_SCRIPTS=()
declare -a ALL_SERVICES=()
discover_scripts() {
local script basename method service
for script in "${SCRIPT_DIR}"/deploy-docker-*.sh "${SCRIPT_DIR}"/deploy-local-*.sh; do
[[ -f "$script" ]] || continue
basename="$(basename "$script" .sh)" # deploy-docker-hermes
method="${basename#deploy-}" # docker-hermes
method="${method%%-*}" # docker or local
service="${basename#deploy-${method}-}" # hermes
case "$method" in
docker) DOCKER_SCRIPTS["$service"]="$script" ;;
local) LOCAL_SCRIPTS["$service"]="$script" ;;
esac
done
# Build sorted unique service list
local -A seen=()
for s in "${!DOCKER_SCRIPTS[@]}" "${!LOCAL_SCRIPTS[@]}"; do
seen["$s"]=1
done
IFS=$'\n' read -r -d '' -a ALL_SERVICES < <(printf '%s\n' "${!seen[@]}" | sort && printf '\0') || true
}
# ── Usage / list ─────────────────────────────────────────────────────────────
print_usage() {
echo ""
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
echo -e "${CYAN} Deploy — Unified Wrapper${NC}"
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
echo ""
echo -e " ${BOLD}Usage:${NC} deploy.sh [flags] <service>"
echo ""
echo -e " ${BOLD}Flags:${NC}"
echo -e " ${GREEN}--local, -l${NC} Use bare-metal (local) deploy instead of Docker"
echo -e " ${GREEN}--remove, -r${NC} Remove the service (keep data)"
echo -e " ${GREEN}--purge, -p${NC} Delete all data (requires --remove)"
echo -e " ${GREEN}--yes, -y${NC} Skip confirmations"
echo -e " ${GREEN}--domain <fqdn>${NC} Set the service domain"
echo -e " ${GREEN}--dir <name>${NC} Instance directory (for web)"
echo -e " ${GREEN}--cold${NC} Cold backup mode (passed through)"
echo ""
echo -e " ${BOLD}Available services:${NC}"
echo ""
# Table header
printf " ${DIM}%-16s %-8s %-8s${NC}\n" "SERVICE" "DOCKER" "LOCAL"
printf " ${DIM}%-16s %-8s %-8s${NC}\n" "───────────────" "────────" "────────"
for service in "${ALL_SERVICES[@]}"; do
local d_mark l_mark
if [[ -n "${DOCKER_SCRIPTS[$service]+x}" ]]; then
d_mark="${GREEN} ✓${NC}"
else
d_mark="${DIM} —${NC}"
fi
if [[ -n "${LOCAL_SCRIPTS[$service]+x}" ]]; then
l_mark="${GREEN} ✓${NC}"
else
l_mark="${DIM} —${NC}"
fi
printf " %-16s %b %b\n" "$service" "$d_mark" "$l_mark"
done
echo ""
echo -e " ${BOLD}Examples:${NC}"
echo -e " ${DIM}deploy.sh mattermost${NC} # Docker deploy"
echo -e " ${DIM}deploy.sh -l paperclip --domain clip.an2.io${NC} # Local deploy"
echo -e " ${DIM}deploy.sh -r -p gitea${NC} # Remove + purge"
echo -e " ${DIM}deploy.sh web --domain w.an2.io --dir acme${NC} # Multi-instance"
echo ""
}
# ── Main ─────────────────────────────────────────────────────────────────────
discover_scripts
# Parse wrapper flags — separate them from pass-through flags
USE_LOCAL=0
SERVICE=""
PASSTHROUGH=()
while [[ $# -gt 0 ]]; do
case "$1" in
--local|-l)
USE_LOCAL=1
shift
;;
--remove|-r)
PASSTHROUGH+=("--remove")
shift
;;
--purge|-p)
PASSTHROUGH+=("--purge")
shift
;;
--yes|-y)
PASSTHROUGH+=("--yes")
shift
;;
--domain)
PASSTHROUGH+=("--domain" "$2")
shift 2
;;
--dir)
PASSTHROUGH+=("--dir" "$2")
shift 2
;;
--cold)
PASSTHROUGH+=("--cold")
shift
;;
-*)
# Unknown flag — pass through
PASSTHROUGH+=("$1")
shift
;;
*)
if [[ -z "$SERVICE" ]]; then
SERVICE="$1"
else
# Extra positional — pass through
PASSTHROUGH+=("$1")
fi
shift
;;
esac
done
# No service specified — show usage
if [[ -z "$SERVICE" ]]; then
print_usage
exit 0
fi
# Resolve script
TARGET_SCRIPT=""
if (( USE_LOCAL )); then
if [[ -n "${LOCAL_SCRIPTS[$SERVICE]+x}" ]]; then
TARGET_SCRIPT="${LOCAL_SCRIPTS[$SERVICE]}"
else
echo -e "${RED}[FAIL]${NC} No local deploy script for '${SERVICE}'."
if [[ -n "${DOCKER_SCRIPTS[$SERVICE]+x}" ]]; then
echo -e " A Docker variant exists — run without ${GREEN}-l${NC}."
fi
exit 1
fi
else
if [[ -n "${DOCKER_SCRIPTS[$SERVICE]+x}" ]]; then
TARGET_SCRIPT="${DOCKER_SCRIPTS[$SERVICE]}"
elif [[ -n "${LOCAL_SCRIPTS[$SERVICE]+x}" ]]; then
echo -e "${YELLOW}[WARN]${NC} No Docker variant for '${SERVICE}' — using local."
TARGET_SCRIPT="${LOCAL_SCRIPTS[$SERVICE]}"
else
echo -e "${RED}[FAIL]${NC} Unknown service '${SERVICE}'."
echo ""
echo -e " Available: ${ALL_SERVICES[*]}"
exit 1
fi
fi
# Dispatch
exec bash "$TARGET_SCRIPT" "${PASSTHROUGH[@]}"