From e6c8695c61b3354b888808882715524e36fd549b Mon Sep 17 00:00:00 2001
From: Ajit Padhi
Date: Fri, 28 Nov 2025 10:56:17 +0530
Subject: [PATCH 1/4] Optimized Deployment workflow by separating jobs into
individual workflows
---
.github/workflows/deploy-linux.yml | 85 ++++
.github/workflows/deploy-orchestrator.yml | 180 +++++++++
.github/workflows/deploy-windows.yml | 85 ++++
.github/workflows/job-azure-deploy.yml | 400 +++++++++++++++++++
.github/workflows/job-cleanup-resources.yml | 125 ++++++
.github/workflows/job-docker-build.yml | 131 ++++++
.github/workflows/job-send-notifications.yml | 227 +++++++++++
.github/workflows/job-test-automation.yml | 185 +++++++++
8 files changed, 1418 insertions(+)
create mode 100644 .github/workflows/deploy-linux.yml
create mode 100644 .github/workflows/deploy-orchestrator.yml
create mode 100644 .github/workflows/deploy-windows.yml
create mode 100644 .github/workflows/job-azure-deploy.yml
create mode 100644 .github/workflows/job-cleanup-resources.yml
create mode 100644 .github/workflows/job-docker-build.yml
create mode 100644 .github/workflows/job-send-notifications.yml
create mode 100644 .github/workflows/job-test-automation.yml
diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml
new file mode 100644
index 000000000..b6845dd41
--- /dev/null
+++ b/.github/workflows/deploy-linux.yml
@@ -0,0 +1,85 @@
+name: Deploy-Test-Cleanup Linux
+on:
+ workflow_dispatch:
+ inputs:
+ azure_location:
+ description: 'Azure Location For Deployment'
+ required: false
+ default: 'australiaeast'
+ type: choice
+ options:
+ - 'australiaeast'
+ - 'centralus'
+ - 'eastasia'
+ - 'eastus2'
+ - 'japaneast'
+ - 'northeurope'
+ - 'southeastasia'
+ - 'uksouth'
+ resource_group_name:
+ description: 'Resource Group Name (Optional)'
+ required: false
+ default: ''
+ type: string
+ waf_enabled:
+ description: 'Enable WAF'
+ required: false
+ default: false
+ type: boolean
+ exp:
+ description: 'Enable EXP'
+ required: false
+ default: false
+ type: boolean
+ build_docker_image:
+ description: 'Build And Push Docker Image (Optional)'
+ required: false
+ default: false
+ type: boolean
+ cleanup_resources:
+ description: 'Cleanup Deployed Resources'
+ required: false
+ default: false
+ type: boolean
+ run_e2e_tests:
+ description: 'Run End-to-End Tests'
+ required: false
+ default: 'GoldenPath-Testing'
+ type: choice
+ options:
+ - 'GoldenPath-Testing'
+ - 'Smoke-Testing'
+ - 'None'
+ azure_env_log_anlytics_workspace_id:
+ description: 'Log Analytics Workspace ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ azure_existing_ai_project_resource_id:
+ description: 'AI Project Resource ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+
+jobs:
+ Run:
+ uses: ./.github/workflows/deploy-orchestrator.yml
+ with:
+ runner_os: ubuntu-latest
+ azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
+ resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
+ waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
+ EXP: ${{ github.event.inputs.EXP == 'true' }}
+ build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
+ cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
+ run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
+ azure_env_log_anlytics_workspace_id: ${{ github.event.inputs.azure_env_log_anlytics_workspace_id || '' }}
+ azure_existing_ai_project_resource_id: ${{ github.event.inputs.azure_existing_ai_project_resource_id || '' }}
+ existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}
+ trigger_type: ${{ github.event_name }}
+ secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
new file mode 100644
index 000000000..d2d5748d5
--- /dev/null
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -0,0 +1,180 @@
+name: Deployment orchestrator v2
+
+on:
+ workflow_call:
+ inputs:
+ runner_os:
+ description: 'Runner OS (ubuntu-latest or windows-latest)'
+ required: true
+ type: string
+ azure_location:
+ description: 'Azure Location For Deployment'
+ required: false
+ default: 'australiaeast'
+ type: string
+ resource_group_name:
+ description: 'Resource Group Name (Optional)'
+ required: false
+ default: ''
+ type: string
+ waf_enabled:
+ description: 'Enable WAF'
+ required: false
+ default: false
+ type: boolean
+ exp:
+ description: 'Enable EXP'
+ required: false
+ default: false
+ type: boolean
+ build_docker_image:
+ description: 'Build And Push Docker Image (Optional)'
+ required: false
+ default: false
+ type: boolean
+ cleanup_resources:
+ description: 'Cleanup Deployed Resources'
+ required: false
+ default: false
+ type: boolean
+ run_e2e_tests:
+ description: 'Run End-to-End Tests'
+ required: false
+ default: 'GoldenPath-Testing'
+ type: string
+ azure_env_log_anlytics_workspace_id:
+ description: 'Log Analytics Workspace ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ azure_existing_ai_project_resource_id:
+ description: 'AI Project Resource ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+ trigger_type:
+ description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
+ required: true
+ type: string
+ secrets:
+ AZURE_CLIENT_ID:
+ required: true
+ AZURE_CLIENT_SECRET:
+ required: true
+ AZURE_TENANT_ID:
+ required: true
+ AZURE_SUBSCRIPTION_ID:
+ required: true
+ ACR_TEST_LOGIN_SERVER:
+ required: true
+ ACR_TEST_USERNAME:
+ required: true
+ ACR_TEST_PASSWORD:
+ required: true
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
+ required: false
+ AZURE_ENV_FOUNDRY_PROJECT_ID:
+ required: false
+ EMAILNOTIFICATION_LOGICAPP_URL_TA:
+ required: false
+ outputs:
+ CONTAINER_WEB_APPURL:
+ description: "Container Web App URL"
+ value: ${{ jobs.deploy.outputs.CONTAINER_WEB_APPURL }}
+ RESOURCE_GROUP_NAME:
+ description: "Resource Group Name"
+ value: ${{ jobs.deploy.outputs.RESOURCE_GROUP_NAME }}
+
+env:
+ AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
+
+jobs:
+ docker-build:
+ uses: ./.github/workflows/job-docker-build.yml
+ with:
+ trigger_type: ${{ inputs.trigger_type }}
+ build_docker_image: ${{ inputs.build_docker_image }}
+ secrets:
+ ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }}
+ ACR_TEST_PASSWORD: ${{ secrets.ACR_TEST_PASSWORD }}
+
+ deploy:
+ if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)
+ needs: docker-build
+ uses: ./.github/workflows/job-azure-deploy.yml
+ with:
+ trigger_type: ${{ inputs.trigger_type }}
+ runner_os: ${{ inputs.runner_os }}
+ azure_location: ${{ inputs.azure_location }}
+ resource_group_name: ${{ inputs.resource_group_name }}
+ waf_enabled: ${{ inputs.waf_enabled }}
+ EXP: ${{ inputs.exp }}
+ build_docker_image: ${{ inputs.build_docker_image }}
+ existing_webapp_url: ${{ inputs.existing_webapp_url }}
+ azure_env_log_anlytics_workspace_id: ${{ inputs.azure_env_log_anlytics_workspace_id }}
+ azure_existing_ai_project_resource_id: ${{ inputs.azure_existing_ai_project_resource_id }}
+ docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }}
+ secrets:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.azure_env_log_anlytics_workspace_id }}
+ AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
+
+ e2e-test:
+ if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))
+ needs: [docker-build, deploy]
+ uses: ./.github/workflows/job-test-automation.yml
+ with:
+ KMGENERIC_URL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}
+ KMGENERIC_URL_API: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}
+ TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }}
+ secrets: inherit
+
+ send-notification:
+ if: always()
+ needs: [docker-build, deploy, e2e-test]
+ uses: ./.github/workflows/job-send-notifications.yml
+ with:
+ trigger_type: ${{ inputs.trigger_type }}
+ waf_enabled: ${{ inputs.waf_enabled }}
+ EXP: ${{ inputs.exp }}
+ run_e2e_tests: ${{ inputs.run_e2e_tests }}
+ existing_webapp_url: ${{ inputs.existing_webapp_url }}
+ deploy_result: ${{ needs.deploy.result }}
+ e2e_test_result: ${{ needs.e2e-test.result }}
+ CONTAINER_WEB_APPURL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL }}
+ RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
+ QUOTA_FAILED: ${{ needs.deploy.outputs.QUOTA_FAILED }}
+ TEST_SUCCESS: ${{ needs.e2e-test.outputs.TEST_SUCCESS }}
+ TEST_REPORT_URL: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }}
+ secrets:
+ EMAILNOTIFICATION_LOGICAPP_URL_TA: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
+
+ cleanup-deployment:
+ if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null)
+ needs: [docker-build, deploy, e2e-test]
+ uses: ./.github/workflows/job-cleanup-resources.yml
+ with:
+ runner_os: ${{ inputs.runner_os }}
+ trigger_type: ${{ inputs.trigger_type }}
+ cleanup_resources: ${{ inputs.cleanup_resources }}
+ existing_webapp_url: ${{ inputs.existing_webapp_url }}
+ RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
+ AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ ENV_NAME: ${{ needs.deploy.outputs.ENV_NAME }}
+ IMAGE_TAG: ${{ needs.deploy.outputs.IMAGE_TAG }}
+ secrets:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
\ No newline at end of file
diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml
new file mode 100644
index 000000000..538e53694
--- /dev/null
+++ b/.github/workflows/deploy-windows.yml
@@ -0,0 +1,85 @@
+name: Deploy-Test-Cleanup Windows
+on:
+ workflow_dispatch:
+ inputs:
+ azure_location:
+ description: 'Azure Location For Deployment'
+ required: false
+ default: 'australiaeast'
+ type: choice
+ options:
+ - 'australiaeast'
+ - 'centralus'
+ - 'eastasia'
+ - 'eastus2'
+ - 'japaneast'
+ - 'northeurope'
+ - 'southeastasia'
+ - 'uksouth'
+ resource_group_name:
+ description: 'Resource Group Name (Optional)'
+ required: false
+ default: ''
+ type: string
+ waf_enabled:
+ description: 'Enable WAF'
+ required: false
+ default: false
+ type: boolean
+ exp:
+ description: 'Enable EXP'
+ required: false
+ default: false
+ type: boolean
+ build_docker_image:
+ description: 'Build And Push Docker Image (Optional)'
+ required: false
+ default: false
+ type: boolean
+ cleanup_resources:
+ description: 'Cleanup Deployed Resources'
+ required: false
+ default: false
+ type: boolean
+ run_e2e_tests:
+ description: 'Run End-to-End Tests'
+ required: false
+ default: 'GoldenPath-Testing'
+ type: choice
+ options:
+ - 'GoldenPath-Testing'
+ - 'Smoke-Testing'
+ - 'None'
+ azure_env_log_anlytics_workspace_id:
+ description: 'Log Analytics Workspace ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ azure_existing_ai_project_resource_id:
+ description: 'AI Project Resource ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+
+jobs:
+ Run:
+ uses: ./.github/workflows/deploy-orchestrator.yml
+ with:
+ runner_os: windows-latest
+ azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
+ resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
+ waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
+ EXP: ${{ github.event.inputs.exp == 'true' }}
+ build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
+ cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
+ run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
+ azure_env_log_anlytics_workspace_id: ${{ github.event.inputs.azure_env_log_anlytics_workspace_id || '' }}
+ azure_existing_ai_project_resource_id: ${{ github.event.inputs.azure_existing_ai_project_resource_id || '' }}
+ existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}
+ trigger_type: ${{ github.event_name }}
+ secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/job-azure-deploy.yml b/.github/workflows/job-azure-deploy.yml
new file mode 100644
index 000000000..ac3562b69
--- /dev/null
+++ b/.github/workflows/job-azure-deploy.yml
@@ -0,0 +1,400 @@
+name: Deploy Job v2
+
+on:
+ workflow_call:
+ inputs:
+ trigger_type:
+ description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
+ required: true
+ type: string
+ runner_os:
+ description: 'Runner OS (ubuntu-latest or windows-latest)'
+ required: true
+ type: string
+ azure_location:
+ description: 'Azure Location For Deployment'
+ required: false
+ default: 'australiaeast'
+ type: string
+ resource_group_name:
+ description: 'Resource Group Name (Optional)'
+ required: false
+ default: ''
+ type: string
+ waf_enabled:
+ description: 'Enable WAF'
+ required: false
+ default: false
+ type: boolean
+ exp:
+ description: 'Enable EXP'
+ required: false
+ default: false
+ type: boolean
+ build_docker_image:
+ description: 'Build And Push Docker Image (Optional)'
+ required: false
+ default: false
+ type: boolean
+ cleanup_resources:
+ description: 'Cleanup Deployed Resources'
+ required: false
+ default: false
+ type: boolean
+ run_e2e_tests:
+ description: 'Run End-to-End Tests'
+ required: false
+ default: 'GoldenPath-Testing'
+ type: string
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+ azure_env_log_anlytics_workspace_id:
+ description: 'Log Analytics Workspace ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ azure_existing_ai_project_resource_id:
+ description: 'AI Project Resource ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ docker_image_tag:
+ description: 'Docker Image Tag from build job'
+ required: false
+ default: ''
+ type: string
+ secrets:
+ AZURE_CLIENT_ID:
+ required: true
+ AZURE_CLIENT_SECRET:
+ required: true
+ AZURE_TENANT_ID:
+ required: true
+ AZURE_SUBSCRIPTION_ID:
+ required: true
+ ACR_TEST_LOGIN_SERVER:
+ required: true
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
+ required: false
+ AZURE_ENV_FOUNDRY_PROJECT_ID:
+ required: false
+ outputs:
+ invoice_schema_id:
+ description: "Invoice Schema ID"
+ value: ${{ jobs.deploy-linux.outputs.invoice_schema_id || jobs.deploy-windows.outputs.invoice_schema_id }}
+ propertydamageclaimform_schema_id:
+ description: "Property Damage Claim Form Schema ID"
+ value: ${{ jobs.deploy-linux.outputs.propertydamageclaimform_schema_id || jobs.deploy-windows.outputs.propertydamageclaimform_schema_id }}
+ RESOURCE_GROUP_NAME:
+ description: "Resource Group Name"
+ value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
+ CONTAINER_WEB_APPURL:
+ description: "Container Web App URL"
+ value: ${{ jobs.deploy-linux.outputs.CONTAINER_WEB_APPURL || jobs.deploy-windows.outputs.CONTAINER_WEB_APPURL }}
+ ENV_NAME:
+ description: "Environment Name"
+ value: ${{ jobs.azure-setup.outputs.ENV_NAME }}
+ AZURE_LOCATION:
+ description: "Azure Location"
+ value: ${{ jobs.azure-setup.outputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION:
+ description: "Azure OpenAI Location"
+ value: ${{ jobs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ IMAGE_TAG:
+ description: "Docker Image Tag Used"
+ value: ${{ jobs.azure-setup.outputs.IMAGE_TAG }}
+ QUOTA_FAILED:
+ description: "Quota Check Failed Flag"
+ value: ${{ jobs.azure-setup.outputs.QUOTA_FAILED }}
+
+env:
+ GPT_MIN_CAPACITY: 100
+ BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
+ WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }}
+ EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }}
+ CLEANUP_RESOURCES: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.cleanup_resources || true) || true }}
+ RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }}
+ BUILD_DOCKER_IMAGE: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.build_docker_image || false) || false }}
+
+jobs:
+ azure-setup:
+ name: Azure Setup
+ if: inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null
+ runs-on: ubuntu-latest
+ outputs:
+ RESOURCE_GROUP_NAME: ${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }}
+ ENV_NAME: ${{ steps.generate_env_name.outputs.ENV_NAME }}
+ AZURE_LOCATION: ${{ steps.set_region.outputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ steps.set_region.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ IMAGE_TAG: ${{ steps.determine_image_tag.outputs.IMAGE_TAG }}
+ QUOTA_FAILED: ${{ steps.quota_failure_output.outputs.QUOTA_FAILED }}
+
+ steps:
+ - name: Validate and Auto-Configure EXP
+ shell: bash
+ run: |
+ echo "π Validating EXP configuration..."
+
+ if [[ "${{ inputs.exp }}" != "true" ]]; then
+ if [[ -n "${{ inputs.azure_env_log_anlytics_workspace_id }}" ]] || [[ -n "${{ inputs.azure_existing_ai_project_resource_id }}" ]]; then
+ echo "π§ AUTO-ENABLING EXP: EXP parameter values were provided but EXP was not explicitly enabled."
+ echo ""
+ echo "You provided values for:"
+ [[ -n "${{ inputs.azure_env_log_anlytics_workspace_id }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.azure_env_log_anlytics_workspace_id }}'"
+ [[ -n "${{ inputs.azure_existing_ai_project_resource_id }}" ]] && echo " - Azure AI Project Resource ID: '${{ inputs.azure_existing_ai_project_resource_id }}'"
+ echo ""
+ echo "β
Automatically enabling EXP to use these values."
+ echo "EXP=true" >> $GITHUB_ENV
+ echo "π EXP has been automatically enabled for this deployment."
+ fi
+ fi
+
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Login to Azure
+ shell: bash
+ run: |
+ az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
+ az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+ - name: Run Quota Check
+ id: quota-check
+ shell: bash
+ run: |
+ export AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }}
+ export AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }}
+ export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }}
+ export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
+ export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }}
+ export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}"
+
+ chmod +x infra/scripts/checkquota.sh
+ if ! infra/scripts/checkquota.sh; then
+ if grep -q "No region with sufficient quota found" infra/scripts/checkquota.sh; then
+ echo "QUOTA_FAILED=true" >> $GITHUB_ENV
+ fi
+ exit 1
+ fi
+
+ - name: Set Quota Failure Output
+ id: quota_failure_output
+ if: env.QUOTA_FAILED == 'true'
+ shell: bash
+ run: |
+ echo "QUOTA_FAILED=true" >> $GITHUB_OUTPUT
+ echo "Quota check failed - will notify via separate notification job"
+
+ - name: Fail Pipeline if Quota Check Fails
+ if: env.QUOTA_FAILED == 'true'
+ shell: bash
+ run: exit 1
+
+ - name: Set Deployment Region
+ id: set_region
+ shell: bash
+ run: |
+ echo "Selected Region from Quota Check: $VALID_REGION"
+ echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_ENV
+ echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT
+
+ if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then
+ USER_SELECTED_LOCATION="${{ inputs.azure_location }}"
+ echo "Using user-selected Azure location: $USER_SELECTED_LOCATION"
+ echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_ENV
+ echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_OUTPUT
+ else
+ echo "Using location from quota check for automatic triggers: $VALID_REGION"
+ echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_ENV
+ echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Generate Resource Group Name
+ id: generate_rg_name
+ shell: bash
+ run: |
+ # Check if a resource group name was provided as input
+ if [[ -n "${{ inputs.resource_group_name }}" ]]; then
+ echo "Using provided Resource Group name: ${{ inputs.resource_group_name }}"
+ echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV
+ else
+ echo "Generating a unique resource group name..."
+ ACCL_NAME="cp" # Account name as specified
+ SHORT_UUID=$(uuidgen | cut -d'-' -f1)
+ UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}"
+ echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV
+ echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}"
+ fi
+
+ - name: Install Bicep CLI
+ shell: bash
+ run: az bicep install
+
+ - name: Check and Create Resource Group
+ id: check_create_rg
+ shell: bash
+ run: |
+ set -e
+ echo "π Checking if resource group '$RESOURCE_GROUP_NAME' exists..."
+ rg_exists=$(az group exists --name $RESOURCE_GROUP_NAME)
+ if [ "$rg_exists" = "false" ]; then
+ echo "π¦ Resource group does not exist. Creating new resource group '$RESOURCE_GROUP_NAME' in location '$AZURE_LOCATION'..."
+ az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION || { echo "β Error creating resource group"; exit 1; }
+ echo "β
Resource group '$RESOURCE_GROUP_NAME' created successfully."
+ else
+ echo "β
Resource group '$RESOURCE_GROUP_NAME' already exists. Deploying to existing resource group."
+ fi
+ echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT
+ echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV
+
+ - name: Generate Unique Solution Prefix
+ id: generate_solution_prefix
+ shell: bash
+ run: |
+ set -e
+ COMMON_PART="psldg"
+ TIMESTAMP=$(date +%s)
+ UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6)
+ UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}"
+ echo "SOLUTION_PREFIX=${UNIQUE_SOLUTION_PREFIX}" >> $GITHUB_ENV
+ echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}"
+
+ - name: Determine Docker Image Tag
+ id: determine_image_tag
+ shell: bash
+ run: |
+ if [[ "${{ env.BUILD_DOCKER_IMAGE }}" == "true" ]]; then
+ if [[ -n "${{ inputs.docker_image_tag }}" ]]; then
+ IMAGE_TAG="${{ inputs.docker_image_tag }}"
+ echo "π Using Docker image tag from build job: $IMAGE_TAG"
+ else
+ echo "β Docker build job failed or was skipped, but BUILD_DOCKER_IMAGE is true"
+ exit 1
+ fi
+ else
+ echo "π·οΈ Using existing Docker image based on branch..."
+ BRANCH_NAME="${{ env.BRANCH_NAME }}"
+ echo "Current branch: $BRANCH_NAME"
+
+ if [[ "$BRANCH_NAME" == "main" ]]; then
+ IMAGE_TAG="latest"
+ echo "Using main branch - image tag: latest"
+ elif [[ "$BRANCH_NAME" == "dev" ]]; then
+ IMAGE_TAG="dev"
+ echo "Using dev branch - image tag: dev"
+ elif [[ "$BRANCH_NAME" == "demo" ]]; then
+ IMAGE_TAG="demo"
+ echo "Using demo branch - image tag: demo"
+ elif [[ "$BRANCH_NAME" == "hotfix" ]]; then
+ BASE_TAG="hotfix"
+ elif [[ "$BRANCH_NAME" == "dependabotchanges" ]]; then
+ BASE_TAG="dependabotchanges"
+ else
+ IMAGE_TAG="latest"
+ echo "Using default for branch '$BRANCH_NAME' - image tag: latest"
+ fi
+
+ echo "Using existing Docker image tag: $IMAGE_TAG"
+ fi
+
+ echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
+ echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT
+
+ - name: Generate Unique Environment Name
+ id: generate_env_name
+ shell: bash
+ run: |
+ COMMON_PART="pslc"
+ TIMESTAMP=$(date +%s)
+ UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6)
+ UNIQUE_ENV_NAME="${COMMON_PART}${UPDATED_TIMESTAMP}"
+ echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_ENV
+ echo "Generated Environment Name: ${UNIQUE_ENV_NAME}"
+ echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_OUTPUT
+
+ - name: Display Workflow Configuration to GitHub Summary
+ shell: bash
+ run: |
+ echo "## π Workflow Configuration Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Configuration | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|---------------|-------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Trigger Type** | \`${{ github.event_name }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Branch** | \`${{ env.BRANCH_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Runner OS** | \`${{ inputs.runner_os }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **WAF Enabled** | ${{ env.WAF_ENABLED == 'true' && 'β
Yes' || 'β No' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **EXP Enabled** | ${{ env.EXP == 'true' && 'β
Yes' || 'β No' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Run E2E Tests** | \`${{ env.RUN_E2E_TESTS }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Cleanup Resources** | ${{ env.CLEANUP_RESOURCES == 'true' && 'β
Yes' || 'β No' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Build Docker Image** | ${{ env.BUILD_DOCKER_IMAGE == 'true' && 'β
Yes' || 'β No' }} |" >> $GITHUB_STEP_SUMMARY
+
+ if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then
+ echo "| **Azure Location** | \`${{ inputs.azure_location }}\` (User Selected) |" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ if [[ -n "${{ inputs.resource_group_name }}" ]]; then
+ echo "| **Resource Group** | \`${{ inputs.resource_group_name }}\` (Pre-specified) |" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` (Auto-generated) |" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ if [[ "${{ inputs.trigger_type }}" != "workflow_dispatch" ]]; then
+ echo "βΉοΈ **Note:** Automatic Trigger - Using Non-WAF + Non-EXP configuration" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "βΉοΈ **Note:** Manual Trigger - Using user-specified configuration" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ deploy-linux:
+ name: Deploy on Linux
+ needs: azure-setup
+ if: inputs.runner_os == 'ubuntu-latest' && always() && needs.azure-setup.result == 'success'
+ uses: ./.github/workflows/job-deploy-linux.yml
+ with:
+ ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ needs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }}
+ RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
+ IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }}
+ BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }}
+ EXP: ${{ github.event.inputs.exp || 'false' }}
+ WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }}
+ secrets:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
+
+ deploy-windows:
+ name: Deploy on Windows
+ needs: azure-setup
+ if: inputs.runner_os == 'windows-latest' && always() && needs.azure-setup.result == 'success'
+ uses: ./.github/workflows/job-deploy-windows.yml
+ with:
+ ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ needs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }}
+ RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
+ IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }}
+ BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }}
+ EXP: ${{ github.event.inputs.exp || 'false' }}
+ WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }}
+ secrets:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
\ No newline at end of file
diff --git a/.github/workflows/job-cleanup-resources.yml b/.github/workflows/job-cleanup-resources.yml
new file mode 100644
index 000000000..12e6a6cfc
--- /dev/null
+++ b/.github/workflows/job-cleanup-resources.yml
@@ -0,0 +1,125 @@
+name: Cleanup Deployment Job v2
+
+on:
+ workflow_call:
+ inputs:
+ runner_os:
+ description: 'Runner OS (ubuntu-latest or windows-latest)'
+ required: true
+ type: string
+ trigger_type:
+ description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
+ required: true
+ type: string
+ cleanup_resources:
+ description: 'Cleanup Deployed Resources'
+ required: false
+ default: false
+ type: boolean
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+ RESOURCE_GROUP_NAME:
+ description: 'Resource Group Name to cleanup'
+ required: true
+ type: string
+ AZURE_LOCATION:
+ description: 'Azure Location'
+ required: true
+ type: string
+ AZURE_ENV_OPENAI_LOCATION:
+ description: 'Azure OpenAI Location'
+ required: true
+ type: string
+ ENV_NAME:
+ description: 'Environment Name'
+ required: true
+ type: string
+ IMAGE_TAG:
+ description: 'Docker Image Tag'
+ required: true
+ type: string
+ secrets:
+ AZURE_CLIENT_ID:
+ required: true
+ AZURE_CLIENT_SECRET:
+ required: true
+ AZURE_TENANT_ID:
+ required: true
+ AZURE_SUBSCRIPTION_ID:
+ required: true
+
+jobs:
+ cleanup-deployment:
+ if: inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null)
+ runs-on: ${{ inputs.runner_os }}
+ continue-on-error: true
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ ENV_NAME: ${{ inputs.ENV_NAME }}
+ IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ steps:
+ - name: Setup Azure CLI
+ shell: bash
+ run: |
+ if [[ "${{ runner.os }}" == "Linux" ]]; then
+ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
+ fi
+ az --version
+
+ - name: Login to Azure
+ shell: bash
+ run: |
+ az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
+ az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+ - name: Delete Resource Group (Optimized Cleanup)
+ id: delete_rg
+ shell: bash
+ run: |
+ set -e
+ echo "ποΈ Starting optimized resource cleanup..."
+ echo "Deleting resource group: ${{ env.RESOURCE_GROUP_NAME }}"
+
+ az group delete \
+ --name "${{ env.RESOURCE_GROUP_NAME }}" \
+ --yes \
+ --no-wait
+
+ echo "β
Resource group deletion initiated (running asynchronously)"
+ echo "Note: Resources will be cleaned up in the background"
+
+ - name: Logout from Azure
+ if: always()
+ shell: bash
+ run: |
+ azd auth logout || true
+ az logout || echo "Warning: Failed to logout from Azure CLI"
+ echo "Logged out from Azure."
+
+ - name: Generate Cleanup Job Summary
+ if: always()
+ shell: bash
+ run: |
+ echo "## π§Ή Cleanup Job Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resouce Group deletion Status** | ${{ steps.delete_rg.outcome == 'success' && 'β
Initiated' || 'β Failed' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ steps.delete_rg.outcome }}" == "success" ]]; then
+ echo "### β
Cleanup Details" >> $GITHUB_STEP_SUMMARY
+ echo "- Successfully initiated deletion for Resource Group \`${{ env.RESOURCE_GROUP_NAME }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Cleanup Failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Cleanup process encountered an error" >> $GITHUB_STEP_SUMMARY
+ echo "- Manual cleanup may be required for:" >> $GITHUB_STEP_SUMMARY
+ echo " - Resource Group: \`${{ env.RESOURCE_GROUP_NAME }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the cleanup-deployment job logs for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
\ No newline at end of file
diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml
new file mode 100644
index 000000000..800dd5591
--- /dev/null
+++ b/.github/workflows/job-docker-build.yml
@@ -0,0 +1,131 @@
+name: Docker Build Job
+
+on:
+ workflow_call:
+ inputs:
+ trigger_type:
+ description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
+ required: true
+ type: string
+ build_docker_image:
+ description: 'Build And Push Docker Image (Optional)'
+ required: false
+ default: false
+ type: boolean
+ secrets:
+ ACR_TEST_LOGIN_SERVER:
+ required: true
+ ACR_TEST_USERNAME:
+ required: true
+ ACR_TEST_PASSWORD:
+ required: true
+ outputs:
+ IMAGE_TAG:
+ description: "Generated Docker Image Tag"
+ value: ${{ jobs.docker-build.outputs.IMAGE_TAG }}
+
+env:
+ BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
+
+jobs:
+ docker-build:
+ if: inputs.trigger_type == 'workflow_dispatch' && inputs.build_docker_image == true
+ runs-on: ubuntu-latest
+ outputs:
+ IMAGE_TAG: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Generate Unique Docker Image Tag
+ id: generate_docker_tag
+ shell: bash
+ run: |
+ echo "π¨ Building new Docker image - generating unique tag..."
+ TIMESTAMP=$(date +%Y%m%d-%H%M%S)
+ RUN_ID="${{ github.run_id }}"
+ BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
+ CLEAN_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9._-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
+ UNIQUE_TAG="${CLEAN_BRANCH_NAME}-${TIMESTAMP}-${RUN_ID}"
+ echo "IMAGE_TAG=$UNIQUE_TAG" >> $GITHUB_ENV
+ echo "IMAGE_TAG=$UNIQUE_TAG" >> $GITHUB_OUTPUT
+ echo "Generated unique Docker tag: $UNIQUE_TAG"
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Azure Container Registry
+ uses: azure/docker-login@v2
+ with:
+ login-server: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ username: ${{ secrets.ACR_TEST_USERNAME }}
+ password: ${{ secrets.ACR_TEST_PASSWORD }}
+
+ # - name: Build and Push ContentProcessor Docker image
+ # uses: docker/build-push-action@v6
+ # env:
+ # DOCKER_BUILD_SUMMARY: false
+ # with:
+ # context: ./src/ContentProcessor
+ # file: ./src/ContentProcessor/Dockerfile
+ # push: true
+ # tags: |
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+
+ # - name: Build and Push ContentProcessorAPI Docker image
+ # uses: docker/build-push-action@v6
+ # env:
+ # DOCKER_BUILD_SUMMARY: false
+ # with:
+ # context: ./src/ContentProcessorAPI
+ # file: ./src/ContentProcessorAPI/Dockerfile
+ # push: true
+ # tags: |
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+
+ # - name: Build and Push ContentProcessorWeb Docker image
+ # uses: docker/build-push-action@v6
+ # env:
+ # DOCKER_BUILD_SUMMARY: false
+ # with:
+ # context: ./src/ContentProcessorWeb
+ # file: ./src/ContentProcessorWeb/Dockerfile
+ # push: true
+ # tags: |
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+
+ - name: Verify Docker Image Build
+ shell: bash
+ run: |
+ echo "β
Docker image successfully built and pushed"
+ echo "Image tag: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}"
+
+ - name: Generate Docker Build Summary
+ if: always()
+ shell: bash
+ run: |
+ ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}")
+ echo "## π³ Docker Build Job Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Job Status** | ${{ job.status == 'success' && 'β
Success' || 'β Failed' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Image Tag** | \`${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Branch** | ${{ env.BRANCH_NAME }} |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ job.status }}" == "success" ]]; then
+ echo "### β
Build Details" >> $GITHUB_STEP_SUMMARY
+ echo "Successfully built and pushed three Docker images to ACR:" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY
+ echo "- \`${ACR_NAME}.azurecr.io/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "- \`${ACR_NAME}.azurecr.io/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "- \`${ACR_NAME}.azurecr.io/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Build Failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Docker build process encountered an error" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the docker-build job for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
\ No newline at end of file
diff --git a/.github/workflows/job-send-notifications.yml b/.github/workflows/job-send-notifications.yml
new file mode 100644
index 000000000..c1280cdac
--- /dev/null
+++ b/.github/workflows/job-send-notifications.yml
@@ -0,0 +1,227 @@
+name: Send Notification Job v2
+
+on:
+ workflow_call:
+ inputs:
+ trigger_type:
+ description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
+ required: true
+ type: string
+ waf_enabled:
+ description: 'Enable WAF'
+ required: false
+ default: false
+ type: boolean
+ exp:
+ description: 'Enable EXP'
+ required: false
+ default: false
+ type: boolean
+ run_e2e_tests:
+ description: 'Run End-to-End Tests'
+ required: false
+ default: 'GoldenPath-Testing'
+ type: string
+ existing_webapp_url:
+ description: 'Existing Container WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+ deploy_result:
+ description: 'Deploy job result (success, failure, skipped)'
+ required: true
+ type: string
+ e2e_test_result:
+ description: 'E2E test job result (success, failure, skipped)'
+ required: true
+ type: string
+ CONTAINER_WEB_APPURL:
+ description: 'Container Web App URL'
+ required: false
+ default: ''
+ type: string
+ RESOURCE_GROUP_NAME:
+ description: 'Resource Group Name'
+ required: false
+ default: ''
+ type: string
+ QUOTA_FAILED:
+ description: 'Quota Check Failed Flag'
+ required: false
+ default: 'false'
+ type: string
+ TEST_SUCCESS:
+ description: 'Test Success Flag'
+ required: false
+ default: ''
+ type: string
+ TEST_REPORT_URL:
+ description: 'Test Report URL'
+ required: false
+ default: ''
+ type: string
+ secrets:
+ EMAILNOTIFICATION_LOGICAPP_URL_TA:
+ required: false
+
+env:
+ GPT_MIN_CAPACITY: 100
+ BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
+ WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }}
+ EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }}
+ RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }}
+
+jobs:
+ send-notification:
+ runs-on: ubuntu-latest
+ continue-on-error: true
+ env:
+ accelerator_name: "Content Processing"
+ steps:
+ - name: Determine Test Suite Display Name
+ id: test_suite
+ shell: bash
+ run: |
+ if [ "${{ env.RUN_E2E_TESTS }}" = "GoldenPath-Testing" ]; then
+ TEST_SUITE_NAME="Golden Path Testing"
+ elif [ "${{ env.RUN_E2E_TESTS }}" = "Smoke-Testing" ]; then
+ TEST_SUITE_NAME="Smoke Testing"
+ elif [ "${{ env.RUN_E2E_TESTS }}" = "None" ]; then
+ TEST_SUITE_NAME="None"
+ else
+ TEST_SUITE_NAME="${{ env.RUN_E2E_TESTS }}"
+ fi
+ echo "TEST_SUITE_NAME=$TEST_SUITE_NAME" >> $GITHUB_OUTPUT
+ echo "Test Suite: $TEST_SUITE_NAME"
+
+ - name: Send Quota Failure Notification
+ if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED == 'true'
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ EMAIL_BODY=$(cat <Dear Team,
We would like to inform you that the ${{ env.accelerator_name }} deployment has failed due to insufficient quota in the requested regions.
Issue Details:
β’ Quota check failed for GPT model
β’ Required GPT Capacity: ${{ env.GPT_MIN_CAPACITY }}
β’ Checked Regions: ${{ vars.AZURE_REGIONS }}
Run URL: ${RUN_URL}
Please resolve the quota issue and retry the deployment.
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Failed (Insufficient Quota)"
+ }
+ EOF
+ )
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send quota failure notification"
+
+ - name: Send Deployment Failure Notification
+ if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED != 'true'
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment process has encountered an issue and has failed to complete successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ WAF Enabled: ${{ env.WAF_ENABLED }}
β’ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Please investigate the deployment failure at your earliest convenience.
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Failed"
+ }
+ EOF
+ )
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send deployment failure notification"
+
+ - name: Send Success Notification
+ if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.TEST_SUCCESS == 'true')
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}"
+ RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+ TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+
+ if [ "${{ inputs.e2e_test_result }}" = "skipped" ]; then
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment has completed successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ Web App URL: ${WEBAPP_URL}
β’ E2E Tests: Skipped (as configured)
Configuration:
β’ WAF Enabled: ${{ env.WAF_ENABLED }}
β’ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Deployment Success"
+ }
+ EOF
+ )
+ else
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment and testing process has completed successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ Web App URL: ${WEBAPP_URL}
β’ E2E Tests: Passed β
β’ Test Suite: ${TEST_SUITE_NAME}
β’ Test Report: View Report
Configuration:
β’ WAF Enabled: ${{ env.WAF_ENABLED }}
β’ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Success"
+ }
+ EOF
+ )
+ fi
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send success notification"
+
+ - name: Send Test Failure Notification
+ if: inputs.deploy_result == 'success' && inputs.e2e_test_result != 'skipped' && inputs.TEST_SUCCESS != 'true'
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
+ WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}"
+ RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that ${{ env.accelerator_name }} accelerator test automation process has encountered issues and failed to complete successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ Web App URL: ${WEBAPP_URL}
β’ Deployment Status: β
Success
β’ E2E Tests: β Failed
β’ Test Suite: ${TEST_SUITE_NAME}
Test Details:
β’ Test Report: View Report
Run URL: ${RUN_URL}
Please investigate the matter at your earliest convenience.
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Failed"
+ }
+ EOF
+ )
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send test failure notification"
+
+ - name: Send Existing URL Success Notification
+ if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'success' && (inputs.TEST_SUCCESS == 'true' || inputs.TEST_SUCCESS == '')
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ EXISTING_URL="${{ inputs.existing_webapp_url }}"
+ TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and testing process has completed successfully.
Test Results:
β’ Status: β
Passed
β’ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+β’ Test Report: View Report}
β’ Target URL: ${EXISTING_URL}
Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Passed (Existing URL)"
+ }
+ EOF
+ )
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send existing URL success notification"
+
+ - name: Send Existing URL Test Failure Notification
+ if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'failure'
+ shell: bash
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ EXISTING_URL="${{ inputs.existing_webapp_url }}"
+ TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.
Failure Details:
β’ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+β’ Test Report: View Report}
β’ Test Suite: ${TEST_SUITE_NAME}
β’ Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Failed (Existing URL)"
+ }
+ EOF
+ )
+
+ curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ -H "Content-Type: application/json" \
+ -d "$EMAIL_BODY" || echo "Failed to send existing URL test failure notification"
\ No newline at end of file
diff --git a/.github/workflows/job-test-automation.yml b/.github/workflows/job-test-automation.yml
new file mode 100644
index 000000000..c0b9dca52
--- /dev/null
+++ b/.github/workflows/job-test-automation.yml
@@ -0,0 +1,185 @@
+name: Test Automation KMGeneric v2
+
+on:
+ workflow_call:
+ inputs:
+ KMGENERIC_URL:
+ required: false
+ type: string
+ description: "Web URL for KMGeneric (overrides environment variable)"
+ KMGENERIC_URL_API:
+ required: false
+ type: string
+ description: "API URL for KMGeneric (overrides environment variable)"
+ TEST_SUITE:
+ required: false
+ type: string
+ default: "GoldenPath-Testing"
+ description: "Test suite to run: 'Smoke-Testing', 'GoldenPath-Testing' "
+ secrets:
+ EMAILNOTIFICATION_LOGICAPP_URL_TA:
+ required: false
+ description: "Logic App URL for email notifications"
+ outputs:
+ TEST_SUCCESS:
+ description: "Whether tests passed"
+ value: ${{ jobs.test.outputs.TEST_SUCCESS }}
+ TEST_REPORT_URL:
+ description: "URL to test report artifact"
+ value: ${{ jobs.test.outputs.TEST_REPORT_URL }}
+env:
+ # Use input URL if provided (from deploy pipeline), otherwise fall back to vars
+ url: ${{ inputs.KMGENERIC_URL }}
+ api_url: ${{ inputs.KMGENERIC_URL_API}}
+ accelerator_name: "KMGeneric"
+ test_suite: ${{ inputs.TEST_SUITE }}
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ outputs:
+ TEST_SUCCESS: ${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}
+ TEST_REPORT_URL: ${{ steps.upload_report.outputs.artifact-url }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Set up Python
+ uses: actions/setup-python@v6
+ with:
+ python-version: '3.13'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r tests/e2e-test/requirements.txt
+
+ - name: Ensure browsers are installed
+ run: python -m playwright install --with-deps chromium
+
+ - name: Validate URL
+ run: |
+ if [ -z "${{ env.url }}" ]; then
+ echo "ERROR: No URL provided for testing"
+ exit 1
+ elif [ -z "${{ env.api_url }}" ]; then
+ echo "ERROR: No API URL provided for testing"
+ exit 1
+ fi
+ echo "Testing URL: ${{ env.url }}"
+ echo "Testing API URL: ${{ env.api_url }}"
+
+ - name: Wait for Application to be Ready
+ run: |
+ echo "Waiting for application to be ready at ${{ env.url }} "
+ max_attempts=10
+ attempt=1
+
+ while [ $attempt -le $max_attempts ]; do
+ echo "Attempt $attempt: Checking if application is ready..."
+ if curl -f -s "${{ env.url }}" > /dev/null; then
+ echo "Application is ready!"
+ break
+ fi
+
+ if [ $attempt -eq $max_attempts ]; then
+ echo "Application is not ready after $max_attempts attempts"
+ exit 1
+ fi
+
+ echo "Application not ready, waiting 30 seconds..."
+ sleep 30
+ attempt=$((attempt + 1))
+ done
+
+ - name: Run tests(1)
+ id: test1
+ run: |
+ xvfb-run pytest --headed --html=report/report.html --self-contained-html
+ working-directory: tests/e2e-test
+ continue-on-error: true
+
+ - name: Sleep for 30 seconds
+ if: ${{ steps.test1.outcome == 'failure' }}
+ run: sleep 30s
+ shell: bash
+
+ - name: Run tests(2)
+ if: ${{ steps.test1.outcome == 'failure' }}
+ id: test2
+ run: |
+ xvfb-run pytest --headed --html=report/report.html --self-contained-html
+ working-directory: tests/e2e-test
+ continue-on-error: true
+
+ - name: Sleep for 60 seconds
+ if: ${{ steps.test2.outcome == 'failure' }}
+ run: sleep 60s
+ shell: bash
+
+ - name: Run tests(3)
+ if: ${{ steps.test2.outcome == 'failure' }}
+ id: test3
+ run: |
+ xvfb-run pytest --headed --html=report/report.html --self-contained-html
+ working-directory: tests/e2e-test
+
+ - name: Upload test report
+ id: upload_report
+ uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+
+ name: test-report-${{ github.run_id }}
+ path: tests/e2e-test/report/*
+
+ - name: Generate E2E Test Summary
+ if: always()
+ run: |
+ # Determine test suite type for title
+ if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then
+ echo "## π§ͺ E2E Test Job Summary : Golden Path Testing" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "## π§ͺ E2E Test Job Summary : Smoke Testing" >> $GITHUB_STEP_SUMMARY
+ fi
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
+
+ # Determine overall test result
+ OVERALL_SUCCESS="${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}"
+ if [[ "$OVERALL_SUCCESS" == "true" ]]; then
+ echo "| **Job Status** | β
Success |" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "| **Job Status** | β Failed |" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ echo "| **Target URL** | [${{ env.url }}](${{ env.url }}) |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Test Suite** | \`${{ env.test_suite }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Test Report** | [Download Artifact](${{ steps.upload_report.outputs.artifact-url }}) |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ echo "### π Test Execution Details" >> $GITHUB_STEP_SUMMARY
+ echo "| Attempt | Status | Notes |" >> $GITHUB_STEP_SUMMARY
+ echo "|---------|--------|-------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Test Run 1** | ${{ steps.test1.outcome == 'success' && 'β
Passed' || 'β Failed' }} | Initial test execution |" >> $GITHUB_STEP_SUMMARY
+
+ if [[ "${{ steps.test1.outcome }}" == "failure" ]]; then
+ echo "| **Test Run 2** | ${{ steps.test2.outcome == 'success' && 'β
Passed' || steps.test2.outcome == 'failure' && 'β Failed' || 'βΈοΈ Skipped' }} | Retry after 30s delay |" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ if [[ "${{ steps.test2.outcome }}" == "failure" ]]; then
+ echo "| **Test Run 3** | ${{ steps.test3.outcome == 'success' && 'β
Passed' || steps.test3.outcome == 'failure' && 'β Failed' || 'βΈοΈ Skipped' }} | Final retry after 60s delay |" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ if [[ "$OVERALL_SUCCESS" == "true" ]]; then
+ echo "### β
Test Results" >> $GITHUB_STEP_SUMMARY
+ echo "- End-to-end tests completed successfully" >> $GITHUB_STEP_SUMMARY
+ echo "- Application is functioning as expected" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Test Results" >> $GITHUB_STEP_SUMMARY
+ echo "- All test attempts failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the e2e-test/test job for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
\ No newline at end of file
From c6f291d55d4e63d84524ccfea1d536315702c9e5 Mon Sep 17 00:00:00 2001
From: Ajit Padhi
Date: Tue, 2 Dec 2025 16:59:15 +0530
Subject: [PATCH 2/4] Enhance Deployment Pipeline
---
.github/workflows/deploy-linux.yml | 8 +-
.github/workflows/deploy-orchestrator.yml | 89 +++-----
.github/workflows/deploy-windows.yml | 8 +-
.github/workflows/job-azure-deploy.yml | 88 +++-----
.github/workflows/job-cleanup-resources.yml | 34 ++-
.github/workflows/job-deploy-linux.yml | 206 +++++++++++++++++++
.github/workflows/job-deploy-windows.yml | 200 ++++++++++++++++++
.github/workflows/job-docker-build.yml | 64 ++----
.github/workflows/job-send-notifications.yml | 65 +++---
.github/workflows/job-test-automation.yml | 2 +-
infra/main.parameters.json | 13 +-
infra/main.waf.parameters.json | 13 +-
12 files changed, 557 insertions(+), 233 deletions(-)
create mode 100644 .github/workflows/job-deploy-linux.yml
create mode 100644 .github/workflows/job-deploy-windows.yml
diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml
index b6845dd41..2a467e60c 100644
--- a/.github/workflows/deploy-linux.yml
+++ b/.github/workflows/deploy-linux.yml
@@ -1,5 +1,9 @@
name: Deploy-Test-Cleanup Linux
on:
+ push:
+ branches:
+ - main
+ - dev
workflow_dispatch:
inputs:
azure_location:
@@ -61,7 +65,7 @@ on:
default: ''
type: string
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
@@ -74,7 +78,7 @@ jobs:
azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
- EXP: ${{ github.event.inputs.EXP == 'true' }}
+ exp: ${{ github.event.inputs.exp == 'true' }}
build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
index d2d5748d5..daa6a5389 100644
--- a/.github/workflows/deploy-orchestrator.yml
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -1,4 +1,4 @@
-name: Deployment orchestrator v2
+name: Deployment orchestrator
on:
workflow_call:
@@ -53,7 +53,7 @@ on:
default: ''
type: string
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
@@ -61,34 +61,6 @@ on:
description: 'Trigger type (workflow_dispatch, pull_request, schedule)'
required: true
type: string
- secrets:
- AZURE_CLIENT_ID:
- required: true
- AZURE_CLIENT_SECRET:
- required: true
- AZURE_TENANT_ID:
- required: true
- AZURE_SUBSCRIPTION_ID:
- required: true
- ACR_TEST_LOGIN_SERVER:
- required: true
- ACR_TEST_USERNAME:
- required: true
- ACR_TEST_PASSWORD:
- required: true
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
- required: false
- AZURE_ENV_FOUNDRY_PROJECT_ID:
- required: false
- EMAILNOTIFICATION_LOGICAPP_URL_TA:
- required: false
- outputs:
- CONTAINER_WEB_APPURL:
- description: "Container Web App URL"
- value: ${{ jobs.deploy.outputs.CONTAINER_WEB_APPURL }}
- RESOURCE_GROUP_NAME:
- description: "Resource Group Name"
- value: ${{ jobs.deploy.outputs.RESOURCE_GROUP_NAME }}
env:
AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
@@ -99,10 +71,7 @@ jobs:
with:
trigger_type: ${{ inputs.trigger_type }}
build_docker_image: ${{ inputs.build_docker_image }}
- secrets:
- ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
- ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }}
- ACR_TEST_PASSWORD: ${{ secrets.ACR_TEST_PASSWORD }}
+ secrets: inherit
deploy:
if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)
@@ -114,28 +83,23 @@ jobs:
azure_location: ${{ inputs.azure_location }}
resource_group_name: ${{ inputs.resource_group_name }}
waf_enabled: ${{ inputs.waf_enabled }}
- EXP: ${{ inputs.exp }}
+ exp: ${{ inputs.exp }}
build_docker_image: ${{ inputs.build_docker_image }}
existing_webapp_url: ${{ inputs.existing_webapp_url }}
azure_env_log_anlytics_workspace_id: ${{ inputs.azure_env_log_anlytics_workspace_id }}
azure_existing_ai_project_resource_id: ${{ inputs.azure_existing_ai_project_resource_id }}
docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }}
- secrets:
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.azure_env_log_anlytics_workspace_id }}
- AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
+ run_e2e_tests: ${{ inputs.run_e2e_tests }}
+ cleanup_resources: ${{ inputs.cleanup_resources }}
+ secrets: inherit
e2e-test:
- if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))
+ if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.WEB_APP_URL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))
needs: [docker-build, deploy]
uses: ./.github/workflows/job-test-automation.yml
with:
- KMGENERIC_URL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}
- KMGENERIC_URL_API: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}
+ KMGENERIC_URL: ${{ needs.deploy.outputs.WEB_APP_URL || inputs.existing_webapp_url }}
+ KMGENERIC_URL_API: ${{ needs.deploy.outputs.API_APP_URL || inputs.existing_webapp_url }}
TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }}
secrets: inherit
@@ -146,21 +110,20 @@ jobs:
with:
trigger_type: ${{ inputs.trigger_type }}
waf_enabled: ${{ inputs.waf_enabled }}
- EXP: ${{ inputs.exp }}
+ exp: ${{ inputs.exp }}
run_e2e_tests: ${{ inputs.run_e2e_tests }}
existing_webapp_url: ${{ inputs.existing_webapp_url }}
deploy_result: ${{ needs.deploy.result }}
e2e_test_result: ${{ needs.e2e-test.result }}
- CONTAINER_WEB_APPURL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL }}
- RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
- QUOTA_FAILED: ${{ needs.deploy.outputs.QUOTA_FAILED }}
- TEST_SUCCESS: ${{ needs.e2e-test.outputs.TEST_SUCCESS }}
- TEST_REPORT_URL: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }}
- secrets:
- EMAILNOTIFICATION_LOGICAPP_URL_TA: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
+ web_app_url: ${{ needs.deploy.outputs.WEB_APP_URL }}
+ resource_group_name: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
+ quota_failed: ${{ needs.deploy.outputs.QUOTA_FAILED }}
+ test_success: ${{ needs.e2e-test.outputs.TEST_SUCCESS }}
+ test_report_url: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }}
+ secrets: inherit
cleanup-deployment:
- if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null)
+ if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)
needs: [docker-build, deploy, e2e-test]
uses: ./.github/workflows/job-cleanup-resources.yml
with:
@@ -168,13 +131,9 @@ jobs:
trigger_type: ${{ inputs.trigger_type }}
cleanup_resources: ${{ inputs.cleanup_resources }}
existing_webapp_url: ${{ inputs.existing_webapp_url }}
- RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
- AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }}
- AZURE_ENV_OPENAI_LOCATION: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }}
- ENV_NAME: ${{ needs.deploy.outputs.ENV_NAME }}
- IMAGE_TAG: ${{ needs.deploy.outputs.IMAGE_TAG }}
- secrets:
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
\ No newline at end of file
+ resource_group_name: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}
+ azure_location: ${{ needs.deploy.outputs.AZURE_LOCATION }}
+ azure_env_openai_location: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }}
+ env_name: ${{ needs.deploy.outputs.ENV_NAME }}
+ image_tag: ${{ needs.deploy.outputs.IMAGE_TAG }}
+ secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml
index 538e53694..743125817 100644
--- a/.github/workflows/deploy-windows.yml
+++ b/.github/workflows/deploy-windows.yml
@@ -1,5 +1,9 @@
name: Deploy-Test-Cleanup Windows
on:
+ push:
+ branches:
+ - main
+ - dev
workflow_dispatch:
inputs:
azure_location:
@@ -61,7 +65,7 @@ on:
default: ''
type: string
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
@@ -74,7 +78,7 @@ jobs:
azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
- EXP: ${{ github.event.inputs.exp == 'true' }}
+ exp: ${{ github.event.inputs.exp == 'true' }}
build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
diff --git a/.github/workflows/job-azure-deploy.yml b/.github/workflows/job-azure-deploy.yml
index ac3562b69..de04f4767 100644
--- a/.github/workflows/job-azure-deploy.yml
+++ b/.github/workflows/job-azure-deploy.yml
@@ -1,4 +1,4 @@
-name: Deploy Job v2
+name: Deploy Job
on:
workflow_call:
@@ -47,7 +47,7 @@ on:
default: 'GoldenPath-Testing'
type: string
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
@@ -66,34 +66,16 @@ on:
required: false
default: ''
type: string
- secrets:
- AZURE_CLIENT_ID:
- required: true
- AZURE_CLIENT_SECRET:
- required: true
- AZURE_TENANT_ID:
- required: true
- AZURE_SUBSCRIPTION_ID:
- required: true
- ACR_TEST_LOGIN_SERVER:
- required: true
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
- required: false
- AZURE_ENV_FOUNDRY_PROJECT_ID:
- required: false
outputs:
- invoice_schema_id:
- description: "Invoice Schema ID"
- value: ${{ jobs.deploy-linux.outputs.invoice_schema_id || jobs.deploy-windows.outputs.invoice_schema_id }}
- propertydamageclaimform_schema_id:
- description: "Property Damage Claim Form Schema ID"
- value: ${{ jobs.deploy-linux.outputs.propertydamageclaimform_schema_id || jobs.deploy-windows.outputs.propertydamageclaimform_schema_id }}
RESOURCE_GROUP_NAME:
description: "Resource Group Name"
value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
- CONTAINER_WEB_APPURL:
- description: "Container Web App URL"
- value: ${{ jobs.deploy-linux.outputs.CONTAINER_WEB_APPURL || jobs.deploy-windows.outputs.CONTAINER_WEB_APPURL }}
+ WEB_APP_URL:
+ description: "Web App URL"
+ value: ${{ jobs.deploy-linux.outputs.WEB_APP_URL || jobs.deploy-windows.outputs.WEB_APP_URL }}
+ API_APP_URL:
+ description: "API App URL"
+ value: ${{ jobs.deploy-linux.outputs.API_APP_URL || jobs.deploy-windows.outputs.API_APP_URL }}
ENV_NAME:
description: "Environment Name"
value: ${{ jobs.azure-setup.outputs.ENV_NAME }}
@@ -112,10 +94,11 @@ on:
env:
GPT_MIN_CAPACITY: 100
+ TEXT_EMBEDDING_MIN_CAPACITY: 80
BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }}
EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }}
- CLEANUP_RESOURCES: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.cleanup_resources || true) || true }}
+ CLEANUP_RESOURCES: ${{ inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources }}
RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }}
BUILD_DOCKER_IMAGE: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.build_docker_image || false) || false }}
@@ -155,6 +138,11 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v4
+ - name: Setup Azure CLI
+ run: |
+ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
+ az --version
+
- name: Login to Azure
shell: bash
run: |
@@ -170,29 +158,25 @@ jobs:
export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }}
export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }}
+ export TEXT_EMBEDDING_MIN_CAPACITY=${{ env.TEXT_EMBEDDING_MIN_CAPACITY }}
export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}"
- chmod +x infra/scripts/checkquota.sh
- if ! infra/scripts/checkquota.sh; then
- if grep -q "No region with sufficient quota found" infra/scripts/checkquota.sh; then
+ chmod +x infra/scripts/checkquota_km.sh
+ if ! infra/scripts/checkquota_km.sh; then
+ if grep -q "No region with sufficient quota found" infra/scripts/checkquota_km.sh; then
echo "QUOTA_FAILED=true" >> $GITHUB_ENV
fi
exit 1
fi
-
- - name: Set Quota Failure Output
- id: quota_failure_output
- if: env.QUOTA_FAILED == 'true'
- shell: bash
- run: |
- echo "QUOTA_FAILED=true" >> $GITHUB_OUTPUT
- echo "Quota check failed - will notify via separate notification job"
- name: Fail Pipeline if Quota Check Fails
if: env.QUOTA_FAILED == 'true'
shell: bash
run: exit 1
-
+
+ - name: Install Bicep CLI
+ run: az bicep install
+
- name: Set Deployment Region
id: set_region
shell: bash
@@ -222,17 +206,13 @@ jobs:
echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV
else
echo "Generating a unique resource group name..."
- ACCL_NAME="cp" # Account name as specified
+ ACCL_NAME="kmgeneric" # Account name as specified
SHORT_UUID=$(uuidgen | cut -d'-' -f1)
UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}"
echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV
echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}"
fi
- - name: Install Bicep CLI
- shell: bash
- run: az bicep install
-
- name: Check and Create Resource Group
id: check_create_rg
shell: bash
@@ -255,7 +235,7 @@ jobs:
shell: bash
run: |
set -e
- COMMON_PART="psldg"
+ COMMON_PART="pslkmg"
TIMESTAMP=$(date +%s)
UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6)
UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}"
@@ -365,14 +345,7 @@ jobs:
WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }}
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }}
- secrets:
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
- AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
+ secrets: inherit
deploy-windows:
name: Deploy on Windows
@@ -390,11 +363,4 @@ jobs:
WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }}
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }}
- secrets:
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
- AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}
\ No newline at end of file
+ secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/job-cleanup-resources.yml b/.github/workflows/job-cleanup-resources.yml
index 12e6a6cfc..6d3399776 100644
--- a/.github/workflows/job-cleanup-resources.yml
+++ b/.github/workflows/job-cleanup-resources.yml
@@ -1,4 +1,4 @@
-name: Cleanup Deployment Job v2
+name: Cleanup Deployment Resources
on:
workflow_call:
@@ -17,51 +17,41 @@ on:
default: false
type: boolean
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
- RESOURCE_GROUP_NAME:
+ resource_group_name:
description: 'Resource Group Name to cleanup'
required: true
type: string
- AZURE_LOCATION:
+ azure_location:
description: 'Azure Location'
required: true
type: string
- AZURE_ENV_OPENAI_LOCATION:
+ azure_env_openai_location:
description: 'Azure OpenAI Location'
required: true
type: string
- ENV_NAME:
+ env_name:
description: 'Environment Name'
required: true
type: string
- IMAGE_TAG:
+ image_tag:
description: 'Docker Image Tag'
required: true
type: string
- secrets:
- AZURE_CLIENT_ID:
- required: true
- AZURE_CLIENT_SECRET:
- required: true
- AZURE_TENANT_ID:
- required: true
- AZURE_SUBSCRIPTION_ID:
- required: true
jobs:
cleanup-deployment:
- if: inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null)
runs-on: ${{ inputs.runner_os }}
continue-on-error: true
env:
- RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
- AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
- AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
- ENV_NAME: ${{ inputs.ENV_NAME }}
- IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }}
+ AZURE_LOCATION: ${{ inputs.azure_location }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.azure_env_openai_location }}
+ ENV_NAME: ${{ inputs.env_name }}
+ IMAGE_TAG: ${{ inputs.image_tag }}
steps:
- name: Setup Azure CLI
shell: bash
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
new file mode 100644
index 000000000..a8fd32fa3
--- /dev/null
+++ b/.github/workflows/job-deploy-linux.yml
@@ -0,0 +1,206 @@
+name: Deploy Steps - Linux
+
+on:
+ workflow_call:
+ inputs:
+ ENV_NAME:
+ required: true
+ type: string
+ AZURE_ENV_OPENAI_LOCATION:
+ required: true
+ type: string
+ AZURE_LOCATION:
+ required: true
+ type: string
+ RESOURCE_GROUP_NAME:
+ required: true
+ type: string
+ IMAGE_TAG:
+ required: true
+ type: string
+ BUILD_DOCKER_IMAGE:
+ required: true
+ type: string
+ EXP:
+ required: true
+ type: string
+ WAF_ENABLED:
+ required: false
+ type: string
+ default: 'false'
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
+ required: false
+ type: string
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID:
+ required: false
+ type: string
+ outputs:
+ WEB_APP_URL:
+ description: "Web App URL"
+ value: ${{ jobs.deploy-linux.outputs.WEB_APP_URL }}
+ API_APP_URL:
+ description: "API App URL"
+ value: ${{ jobs.deploy-linux.outputs.API_APP_URL }}
+
+jobs:
+ deploy-linux:
+ runs-on: ubuntu-latest
+ env:
+ AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
+ outputs:
+ WEB_APP_URL: ${{ steps.get_output_linux.outputs.WEB_APP_URL }}
+ API_APP_URL: ${{ steps.get_output_linux.outputs.API_APP_URL }}
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Configure Parameters Based on WAF Setting
+ shell: bash
+ run: |
+ if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then
+ cp infra/main.waf.parameters.json infra/main.parameters.json
+ echo "β
Successfully copied WAF parameters to main parameters file"
+ else
+ echo "π§ Configuring Non-WAF deployment - using default main.parameters.json..."
+ fi
+
+ - name: Setup Azure CLI
+ shell: bash
+ run: |
+ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
+
+ - name: Setup Azure Developer CLI (Linux)
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ curl -fsSL https://aka.ms/install-azd.sh | sudo bash
+ azd version
+
+ - name: Login to AZD
+ id: login-azure
+ shell: bash
+ run: |
+ az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
+ az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }}
+
+ - name: Deploy using azd up and extract values (Linux)
+ id: get_output_linux
+ shell: bash
+ run: |
+ set -e
+ echo "Starting azd deployment..."
+ echo "EXP: ${{ inputs.EXP }}"
+ echo "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}"
+
+ # Install azd (Azure Developer CLI)
+ curl -fsSL https://aka.ms/install-azd.sh | bash
+
+ # Generate current timestamp in desired format: YYYY-MM-DDTHH:MM:SS.SSSSSSSZ
+ current_date=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ")
+
+ echo "Creating environment..."
+ azd env new ${{ inputs.ENV_NAME }} --no-prompt
+ echo "Environment created: ${{ inputs.ENV_NAME }}"
+
+ echo "Setting default subscription..."
+ azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+ # Set additional parameters
+ azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
+ azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}"
+ azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}"
+ azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+ azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}"
+
+ if [[ "${{ inputs.BUILD_DOCKER_IMAGE }}" == "true" ]]; then
+ ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}")
+ azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME"
+ echo "Set ACR name to: $ACR_NAME"
+ else
+ echo "Skipping ACR name configuration (using existing image)"
+ fi
+
+ if [[ "${{ inputs.EXP }}" == "true" ]]; then
+ echo "β
EXP ENABLED - Setting EXP parameters..."
+
+ if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then
+ EXP_LOG_ANALYTICS_ID="${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ else
+ EXP_LOG_ANALYTICS_ID="${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ fi
+
+ if [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then
+ EXP_AI_PROJECT_ID="${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
+ else
+ EXP_AI_PROJECT_ID="${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}"
+ fi
+
+ echo "AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: $EXP_LOG_ANALYTICS_ID"
+ echo "AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: $EXP_AI_PROJECT_ID"
+ azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID="$EXP_LOG_ANALYTICS_ID"
+ azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID="$EXP_AI_PROJECT_ID"
+ else
+ echo "β EXP DISABLED - Skipping EXP parameters"
+ fi
+
+ # Set tags for deployment
+ echo "Setting deployment tags..."
+ azd env set AZURE_TAG_SECURITY_CONTROL="Ignore"
+
+ azd up --no-prompt
+
+ echo "β
Deployment succeeded."
+ echo "$DEPLOY_OUTPUT"
+
+ echo "Extracting deployment outputs..."
+ DEPLOY_OUTPUT=$(azd env get-values --output json)
+ echo "Deployment output: $DEPLOY_OUTPUT"
+
+ if [[ -z "$DEPLOY_OUTPUT" ]]; then
+ echo "Error: Deployment output is empty. Please check the deployment logs."
+ exit 1
+ fi
+
+ export API_APP_URL="$(echo "$DEPLOY_OUTPUT" | jq -r '.API_APP_URL // empty')"
+ echo "API_APP_URL=$API_APP_URL" >> $GITHUB_ENV
+ echo "API_APP_URL=$API_APP_URL" >> $GITHUB_OUTPUT
+
+ export WEB_APP_URL="$(echo "$DEPLOY_OUTPUT" | jq -r '.WEB_APP_URL // empty')"
+ echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_ENV
+ echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT
+
+ - name: Generate Deployment Summary
+ if: always()
+ shell: bash
+ run: |
+ echo "## π Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Job Status** | ${{ job.status == 'success' && 'β
Success' || 'β Failed' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ job.status }}" == "success" ]]; then
+ echo "### β
Deployment Details" >> $GITHUB_STEP_SUMMARY
+ echo "- **Container Web App URL**: [${{ env.WEB_APP_URL }}](${{ env.WEB_APP_URL }})" >> $GITHUB_STEP_SUMMARY
+ echo "- **Container API App URL**: [${{ env.API_APP_URL }}](${{ env.API_APP_URL }})" >> $GITHUB_STEP_SUMMARY
+ echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY
+ echo "- Schemas registered and sample data uploaded successfully" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Deployment Failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the deployment steps above for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ - name: Logout from Azure
+ if: always()
+ shell: bash
+ run: |
+ az logout || true
+ echo "Logged out from Azure."
\ No newline at end of file
diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml
new file mode 100644
index 000000000..82738623a
--- /dev/null
+++ b/.github/workflows/job-deploy-windows.yml
@@ -0,0 +1,200 @@
+name: Deploy Steps - Windows
+
+on:
+ workflow_call:
+ inputs:
+ ENV_NAME:
+ required: true
+ type: string
+ AZURE_ENV_OPENAI_LOCATION:
+ required: true
+ type: string
+ AZURE_LOCATION:
+ required: true
+ type: string
+ RESOURCE_GROUP_NAME:
+ required: true
+ type: string
+ IMAGE_TAG:
+ required: true
+ type: string
+ BUILD_DOCKER_IMAGE:
+ required: true
+ type: string
+ EXP:
+ required: true
+ type: string
+ WAF_ENABLED:
+ required: false
+ type: string
+ default: 'false'
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
+ required: false
+ type: string
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID:
+ required: false
+ type: string
+ AZURE_TAGS:
+ required: false
+ type: string
+ description: 'Optional JSON string of tags to apply to Azure resources'
+ outputs:
+ WEB_APP_URL:
+ description: "Web App URL"
+ value: ${{ jobs.deploy-windows.outputs.WEB_APP_URL }}
+ API_APP_URL:
+ description: "API App URL"
+ value: ${{ jobs.deploy-windows.outputs.API_APP_URL }}
+
+jobs:
+ deploy-windows:
+ runs-on: windows-latest
+ env:
+ AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
+ outputs:
+ WEB_APP_URL: ${{ steps.get_output_windows.outputs.WEB_APP_URL }}
+ API_APP_URL: ${{ steps.get_output_windows.outputs.API_APP_URL }}
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Configure Parameters Based on WAF Setting
+ shell: bash
+ run: |
+ if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then
+ cp infra/main.waf.parameters.json infra/main.parameters.json
+ echo "β
Successfully copied WAF parameters to main parameters file"
+ else
+ echo "π§ Configuring Non-WAF deployment - using default main.parameters.json..."
+ fi
+
+ - name: Setup Azure Developer CLI (Windows)
+ uses: Azure/setup-azd@v2
+
+ - name: Login to AZD
+ id: login-azure
+ shell: bash
+ run: |
+ az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
+ az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }}
+
+
+ - name: Deploy using azd up and extract values (Windows)
+ id: get_output_windows
+ shell: pwsh
+ run: |
+ $ErrorActionPreference = "Stop"
+ Write-Host "Starting azd deployment..."
+ Write-Host "EXP: ${{ inputs.EXP }}"
+ Write-Host "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}"
+
+ Write-Host "Creating environment..."
+ azd env new ${{ inputs.ENV_NAME }} --no-prompt
+ Write-Host "Environment created: ${{ inputs.ENV_NAME }}"
+
+ Write-Host "Setting default subscription..."
+ azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+ # Set additional parameters
+ azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
+ azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}"
+ azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}"
+ azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+ azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}"
+
+ # Set ACR name only when building Docker image
+ if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") {
+ # Extract ACR name from login server and set as environment variable
+ $ACR_NAME = "${{ secrets.ACR_TEST_LOGIN_SERVER }}"
+ azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME"
+ Write-Host "Set ACR name to: $ACR_NAME"
+ } else {
+ Write-Host "Skipping ACR name configuration (using existing image)"
+ }
+
+ if ("${{ inputs.EXP }}" -eq "true") {
+ Write-Host "β
EXP ENABLED - Setting EXP parameters..."
+
+ # Set EXP variables dynamically
+ if ("${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" -ne "") {
+ $EXP_LOG_ANALYTICS_ID = "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ } else {
+ $EXP_LOG_ANALYTICS_ID = "${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ }
+
+ if ("${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" -ne "") {
+ $EXP_AI_PROJECT_ID = "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
+ } else {
+ $EXP_AI_PROJECT_ID = "${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}"
+ }
+
+ Write-Host "AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: $EXP_LOG_ANALYTICS_ID"
+ Write-Host "AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: $EXP_AI_PROJECT_ID"
+ azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID="$EXP_LOG_ANALYTICS_ID"
+ azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID="$EXP_AI_PROJECT_ID"
+ } else {
+ Write-Host "β EXP DISABLED - Skipping EXP parameters"
+ }
+
+ # Set tags for deployment
+ Write-Host "Setting deployment tags..."
+ azd env set AZURE_TAG_SECURITY_CONTROL="Ignore"
+
+ # Deploy using azd up
+ azd up --no-prompt
+
+ Write-Host "β
Deployment succeeded."
+
+ # Get deployment outputs using azd
+ Write-Host "Extracting deployment outputs..."
+ $DEPLOY_OUTPUT = azd env get-values --output json | ConvertFrom-Json
+ Write-Host "Deployment output: $($DEPLOY_OUTPUT | ConvertTo-Json -Depth 10)"
+
+ if (-not $DEPLOY_OUTPUT) {
+ Write-Host "Error: Deployment output is empty. Please check the deployment logs."
+ exit 1
+ }
+
+ # Export variables only after successful deploy
+ $API_APP_URL = $DEPLOY_OUTPUT.API_APP_URL
+ "API_APP_URL=$API_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ "API_APP_URL=$API_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
+
+ $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL
+ "WEB_APP_URL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ "WEB_APP_URL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
+
+ - name: Generate Deployment Summary
+ if: always()
+ shell: bash
+ run: |
+ echo "## π Deploy Job Summary (Windows)" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
+ echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
+ echo "| **Job Status** | ${{ job.status == 'success' && 'β
Success' || 'β Failed' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [ "${{ job.status }}" == "success" ]; then
+ echo "### β
Deployment Details" >> $GITHUB_STEP_SUMMARY
+ echo "- **Container Web App URL**: [${{ env.WEB_APP_URL }}](${{ env.WEB_APP_URL }})" >> $GITHUB_STEP_SUMMARY
+ echo "- **Container API App URL**: [${{ env.API_APP_URL }}](${{ env.API_APP_URL }})" >> $GITHUB_STEP_SUMMARY
+ echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY
+ echo "- Schemas registered and sample data uploaded successfully" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Deployment Failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the deployment steps above for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ - name: Logout from Azure
+ if: always()
+ shell: bash
+ run: |
+ az logout || true
+ echo "Logged out from Azure."
\ No newline at end of file
diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml
index 800dd5591..7f7d99902 100644
--- a/.github/workflows/job-docker-build.yml
+++ b/.github/workflows/job-docker-build.yml
@@ -12,13 +12,6 @@ on:
required: false
default: false
type: boolean
- secrets:
- ACR_TEST_LOGIN_SERVER:
- required: true
- ACR_TEST_USERNAME:
- required: true
- ACR_TEST_PASSWORD:
- required: true
outputs:
IMAGE_TAG:
description: "Generated Docker Image Tag"
@@ -61,41 +54,25 @@ jobs:
username: ${{ secrets.ACR_TEST_USERNAME }}
password: ${{ secrets.ACR_TEST_PASSWORD }}
- # - name: Build and Push ContentProcessor Docker image
- # uses: docker/build-push-action@v6
- # env:
- # DOCKER_BUILD_SUMMARY: false
- # with:
- # context: ./src/ContentProcessor
- # file: ./src/ContentProcessor/Dockerfile
- # push: true
- # tags: |
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
-
- # - name: Build and Push ContentProcessorAPI Docker image
- # uses: docker/build-push-action@v6
- # env:
- # DOCKER_BUILD_SUMMARY: false
- # with:
- # context: ./src/ContentProcessorAPI
- # file: ./src/ContentProcessorAPI/Dockerfile
- # push: true
- # tags: |
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+ - name: Build and Push Docker Image for WebApp
+ uses: docker/build-push-action@v6
+ with:
+ context: ./src/App
+ file: ./src/App/WebApp.Dockerfile
+ push: True
+ tags: |
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-app:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-app:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
- # - name: Build and Push ContentProcessorWeb Docker image
- # uses: docker/build-push-action@v6
- # env:
- # DOCKER_BUILD_SUMMARY: false
- # with:
- # context: ./src/ContentProcessorWeb
- # file: ./src/ContentProcessorWeb/Dockerfile
- # push: true
- # tags: |
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
- # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+ - name: Build and Push Docker Image for API
+ uses: docker/build-push-action@v6
+ with:
+ context: ./src/api
+ file: ./src/api/ApiApp.Dockerfile
+ push: True
+ tags: |
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
- name: Verify Docker Image Build
shell: bash
@@ -121,9 +98,8 @@ jobs:
echo "Successfully built and pushed three Docker images to ACR:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY
- echo "- \`${ACR_NAME}.azurecr.io/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
- echo "- \`${ACR_NAME}.azurecr.io/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
- echo "- \`${ACR_NAME}.azurecr.io/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "- \`${ACR_NAME}.azurecr.io/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "- \`${ACR_NAME}.azurecr.io/km-web:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
else
echo "### β Build Failed" >> $GITHUB_STEP_SUMMARY
echo "- Docker build process encountered an error" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/job-send-notifications.yml b/.github/workflows/job-send-notifications.yml
index c1280cdac..1ad104360 100644
--- a/.github/workflows/job-send-notifications.yml
+++ b/.github/workflows/job-send-notifications.yml
@@ -1,4 +1,4 @@
-name: Send Notification Job v2
+name: Send Notification Job
on:
workflow_call:
@@ -23,7 +23,7 @@ on:
default: 'GoldenPath-Testing'
type: string
existing_webapp_url:
- description: 'Existing Container WebApp URL (Skips Deployment)'
+ description: 'Existing WebApp URL (Skips Deployment)'
required: false
default: ''
type: string
@@ -35,34 +35,31 @@ on:
description: 'E2E test job result (success, failure, skipped)'
required: true
type: string
- CONTAINER_WEB_APPURL:
- description: 'Container Web App URL'
+ web_app_url:
+ description: 'Web App URL'
required: false
default: ''
type: string
- RESOURCE_GROUP_NAME:
+ resource_group_name:
description: 'Resource Group Name'
required: false
default: ''
type: string
- QUOTA_FAILED:
+ quota_failed:
description: 'Quota Check Failed Flag'
required: false
default: 'false'
type: string
- TEST_SUCCESS:
+ test_success:
description: 'Test Success Flag'
required: false
default: ''
type: string
- TEST_REPORT_URL:
+ test_report_url:
description: 'Test Report URL'
required: false
default: ''
type: string
- secrets:
- EMAILNOTIFICATION_LOGICAPP_URL_TA:
- required: false
env:
GPT_MIN_CAPACITY: 100
@@ -76,7 +73,7 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
env:
- accelerator_name: "Content Processing"
+ accelerator_name: "KM Generic"
steps:
- name: Determine Test Suite Display Name
id: test_suite
@@ -95,7 +92,7 @@ jobs:
echo "Test Suite: $TEST_SUITE_NAME"
- name: Send Quota Failure Notification
- if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED == 'true'
+ if: inputs.deploy_result == 'failure' && inputs.quota_failed == 'true'
shell: bash
run: |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
@@ -112,12 +109,12 @@ jobs:
-d "$EMAIL_BODY" || echo "Failed to send quota failure notification"
- name: Send Deployment Failure Notification
- if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED != 'true'
+ if: inputs.deploy_result == 'failure' && inputs.quota_failed != 'true'
shell: bash
run: |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
-
+ RESOURCE_GROUP="${{ inputs.resource_group_name }}"
+
EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment process has encountered an issue and has failed to complete successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ WAF Enabled: ${{ env.WAF_ENABLED }}
β’ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Please investigate the deployment failure at your earliest convenience.
Best regards,
Your Automation Team
",
@@ -131,15 +128,15 @@ jobs:
-d "$EMAIL_BODY" || echo "Failed to send deployment failure notification"
- name: Send Success Notification
- if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.TEST_SUCCESS == 'true')
+ if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.test_success == 'true')
shell: bash
run: |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}"
- RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
-
+ WEBAPP_URL="${{ inputs.web_app_url || inputs.existing_webapp_url }}"
+ RESOURCE_GROUP="${{ inputs.resource_group_name }}"
+ TEST_REPORT_URL="${{ inputs.test_report_url }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.test_suite_name }}"
+
if [ "${{ inputs.e2e_test_result }}" = "skipped" ]; then
EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and testing process has completed successfully.
Test Results:
β’ Status: β
Passed
β’ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+β’ Test Report: View Report}
β’ Target URL: ${EXISTING_URL}
Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
@@ -211,9 +208,9 @@ jobs:
run: |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
EXISTING_URL="${{ inputs.existing_webapp_url }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
-
+ TEST_REPORT_URL="${{ inputs.test_report_url }}"
+ TEST_SUITE_NAME="${{ steps.test_suite.outputs.test_suite_name }}"
+
EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.
Failure Details:
β’ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+β’ Test Report: View Report}
β’ Test Suite: ${TEST_SUITE_NAME}
β’ Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
diff --git a/.github/workflows/job-test-automation.yml b/.github/workflows/job-test-automation.yml
index c0b9dca52..80f1ad61a 100644
--- a/.github/workflows/job-test-automation.yml
+++ b/.github/workflows/job-test-automation.yml
@@ -1,4 +1,4 @@
-name: Test Automation KMGeneric v2
+name: Test Automation KMGeneric
on:
workflow_call:
diff --git a/infra/main.parameters.json b/infra/main.parameters.json
index aaf7a30a6..b120f5e39 100644
--- a/infra/main.parameters.json
+++ b/infra/main.parameters.json
@@ -14,7 +14,7 @@
"secondaryLocation": {
"value": "${AZURE_SECONDARY_LOCATION}"
},
- "azureAiServiceLocation": {
+ "aiServiceLocation": {
"value": "${AZURE_ENV_OPENAI_LOCATION}"
},
"gptModelDeploymentType": {
@@ -44,6 +44,11 @@
"frontendContainerImageTag": {
"value": "${AZURE_ENV_IMAGETAG=latest_waf}"
},
+ "tags": {
+ "value": {
+ "SecurityControl": "${AZURE_TAG_SECURITY_CONTROL=Ignore}"
+ }
+ },
"enableTelemetry": {
"value": "${AZURE_ENV_ENABLE_TELEMETRY}"
},
@@ -52,6 +57,12 @@
},
"existingAiFoundryAiProjectResourceId": {
"value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}"
+ },
+ "backendContainerRegistryHostname": {
+ "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
+ },
+ "frontendContainerRegistryHostname": {
+ "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
}
}
}
\ No newline at end of file
diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json
index 866c4d330..7f312c4e8 100644
--- a/infra/main.waf.parameters.json
+++ b/infra/main.waf.parameters.json
@@ -14,7 +14,7 @@
"secondaryLocation": {
"value": "${AZURE_SECONDARY_LOCATION}"
},
- "azureAiServiceLocation": {
+ "aiServiceLocation": {
"value": "${AZURE_ENV_OPENAI_LOCATION}"
},
"gptModelDeploymentType": {
@@ -44,6 +44,11 @@
"frontendContainerImageTag": {
"value": "${AZURE_ENV_IMAGETAG=latest_waf}"
},
+ "tags": {
+ "value": {
+ "SecurityControl": "${AZURE_TAG_SECURITY_CONTROL=Ignore}"
+ }
+ },
"enableTelemetry": {
"value": "${AZURE_ENV_ENABLE_TELEMETRY}"
},
@@ -53,6 +58,12 @@
"existingAiFoundryAiProjectResourceId": {
"value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}"
},
+ "backendContainerRegistryHostname": {
+ "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
+ },
+ "frontendContainerRegistryHostname": {
+ "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
+ },
"enableMonitoring": {
"value": true
},
From 08c1f91ebedc86dfcc0e8065ddba9d0b332bb771 Mon Sep 17 00:00:00 2001
From: Ajit Padhi
Date: Tue, 2 Dec 2025 17:00:55 +0530
Subject: [PATCH 3/4] minor update on pipeline
---
.github/workflows/deploy-linux.yml | 1 -
.github/workflows/deploy-windows.yml | 1 -
2 files changed, 2 deletions(-)
diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml
index 2a467e60c..309551b6f 100644
--- a/.github/workflows/deploy-linux.yml
+++ b/.github/workflows/deploy-linux.yml
@@ -3,7 +3,6 @@ on:
push:
branches:
- main
- - dev
workflow_dispatch:
inputs:
azure_location:
diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml
index 743125817..1f587b2d0 100644
--- a/.github/workflows/deploy-windows.yml
+++ b/.github/workflows/deploy-windows.yml
@@ -3,7 +3,6 @@ on:
push:
branches:
- main
- - dev
workflow_dispatch:
inputs:
azure_location:
From 4a7adb539582b03e11fb811331b4a4ffe2b5eea2 Mon Sep 17 00:00:00 2001
From: Ajit Padhi
Date: Wed, 3 Dec 2025 13:08:39 +0530
Subject: [PATCH 4/4] updated parameter md file
---
documents/CustomizingAzdParameters.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/documents/CustomizingAzdParameters.md b/documents/CustomizingAzdParameters.md
index 40e286049..3f8b15693 100644
--- a/documents/CustomizingAzdParameters.md
+++ b/documents/CustomizingAzdParameters.md
@@ -26,6 +26,7 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | `` | Reuses an existing AIFoundry and AIFoundryProject instead of creating a new one. |
| `AZURE_ENV_VM_ADMIN_USERNAME` | string | `take(newGuid(), 20)` | The administrator username for the virtual machine. |
| `AZURE_ENV_VM_ADMIN_PASSWORD` | string | `newGuid()` | The administrator password for the virtual machine. |
+| `AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT` | string | `` | The hostname/endpoint for the container registry used by both backend and frontend containers. |
## How to Set a Parameter