From c6e9ec049e26015d1b9a85e8f9cdc251b4de646d Mon Sep 17 00:00:00 2001 From: satyamsingh_8888 Date: Mon, 14 Sep 2026 13:36:38 +0530 Subject: [PATCH] Add Drone CI pipeline and static-only nginx serving for dev deploy --- .drone.yml | 281 +++++++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 8 ++ nginx.spa.conf | 45 ++++++++ 3 files changed, 334 insertions(+) create mode 100644 .drone.yml create mode 100644 nginx.spa.conf diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 000000000..ced085354 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,281 @@ +kind: pipeline +type: docker +name: auto-deploy + +steps: + + # ============================================================ + # DOCKER BUILD & PUSH + # + # Angular build (npm ci + ng build) Dockerfile ke andar + # multi-stage me hota hai, isliye alag build step nahi chahiye. + # ============================================================ + - name: docker-build-push + image: docker + + volumes: + - name: dockersock + path: /var/run/docker.sock + + commands: + - | + set -e + + # -------------------------------------------------------- + # Repository name comes from Drone + # -------------------------------------------------------- + REPO="$${DRONE_REPO_NAME}" + REPO="$$(echo "$$REPO" | tr '[:upper:]' '[:lower:]')" + + IMAGE="harbor.lincpay:8082/lincpay/$$REPO:$${DRONE_BUILD_NUMBER}" + + echo "==========================================" + echo "DOCKER BUILD & PUSH" + echo "==========================================" + echo "Repository : $$REPO" + echo "Build : $${DRONE_BUILD_NUMBER}" + echo "Image : $$IMAGE" + echo "==========================================" + + # -------------------------------------------------------- + # Harbor login + # -------------------------------------------------------- + echo 'QVgW5QbqlKKtBU2dYApTY28Dd6J36GK3' | \ + docker login harbor.lincpay:8082 \ + -u 'robot$lincpay+drone' \ + --password-stdin + + # -------------------------------------------------------- + # Build + # -------------------------------------------------------- + echo "Building Docker image..." + + docker build \ + -t "$$IMAGE" \ + . + + # -------------------------------------------------------- + # Push + # -------------------------------------------------------- + echo "Pushing Docker image..." + + docker push "$$IMAGE" + + echo "Docker image pushed successfully." + + + # ============================================================ + # DEPLOY + # ============================================================ + - name: deploy + image: docker + + volumes: + - name: dockersock + path: /var/run/docker.sock + + - name: envfiles + path: /platform-env + + commands: + - | + set -e + + # ======================================================== + # REPOSITORY / SERVICE / IMAGE + # ======================================================== + + REPO="$${DRONE_REPO_NAME}" + REPO="$$(echo "$$REPO" | tr '[:upper:]' '[:lower:]')" + + SERVICE_NAME="$${REPO}_app" + + IMAGE="harbor.lincpay:8082/lincpay/$$REPO:$${DRONE_BUILD_NUMBER}" + + echo "==========================================" + echo "DEPLOYMENT" + echo "==========================================" + echo "Repository : $$REPO" + echo "Service : $$SERVICE_NAME" + echo "Image : $$IMAGE" + echo "Placement : node.labels.environment == dev" + echo "==========================================" + + + # ======================================================== + # VALIDATION + # ======================================================== + + if [ -z "$$REPO" ]; then + echo "ERROR: DRONE_REPO_NAME is empty." + exit 1 + fi + + if [ -z "$$SERVICE_NAME" ]; then + echo "ERROR: Service name is empty." + exit 1 + fi + + if [ -z "$$IMAGE" ]; then + echo "ERROR: Docker image is empty." + exit 1 + fi + + echo "Repository verified : $$REPO" + echo "Service verified : $$SERVICE_NAME" + echo "Image verified : $$IMAGE" + + + # ======================================================== + # EXISTING SERVICE + # ======================================================== + + if docker service ls --format '{{.Name}}' | grep -Fxq "$$SERVICE_NAME"; then + + echo "" + echo "==========================================" + echo "EXISTING SERVICE" + echo "==========================================" + echo "Service: $$SERVICE_NAME" + + + # ------------------------------------------------------ + # Check whether dev constraint already exists + # ------------------------------------------------------ + + CONSTRAINT_EXISTS=$$(docker service inspect "$$SERVICE_NAME" \ + --format '{{range .Spec.TaskTemplate.Placement.Constraints}}{{println .}}{{end}}' \ + | grep -Fx 'node.labels.environment == dev' || true) + + + # ------------------------------------------------------ + # Add constraint if missing + # ------------------------------------------------------ + + if [ -z "$$CONSTRAINT_EXISTS" ]; then + + echo "Constraint missing." + echo "Adding: node.labels.environment == dev" + + docker service update \ + --constraint-add 'node.labels.environment == dev' \ + "$$SERVICE_NAME" + + else + + echo "Constraint already exists." + + fi + + + # ------------------------------------------------------ + # Update image + # ------------------------------------------------------ + + echo "Updating service image..." + + docker service update \ + --image "$$IMAGE" \ + --replicas 1 \ + --with-registry-auth \ + "$$SERVICE_NAME" + + + # ======================================================== + # NEW SERVICE + # ======================================================== + + else + + echo "" + echo "==========================================" + echo "NEW SERVICE" + echo "==========================================" + echo "Creating: $$SERVICE_NAME" + + + # ------------------------------------------------------ + # Traefik rule + # + # Construct it without allowing Drone to consume + # the shell backticks. + # ------------------------------------------------------ + + TRAEFIK_RULE='Host(`'$$REPO'.lincpay`)' + + echo "Traefik rule: $$TRAEFIK_RULE" + + + # ------------------------------------------------------ + # Create service + # ------------------------------------------------------ + + docker service create \ + --name "$$SERVICE_NAME" \ + --network edge-network \ + --replicas 1 \ + --constraint 'node.labels.environment == dev' \ + --with-registry-auth \ + --env-file /platform-env/global.env \ + --env-file /platform-env/dev.env \ + --label traefik.enable=true \ + --label "traefik.docker.network=edge-network" \ + --label "traefik.http.routers.$$REPO.rule=$$TRAEFIK_RULE" \ + --label "traefik.http.services.$$REPO.loadbalancer.server.port=80" \ + "$$IMAGE" + + fi + + + # ======================================================== + # FINAL STATUS + # ======================================================== + + echo "" + echo "==========================================" + echo "FINAL SERVICE STATUS" + echo "==========================================" + + docker service ls \ + --filter "name=$$SERVICE_NAME" + + + echo "" + echo "==========================================" + echo "PLACEMENT CONSTRAINT" + echo "==========================================" + + docker service inspect "$$SERVICE_NAME" \ + --format '{{json .Spec.TaskTemplate.Placement}}' + + + echo "" + echo "==========================================" + echo "SERVICE TASKS" + echo "==========================================" + + docker service ps "$$SERVICE_NAME" --no-trunc + + + echo "" + echo "==========================================" + echo "DEPLOYMENT COMPLETE" + echo "==========================================" + + +volumes: + + # ============================================================ + # DOCKER SOCKET + # ============================================================ + - name: dockersock + host: + path: /var/run/docker.sock + + + # ============================================================ + # ENVIRONMENT FILES + # ============================================================ + - name: envfiles + host: + path: /opt/platform/env diff --git a/Dockerfile b/Dockerfile index 5e5750925..f7fd4c7da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,6 +41,14 @@ RUN sh -c "ng build --output-path=/dist $BUILD_ENVIRONMENT_OPTIONS" ############### FROM $NGINX_IMAGE +# envsubst (gettext) alpine-slim me nahi hota — runtime env.js generation ke +# liye zaroori hai, isliye explicitly install kar rahe hain. +RUN apk add --no-cache gettext + +# Static-only nginx config (SPA fallback, no API proxy). Stock default.conf +# ko replace karta hai taaki deep-link refresh par 404 na aaye. +COPY nginx.spa.conf /etc/nginx/conf.d/default.conf + COPY --from=builder /dist/browser /usr/share/nginx/html EXPOSE 80 diff --git a/nginx.spa.conf b/nginx.spa.conf new file mode 100644 index 000000000..86dae6530 --- /dev/null +++ b/nginx.spa.conf @@ -0,0 +1,45 @@ +# Static-only nginx config for the CBSNexora Angular UI. +# NOTE: No API reverse-proxy here by design — the browser calls the Fineract +# backend directly via FINERACT_API_URL (env.js). nginx sirf static files +# serve karta hai + Angular SPA routing handle karta hai. + +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # ---- Compression ---- + gzip on; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_proxied any; + gzip_types text/plain text/css application/javascript application/json + application/xml image/svg+xml font/woff font/woff2; + + # ---- Runtime env: env.js aur index.html kabhi cache na ho ---- + # (env.js har container start par envsubst se regenerate hoti hai; + # index.html hashed asset filenames point karti hai) + location = /assets/env.js { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + expires -1; + } + + location = /index.html { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + expires -1; + } + + # ---- Hashed static assets: lambe time cache ---- + location ~* \.(?:js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 7d; + add_header Cache-Control "public"; + try_files $uri =404; + } + + # ---- Angular SPA fallback: har route index.html par ---- + location / { + try_files $uri $uri/ /index.html; + } +}