295 lines
8.7 KiB
Bash
295 lines
8.7 KiB
Bash
#!/usr/bin/env bash
|
|
# Automated developer environment setup for Stella Ops (Linux/macOS).
|
|
#
|
|
# Usage:
|
|
# ./scripts/setup.sh [--skip-build] [--infra-only] [--images-only] [--skip-images]
|
|
set -euo pipefail
|
|
|
|
# ─── Parse flags ────────────────────────────────────────────────────────────
|
|
|
|
SKIP_BUILD=false
|
|
INFRA_ONLY=false
|
|
IMAGES_ONLY=false
|
|
SKIP_IMAGES=false
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--skip-build) SKIP_BUILD=true ;;
|
|
--infra-only) INFRA_ONLY=true ;;
|
|
--images-only) IMAGES_ONLY=true ;;
|
|
--skip-images) SKIP_IMAGES=true ;;
|
|
-h|--help)
|
|
echo "Usage: $0 [--skip-build] [--infra-only] [--images-only] [--skip-images]"
|
|
exit 0
|
|
;;
|
|
*) echo "Unknown flag: $arg" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
|
if [[ -z "$ROOT" ]]; then
|
|
echo "ERROR: Not inside a git repository." >&2
|
|
exit 1
|
|
fi
|
|
|
|
COMPOSE_DIR="${ROOT}/devops/compose"
|
|
|
|
# ─── Helpers ────────────────────────────────────────────────────────────────
|
|
|
|
step() { printf '\n\033[1;36m>> %s\033[0m\n' "$1"; }
|
|
ok() { printf ' \033[0;32m[OK]\033[0m %s\n' "$1"; }
|
|
warn() { printf ' \033[0;33m[WARN]\033[0m %s\n' "$1"; }
|
|
fail() { printf ' \033[0;31m[FAIL]\033[0m %s\n' "$1"; }
|
|
|
|
has_cmd() { command -v "$1" &>/dev/null; }
|
|
|
|
# ─── 1. Check prerequisites ────────────────────────────────────────────────
|
|
|
|
check_prerequisites() {
|
|
step 'Checking prerequisites'
|
|
local all_good=true
|
|
|
|
# dotnet
|
|
if has_cmd dotnet; then
|
|
local v; v=$(dotnet --version 2>/dev/null)
|
|
if [[ "$v" =~ ^10\. ]]; then
|
|
ok "dotnet $v"
|
|
else
|
|
fail "dotnet $v found, but 10.x is required"
|
|
all_good=false
|
|
fi
|
|
else
|
|
fail 'dotnet SDK not found. Install .NET 10 SDK.'
|
|
all_good=false
|
|
fi
|
|
|
|
# node
|
|
if has_cmd node; then
|
|
local v; v=$(node --version 2>/dev/null | sed 's/^v//')
|
|
local major; major=$(echo "$v" | cut -d. -f1)
|
|
if (( major >= 20 )); then
|
|
ok "node $v"
|
|
else
|
|
fail "node $v found, but 20+ is required"
|
|
all_good=false
|
|
fi
|
|
else
|
|
fail 'node not found. Install Node.js 20+.'
|
|
all_good=false
|
|
fi
|
|
|
|
# npm
|
|
if has_cmd npm; then
|
|
local v; v=$(npm --version 2>/dev/null)
|
|
local major; major=$(echo "$v" | cut -d. -f1)
|
|
if (( major >= 10 )); then
|
|
ok "npm $v"
|
|
else
|
|
fail "npm $v found, but 10+ is required"
|
|
all_good=false
|
|
fi
|
|
else
|
|
fail 'npm not found.'
|
|
all_good=false
|
|
fi
|
|
|
|
# docker
|
|
if has_cmd docker; then
|
|
ok "docker: $(docker --version 2>/dev/null)"
|
|
else
|
|
fail 'docker not found. Install Docker.'
|
|
all_good=false
|
|
fi
|
|
|
|
# docker compose
|
|
if docker compose version &>/dev/null; then
|
|
ok 'docker compose available'
|
|
else
|
|
fail 'docker compose not available. Install Compose V2.'
|
|
all_good=false
|
|
fi
|
|
|
|
# git
|
|
if has_cmd git; then
|
|
ok "$(git --version 2>/dev/null)"
|
|
else
|
|
fail 'git not found.'
|
|
all_good=false
|
|
fi
|
|
|
|
if [[ "$all_good" != "true" ]]; then
|
|
echo 'ERROR: Prerequisites not met. Install missing tools and re-run.' >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ─── 2. Check hosts file ───────────────────────────────────────────────────
|
|
|
|
check_hosts() {
|
|
step 'Checking hosts file for stella-ops.local entries'
|
|
if grep -q 'stella-ops\.local' /etc/hosts 2>/dev/null; then
|
|
ok 'stella-ops.local entries found in /etc/hosts'
|
|
else
|
|
warn 'stella-ops.local entries NOT found in /etc/hosts.'
|
|
echo ' Add the hosts block from docs/dev/DEV_ENVIRONMENT_SETUP.md section 2'
|
|
echo ' to /etc/hosts (use sudo).'
|
|
fi
|
|
}
|
|
|
|
# ─── 3. Ensure .env ────────────────────────────────────────────────────────
|
|
|
|
ensure_env() {
|
|
step 'Ensuring .env file exists'
|
|
local env_file="${COMPOSE_DIR}/.env"
|
|
local env_example="${COMPOSE_DIR}/env/stellaops.env.example"
|
|
|
|
if [[ -f "$env_file" ]]; then
|
|
ok ".env already exists at $env_file"
|
|
elif [[ -f "$env_example" ]]; then
|
|
cp "$env_example" "$env_file"
|
|
ok "Copied $env_example -> $env_file"
|
|
warn 'Review .env and change POSTGRES_PASSWORD at minimum.'
|
|
else
|
|
fail "Neither .env nor env/stellaops.env.example found in $COMPOSE_DIR"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ─── 4. Start infrastructure ───────────────────────────────────────────────
|
|
|
|
start_infra() {
|
|
step 'Starting infrastructure containers (docker-compose.dev.yml)'
|
|
cd "$COMPOSE_DIR"
|
|
|
|
docker compose -f docker-compose.dev.yml up -d
|
|
|
|
echo ' Waiting for containers to become healthy...'
|
|
local max_wait=120
|
|
local elapsed=0
|
|
while (( elapsed < max_wait )); do
|
|
local all_healthy=true
|
|
while IFS= read -r line; do
|
|
[[ -z "$line" ]] && continue
|
|
local health; health=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin).get('Health',''))" 2>/dev/null || true)
|
|
if [[ -n "$health" && "$health" != "healthy" ]]; then
|
|
all_healthy=false
|
|
fi
|
|
done < <(docker compose -f docker-compose.dev.yml ps --format json 2>/dev/null)
|
|
|
|
if [[ "$all_healthy" == "true" && $elapsed -gt 5 ]]; then
|
|
ok 'All infrastructure containers healthy'
|
|
cd "$ROOT"
|
|
return
|
|
fi
|
|
sleep 5
|
|
elapsed=$((elapsed + 5))
|
|
done
|
|
warn "Timed out waiting for healthy status after ${max_wait}s."
|
|
cd "$ROOT"
|
|
}
|
|
|
|
# ─── 5. Build .NET solutions ───────────────────────────────────────────────
|
|
|
|
build_solutions() {
|
|
step 'Building all .NET solutions'
|
|
local script="${ROOT}/scripts/build-all-solutions.sh"
|
|
if [[ -x "$script" ]]; then
|
|
"$script"
|
|
ok '.NET solutions built successfully'
|
|
elif [[ -f "$script" ]]; then
|
|
bash "$script"
|
|
ok '.NET solutions built successfully'
|
|
else
|
|
warn "Build script not found at $script. Skipping .NET build."
|
|
fi
|
|
}
|
|
|
|
# ─── 6. Build Docker images ────────────────────────────────────────────────
|
|
|
|
build_images() {
|
|
step 'Building Docker images'
|
|
local script="${ROOT}/devops/docker/build-all.sh"
|
|
if [[ -x "$script" ]]; then
|
|
"$script"
|
|
ok 'Docker images built successfully'
|
|
elif [[ -f "$script" ]]; then
|
|
bash "$script"
|
|
ok 'Docker images built successfully'
|
|
else
|
|
warn "Build script not found at $script. Skipping image build."
|
|
fi
|
|
}
|
|
|
|
# ─── 7. Start full platform ────────────────────────────────────────────────
|
|
|
|
start_platform() {
|
|
step 'Starting full Stella Ops platform'
|
|
cd "$COMPOSE_DIR"
|
|
docker compose -f docker-compose.stella-ops.yml up -d
|
|
ok 'Platform services started'
|
|
cd "$ROOT"
|
|
}
|
|
|
|
# ─── 8. Smoke test ─────────────────────────────────────────────────────────
|
|
|
|
smoke_test() {
|
|
step 'Running smoke tests'
|
|
|
|
if docker exec stellaops-dev-postgres pg_isready -U stellaops &>/dev/null; then
|
|
ok 'PostgreSQL'
|
|
else
|
|
warn 'PostgreSQL not responding'
|
|
fi
|
|
|
|
local pong; pong=$(docker exec stellaops-dev-valkey valkey-cli ping 2>/dev/null || true)
|
|
if [[ "$pong" == "PONG" ]]; then
|
|
ok 'Valkey'
|
|
else
|
|
warn 'Valkey not responding'
|
|
fi
|
|
}
|
|
|
|
# ─── Main ───────────────────────────────────────────────────────────────────
|
|
|
|
echo '============================================='
|
|
echo ' Stella Ops Developer Environment Setup'
|
|
echo '============================================='
|
|
|
|
check_prerequisites
|
|
check_hosts
|
|
|
|
if [[ "$IMAGES_ONLY" == "true" ]]; then
|
|
build_images
|
|
echo ''
|
|
echo 'Done (images only).'
|
|
exit 0
|
|
fi
|
|
|
|
ensure_env
|
|
start_infra
|
|
|
|
if [[ "$INFRA_ONLY" == "true" ]]; then
|
|
smoke_test
|
|
echo ''
|
|
echo 'Done (infra only). Infrastructure is running.'
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$SKIP_BUILD" != "true" ]]; then
|
|
build_solutions
|
|
fi
|
|
|
|
if [[ "$SKIP_IMAGES" != "true" ]]; then
|
|
build_images
|
|
fi
|
|
|
|
start_platform
|
|
smoke_test
|
|
|
|
echo ''
|
|
echo '============================================='
|
|
echo ' Setup complete!'
|
|
echo ' Platform: https://stella-ops.local'
|
|
echo ' Docs: docs/dev/DEV_ENVIRONMENT_SETUP.md'
|
|
echo '============================================='
|