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" # ========================= # 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) - migrations diambil dari repo GitLab # ========================= migrate_staging: stage: migrate rules: - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' needs: - job: build_staging artifacts: false script: | set -e # ✅ Load env dari server (.env hanya ada di server) cd "$DEPLOY_DIR" test -f .env || (echo "❌ .env not found in $DEPLOY_DIR" && exit 1) set -a . ./.env set +a # ✅ Generate DATABASE_URL dari DB_* 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) export DATABASE_URL="postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=${DB_SSLMODE:-disable}" echo "✅ DATABASE_URL ready" # ✅ migrations dari repo echo "✅ Checking migrations from repo..." ls -lah "$CI_PROJECT_DIR/internal/database/migrations" echo "✅ Running migrations via migrate/migrate container" set +e docker run --rm \ -v "$CI_PROJECT_DIR/internal/database/migrations:/migrations:ro" \ migrate/migrate:v4.15.2 \ -path=/migrations -database "$DATABASE_URL" up code=$? set -e if [ $code -eq 0 ]; then echo "✅ Migration applied successfully" elif [ $code -eq 1 ]; then echo "✅ No change (already up to date)" else echo "❌ Migration failed with exit code $code" exit $code fi # ========================= # 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 docker-compose.yaml || (echo "❌ docker-compose.yaml not found in $DEPLOY_DIR" && exit 1) test -f .env || (echo "❌ .env not found in $DEPLOY_DIR" && exit 1) docker compose pull docker compose up -d --force-recreate docker image prune -f # ========================= # SEED (MANUAL) # ========================= 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 docker-compose.yaml || (echo "❌ docker-compose.yaml not found in $DEPLOY_DIR" && exit 1) test -f .env || (echo "❌ .env not found in $DEPLOY_DIR" && exit 1) echo "✅ Pull latest seed image" docker compose pull seed || true echo "🌱 Running seeder..." docker compose run --rm seed echo "✅ Seed completed"