#!/bin/bash # deploy.sh – Bygg och starta om recipe-app # Kör från: /opt/containers/recipe-app/ # Kräver: .env-fil i samma mapp # # Användning: # ./deploy.sh – bygg allt (backend + flutter + importer) # ./deploy.sh --backend – bygg bara backend (snabbast, ~2-3 min) # ./deploy.sh --flutter – bygg bara flutter web-app # ./deploy.sh --importer – bygg bara importer-microservice # ./deploy.sh --seed – kör full seed på databasen (opt-in) # ./deploy.sh --skip-migration – hoppa över automatisk startup-migrering i recipe-api # ./deploy.sh --clean-database – kör migration och därefter underhålls-SQL som rensar data men behåller kategorier # ./deploy.sh --pull-always – kontrollera uppdateringar för basimages # ./deploy.sh --backend --seed – kombinera flaggor fritt (git pull körs alltid) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" START_TS="$(date +%s)" # ── Flaggor ────────────────────────────────────────────────────────────────── BUILD_BACKEND=false BUILD_FLUTTER=false BUILD_IMPORTER=false RUN_SEED=false RUN_CLEAN_DATABASE=false SKIP_MIGRATION=false PULL_IMAGES=false # --pull=false är standard (snabbt) BUILD_ALL=true # om inga specifika tjänster anges, bygg allt # ── Hjälpfunktioner ─────────────────────────────────────────────────────────── info() { echo "[INFO] $*"; } warn() { echo "[WARN] $*"; } fatal() { echo "[ERROR] $*"; exit 1; } require_cmd() { command -v "$1" >/dev/null 2>&1 || fatal "Kommando saknas: $1" } read_env_value() { local key="$1" local line line=$(grep -E "^${key}=" .env | tail -n 1 || true) line="${line#*=}" line="${line%\"}" line="${line#\"}" line="${line%\'}" line="${line#\'}" printf '%s' "$line" } wait_for_backend_prisma() { info "Väntar på att backend är redo för Prisma-kommandon..." for i in $(seq 1 30); do if docker exec recipe-api sh -lc "test -f /app/prisma/schema.prisma" >/dev/null 2>&1; then return 0 fi info " ...försök $i/30" sleep 2 done return 1 } wait_for_db() { local root_password="$1" info "Väntar på att databasen är redo..." for i in $(seq 1 30); do if docker exec recipe-db mariadb-admin ping -h 127.0.0.1 -uroot -p"$root_password" --silent 2>/dev/null; then return 0 fi info " ...försök $i/30" sleep 2 done return 1 } run_prisma_migrate_deploy() { local output info "Kör Prisma-migrationer (deploy)..." info " ▶ Kör: npx prisma migrate deploy" if ! output=$(docker exec recipe-api sh -lc "cd /app && npx prisma migrate deploy --schema prisma/schema.prisma" 2>&1); then echo "$output" fatal "Prisma migration misslyckades." fi echo "$output" if echo "$output" | grep -qi "No pending migrations"; then info "Migration-status: inga väntande migrationer." elif echo "$output" | grep -qi "Applying migration"; then info "Migration-status: minst en migration applicerades." else warn "Migration-status: kunde inte avgöra om nya migrationer applicerades." fi info "Migrationer slutförda utan fel." } run_prisma_generate() { info "Uppdaterar Prisma Client..." docker exec recipe-api sh -lc "cd /app && npx prisma generate --schema prisma/schema.prisma" } for arg in "$@"; do case "$arg" in --backend) BUILD_BACKEND=true; BUILD_ALL=false ;; --flutter) BUILD_FLUTTER=true; BUILD_ALL=false ;; --importer) BUILD_IMPORTER=true; BUILD_ALL=false ;; --seed) RUN_SEED=true ;; --skip-migration) SKIP_MIGRATION=true ;; --clean-database) RUN_CLEAN_DATABASE=true; BUILD_BACKEND=true; BUILD_ALL=false ;; --pull-always) PULL_IMAGES=true ;; --help|-h) sed -n '/^# Användning:/,/^[^#]/p' "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) fatal "Okänd flagga: $arg (--help för hjälp)" ;; esac done if [ "$BUILD_ALL" = true ]; then BUILD_BACKEND=true BUILD_FLUTTER=true BUILD_IMPORTER=true fi # Om databasrensning begärs, stäng av automigrering i containern för att undvika dubbelkörning. if [ "$RUN_CLEAN_DATABASE" = true ]; then SKIP_MIGRATION=true fi # ── Validering ──────────────────────────────────────────────────────────────── [ -f ".env" ] || fatal ".env saknas. Kör: cp .env.example .env && nano .env" require_cmd git require_cmd docker if [ "$BUILD_BACKEND" = true ] || [ "$RUN_SEED" = true ] || [ "$RUN_CLEAN_DATABASE" = true ]; then require_cmd grep fi export SKIP_MIGRATION COMPOSE_CMD=(docker compose -f compose.yml -f compose.flutter.yml) # ── Git pull ────────────────────────────────────────────────────────────────── info "Hämtar senaste kod (recipe-app)..." git pull origin main if [ -d "$SCRIPT_DIR/../microservice-importer/.git" ]; then info "Hämtar senaste kod (microservice-importer)..." (cd "$SCRIPT_DIR/../microservice-importer" && git pull origin main) else warn "microservice-importer repo hittades inte på förväntad path, hoppar över git pull där." fi # ── Bygger valda tjänster ───────────────────────────────────────────────────── SERVICES=() [ "$BUILD_BACKEND" = true ] && SERVICES+=(recipe-api) [ "$BUILD_FLUTTER" = true ] && SERVICES+=(recipe-flutter) [ "$BUILD_IMPORTER" = true ] && SERVICES+=(importer-api) if [ "${#SERVICES[@]}" -eq 0 ]; then info "Bygger: alla tjänster..." else info "Bygger: ${SERVICES[*]}" fi if [ "$PULL_IMAGES" = true ]; then info "(kontrollerar uppdateringar för basimages...)" "${COMPOSE_CMD[@]}" build "${SERVICES[@]}" else "${COMPOSE_CMD[@]}" build --pull=false "${SERVICES[@]}" fi info "Startar tjänster..." "${COMPOSE_CMD[@]}" up -d # ── Databasrensning (opt-in) ────────────────────────────────────────────────── if [ "$RUN_CLEAN_DATABASE" = true ]; then CLEAN_SQL_FILE="backend/prisma/maintenance/clean-database.sql" wait_for_backend_prisma || fatal "Backend blev inte redo för Prisma-kommandon i tid." info "Säkerställer uppdaterat databasschema före rensning..." run_prisma_migrate_deploy [ -f "$CLEAN_SQL_FILE" ] || fatal "Saknar $CLEAN_SQL_FILE" MARIADB_ROOT_PASSWORD="$(read_env_value MARIADB_ROOT_PASSWORD)" MARIADB_DATABASE="$(read_env_value MARIADB_DATABASE)" [ -n "$MARIADB_ROOT_PASSWORD" ] || fatal "MARIADB_ROOT_PASSWORD saknas i .env" [ -n "$MARIADB_DATABASE" ] || fatal "MARIADB_DATABASE saknas i .env" info "Kör databasrensning från $CLEAN_SQL_FILE ..." docker exec -i recipe-db mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE" < "$CLEAN_SQL_FILE" info "Databasrensning klar (kategorier bevarade enligt SQL-filen)." run_prisma_generate fi # Visa Prisma Client-output även vid vanlig deploy när automigrering är aktiv. if [ "$RUN_CLEAN_DATABASE" = false ] && [ "$SKIP_MIGRATION" = false ] && [ "$BUILD_BACKEND" = true ]; then wait_for_backend_prisma || fatal "Backend blev inte redo för Prisma-kommandon i tid." run_prisma_generate fi # ── Seed (opt-in) ───────────────────────────────────────────────────────────── if [ "$RUN_SEED" = true ]; then MARIADB_ROOT_PASSWORD="$(read_env_value MARIADB_ROOT_PASSWORD)" MARIADB_DATABASE="$(read_env_value MARIADB_DATABASE)" [ -n "$MARIADB_ROOT_PASSWORD" ] || fatal "MARIADB_ROOT_PASSWORD saknas i .env" [ -n "$MARIADB_DATABASE" ] || fatal "MARIADB_DATABASE saknas i .env" wait_for_db "$MARIADB_ROOT_PASSWORD" || fatal "Databasen blev inte redo i tid." if [ -f "db/seeds/seed_all.sql" ]; then docker exec -i recipe-db mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE" < db/seeds/seed_all.sql info "Full seed klar." else warn "Ingen db/seeds/seed_all.sql hittades — hoppar över seed." fi fi info "Status:" "${COMPOSE_CMD[@]}" ps END_TS="$(date +%s)" DURATION="$((END_TS - START_TS))" info "Deploy klart på ${DURATION}s."