Cloning from the prod directory made SHA fetches fail, and APP_HOST_PORT 18180 collided with production Reverb.
173 lines
6.3 KiB
Bash
Executable File
173 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# One-time bootstrap for the AndyTranscribe staging instance on z00.
|
|
# Creates ~/andyTranscibe-stage, a unique .env, the stage Caddy Docker network,
|
|
# and the Gitea STAGE_DEPLOY_PATHS secret.
|
|
set -euo pipefail
|
|
|
|
GITEA_DIR="${GITEA_DIR:-${HOME}/gitea}"
|
|
REPO_OWNER="${REPO_OWNER:-ben}"
|
|
REPO_NAME="${REPO_NAME:-AndyTranscribe}"
|
|
REGISTRY_HOST="${REGISTRY_HOST:-gitea.z00.nu}"
|
|
STAGE_PATH="${STAGE_PATH:-${HOME}/andyTranscibe-stage}"
|
|
GITEA_REPO_URL="https://${REGISTRY_HOST}/${REPO_OWNER}/${REPO_NAME}.git"
|
|
STAGE_URL="${STAGE_URL:-https://stage.transcribe.z00.nu}"
|
|
REVERB_PUBLIC_HOST="${REVERB_PUBLIC_HOST:-reverb.stage.transcribe.z00.nu}"
|
|
CONTAINER_PREFIX="${CONTAINER_PREFIX:-andytranscribe-stage}"
|
|
CADDY_NETWORK="${CADDY_NETWORK:-andytranscribe-stage-caddy}"
|
|
PROD_CADDY_NETWORK="${PROD_CADDY_NETWORK:-caddy-proxy-manager-test_caddy-test-network}"
|
|
CADDY_CONTAINER="${CADDY_CONTAINER:-}"
|
|
CREDENTIALS_FILE="${GITEA_DIR}/.credentials"
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
upsert_env() {
|
|
local file="$1"
|
|
local key="$2"
|
|
local value="$3"
|
|
python3 - "$file" "$key" "$value" <<'PY'
|
|
import re
|
|
import sys
|
|
|
|
path, key, value = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
text = open(path).read()
|
|
pattern = re.compile(r"^" + re.escape(key) + r"=.*$", re.M)
|
|
replacement = f"{key}={value}"
|
|
if pattern.search(text):
|
|
text = pattern.sub(replacement, text, count=1)
|
|
else:
|
|
text = text.rstrip("\n") + "\n" + replacement + "\n"
|
|
open(path, "w").write(text)
|
|
PY
|
|
}
|
|
|
|
if [[ ! -f "${CREDENTIALS_FILE}" ]]; then
|
|
echo "Missing ${CREDENTIALS_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# shellcheck disable=SC1090
|
|
source "${CREDENTIALS_FILE}"
|
|
|
|
API="https://${REGISTRY_HOST}/api/v1"
|
|
AUTH=(-u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}")
|
|
|
|
if ! curl -fsS "${AUTH[@]}" "${API}/repos/${REPO_OWNER}/${REPO_NAME}" >/dev/null 2>&1; then
|
|
echo "Repository ${REPO_OWNER}/${REPO_NAME} not found on ${REGISTRY_HOST}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -d "${STAGE_PATH}/.git" ]]; then
|
|
mkdir -p "$(dirname "${STAGE_PATH}")"
|
|
git clone "${GITEA_REPO_URL}" "${STAGE_PATH}"
|
|
fi
|
|
|
|
(
|
|
cd "${STAGE_PATH}"
|
|
# Never fetch from the prod checkout; CI deploys by SHA against this origin.
|
|
git remote set-url origin "${GITEA_REPO_URL}"
|
|
git fetch origin || true
|
|
if git rev-parse --verify origin/stage >/dev/null 2>&1; then
|
|
git checkout stage
|
|
git pull --ff-only origin stage || true
|
|
else
|
|
echo "Remote branch origin/stage not found yet; leaving $(git branch --show-current)."
|
|
fi
|
|
)
|
|
|
|
mkdir -p \
|
|
"${STAGE_PATH}/database" \
|
|
"${STAGE_PATH}/storage/app/private/recordings" \
|
|
"${STAGE_PATH}/storage/app/public" \
|
|
"${STAGE_PATH}/storage/framework/cache" \
|
|
"${STAGE_PATH}/storage/framework/sessions" \
|
|
"${STAGE_PATH}/storage/framework/views" \
|
|
"${STAGE_PATH}/storage/logs" \
|
|
"${STAGE_PATH}/bootstrap/cache"
|
|
|
|
if [[ ! -f "${STAGE_PATH}/database/database.sqlite" ]]; then
|
|
touch "${STAGE_PATH}/database/database.sqlite"
|
|
fi
|
|
|
|
ENV_SRC="${STAGE_PATH}/.env.example"
|
|
if [[ ! -f "${ENV_SRC}" ]]; then
|
|
ENV_SRC="${REPO_ROOT}/.env.example"
|
|
fi
|
|
|
|
if [[ ! -f "${STAGE_PATH}/.env" ]]; then
|
|
cp "${ENV_SRC}" "${STAGE_PATH}/.env"
|
|
upsert_env "${STAGE_PATH}/.env" "APP_ENV" "production"
|
|
upsert_env "${STAGE_PATH}/.env" "APP_DEBUG" "false"
|
|
upsert_env "${STAGE_PATH}/.env" "APP_KEY" "base64:$(openssl rand -base64 32)"
|
|
upsert_env "${STAGE_PATH}/.env" "APP_URL" "${STAGE_URL}"
|
|
upsert_env "${STAGE_PATH}/.env" "PUBLIC_APP_URL" "${STAGE_URL}"
|
|
# Prod already binds 18080 (app), 18180 (reverb), and 18090 (whisper).
|
|
upsert_env "${STAGE_PATH}/.env" "APP_HOST_PORT" "18280"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_HOST_PORT" "18281"
|
|
upsert_env "${STAGE_PATH}/.env" "WHISPER_HOST_PORT" "18290"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_APP_ID" "$(openssl rand -hex 8)"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_APP_KEY" "$(openssl rand -hex 16)"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_APP_SECRET" "$(openssl rand -hex 20)"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_PUBLIC_HOST" "${REVERB_PUBLIC_HOST}"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_PUBLIC_PORT" "443"
|
|
upsert_env "${STAGE_PATH}/.env" "REVERB_PUBLIC_SCHEME" "https"
|
|
upsert_env "${STAGE_PATH}/.env" "CONTAINER_PREFIX" "${CONTAINER_PREFIX}"
|
|
upsert_env "${STAGE_PATH}/.env" "CADDY_NETWORK" "${CADDY_NETWORK}"
|
|
echo "Wrote ${STAGE_PATH}/.env"
|
|
else
|
|
echo "Keeping existing ${STAGE_PATH}/.env"
|
|
fi
|
|
|
|
if ! docker network inspect "${CADDY_NETWORK}" >/dev/null 2>&1; then
|
|
docker network create "${CADDY_NETWORK}"
|
|
echo "Created Docker network ${CADDY_NETWORK}"
|
|
fi
|
|
|
|
if [[ -z "${CADDY_CONTAINER}" ]]; then
|
|
CADDY_CONTAINER="$(
|
|
docker network inspect "${PROD_CADDY_NETWORK}" \
|
|
--format '{{range .Containers}}{{.Name}}{{"\n"}}{{end}}' \
|
|
| grep -i caddy \
|
|
| head -1 || true
|
|
)"
|
|
fi
|
|
|
|
if [[ -z "${CADDY_CONTAINER}" ]]; then
|
|
echo "Could not find a Caddy container on ${PROD_CADDY_NETWORK}." >&2
|
|
echo "Set CADDY_CONTAINER and re-run: docker network connect ${CADDY_NETWORK} <caddy-container>" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if docker network inspect "${CADDY_NETWORK}" --format '{{range .Containers}}{{.Name}}{{"\n"}}{{end}}' | grep -qx "${CADDY_CONTAINER}"; then
|
|
echo "Caddy container ${CADDY_CONTAINER} already on ${CADDY_NETWORK}"
|
|
else
|
|
docker network connect "${CADDY_NETWORK}" "${CADDY_CONTAINER}"
|
|
echo "Attached ${CADDY_CONTAINER} to ${CADDY_NETWORK}"
|
|
fi
|
|
|
|
set_secret() {
|
|
local name="$1"
|
|
local value="$2"
|
|
local tmp
|
|
tmp="$(mktemp)"
|
|
python3 -c 'import json,sys; json.dump({"data": sys.argv[1]}, open(sys.argv[2], "w"))' "${value}" "${tmp}"
|
|
curl -fsS "${AUTH[@]}" -X PUT \
|
|
"${API}/repos/${REPO_OWNER}/${REPO_NAME}/actions/secrets/${name}" \
|
|
-H "Content-Type: application/json" \
|
|
--data-binary @"${tmp}" >/dev/null
|
|
rm -f "${tmp}"
|
|
}
|
|
|
|
set_secret "STAGE_DEPLOY_PATHS" "${STAGE_PATH}"
|
|
|
|
echo "Stage instance ready at ${STAGE_PATH}"
|
|
echo "Public URL: ${STAGE_URL}"
|
|
echo "Reverb host: ${REVERB_PUBLIC_HOST}"
|
|
echo "Caddy network: ${CADDY_NETWORK} (container ${CADDY_CONTAINER})"
|
|
echo "Gitea secret STAGE_DEPLOY_PATHS=${STAGE_PATH}"
|
|
echo
|
|
echo "Still required: DNS for stage.transcribe.z00.nu and ${REVERB_PUBLIC_HOST},"
|
|
echo "plus Caddy Proxy Manager hosts pointing at ${CONTAINER_PREFIX}-app:80"
|
|
echo "and ${CONTAINER_PREFIX}-reverb:8080."
|
|
echo "Then: git checkout -b stage && git push -u origin stage"
|