79 lines
3.6 KiB
Bash
Executable File
79 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# setup-space.sh: create the single space and its first admin on the
|
|
# docker-compose.yml stack. Wraps scripts/setup.mjs (the same code as
|
|
# `pnpm setup`) and runs it in a container on the stack's network, so the
|
|
# host needs only Docker: no Node, no pnpm, no node_modules.
|
|
#
|
|
# Usage: scripts/setup-space.sh [command] [setup.mjs flags]
|
|
# scripts/setup-space.sh interactive: space, then admin
|
|
# scripts/setup-space.sh doctor check config and DB connectivity
|
|
# scripts/setup-space.sh --yes \
|
|
# --admin-email [email protected] --admin-password '...'
|
|
#
|
|
# Reads from .env: SERVICE_ROLE_KEY, ANON_KEY, NEXT_PUBLIC_APP_URL,
|
|
# NEXT_PUBLIC_SITE_NAME and NEXT_PUBLIC_SINGLE_TENANT_SPACE_SLUG (used as the
|
|
# default space name and slug), and any SETUP_* values. Flags override these.
|
|
# The stack must already be running. If the database has no schema yet (a fresh
|
|
# volume), scripts/schema.sql is applied first.
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
ENV_FILE="$ROOT/.env"
|
|
NETWORK="hackerspace_net"
|
|
IMAGE="hackerspace-setup:local"
|
|
|
|
command -v docker >/dev/null || { echo "error: docker is required" >&2; exit 1; }
|
|
[[ -f "$ENV_FILE" ]] || { echo "error: $ENV_FILE not found; run scripts/generate-env.sh first" >&2; exit 1; }
|
|
docker network inspect "$NETWORK" >/dev/null 2>&1 \
|
|
|| { echo "error: network $NETWORK not found; start the stack with 'docker compose up -d'" >&2; exit 1; }
|
|
|
|
# Read single keys instead of sourcing the file, so nothing in it is executed.
|
|
env_get() { grep -E "^$1=" "$ENV_FILE" | tail -n1 | cut -d= -f2- || true; }
|
|
|
|
SERVICE_KEY="$(env_get SERVICE_ROLE_KEY)"
|
|
ANON="$(env_get ANON_KEY)"
|
|
[[ -n "$SERVICE_KEY" && -n "$ANON" ]] \
|
|
|| { echo "error: SERVICE_ROLE_KEY or ANON_KEY is empty in .env" >&2; exit 1; }
|
|
|
|
export NEXT_PUBLIC_SUPABASE_URL="http://kong:8000"
|
|
export NEXT_PUBLIC_SUPABASE_ANON_KEY="$ANON"
|
|
export SUPABASE_SERVICE_ROLE_KEY="$SERVICE_KEY"
|
|
export NEXT_PUBLIC_APP_URL="$(env_get NEXT_PUBLIC_APP_URL)"
|
|
|
|
for name in SETUP_SPACE_NAME SETUP_SPACE_SLUG SETUP_SPACE_CITY \
|
|
SETUP_ADMIN_EMAIL SETUP_ADMIN_PASSWORD SETUP_ADMIN_NAME; do
|
|
export "$name=$(env_get "$name")"
|
|
done
|
|
[[ -n "$SETUP_SPACE_NAME" ]] || export SETUP_SPACE_NAME="$(env_get NEXT_PUBLIC_SITE_NAME)"
|
|
[[ -n "$SETUP_SPACE_SLUG" ]] || export SETUP_SPACE_SLUG="$(env_get NEXT_PUBLIC_SINGLE_TENANT_SPACE_SLUG)"
|
|
|
|
dc() { docker compose -f "$ROOT/docker-compose.yml" "$@"; }
|
|
|
|
if [[ "$(dc exec -T db psql -U postgres -d postgres -Atc "select to_regclass('public.spaces') is not null" 2>/dev/null)" != "t" ]]; then
|
|
echo "No schema found; applying scripts/schema.sql"
|
|
dc exec -T db psql -v ON_ERROR_STOP=1 -q -U postgres -d postgres < "$ROOT/scripts/schema.sql" >/dev/null
|
|
# PostgREST caches the schema; restart so it sees the new tables.
|
|
dc restart rest >/dev/null
|
|
until [[ "$(dc ps rest --format '{{.State}}')" == "running" ]]; do sleep 1; done
|
|
sleep 3
|
|
fi
|
|
|
|
# The Dockerfile deps stage is Node plus installed node_modules; the scripts
|
|
# directory is mounted so edits to setup.mjs apply without a rebuild.
|
|
docker build -q --target deps -t "$IMAGE" "$ROOT" >/dev/null
|
|
|
|
tty_flags=()
|
|
[[ -t 0 && -t 1 ]] && tty_flags=(-it)
|
|
|
|
# `-e NAME` without a value forwards the variable, so secrets stay off the
|
|
# docker command line.
|
|
exec docker run --rm "${tty_flags[@]}" --network "$NETWORK" \
|
|
-v "$ROOT/scripts:/app/scripts:ro" \
|
|
-e NEXT_PUBLIC_SUPABASE_URL -e NEXT_PUBLIC_SUPABASE_ANON_KEY \
|
|
-e SUPABASE_SERVICE_ROLE_KEY -e NEXT_PUBLIC_APP_URL \
|
|
-e SETUP_SPACE_NAME -e SETUP_SPACE_SLUG -e SETUP_SPACE_CITY \
|
|
-e SETUP_ADMIN_EMAIL -e SETUP_ADMIN_PASSWORD -e SETUP_ADMIN_NAME \
|
|
"$IMAGE" node scripts/setup.mjs "$@"
|