ci(deploy): add migration control and deployment improvements
- Add SKIP_MIGRATION environment variable to control automatic Prisma migrations in backend - Update Dockerfile to conditionally run migrations based on SKIP_MIGRATION flag - Enhance deploy.sh with: - Better error handling using set -euo pipefail - New --skip-migration flag to bypass automatic migration startup - Improved documentation and help text - New helper functions for waiting on services and database - Better status reporting for migration results - Update compose.yml to include SKIP_MIGRATION environment variable
This commit is contained in:
+1
-1
@@ -31,4 +31,4 @@ COPY --from=builder /app/prisma ./prisma
|
|||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD ["sh", "-c", "until ./node_modules/.bin/prisma migrate deploy; do echo 'Migration failed, retrying in 5s...'; sleep 5; done && node dist/main"]
|
CMD ["sh", "-c", "if [ \"${SKIP_MIGRATION:-false}\" != \"true\" ]; then echo 'Running automatic Prisma migration...'; until ./node_modules/.bin/prisma migrate deploy --schema prisma/schema.prisma; do echo 'Migration failed, retrying in 5s...'; sleep 5; done; else echo 'Skipping automatic Prisma migration (SKIP_MIGRATION=true).'; fi && node dist/main"]
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ services:
|
|||||||
IMPORTER_SERVICE_URL: "http://importer-api:3001"
|
IMPORTER_SERVICE_URL: "http://importer-api:3001"
|
||||||
RECEIPT_TRACE_DECISIONS: "${RECEIPT_TRACE_DECISIONS:-0}"
|
RECEIPT_TRACE_DECISIONS: "${RECEIPT_TRACE_DECISIONS:-0}"
|
||||||
PRISMA_LOG_QUERIES: "${PRISMA_LOG_QUERIES:-0}"
|
PRISMA_LOG_QUERIES: "${PRISMA_LOG_QUERIES:-0}"
|
||||||
|
SKIP_MIGRATION: "${SKIP_MIGRATION:-false}"
|
||||||
volumes:
|
volumes:
|
||||||
- recipe_images:/app/recipe-images
|
- recipe_images:/app/recipe-images
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
@@ -9,15 +9,17 @@
|
|||||||
# ./deploy.sh --flutter – bygg bara flutter web-app
|
# ./deploy.sh --flutter – bygg bara flutter web-app
|
||||||
# ./deploy.sh --importer – bygg bara importer-microservice
|
# ./deploy.sh --importer – bygg bara importer-microservice
|
||||||
# ./deploy.sh --seed – kör full seed på databasen (opt-in)
|
# ./deploy.sh --seed – kör full seed på databasen (opt-in)
|
||||||
# ./deploy.sh --migrate – kör Prisma-migrationer (opt-in)
|
# ./deploy.sh --migrate – kör Prisma-migrationer explicit (opt-in)
|
||||||
|
# ./deploy.sh --skip-migration – hoppa över automatisk startup-migrering i recipe-api
|
||||||
# ./deploy.sh --clean-database – kör underhålls-SQL som rensar data men behåller kategorier
|
# ./deploy.sh --clean-database – kör underhålls-SQL som rensar data men behåller kategorier
|
||||||
# ./deploy.sh --pull-always – kontrollera uppdateringar för basimages (flutter:3.41.9, node:24.15.0 etc)
|
# ./deploy.sh --pull-always – kontrollera uppdateringar för basimages
|
||||||
# ./deploy.sh --backend --seed – kombinera flaggor fritt (git pull körs alltid)
|
# ./deploy.sh --backend --seed – kombinera flaggor fritt (git pull körs alltid)
|
||||||
|
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
|
START_TS="$(date +%s)"
|
||||||
|
|
||||||
# ── Flaggor ──────────────────────────────────────────────────────────────────
|
# ── Flaggor ──────────────────────────────────────────────────────────────────
|
||||||
BUILD_BACKEND=false
|
BUILD_BACKEND=false
|
||||||
@@ -26,23 +28,94 @@ BUILD_IMPORTER=false
|
|||||||
RUN_SEED=false
|
RUN_SEED=false
|
||||||
RUN_MIGRATE=false
|
RUN_MIGRATE=false
|
||||||
RUN_CLEAN_DATABASE=false
|
RUN_CLEAN_DATABASE=false
|
||||||
|
SKIP_MIGRATION=false
|
||||||
PULL_IMAGES=false # --pull=false är standard (snabbt)
|
PULL_IMAGES=false # --pull=false är standard (snabbt)
|
||||||
BUILD_ALL=true # om inga specifika tjänster anges, bygg allt
|
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."
|
||||||
|
}
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--backend) BUILD_BACKEND=true; BUILD_ALL=false ;;
|
--backend) BUILD_BACKEND=true; BUILD_ALL=false ;;
|
||||||
--flutter) BUILD_FLUTTER=true; BUILD_ALL=false ;;
|
--flutter) BUILD_FLUTTER=true; BUILD_ALL=false ;;
|
||||||
--importer) BUILD_IMPORTER=true; BUILD_ALL=false ;;
|
--importer) BUILD_IMPORTER=true; BUILD_ALL=false ;;
|
||||||
--seed) RUN_SEED=true ;;
|
--seed) RUN_SEED=true ;;
|
||||||
--migrate) RUN_MIGRATE=true; BUILD_BACKEND=true; BUILD_ALL=false ;;
|
--migrate) RUN_MIGRATE=true; BUILD_BACKEND=true; BUILD_ALL=false ;;
|
||||||
--clean-database) RUN_CLEAN_DATABASE=true; BUILD_BACKEND=true; BUILD_ALL=false ;;
|
--skip-migration) SKIP_MIGRATION=true ;;
|
||||||
--pull-always) PULL_IMAGES=true ;;
|
--clean-database) RUN_CLEAN_DATABASE=true; BUILD_BACKEND=true; BUILD_ALL=false ;;
|
||||||
|
--pull-always) PULL_IMAGES=true ;;
|
||||||
--help|-h)
|
--help|-h)
|
||||||
sed -n '/^# Användning:/,/^[^#]/p' "$0" | grep '^#' | sed 's/^# \?//'
|
sed -n '/^# Användning:/,/^[^#]/p' "$0" | grep '^#' | sed 's/^# \?//'
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*) echo "Okänd flagga: $arg (--help för hjälp)"; exit 1 ;;
|
*) fatal "Okänd flagga: $arg (--help för hjälp)" ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -52,99 +125,106 @@ if [ "$BUILD_ALL" = true ]; then
|
|||||||
BUILD_IMPORTER=true
|
BUILD_IMPORTER=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Validering ────────────────────────────────────────────────────────────────
|
# Om explicit migration begärs, stäng av automigrering i containern för att undvika dubbelkörning.
|
||||||
if [ ! -f ".env" ]; then
|
if [ "$RUN_MIGRATE" = true ]; then
|
||||||
echo "Fel: .env saknas. Kopiera .env.example och fyll i värdena:"
|
SKIP_MIGRATION=true
|
||||||
echo " cp .env.example .env && nano .env"
|
|
||||||
exit 1
|
|
||||||
fi
|
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 ] || [ "$RUN_MIGRATE" = true ]; then
|
||||||
|
require_cmd grep
|
||||||
|
fi
|
||||||
|
|
||||||
|
export SKIP_MIGRATION
|
||||||
|
COMPOSE_CMD=(docker compose -f compose.yml -f compose.flutter.yml)
|
||||||
|
|
||||||
# ── Git pull ──────────────────────────────────────────────────────────────────
|
# ── Git pull ──────────────────────────────────────────────────────────────────
|
||||||
echo "Hämtar senaste kod (recipe-app)..."
|
info "Hämtar senaste kod (recipe-app)..."
|
||||||
git pull origin main
|
git pull origin main
|
||||||
|
|
||||||
echo "Hämtar senaste kod (microservice-importer)..."
|
if [ -d "$SCRIPT_DIR/../microservice-importer/.git" ]; then
|
||||||
(cd "$SCRIPT_DIR/../microservice-importer" && git pull origin main)
|
info "Hämtar senaste kod (microservice-importer)..."
|
||||||
|
(cd "$SCRIPT_DIR/../microservice-importer" && git pull origin main)
|
||||||
# ── Bygger valda tjänster ─────────────────────────────────────────────────────
|
|
||||||
COMPOSE="docker compose -f compose.yml -f compose.flutter.yml"
|
|
||||||
SERVICES=""
|
|
||||||
|
|
||||||
[ "$BUILD_BACKEND" = true ] && SERVICES="$SERVICES recipe-api"
|
|
||||||
[ "$BUILD_FLUTTER" = true ] && SERVICES="$SERVICES recipe-flutter"
|
|
||||||
[ "$BUILD_IMPORTER" = true ] && SERVICES="$SERVICES importer-api"
|
|
||||||
|
|
||||||
echo "Bygger: ${SERVICES:-alla tjänster}..."
|
|
||||||
if [ "$PULL_IMAGES" = true ]; then
|
|
||||||
# Kontrollera om nya versioner av basimages finns på Docker Hub / ghcr.io
|
|
||||||
echo " (kontrollerar uppdateringar för basimages...)"
|
|
||||||
$COMPOSE build $SERVICES
|
|
||||||
else
|
else
|
||||||
# Standard: använd lokala cachade images, snabbare
|
warn "microservice-importer repo hittades inte på förväntad path, hoppar över git pull där."
|
||||||
$COMPOSE build --pull=false $SERVICES
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Startar tjänster..."
|
# ── Bygger valda tjänster ─────────────────────────────────────────────────────
|
||||||
$COMPOSE up -d
|
SERVICES=()
|
||||||
|
[ "$BUILD_BACKEND" = true ] && SERVICES+=(recipe-api)
|
||||||
|
[ "$BUILD_FLUTTER" = true ] && SERVICES+=(recipe-flutter)
|
||||||
|
[ "$BUILD_IMPORTER" = true ] && SERVICES+=(importer-api)
|
||||||
|
|
||||||
# ── Prisma migreringar och databasrensning (opt-in) ───────────────────────────
|
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
|
||||||
|
|
||||||
|
# ── Prisma migreringar och databasrensning (opt-in) ─────────────────────────
|
||||||
if [ "$RUN_MIGRATE" = true ] || [ "$RUN_CLEAN_DATABASE" = true ]; then
|
if [ "$RUN_MIGRATE" = true ] || [ "$RUN_CLEAN_DATABASE" = true ]; then
|
||||||
CLEAN_SQL_FILE="backend/prisma/maintenance/clean-database.sql"
|
CLEAN_SQL_FILE="backend/prisma/maintenance/clean-database.sql"
|
||||||
|
|
||||||
echo "Väntar på att backend är redo för Prisma-kommandon..."
|
wait_for_backend_prisma || fatal "Backend blev inte redo för Prisma-kommandon i tid."
|
||||||
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
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo " ...försök $i/30"
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$RUN_MIGRATE" = true ]; then
|
if [ "$RUN_MIGRATE" = true ]; then
|
||||||
echo "Kör Prisma-migrationer (deploy)..."
|
run_prisma_migrate_deploy
|
||||||
docker exec recipe-api sh -lc "cd /app && npx prisma migrate deploy --schema prisma/schema.prisma"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$RUN_CLEAN_DATABASE" = true ]; then
|
if [ "$RUN_CLEAN_DATABASE" = true ]; then
|
||||||
if [ ! -f "$CLEAN_SQL_FILE" ]; then
|
[ -f "$CLEAN_SQL_FILE" ] || fatal "Saknar $CLEAN_SQL_FILE"
|
||||||
echo "Fel: saknar $CLEAN_SQL_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
MARIADB_ROOT_PASSWORD=$(grep MARIADB_ROOT_PASSWORD .env | cut -d '=' -f2 | tr -d '"' | tr -d "'")
|
MARIADB_ROOT_PASSWORD="$(read_env_value MARIADB_ROOT_PASSWORD)"
|
||||||
MARIADB_DATABASE=$(grep MARIADB_DATABASE .env | cut -d '=' -f2 | tr -d '"' | tr -d "'")
|
MARIADB_DATABASE="$(read_env_value MARIADB_DATABASE)"
|
||||||
|
|
||||||
echo "Kör databasrensning från $CLEAN_SQL_FILE ..."
|
[ -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"
|
docker exec -i recipe-db mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE" < "$CLEAN_SQL_FILE"
|
||||||
echo "Databasrensning klar (kategorier bevarade enligt SQL-filen)."
|
info "Databasrensning klar (kategorier bevarade enligt SQL-filen)."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Uppdaterar Prisma Client..."
|
info "Uppdaterar Prisma Client..."
|
||||||
docker exec recipe-api sh -lc "cd /app && npx prisma generate --schema prisma/schema.prisma"
|
docker exec recipe-api sh -lc "cd /app && npx prisma generate --schema prisma/schema.prisma"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Seed (opt-in) ─────────────────────────────────────────────────────────────
|
# ── Seed (opt-in) ─────────────────────────────────────────────────────────────
|
||||||
if [ "$RUN_SEED" = true ]; then
|
if [ "$RUN_SEED" = true ]; then
|
||||||
MARIADB_ROOT_PASSWORD=$(grep MARIADB_ROOT_PASSWORD .env | cut -d '=' -f2 | tr -d '"' | tr -d "'")
|
MARIADB_ROOT_PASSWORD="$(read_env_value MARIADB_ROOT_PASSWORD)"
|
||||||
MARIADB_DATABASE=$(grep MARIADB_DATABASE .env | cut -d '=' -f2 | tr -d '"' | tr -d "'")
|
MARIADB_DATABASE="$(read_env_value MARIADB_DATABASE)"
|
||||||
|
|
||||||
echo "Väntar på att databasen är redo..."
|
[ -n "$MARIADB_ROOT_PASSWORD" ] || fatal "MARIADB_ROOT_PASSWORD saknas i .env"
|
||||||
for i in $(seq 1 30); do
|
[ -n "$MARIADB_DATABASE" ] || fatal "MARIADB_DATABASE saknas i .env"
|
||||||
if docker exec recipe-db mariadb-admin ping -h 127.0.0.1 -uroot -p"$MARIADB_ROOT_PASSWORD" --silent 2>/dev/null; then
|
|
||||||
break
|
wait_for_db "$MARIADB_ROOT_PASSWORD" || fatal "Databasen blev inte redo i tid."
|
||||||
fi
|
|
||||||
echo " ...försök $i/30"
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -f "db/seeds/seed_all.sql" ]; then
|
if [ -f "db/seeds/seed_all.sql" ]; then
|
||||||
docker exec -i recipe-db mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE" \
|
docker exec -i recipe-db mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE" < db/seeds/seed_all.sql
|
||||||
< db/seeds/seed_all.sql
|
info "Full seed klar."
|
||||||
echo "Full seed klar."
|
|
||||||
else
|
else
|
||||||
echo "Ingen db/seeds/seed_all.sql hittades — hoppar över seed."
|
warn "Ingen db/seeds/seed_all.sql hittades — hoppar över seed."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Status:"
|
info "Status:"
|
||||||
$COMPOSE ps
|
"${COMPOSE_CMD[@]}" ps
|
||||||
|
|
||||||
|
END_TS="$(date +%s)"
|
||||||
|
DURATION="$((END_TS - START_TS))"
|
||||||
|
info "Deploy klart på ${DURATION}s."
|
||||||
|
|||||||
Reference in New Issue
Block a user