stages: - build - migrate - deploy - seed default: tags: - self-hosted-stg workflow: rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' when: always - when: never variables: DOCKER_BUILDKIT: "1" IMAGE_TAG: "staging_${CI_COMMIT_SHORT_SHA}" IMAGE_NAME: "${CI_REGISTRY_IMAGE}:${IMAGE_TAG}" IMAGE_LATEST: "${CI_REGISTRY_IMAGE}:staging_latest" DEPLOY_DIR: "/opt/deploy/stg-lti-api" COMPOSE_FILE: "docker-compose.yaml" # ========================= # BUILD (AUTO) # ========================= build_staging: stage: build rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' script: - set -e - docker info - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" - echo "✅ Build image: $IMAGE_NAME" - docker build -t "$IMAGE_NAME" -f Dockerfile . - echo "✅ Push image: $IMAGE_NAME" - docker push "$IMAGE_NAME" - echo "✅ Tag latest: $IMAGE_LATEST" - docker tag "$IMAGE_NAME" "$IMAGE_LATEST" - docker push "$IMAGE_LATEST" # ========================= # MIGRATE (AUTO) - JOIN COMPOSE NETWORK # ========================= migrate_staging: stage: migrate rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' needs: - job: build_staging artifacts: false script: - set -e - echo "✅ Running migrations (staging) ..." # ✅ masuk deploy dir (ada .env + docker-compose) - cd "$DEPLOY_DIR" - test -f "$COMPOSE_FILE" || (echo "❌ $COMPOSE_FILE not found in $DEPLOY_DIR" && exit 1) - test -f .env || (echo "❌ .env not found in $DEPLOY_DIR" && exit 1) # ✅ load env dari server - set -a - . ./.env - set +a # ✅ pastikan DB env ada - test -n "$DB_HOST" || (echo "❌ DB_HOST empty" && exit 1) - test -n "$DB_PORT" || (echo "❌ DB_PORT empty" && exit 1) - test -n "$DB_USER" || (echo "❌ DB_USER empty" && exit 1) - test -n "$DB_PASSWORD" || (echo "❌ DB_PASSWORD empty" && exit 1) - test -n "$DB_NAME" || (echo "❌ DB_NAME empty" && exit 1) # ✅ generate DATABASE_URL - export DATABASE_URL="postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=${DB_SSLMODE:-disable}" - echo "✅ DATABASE_URL=$DATABASE_URL" # ✅ pastikan postgres container hidup supaya network exist - echo "✅ Ensuring postgres & redis running ..." - docker compose -f "$COMPOSE_FILE" up -d postgres-sso redis-sso || true # NOTE: ganti postgres-sso/redis-sso sesuai nama service di docker-compose lti kamu: # kalau lti compose pakai stg-postgres-lti / stg-redis-lti, ganti di line ini. # ✅ ambil network name compose (1st network) - export COMPOSE_NETWORK="$(docker compose -f "$COMPOSE_FILE" config | awk '/networks:/ {getline; print $1}' | tr -d ':')" - echo "✅ Compose network key: $COMPOSE_NETWORK" # ✅ ambil nama network aktual di docker (prefix foldername_) - export NETWORK_NAME="$(docker network ls --format '{{.Name}}' | grep "_${COMPOSE_NETWORK}$" | head -n 1)" - test -n "$NETWORK_NAME" || (echo "❌ Cannot find docker network for compose ($COMPOSE_NETWORK)" && exit 1) - echo "✅ Docker network detected: $NETWORK_NAME" # ✅ migrations dari repo (CI workspace) - echo "✅ Checking migrations from repo..." - ls -lah "$CI_PROJECT_DIR/internal/database/migrations" # ✅ run migrate (JOIN NETWORK) - echo "✅ Running migrations via migrate/migrate container ..." - set +e - out=$(docker run --rm \ --network "$NETWORK_NAME" \ -v "$CI_PROJECT_DIR/internal/database/migrations:/migrations:ro" \ migrate/migrate:v4.15.2 \ -path=/migrations -database "$DATABASE_URL" up 2>&1) - code=$? - set -e - echo "$out" # ✅ handle no change properly - | if echo "$out" | grep -qi "no change"; then echo "✅ No change (already up to date)" exit 0 fi if [ $code -ne 0 ]; then echo "❌ Migration failed with exit code $code" exit $code fi echo "✅ Migration applied successfully" # ========================= # DEPLOY (AUTO) # ========================= deploy_staging: stage: deploy rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' needs: - job: migrate_staging artifacts: false - job: build_staging artifacts: false script: - set -e - docker info - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" - cd "$DEPLOY_DIR" - test -f "$COMPOSE_FILE" || (echo "❌ $COMPOSE_FILE not found in $DEPLOY_DIR" && exit 1) - test -f .env || (echo "❌ .env not found in $DEPLOY_DIR" && exit 1) - docker compose -f "$COMPOSE_FILE" pull - docker compose -f "$COMPOSE_FILE" up -d --force-recreate - docker image prune -f # ========================= # SEED (MANUAL) - OPTIONAL # ========================= seed_staging: stage: seed rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' needs: - job: deploy_staging artifacts: false when: manual allow_failure: false script: - set -e - cd "$DEPLOY_DIR" - test -f "$COMPOSE_FILE" || (echo "❌ $COMPOSE_FILE not found" && exit 1) - test -f .env || (echo "❌ .env not found" && exit 1) - docker compose -f "$COMPOSE_FILE" pull seed || true - docker compose -f "$COMPOSE_FILE" run --rm seed