mirror of
https://github.com/ToolJet/ToolJet
synced 2026-04-21 13:37:28 +00:00
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:
parent
7a4e13366d
commit
893e23de09
1 changed files with 219 additions and 0 deletions
219
.github/workflows/deploy-to-stage.yml
vendored
Normal file
219
.github/workflows/deploy-to-stage.yml
vendored
Normal 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
|
||||
Loading…
Reference in a new issue