Add a stage branch deploy beside production on z00.
Pushing stage runs CI and deploys to stage.transcribe.z00.nu with its own data, Reverb credentials, and Caddy network.
This commit is contained in:
Executable
+173
@@ -0,0 +1,173 @@
|
||||
#!/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}"
|
||||
PROD_PATH="${PROD_PATH:-${HOME}/andyTranscibe}"
|
||||
STAGE_PATH="${STAGE_PATH:-${HOME}/andyTranscibe-stage}"
|
||||
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}")"
|
||||
if [[ -d "${PROD_PATH}/.git" ]]; then
|
||||
git clone "${PROD_PATH}" "${STAGE_PATH}"
|
||||
else
|
||||
git clone "https://${REGISTRY_HOST}/${REPO_OWNER}/${REPO_NAME}.git" "${STAGE_PATH}"
|
||||
fi
|
||||
fi
|
||||
|
||||
(
|
||||
cd "${STAGE_PATH}"
|
||||
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}"
|
||||
upsert_env "${STAGE_PATH}/.env" "APP_HOST_PORT" "18180"
|
||||
upsert_env "${STAGE_PATH}/.env" "REVERB_HOST_PORT" "18181"
|
||||
upsert_env "${STAGE_PATH}/.env" "WHISPER_HOST_PORT" "18190"
|
||||
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"
|
||||
Reference in New Issue
Block a user