Feature: Add workflow for building Docker images and deploying to cloud stage AKS and Netlify (#13408)

* Feature: Add workflow for building Docker images and deploying to cloud stage AKS and Netlify

* removed incorrect Dockerfile path

* move azure commands to secrets

* Add wait-for-stabilization job to pause for 4 minutes before deploying frontend

* add the submodules

* changed the kubectl version

* fix image check issue

* Refactor deployment workflow: consolidate jobs and update image tag handling

* fix: update health check endpoint and remove unnecessary sleep step

* fix: improve backend readiness check to validate response content
This commit is contained in:
Adish M 2025-07-15 15:52:32 +05:30 committed by GitHub
parent 7a4e13366d
commit 893e23de09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

219
.github/workflows/deploy-to-stage.yml vendored Normal file
View file

@ -0,0 +1,219 @@
name: Cloud Stage Build Image, Deploy to AKS & Deploy Frontend to Netlify
on:
workflow_dispatch:
inputs:
branch_name:
description: 'Git branch to build from'
required: true
default: 'main'
dockerfile_path:
description: 'Path to Dockerfile'
required: true
default: './docker/cloud/cloud-server.Dockerfile'
type: choice
options:
- ./docker/cloud/cloud-server.Dockerfile
docker_tag:
description: 'Docker tag suffix (e.g., cloud-staging-v14)'
required: true
jobs:
full-deploy:
name: Build Image, Deploy to AKS & Netlify
runs-on: ubuntu-latest
steps:
- name: ✅ Check user authorization
run: |
allowed_user1=${{ secrets.ALLOWED_USER1_USERNAME }}
allowed_user2=${{ secrets.ALLOWED_USER2_USERNAME }}
allowed_user3=${{ secrets.ALLOWED_USER3_USERNAME }}
if [[ "${{ github.actor }}" != "$allowed_user1" && \
"${{ github.actor }}" != "$allowed_user2" && \
"${{ github.actor }}" != "$allowed_user3" ]]; then
echo "❌ User '${{ github.actor }}' is not authorized to trigger this workflow."
exit 1
else
echo "✅ User '${{ github.actor }}' is authorized."
fi
- name: Checkout Repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch_name }}
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: DockerHub Login
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Generate full Docker tag
id: taggen
run: |
input_tag="${{ github.event.inputs.docker_tag }}"
if [[ -z "$input_tag" ]]; then
echo "❌ docker_tag input is empty. Aborting..."
exit 1
fi
if [[ "$input_tag" == *"/"* ]]; then
echo "IMAGE_TAG=$input_tag" >> $GITHUB_ENV
else
echo "IMAGE_TAG=tooljet/tj-osv:$input_tag" >> $GITHUB_ENV
fi
- name: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ${{ github.event.inputs.dockerfile_path }}
push: true
tags: ${{ env.IMAGE_TAG }}
platforms: linux/amd64
build-args: |
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
BRANCH_NAME=${{ github.event.inputs.branch_name }}
- name: Show the full Docker tag
run: |
echo "✅ Docker image tagged as: $IMAGE_TAG"
# Deploy to AKS
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS_STAGE }}
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Set AKS Context
run: ${{ secrets.CONNECT_TO_AKS_STAGE }}
- name: Set Image in AKS Deployment
run: |
kubectl set image deployment/tooljet tooljet=$IMAGE_TAG
- name: Wait for pod readiness
run: |
echo "⏳ Waiting for pod(s) in deployment 'tooljet' to be ready..."
kubectl rollout status deployment/tooljet --timeout=10m
- name: Wait until backend is reachable
run: |
for i in {1..60}; do
response=$(curl -s --fail https://gcpstage-server.tooljet.ai/health || true)
if [[ "$response" == *'"works":"yeah"'* ]]; then
echo "✅ Backend is up and healthy"
exit 0
fi
echo "⏳ Waiting for backend to be ready... ($i/60)"
sleep 5
done
echo "❌ Backend not ready in time or response invalid"
exit 1
deploy-frontend:
name: Deploy Frontend to Netlify
runs-on: ubuntu-latest
needs: full-deploy
steps:
- name: ✅ Check user authorization
run: |
allowed_user1=${{ secrets.ALLOWED_USER1_USERNAME }}
allowed_user2=${{ secrets.ALLOWED_USER2_USERNAME }}
allowed_user3=${{ secrets.ALLOWED_USER3_USERNAME }}
if [[ "${{ github.actor }}" != "$allowed_user1" && \
"${{ github.actor }}" != "$allowed_user2" && \
"${{ github.actor }}" != "$allowed_user3" ]]; then
echo "❌ User '${{ github.actor }}' is not authorized to trigger this workflow."
exit 1
else
echo "✅ User '${{ github.actor }}' is authorized."
fi
- name: 📥 Manual Git checkout with submodules
run: |
set -e
BRANCH="${{ github.event.inputs.branch_name }}"
REPO="https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/${{ github.repository }}"
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
git config --global http.version HTTP/1.1
git config --global http.postBuffer 524288000
echo "👉 Cloning $REPO (branch: $BRANCH)"
git clone --recurse-submodules --depth=1 --branch "$BRANCH" "$REPO" repo
cd repo
echo "🔁 Updating submodules"
git submodule update --init --recursive
echo "🔀 Attempting to checkout '$BRANCH' in each submodule and validating"
BRANCH="$BRANCH" git submodule foreach --recursive bash -c '
name="$sm_path"
echo "↪ $name: checking out branch $BRANCH"
if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null; then
git fetch origin "$BRANCH:$BRANCH"
git checkout "$BRANCH"
else
echo "⚠️ Branch not found, falling back to main"
git checkout main && git pull origin main
fi
'
- name: 🧰 Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 22.15.1
- name: 📦 Install dependencies
run: npm install
working-directory: repo
- name: 🛠️ Build project
run: npm run build:plugins:prod && npm run build:frontend
working-directory: repo
env:
GOOGLE_MAPS_API_KEY: ${{ secrets.CLOUD_GOOGLE_MAPS_API_KEY }}
NODE_ENV: ${{ secrets.CLOUD_NODE_ENV }}
NODE_OPTIONS: ${{ secrets.CLOUD_NODE_OPTIONS }}
SENTRY_AUTH_TOKEN: ${{ secrets.CLOUD_SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.CLOUD_SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.CLOUD_SENTRY_PROJECT }}
SERVE_CLIENT: ${{ secrets.CLOUD_SERVE_CLIENT }}
SERVER_IP: ${{ secrets.CLOUD_SERVER_IP }}
TJDB_SQL_MODE_DISABLE: ${{ secrets.CLOUD_TJDB_SQL_MODE_DISABLE }}
TOOLJET_SERVER_URL: ${{ secrets.CLOUD_TOOLJET_SERVER_URL }}
TOOLJET_EDITION: cloud
WEBSITE_SIGNUP_URL: https://website-stage.tooljet.ai/ai-create-account
- name: 🚀 Deploy to Netlify
run: |
npm install -g netlify-cli
netlify deploy --prod --dir=frontend/build --auth=$NETLIFY_AUTH_TOKEN --site=${{ secrets.CLOUD_NETLIFY_SITE_ID }}
working-directory: repo
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
GOOGLE_MAPS_API_KEY: ${{ secrets.CLOUD_GOOGLE_MAPS_API_KEY }}
NODE_ENV: ${{ secrets.CLOUD_NODE_ENV }}
NODE_OPTIONS: ${{ secrets.CLOUD_NODE_OPTIONS }}
SENTRY_AUTH_TOKEN: ${{ secrets.CLOUD_SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.CLOUD_SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.CLOUD_SENTRY_PROJECT }}
SERVE_CLIENT: ${{ secrets.CLOUD_SERVE_CLIENT }}
SERVER_IP: ${{ secrets.CLOUD_SERVER_IP }}
TJDB_SQL_MODE_DISABLE: ${{ secrets.CLOUD_TJDB_SQL_MODE_DISABLE }}
TOOLJET_SERVER_URL: ${{ secrets.CLOUD_TOOLJET_SERVER_URL }}
WEBSITE_SIGNUP_URL: https://website-stage.tooljet.ai/ai-create-account
TOOLJET_EDITION: cloud