diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2417298f..a11b91e1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,35 +1,177 @@ +stages: + - build + - gitops + +variables: + AWS_REGION: ap-southeast-3 + ECR_REGISTRY: 886436954922.dkr.ecr.ap-southeast-3.amazonaws.com + ECR_REPO_NAME: mbugroup/lti-api + ECR_REPOSITORY: ${ECR_REGISTRY}/${ECR_REPO_NAME} + TARGET_PLATFORM: linux/amd64 + + DOCKER_HOST: unix:///var/run/docker.sock + DOCKER_TLS_CERTDIR: "" + DOCKER_BUILDKIT: "1" + 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 + # run untuk branch utama & MR + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "development"' + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "production"' - when: never -include: - # khusus MR (notif) - - local: "ci/merge_request.yml" - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' +# ========================= +# Helper: login ECR +# ========================= +.ecr_login: &ecr_login | + AWS_CLI_ENV_ARGS="" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_REGION=$AWS_REGION" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}" + if [ -n "${AWS_SESSION_TOKEN:-}" ]; then + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN" + fi - # khusus push ke branch env - - local: "ci/development.yml" - rules: - - if: '$CI_COMMIT_BRANCH == "development"' + PASS="$(docker run --rm $AWS_CLI_ENV_ARGS public.ecr.aws/aws-cli/aws-cli:latest \ + ecr get-login-password --region "$AWS_REGION" || true)" + if [ -z "$PASS" ]; then + echo "ERROR: Failed to get ECR login password." + exit 1 + fi + echo "$PASS" | docker login --username AWS --password-stdin "$ECR_REGISTRY" - - local: "ci/staging.yml" - rules: - - if: '$CI_COMMIT_BRANCH == "staging"' +# ========================= +# MR +# ========================= +build_mr: + stage: build + image: public.ecr.aws/docker/library/docker:27 + tags: [self-hosted-dev] + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "production"' + variables: + IMAGE_TAG: "prod-mr-${CI_COMMIT_SHORT_SHA}" + before_script: + - set -eu + - docker version + - docker info + - *ecr_login + script: | + set -eu + echo "Build (MR) : $ECR_REPOSITORY:$IMAGE_TAG" + docker build --platform "$TARGET_PLATFORM" -f Dockerfile -t "$ECR_REPOSITORY:$IMAGE_TAG" . + echo "Pushing image for MR..." + docker push "$ECR_REPOSITORY:$IMAGE_TAG" - - local: "ci/production.yml" - rules: - - if: '$CI_COMMIT_BRANCH == "production"' +# ========================= +# DEVELOPMENT (push branch development) +# ========================= +build_push_dev: + stage: build + image: public.ecr.aws/docker/library/docker:27 + tags: [self-hosted-dev] + rules: + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "development"' + variables: + IMAGE_TAG: "dev-${CI_COMMIT_SHORT_SHA}" + before_script: + - set -eu + - docker version + - docker info + - *ecr_login + script: | + set -eu + echo "Build & push (dev): $ECR_REPOSITORY:$IMAGE_TAG" + docker build --platform "$TARGET_PLATFORM" -f Dockerfile -t "$ECR_REPOSITORY:$IMAGE_TAG" . + docker push "$ECR_REPOSITORY:$IMAGE_TAG" + +update_gitops_dev_lti: + stage: gitops + image: public.ecr.aws/docker/library/alpine:3.20 + tags: [self-hosted-dev] + rules: + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "development"' + needs: ["build_push_dev"] + variables: + IMAGE_TAG: "dev-${CI_COMMIT_SHORT_SHA}" + GITOPS_BRANCH: main + VALUES_FILE: environments/lti/dev/lti-values-dev.yaml + GITOPS_REPO_URL: https://oauth2:${GITOPS_TOKEN}@gitlab.com/cristian.anggita.parjaman/gitops.git + before_script: + - set -eu + - apk add --no-cache git yq + - git config --global user.email "ci@gitlab" + - git config --global user.name "gitlab-ci" + script: | + set -eu + rm -rf gitops + git clone --depth 1 --branch "$GITOPS_BRANCH" "$GITOPS_REPO_URL" gitops + cd gitops + + echo "Updating dev image.tag to $IMAGE_TAG" + yq -i '.image.tag = strenv(IMAGE_TAG)' "$VALUES_FILE" + + git add "$VALUES_FILE" + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + git commit -m "lti dev deploy ${IMAGE_TAG}" + git push origin "$GITOPS_BRANCH" + +# ========================= +# PRODUCTION (push branch production) +# ========================= +build_push_prod: + stage: build + image: public.ecr.aws/docker/library/docker:27 + tags: [self-hosted-dev] + rules: + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + variables: + IMAGE_TAG: "prod-${CI_COMMIT_SHORT_SHA}" + before_script: + - set -eu + - docker version + - docker info + - *ecr_login + script: | + set -eu + echo "Build & push (prod): $ECR_REPOSITORY:$IMAGE_TAG" + docker build --platform "$TARGET_PLATFORM" -f Dockerfile -t "$ECR_REPOSITORY:$IMAGE_TAG" . + docker push "$ECR_REPOSITORY:$IMAGE_TAG" + +update_gitops_prod_lti: + stage: gitops + image: public.ecr.aws/docker/library/alpine:3.20 + tags: [self-hosted-dev] + rules: + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "production"' + needs: ["build_push_prod"] + variables: + IMAGE_TAG: "prod-${CI_COMMIT_SHORT_SHA}" + GITOPS_BRANCH: main + VALUES_FILE: environments/lti/prod/lti-values-prod.yaml + GITOPS_REPO_URL: https://oauth2:${GITOPS_TOKEN}@gitlab.com/cristian.anggita.parjaman/gitops.git + before_script: + - set -eu + - apk add --no-cache git yq + - git config --global user.email "ci@gitlab" + - git config --global user.name "gitlab-ci" + script: | + set -eu + rm -rf gitops + git clone --depth 1 --branch "$GITOPS_BRANCH" "$GITOPS_REPO_URL" gitops + cd gitops + + echo "Updating prod image.tag to $IMAGE_TAG" + yq -i '.image.tag = strenv(IMAGE_TAG)' "$VALUES_FILE" + + git add "$VALUES_FILE" + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + git commit -m "lti prod deploy ${IMAGE_TAG}" + git push origin "$GITOPS_BRANCH" diff --git a/README.md b/README.md index 5b502da1..4839caf4 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,4 @@ IT Development PT Mitra Berlian Unggas Group ## 📃 License > This project is private. All rights reserved. +# mr test Sat 7 Feb 2026 00:14:58 WIB diff --git a/ci/development.yml b/ci/development.yml index 7b4733b5..9b3a757f 100644 --- a/ci/development.yml +++ b/ci/development.yml @@ -1,91 +1,159 @@ stages: - - deploy + - build + - gitops -deploy-dev: - stage: deploy - image: alpine:3.20 +variables: + AWS_REGION: ap-southeast-3 + ECR_REGISTRY: 886436954922.dkr.ecr.ap-southeast-3.amazonaws.com + ECR_REPO_NAME: mbugroup/lti-api + ECR_REPOSITORY: ${ECR_REGISTRY}/${ECR_REPO_NAME} + DOCKER_HOST: unix:///var/run/docker.sock + DOCKER_TLS_CERTDIR: "" + DOCKER_BUILDKIT: "1" + +workflow: + rules: + - if: '$CI_COMMIT_BRANCH' + +# ========================= +# Helper: login ECR +# ========================= +.ecr_login: &ecr_login | + AWS_CLI_ENV_ARGS="" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_REGION=$AWS_REGION" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}" + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}" + if [ -n "${AWS_SESSION_TOKEN:-}" ]; then + AWS_CLI_ENV_ARGS="$AWS_CLI_ENV_ARGS -e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN" + fi + + PASS="$(docker run --rm $AWS_CLI_ENV_ARGS public.ecr.aws/aws-cli/aws-cli:latest \ + ecr get-login-password --region "$AWS_REGION" || true)" + if [ -z "$PASS" ]; then + echo "ERROR: Failed to get ECR login password." + exit 1 + fi + echo "$PASS" | docker login --username AWS --password-stdin "$ECR_REGISTRY" + +# ========================= +# DEV +# ========================= +build_push_dev_lti: + stage: build + image: public.ecr.aws/docker/library/docker:27 + tags: [self-hosted-dev] rules: - if: '$CI_COMMIT_BRANCH == "development"' - when: on_success - - when: never - variables: - DEPLOY_APP: "LTI-MBUGROUP" - GIT_SUBMODULE_STRATEGY: recursive - GIT_DEPTH: "1" - + IMAGE_TAG: "dev-${CI_COMMIT_SHORT_SHA}" before_script: - - echo "🧰 Installing dependencies..." - - apk update && apk add --no-cache openssh git curl bash + - set -eu + - docker version + - docker info + - *ecr_login + script: | + set -eu + echo "Build & push: $ECR_REPOSITORY:$IMAGE_TAG" - # Setup SSH di runner - - mkdir -p ~/.ssh - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - eval "$(ssh-agent -s)" - - ssh-add ~/.ssh/id_rsa + docker build \ + -t "$ECR_REPOSITORY:$IMAGE_TAG" \ + . - # Trust host keys (server + gitlab) biar SSH gak nanya interaktif - - ssh-keyscan -H "$SERVER_IP" >> ~/.ssh/known_hosts - - ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts + docker push "$ECR_REPOSITORY:$IMAGE_TAG" - script: - - echo "🚀 Deploying latest code to $SERVER_USER@$SERVER_IP" - - > - if ssh -o StrictHostKeyChecking=no "$SERVER_USER@$SERVER_IP" " - set -e +update_gitops_dev_lti: + stage: gitops + image: public.ecr.aws/docker/library/alpine:3.20 + tags: [self-hosted-dev] + rules: + - if: '$CI_COMMIT_BRANCH == "development"' + needs: ["build_push_dev_lti"] + variables: + IMAGE_TAG: "dev-${CI_COMMIT_SHORT_SHA}" + GITOPS_BRANCH: main + VALUES_FILE: environments/lti/dev/lti-values-dev.yaml + GITOPS_REPO_URL: https://oauth2:${GITOPS_TOKEN}@gitlab.com/cristian.anggita.parjaman/gitops.git + before_script: + - set -eu + - apk add --no-cache git yq + - git config --global user.email "ci@gitlab" + - git config --global user.name "gitlab-ci" + script: | + set -eu + rm -rf gitops + git clone --depth 1 --branch "$GITOPS_BRANCH" "$GITOPS_REPO_URL" gitops + cd gitops - cd /home/devops/docker/deployment/development/lti-api + echo "Updating DEV image.tag to $IMAGE_TAG in $VALUES_FILE" + yq -i '.image.repository = strenv(ECR_REPOSITORY)' "$VALUES_FILE" + yq -i '.image.tag = strenv(IMAGE_TAG)' "$VALUES_FILE" - # Pastikan remote origin SSH (antisipasi kalau pernah ke-set HTTPS) - git remote set-url origin git@gitlab.com:mbugroup/lti-api.git + git add "$VALUES_FILE" + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + git commit -m "lti dev deploy ${IMAGE_TAG}" + git push origin "$GITOPS_BRANCH" - # Pastikan server percaya gitlab.com juga (untuk git fetch via SSH) - mkdir -p ~/.ssh - ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts +# ========================= +# PROD +# ========================= +# build_push_prod_lti: +# stage: build +# image: public.ecr.aws/docker/library/docker:27 +# tags: [self-hosted-dev] +# rules: +# - if: '$CI_COMMIT_BRANCH == "production"' +# variables: +# IMAGE_TAG: "prod-${CI_COMMIT_SHORT_SHA}" +# before_script: +# - set -eu +# - docker version +# - docker info +# - *ecr_login +# script: | +# set -eu +# echo "Build & push: $ECR_REPOSITORY:$IMAGE_TAG" - # Fetch/reset pakai SSH - GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no' git fetch origin development - git reset --hard origin/development +# docker build \ +# -t "$ECR_REPOSITORY:$IMAGE_TAG" \ +# . - docker compose restart dev-api-lti || docker compose up -d dev-api-lti - "; then - STATUS='success'; - else - STATUS='failed'; - fi; +# docker push "$ECR_REPOSITORY:$IMAGE_TAG" - RUN_URL="${CI_PROJECT_URL}/-/pipelines/${CI_PIPELINE_ID}"; +# update_gitops_prod_lti: +# stage: gitops +# image: public.ecr.aws/docker/library/alpine:3.20 +# tags: [self-hosted-dev] +# rules: +# - if: '$CI_COMMIT_BRANCH == "production"' +# needs: ["build_push_prod_lti"] +# variables: +# IMAGE_TAG: "prod-${CI_COMMIT_SHORT_SHA}" +# GITOPS_BRANCH: main +# VALUES_FILE: environments/lti/prod/lti-values-prod.yaml +# GITOPS_REPO_URL: https://oauth2:${GITOPS_TOKEN}@gitlab.com/cristian.anggita.parjaman/gitops.git +# before_script: +# - set -eu +# - apk add --no-cache git yq +# - git config --global user.email "ci@gitlab" +# - git config --global user.name "gitlab-ci" +# script: | +# set -eu +# rm -rf gitops +# git clone --depth 1 --branch "$GITOPS_BRANCH" "$GITOPS_REPO_URL" gitops +# cd gitops - if [ "$STATUS" = "success" ]; then - COLOR=3066993; - TITLE="✅ Deployment API Succeeded"; - DESC="Deployment job on branch \`${CI_COMMIT_REF_NAME}\` completed successfully."; - else - COLOR=15158332; - TITLE="❌ Deployment API Failed Gaes"; - DESC="Deployment job on branch \`${CI_COMMIT_REF_NAME}\` failed."; - fi; +# echo "Updating PROD image.tag to $IMAGE_TAG in $VALUES_FILE" +# yq -i '.image.repository = strenv(ECR_REPOSITORY)' "$VALUES_FILE" +# yq -i '.image.tag = strenv(IMAGE_TAG)' "$VALUES_FILE" - echo "{ - \"username\": \"CI Bot\", - \"embeds\": [{ - \"title\": \"$TITLE\", - \"description\": \"$DESC\", - \"color\": $COLOR, - \"fields\": [ - {\"name\": \"Repository\", \"value\": \"${CI_PROJECT_PATH}\", \"inline\": true}, - {\"name\": \"Actor\", \"value\": \"${GITLAB_USER_LOGIN}\", \"inline\": true}, - {\"name\": \"Commit\", \"value\": \"${CI_COMMIT_SHA}\", \"inline\": false}, - {\"name\": \"Pipeline\", \"value\": \"[Open run](${RUN_URL})\", \"inline\": false} - ] - }] - }" > payload.json; - - echo "📡 Sending notification to Discord..."; - curl -sS -H "Content-Type: application/json" \ - -d @payload.json "$DISCORD_WEBHOOK_URL"; - - environment: - name: development +# git add "$VALUES_FILE" +# if git diff --cached --quiet; then +# echo "No changes to commit" +# exit 0 +# fi +# git commit -m "lti prod deploy ${IMAGE_TAG}" +# git push origin "$GITOPS_BRANCH" \ No newline at end of file