diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index efda72f0..f829f049 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,76 +1,62 @@ -stages: [notify] +stages: + - build + - deploy + +variables: + DOCKER_BUILDKIT: "1" + COMPOSE_DOCKER_CLI_BUILD: "1" + DOCKER_DRIVER: overlay2 + BUILDKIT_PROGRESS: plain + IMAGE_NAME: "$CI_REGISTRY_IMAGE/web-lti:development_${CI_COMMIT_SHORT_SHA}" + NODE_ENV: "production" + HUSKY_SKIP_INSTALL: "1" + NEXT_PUBLIC_API_BASE_URL: "${NEXT_PUBLIC_API_BASE_URL}" + NEXT_PUBLIC_LTI_API_START_URL: "${NEXT_PUBLIC_LTI_API_START_URL}" + +build-image: + stage: build + image: docker:27.0.3 + services: + - docker:dind -# --- Notify when MR is opened/updated --- -notify_discord_mr: - stage: notify - image: alpine:3.20 - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - variables: - WEBHOOK_URL: $DISCORD_WEBHOOK_URL before_script: - - apk add --no-cache curl jq - script: | - MR_URL="${CI_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}" + - echo "Login to registry" + - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" - jq -n \ - --arg repo "$CI_PROJECT_PATH" \ - --arg mr "#${CI_MERGE_REQUEST_IID}" \ - --arg url "$MR_URL" \ - --arg requestor "${GITLAB_USER_LOGIN:-$GITLAB_USER_NAME}" \ - --arg source "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" \ - --arg target "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" \ - --arg title "$CI_MERGE_REQUEST_TITLE" \ - '{ - username: "CI Bot - FE", - embeds: [{ - title: "📣 [LTI WEB CLIENT] Merge Request Opened/Updated", - description: ($mr + " in " + $repo), - url: $url, - color: 3447003, - fields: [ - {name: "Author", value: $requestor, inline: true}, - {name: "Source → Target", value: ($source + " → " + $target), inline: true}, - {name: "Title", value: $title} - ] - }] - }' \ - | curl -sS -H "Content-Type: application/json" -d @- "$WEBHOOK_URL" + script: + - | + docker build \ + --build-arg NEXT_PUBLIC_API_BASE_URL="$NEXT_PUBLIC_API_BASE_URL" \ + --build-arg NEXT_PUBLIC_LTI_API_START_URL="$NEXT_PUBLIC_LTI_API_START_URL" \ + --build-arg NODE_ENV="$NODE_ENV" \ + --build-arg HUSKY_SKIP_INSTALL="$HUSKY_SKIP_INSTALL" \ + --cache-from "$CI_REGISTRY_IMAGE/web-lti:latest" \ + -t "$IMAGE_NAME" . + - docker push "$IMAGE_NAME" + - docker image prune -af --filter "until=72h" + + after_script: "echo 'Build complete: $IMAGE_NAME' && docker system prune -af || true && docker volume prune -f || true" -# --- Notify when MR is merged --- -notify_discord_merge: - stage: notify - image: alpine:3.20 rules: - # Only run for merge request pipelines that are in merged state - - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_STATE == "merged"' - variables: - WEBHOOK_URL: $DISCORD_WEBHOOK_URL - before_script: - - apk add --no-cache curl jq - script: | - MR_URL="${CI_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}" + - if: '$CI_COMMIT_BRANCH == "development"' - jq -n \ - --arg repo "$CI_PROJECT_PATH" \ - --arg mr "#${CI_MERGE_REQUEST_IID}" \ - --arg url "$MR_URL" \ - --arg requestor "${CI_MERGE_REQUEST_AUTHOR}" \ - --arg source "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" \ - --arg target "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" \ - --arg title "$CI_MERGE_REQUEST_TITLE" \ - '{ - username: "CI Bot - FE", - embeds: [{ - title: "✅ [LTI WEB CLIENT] Merge Request Merged", - description: ($mr + " has been merged into " + $repo), - url: $url, - color: 3066993, - fields: [ - {name: "Author", value: $requestor, inline: true}, - {name: "Source → Target", value: ($source + " → " + $target), inline: true}, - {name: "Title", value: $title} - ] - }] - }' \ - | curl -sS -H "Content-Type: application/json" -d @- "$WEBHOOK_URL" +deploy-dev: + stage: deploy + image: alpine:3.20 + + before_script: + - apk add --no-cache openssh curl + - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" | base64 -d > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - eval $(ssh-agent -s) + - ssh-add ~/.ssh/id_rsa + - ssh-keyscan -H "$SERVER_IP" >> ~/.ssh/known_hosts + + script: + - ssh -o StrictHostKeyChecking=no \"$SERVER_USER@$SERVER_IP\" \"docker stop dev-web-lti || true && docker rm dev-web-lti || true && docker pull $CI_REGISTRY_IMAGE/web-lti:development_${CI_COMMIT_SHORT_SHA} && docker run -d --name dev-web-lti --network dev-lti-network -p 3002:3000 $CI_REGISTRY_IMAGE/web-lti:development_${CI_COMMIT_SHORT_SHA}\" + + after_script: "echo 'Deploy finished for $IMAGE_NAME'" + + rules: + - if: '$CI_COMMIT_BRANCH == "development"' \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a3a2e197 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM node:20-alpine + +RUN apk add --no-cache git bash build-base curl + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY . . + +# Buat config agar Next tahu output: export +RUN echo "const config = { output: 'export', images: { unoptimized: true } }; export default config;" > next.config.mjs + +# Build project (Next.js 15 otomatis static export) +RUN NEXT_DISABLE_TURBOPACK=1 npx next build + +# Copy static assets dan hasil build agar bisa diakses +RUN mkdir -p .next/server/app/_next && \ + cp -r .next/static .next/server/app/_next/static && \ + cp -r public/* .next/server/app/ + +EXPOSE 3000 + +CMD ["npx", "serve", ".next/server/app", "-l", "3000"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..8d658170 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,39 @@ +version: "3.9" + +services: + dev-web-lti: + container_name: dev-web-lti + build: + context: . + dockerfile: Dockerfile + ports: + - "3002:3000" + env_file: + - .env + environment: + NODE_ENV: production + APP_ENV: production + networks: + - dev-lti-network + restart: always + deploy: + resources: + limits: + cpus: "3.0" + memory: 3G + reservations: + cpus: "1.0" + memory: 512M + extra_hosts: + - "host.docker.internal:host-gateway" + # Optional: aktifkan healthcheck jika punya endpoint + # healthcheck: + # test: ["CMD-SHELL", "curl -fsS http://localhost:3000/api/healthz || exit 1"] + # interval: 10s + # timeout: 3s + # retries: 10 + # start_period: 15s + +networks: + dev-lti-network: + external: true \ No newline at end of file