deploy.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# ============================================================================
# vFusion deploy script
# ============================================================================
# Runs on the docker host. Pulls latest code from GitHub, renders .env from
# .env.tpl using the 1Password service account token, and rebuilds + recreates
# the stack.
#
# Prerequisites on the deploy host:
# 1. `op` (1Password) CLI installed
# 2. /etc/op-token exists (root:docker 0640) with a 1Password service
# account token scoped to the vault holding this app's secrets.
# 3. This repo cloned somewhere on the host.
#
# Usage (run from anywhere — the script locates its own directory):
# ./deploy.sh # rebuild all services
# ./deploy.sh backend worker # rebuild specific services only
# ============================================================================
set -euo pipefail
# Resolve the repo root from the script's own location so this works
# wherever the repo is cloned, with no hardcoded host path.
SERVICE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TOKEN_FILE="/etc/op-token"
ENV_FILE="${SERVICE_DIR}/.env"
ENV_TEMPLATE="${SERVICE_DIR}/.env.tpl"
SERVICES=("$@")
# ---- Pre-flight checks ----
if ! command -v docker >/dev/null 2>&1; then
echo "ERROR: 'docker' not found in PATH." >&2
exit 1
fi
# The 1Password path is optional. A host that manages .env by hand (the
# common case if you don't use a secrets manager) just needs the .env to
# exist — only the templated path needs `op` and the service-account token.
USE_OP=0
if [[ -f "$ENV_TEMPLATE" ]]; then
USE_OP=1
if ! command -v op >/dev/null 2>&1; then
echo "ERROR: ${ENV_TEMPLATE} exists but the 'op' CLI is not in PATH." >&2
echo "Install the 1Password CLI, or delete .env.tpl and manage .env by hand." >&2
exit 1
fi
if [[ ! -r "$TOKEN_FILE" ]]; then
echo "ERROR: ${TOKEN_FILE} is not readable by $(id -un)." >&2
echo "Expected: root:docker, mode 0640." >&2
exit 1
fi
elif [[ ! -f "$ENV_FILE" ]]; then
echo "ERROR: neither ${ENV_TEMPLATE} nor ${ENV_FILE} exists." >&2
echo "Create .env (copy .env.example and fill it in), or add a .env.tpl" >&2
echo "with 1Password secret references to have this script render it." >&2
exit 1
fi
# ---- Load service account token ----
if [[ "$USE_OP" -eq 1 ]]; then
export OP_SERVICE_ACCOUNT_TOKEN
OP_SERVICE_ACCOUNT_TOKEN="$(cat "$TOKEN_FILE")"
fi
cd "$SERVICE_DIR"
# ---- Pull latest code ----
echo "==> Pulling latest from git..."
git pull --ff-only
echo
# ---- Render .env from template ----
if [[ "$USE_OP" -eq 1 ]]; then
echo "==> Rendering .env from .env.tpl via 1Password..."
op inject --force -i "$ENV_TEMPLATE" -o "$ENV_FILE"
chmod 600 "$ENV_FILE"
echo " wrote $ENV_FILE ($(wc -c < "$ENV_FILE") bytes, mode 600)"
else
echo "==> No .env.tpl — using the existing $ENV_FILE as-is."
chmod 600 "$ENV_FILE"
fi
echo
# ---- Rebuild and recreate ----
echo "==> Rebuilding and recreating containers..."
export CACHEBUST="$(date +%s)"
if [[ ${#SERVICES[@]} -gt 0 ]]; then
docker compose build "${SERVICES[@]}"
docker compose up -d "${SERVICES[@]}"
else
docker compose build
docker compose up -d
fi
echo
# ---- Follow logs ----
echo "==> Deploy complete. Tailing logs (Ctrl+C to exit)..."
echo
if [[ ${#SERVICES[@]} -gt 0 ]]; then
exec docker compose logs -f --tail=50 "${SERVICES[@]}"
else
exec docker compose logs -f --tail=50
fi