In Docker builds, .git directory is not available in the container,
so git describe --tags fails and fallback is '0.0.0'. Now:
- build.sh passes --build-arg APP_VERSION=${tag} to frontend build
- Dockerfile accepts ARG APP_VERSION and sets ENV
- vite.config.js checks process.env.APP_VERSION first, then git describe
579 lines
19 KiB
Bash
Executable File
579 lines
19 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# #region build [C:2] [TYPE Module]
|
|
# @PURPOSE: Unified build script — local docker compose + release bundles (backend + frontend + agent) + lightweight bundle
|
|
# @COMPLEXITY: 2
|
|
#
|
|
# Usage: ./build.sh <command> [options]
|
|
#
|
|
# Commands:
|
|
# up [profile] Build and start local docker compose (default: current)
|
|
# down [profile] Stop services
|
|
# restart [profile] Rebuild and restart services
|
|
# logs [profile] Tail logs
|
|
# status Show running containers for all profiles
|
|
# bundle <tag> Full release bundle (backend + frontend + postgres .tar.xz's)
|
|
# bundle:light <tag> Lightweight all-in-one bundle (<200 MB, .tar.xz, no Playwright)
|
|
# help Show this help
|
|
#
|
|
# Profiles: current (default), master, enterprise-clean
|
|
# #endregion build
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
BACKEND_ENV_FILE="$SCRIPT_DIR/backend/.env"
|
|
DIST_ROOT="$SCRIPT_DIR/dist/docker"
|
|
|
|
# ---- Docker Compose detection ----
|
|
if docker compose version >/dev/null 2>&1; then
|
|
COMPOSE_CMD=(docker compose)
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
COMPOSE_CMD=(docker-compose)
|
|
else
|
|
echo "Error: docker compose is not available."
|
|
exit 1
|
|
fi
|
|
|
|
# ======================================================================
|
|
# HELPERS
|
|
# ======================================================================
|
|
|
|
# shellcheck disable=SC2206
|
|
setup_compose_profile() {
|
|
local profile="$1"
|
|
case "$profile" in
|
|
master)
|
|
PROFILE_ENV_FILE="$SCRIPT_DIR/.env.master"
|
|
PROJECT_NAME="superset-tools-master"
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
;;
|
|
current|"")
|
|
PROFILE_ENV_FILE="$SCRIPT_DIR/.env.current"
|
|
PROJECT_NAME="superset-tools-current"
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
;;
|
|
enterprise-clean)
|
|
PROFILE_ENV_FILE="$SCRIPT_DIR/.env.enterprise-clean"
|
|
PROJECT_NAME="superset-tools-enterprise"
|
|
COMPOSE_FILE="docker-compose.enterprise-clean.yml"
|
|
;;
|
|
*)
|
|
echo "Error: unknown profile '$profile'. Use: current, master, enterprise-clean."
|
|
exit 1
|
|
;;
|
|
esac
|
|
COMPOSE_ARGS=(-p "$PROJECT_NAME" -f "$COMPOSE_FILE")
|
|
if [[ -f "$PROFILE_ENV_FILE" ]]; then
|
|
COMPOSE_ARGS+=(--env-file "$PROFILE_ENV_FILE")
|
|
fi
|
|
}
|
|
|
|
ensure_backend_encryption_key() {
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
python3 - "$BACKEND_ENV_FILE" <<'PY'
|
|
import base64
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
|
|
def is_valid_fernet_key(raw_value: str) -> bool:
|
|
value = raw_value.strip()
|
|
if not value:
|
|
return False
|
|
try:
|
|
decoded = base64.urlsafe_b64decode(value.encode())
|
|
except Exception:
|
|
return False
|
|
return len(decoded) == 32
|
|
|
|
|
|
def generate_fernet_key() -> str:
|
|
return base64.urlsafe_b64encode(os.urandom(32)).decode()
|
|
|
|
|
|
env_path = Path(sys.argv[1])
|
|
env_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
existing_lines: List[str] = []
|
|
existing_key: Optional[str] = None
|
|
|
|
if env_path.exists():
|
|
existing_lines = env_path.read_text(encoding="utf-8").splitlines()
|
|
for line in existing_lines:
|
|
if line.startswith("ENCRYPTION_KEY="):
|
|
candidate = line.partition("=")[2].strip()
|
|
if is_valid_fernet_key(candidate):
|
|
existing_key = candidate
|
|
break
|
|
|
|
if existing_key is None:
|
|
generated_key = generate_fernet_key()
|
|
filtered_lines = [line for line in existing_lines if not line.startswith("ENCRYPTION_KEY=")]
|
|
filtered_lines.append(f"ENCRYPTION_KEY={generated_key}")
|
|
env_path.write_text("\n".join(filtered_lines) + "\n", encoding="utf-8")
|
|
print(f"[build] ENCRYPTION_KEY ensured in {env_path}")
|
|
else:
|
|
print(f"[build] Existing ENCRYPTION_KEY reused from {env_path}")
|
|
PY
|
|
return
|
|
fi
|
|
|
|
echo "Error: python3 is required to generate backend/.env with ENCRYPTION_KEY."
|
|
exit 1
|
|
}
|
|
|
|
get_image_id() {
|
|
docker image inspect --format '{{.Id}}' "$1"
|
|
}
|
|
|
|
get_repo_digest() {
|
|
local digest
|
|
digest="$(docker image inspect --format '{{join .RepoDigests ","}}' "$1" 2>/dev/null || true)"
|
|
if [[ -n "${digest}" && "${digest}" != "<no value>" ]]; then
|
|
printf '%s' "${digest}"
|
|
else
|
|
printf '%s' "unavailable"
|
|
fi
|
|
}
|
|
|
|
# ======================================================================
|
|
# COMPOSE COMMANDS
|
|
# ======================================================================
|
|
|
|
compose_up() {
|
|
local profile="${1:-current}"
|
|
setup_compose_profile "$profile"
|
|
ensure_backend_encryption_key
|
|
|
|
echo "[build] Profile: $profile (project: $PROJECT_NAME)"
|
|
if [[ -f "$PROFILE_ENV_FILE" ]]; then
|
|
echo "[build] Env file: $PROFILE_ENV_FILE"
|
|
fi
|
|
|
|
echo "[1/2] Building project images..."
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" build
|
|
|
|
echo "[2/2] Starting Docker services..."
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" up -d
|
|
|
|
echo "Done. Services are running."
|
|
echo " ${COMPOSE_CMD[*]} ${COMPOSE_ARGS[*]} ps"
|
|
echo " ${COMPOSE_CMD[*]} ${COMPOSE_ARGS[*]} logs -f"
|
|
}
|
|
|
|
compose_down() {
|
|
local profile="${1:-current}"
|
|
setup_compose_profile "$profile"
|
|
|
|
echo "[build] Stopping $profile (project: $PROJECT_NAME)..."
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" down
|
|
echo "[build] Done."
|
|
}
|
|
|
|
compose_restart() {
|
|
local profile="${1:-current}"
|
|
setup_compose_profile "$profile"
|
|
ensure_backend_encryption_key
|
|
|
|
echo "[build] Restarting $profile (project: $PROJECT_NAME)..."
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" build
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" up -d --force-recreate
|
|
echo "[build] Done."
|
|
}
|
|
|
|
compose_logs() {
|
|
local profile="${1:-current}"
|
|
setup_compose_profile "$profile"
|
|
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" logs -f
|
|
}
|
|
|
|
compose_status() {
|
|
echo "=== superset-tools docker status ==="
|
|
for profile in current master enterprise-clean; do
|
|
setup_compose_profile "$profile"
|
|
echo "--- $profile (project: $PROJECT_NAME) ---"
|
|
"${COMPOSE_CMD[@]}" "${COMPOSE_ARGS[@]}" ps 2>/dev/null || echo "(not running)"
|
|
done
|
|
}
|
|
|
|
# ======================================================================
|
|
# BUNDLE: full release (backend + frontend + postgres .tar's)
|
|
# ======================================================================
|
|
|
|
bundle_release() {
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: tag is required."
|
|
echo "Usage: ./build.sh bundle <tag> (e.g. v1.0.0)"
|
|
exit 1
|
|
fi
|
|
local tag="$1"
|
|
local backend_tag="superset-tools-backend:${tag}"
|
|
local frontend_tag="superset-tools-frontend:${tag}"
|
|
local agent_tag="superset-tools-agent:${tag}"
|
|
|
|
mkdir -p "$DIST_ROOT"
|
|
|
|
echo "[bundle] Building backend image ${backend_tag}..."
|
|
docker build -f docker/backend.Dockerfile -t "${backend_tag}" .
|
|
|
|
echo "[bundle] Building frontend image ${frontend_tag}..."
|
|
docker build --build-arg "APP_VERSION=${tag}" -f docker/frontend.Dockerfile -t "${frontend_tag}" .
|
|
|
|
echo "[bundle] Building agent image ${agent_tag}..."
|
|
docker build -f docker/Dockerfile.agent -t "${agent_tag}" .
|
|
|
|
echo "[bundle] Exporting .tar.xz archives..."
|
|
echo "[bundle] Compressing backend image..."
|
|
docker save "${backend_tag}" | xz -T0 -6 > "${DIST_ROOT}/superset-tools-backend.${tag}.tar.xz"
|
|
echo "[bundle] Compressing frontend image..."
|
|
docker save "${frontend_tag}" | xz -T0 -6 > "${DIST_ROOT}/superset-tools-frontend.${tag}.tar.xz"
|
|
echo "[bundle] Compressing agent image..."
|
|
docker save "${agent_tag}" | xz -T0 -6 > "${DIST_ROOT}/superset-tools-agent.${tag}.tar.xz"
|
|
|
|
echo "[bundle] Calculating checksums..."
|
|
(
|
|
cd "${DIST_ROOT}"
|
|
sha256sum "superset-tools-backend.${tag}.tar.xz" "superset-tools-frontend.${tag}.tar.xz" "superset-tools-agent.${tag}.tar.xz" > "sha256sums.${tag}.txt"
|
|
)
|
|
|
|
local backend_id frontend_id agent_id
|
|
local backend_digest frontend_digest agent_digest
|
|
backend_id="$(get_image_id "${backend_tag}")"
|
|
frontend_id="$(get_image_id "${frontend_tag}")"
|
|
agent_id="$(get_image_id "${agent_tag}")"
|
|
backend_digest="$(get_repo_digest "${backend_tag}")"
|
|
frontend_digest="$(get_repo_digest "${frontend_tag}")"
|
|
agent_digest="$(get_repo_digest "${agent_tag}")"
|
|
|
|
# Генерируем deploy-compose для загрузки pre-built образов (image: + pull_policy: never)
|
|
# Без postgres — используется внешний корпоративный PostgreSQL.
|
|
cat > "${DIST_ROOT}/docker-compose.enterprise-clean.yml" <<DEPLOY
|
|
services:
|
|
backend:
|
|
image: ${backend_tag}
|
|
pull_policy: never
|
|
restart: unless-stopped
|
|
environment:
|
|
DATABASE_URL: postgresql+psycopg2://\${POSTGRES_USER:-postgres}:\${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@\${POSTGRES_HOST:?Set POSTGRES_HOST}:\${POSTGRES_PORT:-5432}/\${POSTGRES_DB:-ss_tools}
|
|
TASKS_DATABASE_URL: postgresql+psycopg2://\${POSTGRES_USER:-postgres}:\${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@\${POSTGRES_HOST:?Set POSTGRES_HOST}:\${POSTGRES_PORT:-5432}/\${POSTGRES_DB:-ss_tools}
|
|
AUTH_DATABASE_URL: postgresql+psycopg2://\${POSTGRES_USER:-postgres}:\${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@\${POSTGRES_HOST:?Set POSTGRES_HOST}:\${POSTGRES_PORT:-5432}/\${POSTGRES_DB:-ss_tools}
|
|
BACKEND_PORT: 8000
|
|
ENABLE_BELIEF_STATE_LOGGING: \${ENABLE_BELIEF_STATE_LOGGING:-true}
|
|
TASK_LOG_LEVEL: \${TASK_LOG_LEVEL:-INFO}
|
|
INITIAL_ADMIN_CREATE: \${INITIAL_ADMIN_CREATE:-false}
|
|
INITIAL_ADMIN_USERNAME: \${INITIAL_ADMIN_USERNAME:-admin}
|
|
INITIAL_ADMIN_PASSWORD: \${INITIAL_ADMIN_PASSWORD:-}
|
|
INITIAL_ADMIN_EMAIL: \${INITIAL_ADMIN_EMAIL:-}
|
|
OPENAI_API_KEY: \${OPENAI_API_KEY:-}
|
|
ANTHROPIC_API_KEY: \${ANTHROPIC_API_KEY:-}
|
|
FEATURES__DATASET_REVIEW: \${FEATURES__DATASET_REVIEW:-true}
|
|
FEATURES__HEALTH_MONITOR: \${FEATURES__HEALTH_MONITOR:-true}
|
|
CERTS_PATH: /opt/certs
|
|
ports:
|
|
- "\${BACKEND_HOST_PORT:-8001}:8000"
|
|
volumes:
|
|
- ./storage:/app/storage
|
|
- \${CERTS_PATH:-./certs}:/opt/certs:ro
|
|
|
|
frontend:
|
|
image: ${frontend_tag}
|
|
pull_policy: never
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- backend
|
|
ports:
|
|
- "\${FRONTEND_HOST_PORT:-8000}:80"
|
|
- "\${FRONTEND_SSL_PORT:-443}:443"
|
|
volumes:
|
|
- \${CERTS_PATH:-./certs}:/opt/certs:ro
|
|
|
|
agent:
|
|
image: ${agent_tag}
|
|
pull_policy: never
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- backend
|
|
environment:
|
|
LLM_API_KEY: \${LLM_API_KEY:-}
|
|
LLM_BASE_URL: \${LLM_BASE_URL:-https://api.openai.com/v1}
|
|
LLM_MODEL: \${LLM_MODEL:-gpt-4o}
|
|
FASTAPI_URL: http://backend:8000
|
|
JWT_SECRET: \${JWT_SECRET:-super-secret-key}
|
|
SERVICE_JWT: \${SERVICE_JWT:-agent-service-secret}
|
|
DATABASE_URL: postgresql+psycopg2://\${POSTGRES_USER:-postgres}:\${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@\${POSTGRES_HOST:?Set POSTGRES_HOST}:\${POSTGRES_PORT:-5432}/\${POSTGRES_DB:-ss_tools}
|
|
GRADIO_SERVER_PORT: 7860
|
|
ports:
|
|
- "\${AGENT_HOST_PORT:-7860}:7860"
|
|
DEPLOY
|
|
|
|
cat > "${DIST_ROOT}/manifest.${tag}.txt" <<EOF
|
|
release_tag=${tag}
|
|
backend_image=${backend_tag}
|
|
backend_image_id=${backend_id}
|
|
backend_repo_digest=${backend_digest}
|
|
backend_archive=superset-tools-backend.${tag}.tar.xz
|
|
frontend_image=${frontend_tag}
|
|
frontend_image_id=${frontend_id}
|
|
frontend_repo_digest=${frontend_digest}
|
|
frontend_archive=superset-tools-frontend.${tag}.tar.xz
|
|
agent_image=${agent_tag}
|
|
agent_image_id=${agent_id}
|
|
agent_repo_digest=${agent_digest}
|
|
agent_archive=superset-tools-agent.${tag}.tar.xz
|
|
compose_file=docker-compose.enterprise-clean.yml
|
|
env_template=.env.enterprise-clean.example
|
|
env_bootstrap_fields=INITIAL_ADMIN_CREATE,INITIAL_ADMIN_USERNAME,INITIAL_ADMIN_PASSWORD,INITIAL_ADMIN_EMAIL
|
|
checksums_file=sha256sums.${tag}.txt
|
|
generated_at_utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
EOF
|
|
|
|
cat > "${DIST_ROOT}/manifest.${tag}.json" <<EOF
|
|
{
|
|
"release_tag": "${tag}",
|
|
"generated_at_utc": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
|
"images": [
|
|
{
|
|
"role": "backend",
|
|
"image": "${backend_tag}",
|
|
"image_id": "${backend_id}",
|
|
"repo_digest": "${backend_digest}",
|
|
"archive": "superset-tools-backend.${tag}.tar.xz"
|
|
},
|
|
{
|
|
"role": "frontend",
|
|
"image": "${frontend_tag}",
|
|
"image_id": "${frontend_id}",
|
|
"repo_digest": "${frontend_digest}",
|
|
"archive": "superset-tools-frontend.${tag}.tar.xz"
|
|
},
|
|
{
|
|
"role": "agent",
|
|
"image": "${agent_tag}",
|
|
"image_id": "${agent_id}",
|
|
"repo_digest": "${agent_digest}",
|
|
"archive": "superset-tools-agent.${tag}.tar.xz"
|
|
}
|
|
],
|
|
"compose_file": "docker-compose.enterprise-clean.yml",
|
|
"env_template": ".env.enterprise-clean.example",
|
|
"env_bootstrap_fields": [
|
|
"INITIAL_ADMIN_CREATE",
|
|
"INITIAL_ADMIN_USERNAME",
|
|
"INITIAL_ADMIN_PASSWORD",
|
|
"INITIAL_ADMIN_EMAIL"
|
|
],
|
|
"checksums_file": "sha256sums.${tag}.txt"
|
|
}
|
|
EOF
|
|
|
|
cp "${SCRIPT_DIR}/.env.enterprise-clean.example" "${DIST_ROOT}/.env.enterprise-clean.example"
|
|
|
|
echo "[bundle] ✅ Bundle created in ${DIST_ROOT}"
|
|
echo " # Load images (decompress stream):"
|
|
echo " xz -dc ${DIST_ROOT}/superset-tools-backend.${tag}.tar.xz | docker load"
|
|
echo " xz -dc ${DIST_ROOT}/superset-tools-frontend.${tag}.tar.xz | docker load"
|
|
echo " xz -dc ${DIST_ROOT}/superset-tools-agent.${tag}.tar.xz | docker load"
|
|
echo " # Edit .env.enterprise-clean.example -> .env.enterprise-clean, then:"
|
|
echo " docker compose -f ${DIST_ROOT}/docker-compose.enterprise-clean.yml up"
|
|
echo ""
|
|
echo " NOTE: '${tag}' bundle uses external PostgreSQL (set POSTGRES_HOST)."
|
|
echo " Corporate certs: mount .crt files via CERTS_PATH=./certs (optional)."
|
|
}
|
|
|
|
# ======================================================================
|
|
# BUNDLE: lightweight all-in-one (single image, no Playwright, <200 MB)
|
|
# ======================================================================
|
|
|
|
bundle_light() {
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: tag is required."
|
|
echo "Usage: ./build.sh bundle:light <tag> (e.g. v1.0.0)"
|
|
exit 1
|
|
fi
|
|
local tag="$1"
|
|
local image_tag="superset-tools:${tag}"
|
|
|
|
mkdir -p "$DIST_ROOT"
|
|
|
|
echo "[bundle:light] Building all-in-one image ${image_tag}..."
|
|
docker build -f docker/all-in-one.Dockerfile -t "${image_tag}" .
|
|
|
|
echo "[bundle:light] Exporting .tar.xz..."
|
|
docker save "${image_tag}" | xz -T0 -6 > "${DIST_ROOT}/superset-tools.${tag}.tar.xz"
|
|
|
|
echo "[bundle:light] Calculating checksums..."
|
|
(
|
|
cd "${DIST_ROOT}"
|
|
sha256sum "superset-tools.${tag}.tar.xz" > "sha256sums-light.${tag}.txt"
|
|
)
|
|
|
|
local img_id repo_digest
|
|
img_id="$(get_image_id "${image_tag}")"
|
|
repo_digest="$(get_repo_digest "${image_tag}")"
|
|
|
|
cat > "${DIST_ROOT}/manifest-light.${tag}.txt" <<EOF
|
|
release_tag=${tag}
|
|
image=${image_tag}
|
|
image_id=${img_id}
|
|
repo_digest=${repo_digest}
|
|
archive=superset-tools.${tag}.tar.xz
|
|
compose_file=docker-compose.light.yml
|
|
checksums_file=sha256sums-light.${tag}.txt
|
|
generated_at_utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
EOF
|
|
|
|
cat > "${DIST_ROOT}/manifest-light.${tag}.json" <<EOF
|
|
{
|
|
"release_tag": "${tag}",
|
|
"generated_at_utc": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
|
"image": "${image_tag}",
|
|
"image_id": "${img_id}",
|
|
"repo_digest": "${repo_digest}",
|
|
"archive": "superset-tools.${tag}.tar.xz",
|
|
"compose_file": "docker-compose.light.yml",
|
|
"checksums_file": "sha256sums-light.${tag}.txt"
|
|
}
|
|
EOF
|
|
|
|
cat > "${DIST_ROOT}/docker-compose.light.yml" <<'COMPOSE'
|
|
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
pull_policy: never
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: ${POSTGRES_DB:-ss_tools}
|
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}
|
|
ports:
|
|
- "${POSTGRES_HOST_PORT:-5432}:5432"
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-ss_tools}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
app:
|
|
image: ${IMAGE:-superset-tools:latest}
|
|
pull_policy: never
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-ss_tools}
|
|
BACKEND_PORT: 8000
|
|
INITIAL_ADMIN_CREATE: ${INITIAL_ADMIN_CREATE:-false}
|
|
INITIAL_ADMIN_USERNAME: ${INITIAL_ADMIN_USERNAME:-admin}
|
|
INITIAL_ADMIN_PASSWORD: ${INITIAL_ADMIN_PASSWORD:-}
|
|
INITIAL_ADMIN_EMAIL: ${INITIAL_ADMIN_EMAIL:-}
|
|
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
|
FEATURES__DATASET_REVIEW: ${FEATURES__DATASET_REVIEW:-true}
|
|
FEATURES__HEALTH_MONITOR: ${FEATURES__HEALTH_MONITOR:-true}
|
|
ports:
|
|
- "${APP_HOST_PORT:-8000}:8000"
|
|
volumes:
|
|
- ./storage:/app/storage
|
|
|
|
volumes:
|
|
postgres_data:
|
|
COMPOSE
|
|
|
|
cp "${SCRIPT_DIR}/.env.enterprise-clean.example" "${DIST_ROOT}/.env.light.example"
|
|
|
|
echo "[bundle:light] ✅ Lightweight bundle created in ${DIST_ROOT}"
|
|
echo " # Load image:"
|
|
echo " xz -dc ${DIST_ROOT}/superset-tools.${tag}.tar.xz | docker load"
|
|
echo " docker compose -f ${DIST_ROOT}/docker-compose.light.yml up"
|
|
echo ""
|
|
echo " Single container (without compose):"
|
|
echo " docker run -p 8000:8000 --env-file backend/.env ${image_tag}"
|
|
}
|
|
|
|
# ======================================================================
|
|
# HELP
|
|
# ======================================================================
|
|
|
|
show_help() {
|
|
cat <<'HELP'
|
|
Usage: ./build.sh <command> [options]
|
|
|
|
Commands for local docker:
|
|
up [profile] Build and start services (default: current)
|
|
down [profile] Stop and remove containers
|
|
restart [profile] Rebuild and restart services
|
|
logs [profile] Tail logs from all services
|
|
status Show running containers for all profiles
|
|
|
|
Commands for release bundles:
|
|
bundle <tag> Build release images (backend + frontend + agent .tar.xz's).
|
|
NOTE: external PostgreSQL only — no bundled postgres image.
|
|
Example: ./build.sh bundle v1.0.0
|
|
|
|
bundle:light <tag> Lightweight all-in-one image (.tar.xz, <200 MB, no Playwright)
|
|
Example: ./build.sh bundle:light v1.0.0
|
|
|
|
Profiles: current (default), master, enterprise-clean
|
|
|
|
Backward-compatible shortcuts:
|
|
./build.sh -> ./build.sh up current
|
|
./build.sh master -> ./build.sh up master
|
|
./build.sh enterprise-clean -> ./build.sh up enterprise-clean
|
|
|
|
Output:
|
|
Local docker: docker compose -p superset-tools-{profile}
|
|
Bundle artifacts: dist/docker/
|
|
|
|
Notes:
|
|
- 'current' and 'master' use docker-compose.yml (dev, with local postgres).
|
|
- 'enterprise-clean' uses docker-compose.enterprise-clean.yml (build from source,
|
|
external postgres, corporate certs, optional nginx SSL).
|
|
HELP
|
|
}
|
|
|
|
# ======================================================================
|
|
# MAIN DISPATCH
|
|
# ======================================================================
|
|
|
|
main() {
|
|
local CMD="${1:-up}"
|
|
shift 2>/dev/null || true
|
|
|
|
case "$CMD" in
|
|
up|down|restart|logs|bundle|bundle:light|status|help|-h|--help)
|
|
# Valid commands — proceed
|
|
;;
|
|
*)
|
|
# Backward compat: treat unknown arg as profile for "up"
|
|
local profile="$CMD"
|
|
CMD="up"
|
|
set -- "$profile" "$@"
|
|
;;
|
|
esac
|
|
|
|
case "$CMD" in
|
|
up) compose_up "${1:-current}" ;;
|
|
down) compose_down "${1:-current}" ;;
|
|
restart) compose_restart "${1:-current}" ;;
|
|
logs) compose_logs "${1:-current}" ;;
|
|
bundle) bundle_release "$@" ;;
|
|
bundle:light) bundle_light "$@" ;;
|
|
status) compose_status ;;
|
|
help|-h|--help) show_help ;;
|
|
*)
|
|
echo "Error: unknown command '$CMD'. See ./build.sh help"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|