diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a4778a3..2417298f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,15 +1,29 @@ workflow: rules: + # MR pipeline - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + when: always + + # Push pipeline hanya untuk env branch - if: '$CI_COMMIT_BRANCH == "development"' + when: always - if: '$CI_COMMIT_BRANCH == "staging"' + when: always - if: '$CI_COMMIT_BRANCH == "production"' + when: always + + # Selain itu jangan buat pipeline - when: never include: - - local: "ci/development.yml" + # khusus MR (notif) + - local: "ci/merge_request.yml" rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + + # khusus push ke branch env + - local: "ci/development.yml" + rules: - if: '$CI_COMMIT_BRANCH == "development"' - local: "ci/staging.yml" diff --git a/ci/development.yml b/ci/development.yml index 43d574b9..7b4733b5 100644 --- a/ci/development.yml +++ b/ci/development.yml @@ -4,9 +4,14 @@ stages: deploy-dev: stage: deploy image: alpine:3.20 + + rules: + - if: '$CI_COMMIT_BRANCH == "development"' + when: on_success + - when: never + variables: DEPLOY_APP: "LTI-MBUGROUP" - # Opsional: kalau pakai submodule, ini bikin clone submodule pakai SSH juga GIT_SUBMODULE_STRATEGY: recursive GIT_DEPTH: "1" @@ -27,7 +32,6 @@ deploy-dev: script: - echo "🚀 Deploying latest code to $SERVER_USER@$SERVER_IP" - - > if ssh -o StrictHostKeyChecking=no "$SERVER_USER@$SERVER_IP" " set -e @@ -83,8 +87,5 @@ deploy-dev: curl -sS -H "Content-Type: application/json" \ -d @payload.json "$DISCORD_WEBHOOK_URL"; - only: - - development - environment: name: development diff --git a/ci/merge_request.yml b/ci/merge_request.yml new file mode 100644 index 00000000..3c43d027 --- /dev/null +++ b/ci/merge_request.yml @@ -0,0 +1,48 @@ +stages: + - notify + +notify_discord_on_mr_request_main_dev: + stage: notify + image: alpine:3.20 + rules: + # hanya MR yang target ke main atau development + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "development")' + when: on_success + - when: never + + script: + - apk add --no-cache curl jq coreutils + - | + TIME_HUMAN="$(date '+%d/%m/%y, %H.%M')" + TIME_ISO="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + + TITLE="${CI_MERGE_REQUEST_TITLE}" + IID="!${CI_MERGE_REQUEST_IID}" + USER_LINE="${GITLAB_USER_NAME} (${GITLAB_USER_LOGIN})" + PROJECT_PATH="${CI_PROJECT_PATH}" + USERNAME="${GITLAB_USER_LOGIN}" + MR_URL="${CI_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}" + + DESC="$(printf "**%s**\n\n%s opened merge request %s %s\n%s" \ + "$USERNAME" "$USER_LINE" "$IID" "$TITLE" "$TIME_HUMAN")" + + payload=$(jq -n \ + --arg desc "$DESC" \ + --arg project "$PROJECT_PATH" \ + --arg timeiso "$TIME_ISO" \ + --arg mrurl "$MR_URL" \ + '{ + "username": "Mock-api - Merge Requests", + "embeds": [ + { + "description": ($desc + "\n" + $mrurl), + "color": 15105570, + "footer": { "text": $project }, + "timestamp": $timeiso + } + ] + }') + + curl -sS -H "Content-Type: application/json" \ + -d "$payload" \ + "$DISCORD_WEBHOOK_URL" diff --git a/ci/production.yml b/ci/production.yml index 48bf64fb..ed1a2d72 100644 --- a/ci/production.yml +++ b/ci/production.yml @@ -8,12 +8,6 @@ default: tags: - self-hosted-prod -workflow: - rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' - when: always - - when: never - variables: DOCKER_BUILDKIT: "1" @@ -30,7 +24,9 @@ variables: build_production: stage: build rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + - if: '$CI_COMMIT_BRANCH == "production"' + when: on_success + - when: never script: | set -e docker info @@ -47,14 +43,15 @@ build_production: docker tag "$IMAGE_NAME" "$IMAGE_LATEST" docker push "$IMAGE_LATEST" - # ========================= # MIGRATE (PRODUCTION) # ========================= migrate_production: stage: migrate rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + - if: '$CI_COMMIT_BRANCH == "production"' + when: on_success + - when: never needs: - job: build_production artifacts: false @@ -66,12 +63,10 @@ migrate_production: 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 - # ✅ validasi 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) @@ -81,21 +76,13 @@ migrate_production: 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 & redis ON (sesuaikan nama service compose kamu!) - echo "✅ Ensuring postgres & redis running ..." + # NOTE: pastikan nama servicenya benar untuk production (ini sebelumnya masih stg-*) docker compose -f "$COMPOSE_FILE" up -d stg-postgres-lti stg-redis-lti || true - # ✅ Ambil network key dari compose COMPOSE_NETWORK_KEY="$(docker compose -f "$COMPOSE_FILE" config | awk '/networks:/ {getline; print $1}' | tr -d ':')" - echo "✅ Compose network key: $COMPOSE_NETWORK_KEY" - - # ✅ Cari network name yang dipakai docker NETWORK_NAME="$(docker network ls --format '{{.Name}}' | grep "_${COMPOSE_NETWORK_KEY}$" | head -n 1)" test -n "$NETWORK_NAME" || (echo "❌ Cannot find docker network for compose ($COMPOSE_NETWORK_KEY)" && 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" @@ -111,7 +98,6 @@ migrate_production: echo "$out" - # ✅ Handle no change dengan benar (tidak false-success) if echo "$out" | grep -qi "no change"; then echo "✅ No change (already up to date)" exit 0 @@ -124,17 +110,16 @@ migrate_production: echo "✅ Migration applied successfully" - # ========================= # DEPLOY (AUTO) # ========================= deploy_production: stage: deploy rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + - if: '$CI_COMMIT_BRANCH == "production"' + when: on_success + - when: never needs: -# - job: migrate_production -# artifacts: false - job: build_production artifacts: false script: | @@ -150,7 +135,6 @@ deploy_production: docker compose -f "$COMPOSE_FILE" up -d --force-recreate docker image prune -f - # ========================= # SEED (MANUAL) # ========================= @@ -159,9 +143,10 @@ seed_production: rules: - if: '$CI_COMMIT_BRANCH == "production"' when: manual + - when: never script: | set -e - cd /opt/deploy/lti + cd "$DEPLOY_DIR" test -f .env || (echo "❌ .env not found" && exit 1) echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" diff --git a/ci/staging.yml b/ci/staging.yml index e3eaabb0..5ac5f2c7 100644 --- a/ci/staging.yml +++ b/ci/staging.yml @@ -8,12 +8,6 @@ default: tags: - self-hosted-stg -workflow: - rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' - when: always - - when: never - variables: DOCKER_BUILDKIT: "1" @@ -30,7 +24,9 @@ variables: build_staging: stage: build rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' + - if: '$CI_COMMIT_BRANCH == "staging"' + when: on_success + - when: never script: | set -e docker info @@ -47,14 +43,15 @@ build_staging: docker tag "$IMAGE_NAME" "$IMAGE_LATEST" docker push "$IMAGE_LATEST" - # ========================= # MIGRATE (AUTO) # ========================= migrate_staging: stage: migrate rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' + - if: '$CI_COMMIT_BRANCH == "staging"' + when: on_success + - when: never needs: - job: build_staging artifacts: false @@ -66,12 +63,10 @@ migrate_staging: 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 - # ✅ validasi 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) @@ -81,21 +76,17 @@ migrate_staging: 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 & redis ON (sesuaikan nama service compose kamu!) echo "✅ Ensuring postgres & redis running ..." docker compose -f "$COMPOSE_FILE" up -d stg-postgres-lti stg-redis-lti || true - # ✅ Ambil network key dari compose COMPOSE_NETWORK_KEY="$(docker compose -f "$COMPOSE_FILE" config | awk '/networks:/ {getline; print $1}' | tr -d ':')" echo "✅ Compose network key: $COMPOSE_NETWORK_KEY" - # ✅ Cari network name yang dipakai docker NETWORK_NAME="$(docker network ls --format '{{.Name}}' | grep "_${COMPOSE_NETWORK_KEY}$" | head -n 1)" test -n "$NETWORK_NAME" || (echo "❌ Cannot find docker network for compose ($COMPOSE_NETWORK_KEY)" && 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" @@ -111,7 +102,6 @@ migrate_staging: echo "$out" - # ✅ Handle no change dengan benar (tidak false-success) if echo "$out" | grep -qi "no change"; then echo "✅ No change (already up to date)" exit 0 @@ -124,14 +114,15 @@ migrate_staging: echo "✅ Migration applied successfully" - # ========================= # DEPLOY (AUTO) # ========================= deploy_staging: stage: deploy rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' + - if: '$CI_COMMIT_BRANCH == "staging"' + when: on_success + - when: never needs: - job: migrate_staging artifacts: false @@ -150,18 +141,18 @@ deploy_staging: docker compose -f "$COMPOSE_FILE" up -d --force-recreate docker image prune -f - # ========================= # SEED (MANUAL) # ========================= seed_staging: stage: seed rules: - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "staging"' + - if: '$CI_COMMIT_BRANCH == "staging"' + when: manual + - when: never needs: - job: deploy_staging artifacts: false - when: manual allow_failure: false script: | set -e @@ -170,4 +161,4 @@ seed_staging: 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% + docker compose -f "$COMPOSE_FILE" run --rm seed