From 38151c98a504ffe4a7ff77ec0b2809a24880b97b Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 15 Dec 2025 17:36:02 +0530 Subject: [PATCH 01/37] pipelines creation initial version v1 --- .github/workflows/deploy-orchestrator.yml | 138 +++++++ .github/workflows/deploy-windows.yml | 100 +++++ .github/workflows/job-cleanup-deployment.yml | 114 ++++++ .github/workflows/job-deploy-windows.yml | 262 ++++++++++++++ .github/workflows/job-deploy.yml | 362 +++++++++++++++++++ .github/workflows/job-docker-build.yml | 99 +++++ .github/workflows/job-send-notification.yml | 224 ++++++++++++ .github/workflows/test-automation-v2.yml | 185 ++++++++++ 8 files changed, 1484 insertions(+) create mode 100644 .github/workflows/deploy-orchestrator.yml create mode 100644 .github/workflows/deploy-windows.yml create mode 100644 .github/workflows/job-cleanup-deployment.yml create mode 100644 .github/workflows/job-deploy-windows.yml create mode 100644 .github/workflows/job-deploy.yml create mode 100644 .github/workflows/job-docker-build.yml create mode 100644 .github/workflows/job-send-notification.yml create mode 100644 .github/workflows/test-automation-v2.yml diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml new file mode 100644 index 00000000..9e99cec1 --- /dev/null +++ b/.github/workflows/deploy-orchestrator.yml @@ -0,0 +1,138 @@ +name: Deployment orchestrator + +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_ANALYTICS_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 + +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: inherit + + deploy: + if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null) + needs: docker-build + uses: ./.github/workflows/job-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_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }} + 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.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/test-automation-v2.yml + with: + DOCGEN_URL: ${{ needs.deploy.outputs.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-notification.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 }} + WEB_APPURL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_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) + needs: [docker-build, deploy, e2e-test] + uses: ./.github/workflows/job-cleanup-deployment.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: inherit diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml new file mode 100644 index 00000000..2e96c838 --- /dev/null +++ b/.github/workflows/deploy-windows.yml @@ -0,0 +1,100 @@ +name: Deploy-Test-Cleanup (v2) Windows +on: + push: + branches: + - main # Adjust this to the branch you want to trigger the deployment on + - dev + - demo + schedule: + - cron: "0 10,22 * * *" # Runs at 10:00 AM and 10:00 PM GMT + + 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_ANALYTICS_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 WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + + # schedule: + # - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT + +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_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_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 diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml new file mode 100644 index 00000000..6b920a4e --- /dev/null +++ b/.github/workflows/job-cleanup-deployment.yml @@ -0,0 +1,114 @@ +name: Cleanup Deployment Job +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 + +jobs: + cleanup-deployment: + 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 "| **Resource 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 diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml new file mode 100644 index 00000000..09af1ad5 --- /dev/null +++ b/.github/workflows/job-deploy-windows.yml @@ -0,0 +1,262 @@ +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 + outputs: + WEB_APPURL: + description: "Container Web App URL" + value: ${{ jobs.deploy-windows.outputs.WEB_APPURL }} + +jobs: + deploy-windows: + runs-on: windows-latest + env: + AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + outputs: + WEB_APPURL: ${{ steps.get_output_windows.outputs.WEB_APPURL }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Install Kubernetes CLI (kubectl) + shell: bash + run: | + az aks install-cli + az extension add --name aks-preview + + - name: Install Helm + shell: bash + run: | + # If helm is already available on the runner, print version and skip installation + if command -v helm >/dev/null 2>&1; then + echo "helm already installed: $(helm version --short 2>/dev/null || true)" + exit 0 + fi + + # Ensure prerequisites are present + sudo apt-get update + sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release + + # Ensure keyrings dir exists + sudo mkdir -p /usr/share/keyrings + + # Add Helm GPG key (use -fS to fail fast on curl errors) + curl -fsSL https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg >/dev/null + + # Add the Helm apt repository + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + + # Install helm + sudo apt-get update + sudo apt-get install -y helm + + # Verify + echo "Installed helm version:" + helm version + + - name: Set up Docker + uses: docker/setup-buildx-action@v3 + with: + driver: docker + + - 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 "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") { + $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" + azd env set AZURE_ENV_ACR_NAME="$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_EXISTING_AI_PROJECT_RESOURCE_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" + } + + # 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 + } + + + $AI_FOUNDRY_RESOURCE_ID = $DEPLOY_OUTPUT.AI_FOUNDRY_RESOURCE_ID + "AI_FOUNDRY_RESOURCE_ID=$AI_FOUNDRY_RESOURCE_ID" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $AI_SEARCH_SERVICE_NAME = $DEPLOY_OUTPUT.AI_SEARCH_SERVICE_NAME + "AI_SEARCH_SERVICE_NAME=$AI_SEARCH_SERVICE_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $AZURE_COSMOSDB_ACCOUNT = $DEPLOY_OUTPUT.AZURE_COSMOSDB_ACCOUNT + "AZURE_COSMOSDB_ACCOUNT=$AZURE_COSMOSDB_ACCOUNT" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $STORAGE_ACCOUNT_NAME = $DEPLOY_OUTPUT.STORAGE_ACCOUNT_NAME + "STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $STORAGE_CONTAINER_NAME = $DEPLOY_OUTPUT.STORAGE_CONTAINER_NAME + "STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $KEY_VAULT_NAME = $DEPLOY_OUTPUT.KEY_VAULT_NAME + "KEY_VAULT_NAME=$KEY_VAULT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $RESOURCE_GROUP_NAME = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME + "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + - name: Run Post-Deployment Script + id: post_deploy + env: + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + shell: bash + run: | + set -e + az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + + echo "Running post-deployment script..." + + bash ./infra/scripts/process_sample_data.sh \ + "${{ env.STORAGE_ACCOUNT_NAME }}" \ + "${{ env.STORAGE_CONTAINER_NAME }}" \ + "${{ env.KEY_VAULT_NAME }}" \ + "${{ env.AZURE_COSMOSDB_ACCOUNT }}" \ + "${{ env.RESOURCE_GROUP_NAME }}" \ + "${{ env.AI_SEARCH_SERVICE_NAME }}" \ + "${{ secrets.AZURE_CLIENT_ID }}" \ + "${{ env.AI_FOUNDRY_RESOURCE_ID }}" + + - name: Generate Deploy Job 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 "| **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 "- **Web App URL**: [${{ steps.get_output_windows.outputs.WEB_APPURL }}](${{ steps.get_output_windows.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY + echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY + echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY + else + echo "### โŒ Deployment Failed" >> $GITHUB_STEP_SUMMARY + echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Check the deploy job 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." diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml new file mode 100644 index 00000000..fc77e6eb --- /dev/null +++ b/.github/workflows/job-deploy.yml @@ -0,0 +1,362 @@ +name: Deploy Job + +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_ANALYTICS_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 + outputs: + RESOURCE_GROUP_NAME: + description: "Resource Group Name" + value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} + WEB_APPURL: + description: "Container Web App URL" + value: ${{ jobs.deploy-linux.outputs.WEB_APPURL || jobs.deploy-windows.outputs.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: 150 + 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 }} + 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_ANALYTICS_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_ANALYTICS_WORKSPACE_ID }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.AZURE_ENV_LOG_ANALYTICS_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 + 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 TEXT_EMBEDDING_MIN_CAPACITY=${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} + export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}" + + chmod +x scripts/checkquota.sh + if ! scripts/checkquota.sh; then + if grep -q "No region with sufficient quota found" 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="docgenv2" # 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 + 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" + + # Determine image tag based on branch + if [[ "$BRANCH_NAME" == "main" ]]; then + IMAGE_TAG="latest_waf" + echo "Using main branch - image tag: latest_waf" + 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" + else + IMAGE_TAG="latest_waf" + echo "Using default for branch '$BRANCH_NAME' - image tag: latest_waf" + 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: ${{ inputs.build_docker_image || 'false' }} + EXP: ${{ inputs.EXP || 'false' }} + WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + secrets: inherit + + 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: ${{ inputs.build_docker_image || 'false' }} + EXP: ${{ inputs.EXP || 'false' }} + WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + secrets: inherit diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml new file mode 100644 index 00000000..62956a43 --- /dev/null +++ b/.github/workflows/job-docker-build.yml @@ -0,0 +1,99 @@ +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 + 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 Docker Image + id: build_push_image + uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_SUMMARY: false + with: + context: ./src + file: ./src/WebApp.Dockerfile + push: true + tags: | + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ 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 one Docker image to ACR:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/webapp:${{ 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 diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml new file mode 100644 index 00000000..87baad34 --- /dev/null +++ b/.github/workflows/job-send-notification.yml @@ -0,0 +1,224 @@ +name: Send Notification Job + +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 + 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 + +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: "DocGen" + 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.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.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" diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml new file mode 100644 index 00000000..085693ba --- /dev/null +++ b/.github/workflows/test-automation-v2.yml @@ -0,0 +1,185 @@ +name: Test Automation DocGen-v2 + +on: + workflow_call: + inputs: + DOCGEN_URL: + required: true + type: string + description: "Web URL for DocGen" + TEST_SUITE: + required: false + type: string + default: "GoldenPath-Testing" + description: "Test suite to run: 'Smoke-Testing', 'GoldenPath-Testing' " + 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: + url: ${{ inputs.DOCGEN_URL }} + accelerator_name: "DocGen" + 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: Login to Azure + 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: 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 + fi + echo "Testing URL: ${{ env.url }}" + echo "Test Suite: ${{ env.test_suite }}" + + + - 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: | + if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest --headed --html=report/report.html --self-contained-html + fi + 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) + id: test2 + if: ${{ steps.test1.outcome == 'failure' }} + run: | + if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest --headed --html=report/report.html --self-contained-html + fi + 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) + id: test3 + if: ${{ steps.test2.outcome == 'failure' }} + run: | + if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest --headed --html=report/report.html --self-contained-html + fi + working-directory: tests/e2e-test + + - name: Upload test report + id: upload_report + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: test-report + 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 c31425c8d35f208f1b146b5aa516cb8fb49790ce Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 15 Dec 2025 17:41:01 +0530 Subject: [PATCH 02/37] removed linux reference --- .github/workflows/job-deploy.yml | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index fc77e6eb..37087128 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -72,7 +72,7 @@ on: value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} WEB_APPURL: description: "Container Web App URL" - value: ${{ jobs.deploy-linux.outputs.WEB_APPURL || jobs.deploy-windows.outputs.WEB_APPURL }} + value: ${{ jobs.deploy-windows.outputs.WEB_APPURL }} ENV_NAME: description: "Environment Name" value: ${{ jobs.azure-setup.outputs.ENV_NAME }} @@ -325,24 +325,6 @@ jobs: 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: ${{ inputs.build_docker_image || 'false' }} - EXP: ${{ inputs.EXP || 'false' }} - WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} - AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} - secrets: inherit - deploy-windows: name: Deploy on Windows needs: azure-setup From ebfd02f3d24dbd05d2a7112bfbcf1487a9a149f9 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 15 Dec 2025 17:45:54 +0530 Subject: [PATCH 03/37] fix v1 --- .github/workflows/job-deploy.yml | 43 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 37087128..34f61a9c 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -143,22 +143,37 @@ jobs: - name: Run Quota Check id: quota-check + shell: pwsh 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 TEXT_EMBEDDING_MIN_CAPACITY=${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} - export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}" + $ErrorActionPreference = "Stop" # Ensure that any error stops the pipeline - chmod +x scripts/checkquota.sh - if ! scripts/checkquota.sh; then - if grep -q "No region with sufficient quota found" scripts/checkquota.sh; then - echo "QUOTA_FAILED=true" >> $GITHUB_ENV - fi - exit 1 - fi + # Path to the PowerShell script for quota check + $quotaCheckScript = "Deployment/checkquota.ps1" + + # Check if the script exists and is executable (not needed for PowerShell like chmod) + if (-not (Test-Path $quotaCheckScript)) { + Write-Host "โŒ Error: Quota check script not found." + exit 1 + } + + # Run the script + .\Deployment\checkquota.ps1 + + # If the script fails, check for the failure message + $quotaFailedMessage = "No region with sufficient quota found" + $output = Get-Content "Deployment/checkquota.ps1" + + if ($output -contains $quotaFailedMessage) { + echo "QUOTA_FAILED=true" >> $GITHUB_ENV + } + env: + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + GPT_MIN_CAPACITY: ${{ env.GPT_CAPACITY }} + TEXT_EMBEDDING_MIN_CAPACITY: ${{ env.TEXT_EMBEDDING_CAPACITY }} + AZURE_REGIONS: "${{ vars.AZURE_REGIONS }}" - name: Set Quota Failure Output id: quota_failure_output From 793bbb430e9dfabbf2d9983e212e3bc7cab72c8c Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 15 Dec 2025 17:54:23 +0530 Subject: [PATCH 04/37] fix v2 --- .github/workflows/job-deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 34f61a9c..af2e534e 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -171,8 +171,8 @@ jobs: AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - GPT_MIN_CAPACITY: ${{ env.GPT_CAPACITY }} - TEXT_EMBEDDING_MIN_CAPACITY: ${{ env.TEXT_EMBEDDING_CAPACITY }} + GPT_MIN_CAPACITY: ${{ env.GPT_MIN_CAPACITY }} + TEXT_EMBEDDING_MIN_CAPACITY: ${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} AZURE_REGIONS: "${{ vars.AZURE_REGIONS }}" - name: Set Quota Failure Output From e947d3ebdd8bc0725b31a5a5f610e3723663faa2 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 11:38:32 +0530 Subject: [PATCH 05/37] post deployment fix --- .github/workflows/job-deploy-windows.yml | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 09af1ad5..dd2ab9c2 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -209,24 +209,24 @@ jobs: - name: Run Post-Deployment Script id: post_deploy - env: - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - shell: bash + shell: pwsh run: | - set -e - az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - echo "Running post-deployment script..." - - bash ./infra/scripts/process_sample_data.sh \ - "${{ env.STORAGE_ACCOUNT_NAME }}" \ - "${{ env.STORAGE_CONTAINER_NAME }}" \ - "${{ env.KEY_VAULT_NAME }}" \ - "${{ env.AZURE_COSMOSDB_ACCOUNT }}" \ - "${{ env.RESOURCE_GROUP_NAME }}" \ - "${{ env.AI_SEARCH_SERVICE_NAME }}" \ - "${{ secrets.AZURE_CLIENT_ID }}" \ - "${{ env.AI_FOUNDRY_RESOURCE_ID }}" + Write-Host "Running post deployment script to upload files..." + cd Deployment + try { + .\uploadfiles.ps1 -EndpointUrl ${{ env.WEB_APPURL }} + Write-Host "ExitCode: $LASTEXITCODE" + if ($LASTEXITCODE -eq $null -or $LASTEXITCODE -eq 0) { + Write-Host "โœ… Post deployment script completed successfully." + } else { + Write-Host "โŒ Post deployment script failed with exit code: $LASTEXITCODE" + exit 1 + } + } + catch { + Write-Host "โŒ Post deployment script failed with error: $($_.Exception.Message)" + exit 1 + } - name: Generate Deploy Job Summary if: always() From 0daefc5bf36ac7c3a719b2fbc212b3eaee867887 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 11:55:45 +0530 Subject: [PATCH 06/37] post dep fix v2 --- .github/workflows/job-deploy-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index dd2ab9c2..fbc7fc23 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -214,7 +214,7 @@ jobs: Write-Host "Running post deployment script to upload files..." cd Deployment try { - .\uploadfiles.ps1 -EndpointUrl ${{ env.WEB_APPURL }} + .\uploadfiles.ps1 -EndpointUrl $env:WEB_APPURL Write-Host "ExitCode: $LASTEXITCODE" if ($LASTEXITCODE -eq $null -or $LASTEXITCODE -eq 0) { Write-Host "โœ… Post deployment script completed successfully." From 56ffec847f5c2b79d9ce22b3a98c5bf3b17c1961 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 14:16:11 +0530 Subject: [PATCH 07/37] post dep fix v3 --- .github/workflows/job-deploy-windows.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index fbc7fc23..23c710f0 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -204,6 +204,14 @@ jobs: "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL + Write-Host "WEB_APP_URL extracted: $WEB_APP_URL" + + if ([string]::IsNullOrWhiteSpace($WEB_APP_URL)) { + Write-Host "โŒ Error: WEB_APP_URL is empty or not found in deployment output." + Write-Host "Available output keys: $($DEPLOY_OUTPUT.PSObject.Properties.Name -join ', ')" + exit 1 + } + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append @@ -212,6 +220,13 @@ jobs: shell: pwsh run: | Write-Host "Running post deployment script to upload files..." + Write-Host "WEB_APPURL value: $env:WEB_APPURL" + + if ([string]::IsNullOrWhiteSpace($env:WEB_APPURL)) { + Write-Host "โŒ Error: WEB_APPURL environment variable is empty." + exit 1 + } + cd Deployment try { .\uploadfiles.ps1 -EndpointUrl $env:WEB_APPURL From d6a39cb152f57a9a9414828def735a89a74a60a7 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 15:16:53 +0530 Subject: [PATCH 08/37] pipeline fix v1 --- .github/workflows/job-deploy-windows.yml | 173 ++++++++++++++++++----- 1 file changed, 138 insertions(+), 35 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 23c710f0..0cdbe5f8 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -167,9 +167,18 @@ jobs: } # Deploy using azd up - azd up --no-prompt - - Write-Host "โœ… Deployment succeeded." + Write-Host "Starting deployment with azd up..." + try { + azd up --no-prompt + if ($LASTEXITCODE -ne 0) { + Write-Host "โŒ Deployment failed with exit code: $LASTEXITCODE" + exit 1 + } + Write-Host "โœ… Deployment succeeded." + } catch { + Write-Host "โŒ Deployment failed with error: $($_.Exception.Message)" + exit 1 + } # Get deployment outputs using azd Write-Host "Extracting deployment outputs..." @@ -177,53 +186,147 @@ jobs: 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." + Write-Host "โŒ Error: Deployment output is empty. Please check the deployment logs." exit 1 } - - $AI_FOUNDRY_RESOURCE_ID = $DEPLOY_OUTPUT.AI_FOUNDRY_RESOURCE_ID - "AI_FOUNDRY_RESOURCE_ID=$AI_FOUNDRY_RESOURCE_ID" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $AI_SEARCH_SERVICE_NAME = $DEPLOY_OUTPUT.AI_SEARCH_SERVICE_NAME - "AI_SEARCH_SERVICE_NAME=$AI_SEARCH_SERVICE_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $AZURE_COSMOSDB_ACCOUNT = $DEPLOY_OUTPUT.AZURE_COSMOSDB_ACCOUNT - "AZURE_COSMOSDB_ACCOUNT=$AZURE_COSMOSDB_ACCOUNT" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $STORAGE_ACCOUNT_NAME = $DEPLOY_OUTPUT.STORAGE_ACCOUNT_NAME - "STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $STORAGE_CONTAINER_NAME = $DEPLOY_OUTPUT.STORAGE_CONTAINER_NAME - "STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $KEY_VAULT_NAME = $DEPLOY_OUTPUT.KEY_VAULT_NAME - "KEY_VAULT_NAME=$KEY_VAULT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $RESOURCE_GROUP_NAME = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME - "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL - Write-Host "WEB_APP_URL extracted: $WEB_APP_URL" + # Save all deployment outputs to GITHUB_ENV + Write-Host "Saving deployment outputs to environment variables..." + "RESOURCE_GROUP_NAME=$($DEPLOY_OUTPUT.RESOURCE_GROUP_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_RESOURCE_GROUP_ID=$($DEPLOY_OUTPUT.AZURE_RESOURCE_GROUP_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "STORAGE_ACCOUNT_NAME=$($DEPLOY_OUTPUT.STORAGE_ACCOUNT_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_SEARCH_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_SEARCH_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_AKS_NAME=$($DEPLOY_OUTPUT.AZURE_AKS_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_AKS_MI_ID=$($DEPLOY_OUTPUT.AZURE_AKS_MI_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_CONTAINER_REGISTRY_NAME=$($DEPLOY_OUTPUT.AZURE_CONTAINER_REGISTRY_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_COGNITIVE_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_COGNITIVE_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_COGNITIVE_SERVICE_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_COGNITIVE_SERVICE_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_OPENAI_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_OPENAI_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_OPENAI_SERVICE_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_OPENAI_SERVICE_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_COSMOSDB_NAME=$($DEPLOY_OUTPUT.AZURE_COSMOSDB_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZ_GPT4O_MODEL_NAME=$($DEPLOY_OUTPUT.AZ_GPT4O_MODEL_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZ_GPT4O_MODEL_ID=$($DEPLOY_OUTPUT.AZ_GPT4O_MODEL_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZ_GPT_EMBEDDING_MODEL_NAME=$($DEPLOY_OUTPUT.AZ_GPT_EMBEDDING_MODEL_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZ_GPT_EMBEDDING_MODEL_ID=$($DEPLOY_OUTPUT.AZ_GPT_EMBEDDING_MODEL_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_APP_CONFIG_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "AZURE_APP_CONFIG_NAME=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # Get AKS managed resource group (node resource group) + Write-Host "Retrieving AKS managed resource group..." + $AKS_NAME = $DEPLOY_OUTPUT.AZURE_AKS_NAME + $RESOURCE_GROUP = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME + $AKS_NODE_RG = az aks show --name $AKS_NAME --resource-group $RESOURCE_GROUP --query "nodeResourceGroup" -o tsv + Write-Host "AKS node resource group: $AKS_NODE_RG" + "krg_name=$AKS_NODE_RG" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # Get Web App URL from AKS public IP + Write-Host "Retrieving Web App URL from AKS..." + $PUBLIC_IP_NAME = az network public-ip list --resource-group $AKS_NODE_RG --query "[?contains(name, 'kubernetes-')].name" -o tsv | Select-Object -First 1 + + if ([string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { + Write-Host "โŒ Error: Could not find public IP in resource group $AKS_NODE_RG" + exit 1 + } - if ([string]::IsNullOrWhiteSpace($WEB_APP_URL)) { - Write-Host "โŒ Error: WEB_APP_URL is empty or not found in deployment output." - Write-Host "Available output keys: $($DEPLOY_OUTPUT.PSObject.Properties.Name -join ', ')" + Write-Host "Found public IP: $PUBLIC_IP_NAME" + $FQDN = az network public-ip show --resource-group $AKS_NODE_RG --name $PUBLIC_IP_NAME --query "dnsSettings.fqdn" -o tsv + + if ([string]::IsNullOrWhiteSpace($FQDN)) { + Write-Host "โŒ Error: Could not retrieve FQDN for public IP $PUBLIC_IP_NAME" exit 1 } + $WEB_APP_URL = "https://$FQDN" + Write-Host "Web App URL: $WEB_APP_URL" + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - name: Run Post-Deployment Script - id: post_deploy + - name: Run Deployment Script with Input + shell: pwsh + run: | + cd Deployment + $input = @" + ${{ secrets.EMAIL }} + yes + "@ + $input | pwsh ./resourcedeployment.ps1 + Write-Host "Resource Group Name is ${{ env.RESOURCE_GROUP_NAME }}" + Write-Host "Kubernetes resource group is ${{ env.AZURE_AKS_NAME }}" + env: + # From GitHub secrets (for login) + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + + # From deployment outputs step (these come from $GITHUB_ENV) + RESOURCE_GROUP_NAME: ${{ env.RESOURCE_GROUP_NAME }} + AZURE_RESOURCE_GROUP_ID: ${{ env.AZURE_RESOURCE_GROUP_ID }} + STORAGE_ACCOUNT_NAME: ${{ env.STORAGE_ACCOUNT_NAME }} + AZURE_SEARCH_SERVICE_NAME: ${{ env.AZURE_SEARCH_SERVICE_NAME }} + AZURE_AKS_NAME: ${{ env.AZURE_AKS_NAME }} + AZURE_AKS_MI_ID: ${{ env.AZURE_AKS_MI_ID }} + AZURE_CONTAINER_REGISTRY_NAME: ${{ env.AZURE_CONTAINER_REGISTRY_NAME }} + AZURE_COGNITIVE_SERVICE_NAME: ${{ env.AZURE_COGNITIVE_SERVICE_NAME }} + AZURE_COGNITIVE_SERVICE_ENDPOINT: ${{ env.AZURE_COGNITIVE_SERVICE_ENDPOINT }} + AZURE_OPENAI_SERVICE_NAME: ${{ env.AZURE_OPENAI_SERVICE_NAME }} + AZURE_OPENAI_SERVICE_ENDPOINT: ${{ env.AZURE_OPENAI_SERVICE_ENDPOINT }} + AZURE_COSMOSDB_NAME: ${{ env.AZURE_COSMOSDB_NAME }} + AZ_GPT4O_MODEL_NAME: ${{ env.AZ_GPT4O_MODEL_NAME }} + AZ_GPT4O_MODEL_ID: ${{ env.AZ_GPT4O_MODEL_ID }} + AZ_GPT_EMBEDDING_MODEL_NAME: ${{ env.AZ_GPT_EMBEDDING_MODEL_NAME }} + AZ_GPT_EMBEDDING_MODEL_ID: ${{ env.AZ_GPT_EMBEDDING_MODEL_ID }} + AZURE_APP_CONFIG_ENDPOINT: ${{ env.AZURE_APP_CONFIG_ENDPOINT }} + AZURE_APP_CONFIG_NAME: ${{ env.AZURE_APP_CONFIG_NAME }} + + - name: Validate Deployment + shell: bash + run: | + webapp_url="${{ env.WEB_APPURL }}" + echo "Validating web app at: $webapp_url" + + # Enhanced health check with retry logic + max_attempts=7 + attempt=1 + success=false + + while [ $attempt -le $max_attempts ] && [ "$success" = false ]; do + echo "Attempt $attempt/$max_attempts: Checking web app health..." + + # Check if web app responds + http_code=$(curl -s -o /dev/null -w "%{http_code}" "$webapp_url" || echo "000") + + if [ "$http_code" -eq 200 ]; then + echo "โœ… Web app is healthy (HTTP $http_code)" + success=true + elif [ "$http_code" -eq 404 ]; then + echo "โŒ Web app not found (HTTP 404)" + break + elif [ "$http_code" -eq 503 ] || [ "$http_code" -eq 502 ]; then + echo "โš ๏ธ Web app temporarily unavailable (HTTP $http_code), retrying..." + sleep 20 + else + echo "โš ๏ธ Web app returned HTTP $http_code, retrying..." + sleep 20 + fi + + attempt=$((attempt + 1)) + done + + if [ "$success" = false ]; then + echo "โŒ Web app validation failed after $max_attempts attempts" + exit 1 + fi + + - name: Run Post Deployment Script shell: pwsh run: | Write-Host "Running post deployment script to upload files..." - Write-Host "WEB_APPURL value: $env:WEB_APPURL" + Write-Host "WEB_APPURL: $env:WEB_APPURL" if ([string]::IsNullOrWhiteSpace($env:WEB_APPURL)) { - Write-Host "โŒ Error: WEB_APPURL environment variable is empty." + Write-Host "โŒ Error: WEB_APPURL is empty" exit 1 } From 39fd71ae10b7965599acfe40039554d578790968 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 15:56:36 +0530 Subject: [PATCH 09/37] pipeline fix v2 --- .github/workflows/job-deploy-windows.yml | 101 +++++++++++++++++------ 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 0cdbe5f8..67a97a7c 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -211,7 +211,7 @@ jobs: "AZURE_APP_CONFIG_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append "AZURE_APP_CONFIG_NAME=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - # Get AKS managed resource group (node resource group) + # Get AKS managed resource group (node resource group) and save for later use Write-Host "Retrieving AKS managed resource group..." $AKS_NAME = $DEPLOY_OUTPUT.AZURE_AKS_NAME $RESOURCE_GROUP = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME @@ -219,29 +219,6 @@ jobs: Write-Host "AKS node resource group: $AKS_NODE_RG" "krg_name=$AKS_NODE_RG" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - # Get Web App URL from AKS public IP - Write-Host "Retrieving Web App URL from AKS..." - $PUBLIC_IP_NAME = az network public-ip list --resource-group $AKS_NODE_RG --query "[?contains(name, 'kubernetes-')].name" -o tsv | Select-Object -First 1 - - if ([string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { - Write-Host "โŒ Error: Could not find public IP in resource group $AKS_NODE_RG" - exit 1 - } - - Write-Host "Found public IP: $PUBLIC_IP_NAME" - $FQDN = az network public-ip show --resource-group $AKS_NODE_RG --name $PUBLIC_IP_NAME --query "dnsSettings.fqdn" -o tsv - - if ([string]::IsNullOrWhiteSpace($FQDN)) { - Write-Host "โŒ Error: Could not retrieve FQDN for public IP $PUBLIC_IP_NAME" - exit 1 - } - - $WEB_APP_URL = "https://$FQDN" - Write-Host "Web App URL: $WEB_APP_URL" - - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - name: Run Deployment Script with Input shell: pwsh run: | @@ -280,6 +257,82 @@ jobs: AZURE_APP_CONFIG_ENDPOINT: ${{ env.AZURE_APP_CONFIG_ENDPOINT }} AZURE_APP_CONFIG_NAME: ${{ env.AZURE_APP_CONFIG_NAME }} + - name: Retrieve Web App URL + id: get_webapp_url + shell: pwsh + run: | + Write-Host "Retrieving Web App URL from AKS..." + Write-Host "Kubernetes resource group: $env:krg_name" + + # Get Web App URL from AKS public IP with retry logic + $maxAttempts = 12 + $attempt = 1 + $PUBLIC_IP_NAME = $null + + while ($attempt -le $maxAttempts) { + Write-Host "Attempt $attempt/$maxAttempts : Checking for public IP..." + + # List all public IPs in the resource group for debugging + $allIPs = az network public-ip list --resource-group $env:krg_name --query "[].name" -o tsv + if ($allIPs) { + Write-Host "Available public IPs: $($allIPs -join ', ')" + } else { + Write-Host "No public IPs found yet in resource group $env:krg_name" + } + + # Try to find kubernetes public IP + $PUBLIC_IP_NAME = az network public-ip list --resource-group $env:krg_name --query "[?contains(name, 'kubernetes-')].name" -o tsv | Select-Object -First 1 + + if (-not [string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { + Write-Host "โœ… Found public IP: $PUBLIC_IP_NAME" + break + } + + if ($attempt -lt $maxAttempts) { + Write-Host "Public IP not found yet, waiting 30 seconds..." + Start-Sleep -Seconds 30 + } + $attempt++ + } + + if ([string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { + Write-Host "โŒ Error: Could not find public IP after $maxAttempts attempts in resource group $env:krg_name" + exit 1 + } + + # Get FQDN with retry + Write-Host "Retrieving FQDN for public IP: $PUBLIC_IP_NAME" + $FQDN = $null + $fqdnAttempts = 5 + $fqdnAttempt = 1 + + while ($fqdnAttempt -le $fqdnAttempts) { + Write-Host "Attempt $fqdnAttempt/$fqdnAttempts : Getting FQDN..." + $FQDN = az network public-ip show --resource-group $env:krg_name --name $PUBLIC_IP_NAME --query "dnsSettings.fqdn" -o tsv + + if (-not [string]::IsNullOrWhiteSpace($FQDN)) { + Write-Host "โœ… Found FQDN: $FQDN" + break + } + + if ($fqdnAttempt -lt $fqdnAttempts) { + Write-Host "FQDN not available yet, waiting 15 seconds..." + Start-Sleep -Seconds 15 + } + $fqdnAttempt++ + } + + if ([string]::IsNullOrWhiteSpace($FQDN)) { + Write-Host "โŒ Error: Could not retrieve FQDN for public IP $PUBLIC_IP_NAME after $fqdnAttempts attempts" + exit 1 + } + + $WEB_APP_URL = "https://$FQDN" + Write-Host "โœ… Web App URL: $WEB_APP_URL" + + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + - name: Validate Deployment shell: bash run: | From 14c9d00f1eeba53fecf4b5b858bb210a8f7d3603 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 16:14:34 +0530 Subject: [PATCH 10/37] fix v3 --- .github/workflows/job-deploy-windows.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 67a97a7c..ba84e8c6 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -133,6 +133,10 @@ jobs: azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}" + # Set infrastructure parameters that azd expects + azd env set aiDeploymentsLocation="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}" + azd env set location="${{ inputs.AZURE_LOCATION }}" + # Set ACR name only when building Docker image if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") { $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" From bd1917983c6adb0f2db26f9b1882d214ba5842f1 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 16:43:12 +0530 Subject: [PATCH 11/37] fix v4 --- .github/workflows/job-deploy-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index ba84e8c6..57bf49aa 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -133,8 +133,8 @@ jobs: azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}" - # Set infrastructure parameters that azd expects - azd env set aiDeploymentsLocation="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}" + # Set infrastructure parameters that azd expects (both use AZURE_LOCATION like CI.yml) + azd env set aiDeploymentsLocation="${{ inputs.AZURE_LOCATION }}" azd env set location="${{ inputs.AZURE_LOCATION }}" # Set ACR name only when building Docker image From 9cfa334ea31dcfbd36cd42369f957e951c4d670b Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 17:23:30 +0530 Subject: [PATCH 12/37] updated ai location --- .github/workflows/job-deploy-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 57bf49aa..3a334525 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -128,7 +128,7 @@ jobs: # 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_ENV_OPENAI_LOCATION="${{ inputs.AZURE_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 }}" @@ -415,7 +415,7 @@ jobs: 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 "| **Azure OpenAI Region** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "${{ job.status }}" == "success" ]]; then From 2f2fdfd5bb34766f3944785672ff5cead4d8bfed Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Tue, 16 Dec 2025 17:46:11 +0530 Subject: [PATCH 13/37] fix v5 --- .github/workflows/job-deploy-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 3a334525..6600b2a9 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -170,10 +170,10 @@ jobs: Write-Host "โŒ EXP DISABLED - Skipping EXP parameters" } - # Deploy using azd up + # Deploy using azd up with inline parameter for aiDeploymentsLocation Write-Host "Starting deployment with azd up..." try { - azd up --no-prompt + azd up --no-prompt --parameter aiDeploymentsLocation="${{ inputs.AZURE_LOCATION }}" if ($LASTEXITCODE -ne 0) { Write-Host "โŒ Deployment failed with exit code: $LASTEXITCODE" exit 1 From bfd953c936c49156ca50475f3c291a139b8c7089 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 17 Dec 2025 09:55:13 +0530 Subject: [PATCH 14/37] added open ai location param --- .github/workflows/job-deploy-windows.yml | 10 +++------- infra/main.parameters.json | 3 +++ infra/main.waf.parameters.json | 3 +++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 6600b2a9..aadceeb0 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -128,15 +128,11 @@ jobs: # Set additional parameters azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" - azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_LOCATION }}" + 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 infrastructure parameters that azd expects (both use AZURE_LOCATION like CI.yml) - azd env set aiDeploymentsLocation="${{ inputs.AZURE_LOCATION }}" - azd env set location="${{ inputs.AZURE_LOCATION }}" - # Set ACR name only when building Docker image if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") { $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" @@ -170,10 +166,10 @@ jobs: Write-Host "โŒ EXP DISABLED - Skipping EXP parameters" } - # Deploy using azd up with inline parameter for aiDeploymentsLocation + # Deploy using azd up Write-Host "Starting deployment with azd up..." try { - azd up --no-prompt --parameter aiDeploymentsLocation="${{ inputs.AZURE_LOCATION }}" + azd up --no-prompt if ($LASTEXITCODE -ne 0) { Write-Host "โŒ Deployment failed with exit code: $LASTEXITCODE" exit 1 diff --git a/infra/main.parameters.json b/infra/main.parameters.json index a649cdda..0e313833 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -8,6 +8,9 @@ "location": { "value": "${AZURE_LOCATION}" }, + "aiDeploymentsLocation": { + "value": "${AZURE_ENV_OPENAI_LOCATION}" + }, "gptModelDeploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" }, diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 6700f98f..337be5fd 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -8,6 +8,9 @@ "location": { "value": "${AZURE_LOCATION}" }, + "aiDeploymentsLocation": { + "value": "${AZURE_ENV_OPENAI_LOCATION}" + }, "gptModelDeploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" }, From aa6108dad9173f2b19253b3d7cbe0b47fa0f0925 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 17 Dec 2025 12:07:36 +0530 Subject: [PATCH 15/37] added docker logs --- .github/workflows/job-deploy-windows.yml | 109 +++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index aadceeb0..5e4d290e 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -91,6 +91,29 @@ jobs: with: driver: docker + - name: Verify Docker Installation + shell: pwsh + run: | + Write-Host "Verifying Docker installation..." + docker --version + docker info + Write-Host "โœ… Docker is ready" + + - name: Login to Azure Container Registry + shell: pwsh + run: | + Write-Host "Pre-authenticating to ACR..." + # Note: Full ACR login will happen in resourcedeployment.ps1 + # This is just to verify ACR credentials are working + if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") { + $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" + Write-Host "ACR Name: $ACR_NAME" + az acr login --name $ACR_NAME + Write-Host "โœ… ACR authentication successful" + } else { + Write-Host "Skipping ACR pre-authentication (using existing images)" + } + - name: Configure Parameters Based on WAF Setting shell: bash run: | @@ -222,14 +245,33 @@ jobs: - name: Run Deployment Script with Input shell: pwsh run: | + $ErrorActionPreference = "Stop" + + # Verify Docker is still running + Write-Host "Verifying Docker before deployment..." + docker ps + cd Deployment $input = @" ${{ secrets.EMAIL }} yes "@ + + Write-Host "Starting resourcedeployment.ps1..." $input | pwsh ./resourcedeployment.ps1 + + if ($LASTEXITCODE -ne 0) { + Write-Host "โŒ resourcedeployment.ps1 failed with exit code: $LASTEXITCODE" + exit 1 + } + + Write-Host "โœ… resourcedeployment.ps1 completed successfully" Write-Host "Resource Group Name is ${{ env.RESOURCE_GROUP_NAME }}" Write-Host "Kubernetes resource group is ${{ env.AZURE_AKS_NAME }}" + + # Verify pods are created + Write-Host "Checking pod status..." + kubectl get pods -n ns-km env: # From GitHub secrets (for login) AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} @@ -333,6 +375,73 @@ jobs: "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + - name: Verify ACR Images + shell: bash + run: | + echo "๐Ÿ” Checking if Docker images exist in ACR..." + ACR_NAME="${{ env.AZURE_CONTAINER_REGISTRY_NAME }}" + + echo "Listing all repositories in ACR: $ACR_NAME" + az acr repository list --name "$ACR_NAME" --output table || echo "No repositories found" + + echo "" + echo "Checking for required images (kmgs namespace)..." + for repo in aiservice kernelmemory frontapp; do + echo "Checking kmgs/$repo..." + tags=$(az acr repository show-tags --name "$ACR_NAME" --repository "kmgs/$repo" --output table 2>/dev/null || echo "NOT FOUND") + if [ "$tags" = "NOT FOUND" ]; then + echo "โŒ Image kmgs/$repo not found in ACR!" + else + echo "โœ… Found tags: $tags" + fi + done + + - name: Check Pod Status and Logs + shell: bash + run: | + echo "๐Ÿ” Checking Kubernetes pod status..." + kubectl get pods -n ns-km -o wide + + echo "" + echo "๐Ÿ“Š Checking pod events..." + kubectl get events -n ns-km --sort-by='.lastTimestamp' | tail -20 + + # Check if any pods are in ImagePullBackOff or Error state + failed_pods=$(kubectl get pods -n ns-km -o json | jq -r '.items[] | select(.status.phase != "Running") | .metadata.name') + + if [ -n "$failed_pods" ]; then + echo "โš ๏ธ Found pods not in Running state:" + echo "$failed_pods" + + # Describe each failed pod for detailed error information + for pod in $failed_pods; do + echo "" + echo "๐Ÿ“‹ Describing pod: $pod" + kubectl describe pod "$pod" -n ns-km | tail -30 + + echo "" + echo "๐Ÿ“„ Checking pod logs (if available):" + kubectl logs "$pod" -n ns-km --tail=50 || echo "No logs available yet" + done + + # Check if ImagePullBackOff is the issue + image_pull_errors=$(kubectl get pods -n ns-km -o json | jq -r '.items[] | select(.status.containerStatuses[].state.waiting.reason == "ImagePullBackOff") | .metadata.name') + + if [ -n "$image_pull_errors" ]; then + echo "" + echo "โŒ ERROR: Pods are failing to pull Docker images!" + echo "This usually means:" + echo "1. Docker images weren't built/pushed to ACR" + echo "2. AKS doesn't have permission to pull from ACR" + echo "3. Image tags are incorrect" + echo "" + echo "Failing pods: $image_pull_errors" + exit 1 + fi + else + echo "โœ… All pods are running successfully" + fi + - name: Validate Deployment shell: bash run: | From 910ebc3722078a5d600472210bf735f1d1ccc7d6 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 17 Dec 2025 12:46:27 +0530 Subject: [PATCH 16/37] docker issue fix v1 --- .github/workflows/job-deploy-windows.yml | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 5e4d290e..bfcec53d 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -41,7 +41,7 @@ on: jobs: deploy-windows: - runs-on: windows-latest + runs-on: ubuntu-latest env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} outputs: @@ -92,27 +92,12 @@ jobs: driver: docker - name: Verify Docker Installation - shell: pwsh + shell: bash run: | - Write-Host "Verifying Docker installation..." + echo "Verifying Docker installation..." docker --version docker info - Write-Host "โœ… Docker is ready" - - - name: Login to Azure Container Registry - shell: pwsh - run: | - Write-Host "Pre-authenticating to ACR..." - # Note: Full ACR login will happen in resourcedeployment.ps1 - # This is just to verify ACR credentials are working - if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") { - $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" - Write-Host "ACR Name: $ACR_NAME" - az acr login --name $ACR_NAME - Write-Host "โœ… ACR authentication successful" - } else { - Write-Host "Skipping ACR pre-authentication (using existing images)" - } + echo "โœ… Docker is ready" - name: Configure Parameters Based on WAF Setting shell: bash From cb4cfd1710e56071014f7f9873a6994322a3a8d1 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 17 Dec 2025 14:40:41 +0530 Subject: [PATCH 17/37] post dep fix v1 --- .github/workflows/job-deploy-windows.yml | 11 +++++++---- .github/workflows/job-deploy.yml | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index bfcec53d..ac915b99 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -467,6 +467,7 @@ jobs: fi - name: Run Post Deployment Script + continue-on-error: true shell: pwsh run: | Write-Host "Running post deployment script to upload files..." @@ -484,13 +485,15 @@ jobs: if ($LASTEXITCODE -eq $null -or $LASTEXITCODE -eq 0) { Write-Host "โœ… Post deployment script completed successfully." } else { - Write-Host "โŒ Post deployment script failed with exit code: $LASTEXITCODE" - exit 1 + Write-Host "โš ๏ธ Post deployment script failed with exit code: $LASTEXITCODE" + Write-Host "โš ๏ธ This is non-critical - deployment will continue" + exit 0 } } catch { - Write-Host "โŒ Post deployment script failed with error: $($_.Exception.Message)" - exit 1 + Write-Host "โš ๏ธ Post deployment script failed with error: $($_.Exception.Message)" + Write-Host "โš ๏ธ This is non-critical - deployment will continue" + exit 0 } - name: Generate Deploy Job Summary diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index af2e534e..bc422bc1 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -217,7 +217,7 @@ jobs: echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV else echo "Generating a unique resource group name..." - ACCL_NAME="docgenv2" # Account name as specified + ACCL_NAME="dkmv2" # 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 From 34eeea2e874bc6e9c93f0b44495ef5ef629edaf3 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 17 Dec 2025 16:50:28 +0530 Subject: [PATCH 18/37] fix v3 --- .github/workflows/job-deploy-windows.yml | 347 ++++------------------- 1 file changed, 61 insertions(+), 286 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index ac915b99..e40a6222 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -45,11 +45,17 @@ jobs: env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} outputs: - WEB_APPURL: ${{ steps.get_output_windows.outputs.WEB_APPURL }} + WEB_APPURL: ${{ steps.get_webapp_url.outputs.WEB_APPURL }} steps: - name: Checkout Code uses: actions/checkout@v4 + - name: Install Azure CLI + shell: bash + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version # Verify installation + - name: Install Kubernetes CLI (kubectl) shell: bash run: | @@ -91,172 +97,69 @@ jobs: with: driver: docker - - name: Verify Docker Installation - shell: bash - run: | - echo "Verifying Docker installation..." - docker --version - docker info - echo "โœ… Docker is ready" - - - 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) + - name: Setup Azure Developer CLI uses: Azure/setup-azd@v2 - - name: Login to AZD - id: login-azure - shell: bash + - name: Login to Azure 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 + - name: Deploy using azd up + id: azd_deploy run: | - $ErrorActionPreference = "Stop" - - Write-Host "Creating environment..." + # Create azd environment azd env new ${{ inputs.ENV_NAME }} --no-prompt - Write-Host "Environment created: ${{ inputs.ENV_NAME }}" - - Write-Host "Setting default subscription..." + + # Set environment variables 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") { - $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" - azd env set AZURE_ENV_ACR_NAME="$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_EXISTING_AI_PROJECT_RESOURCE_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" - } - - # Deploy using azd up - Write-Host "Starting deployment with azd up..." - try { - azd up --no-prompt - if ($LASTEXITCODE -ne 0) { - Write-Host "โŒ Deployment failed with exit code: $LASTEXITCODE" - exit 1 - } - Write-Host "โœ… Deployment succeeded." - } catch { - Write-Host "โŒ Deployment failed with error: $($_.Exception.Message)" - exit 1 - } - - # 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)" + # Deploy + azd up --no-prompt - if (-not $DEPLOY_OUTPUT) { - Write-Host "โŒ Error: Deployment output is empty. Please check the deployment logs." - exit 1 - } - - # Save all deployment outputs to GITHUB_ENV - Write-Host "Saving deployment outputs to environment variables..." - "RESOURCE_GROUP_NAME=$($DEPLOY_OUTPUT.RESOURCE_GROUP_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_RESOURCE_GROUP_ID=$($DEPLOY_OUTPUT.AZURE_RESOURCE_GROUP_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "STORAGE_ACCOUNT_NAME=$($DEPLOY_OUTPUT.STORAGE_ACCOUNT_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_SEARCH_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_SEARCH_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_AKS_NAME=$($DEPLOY_OUTPUT.AZURE_AKS_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_AKS_MI_ID=$($DEPLOY_OUTPUT.AZURE_AKS_MI_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_CONTAINER_REGISTRY_NAME=$($DEPLOY_OUTPUT.AZURE_CONTAINER_REGISTRY_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_COGNITIVE_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_COGNITIVE_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_COGNITIVE_SERVICE_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_COGNITIVE_SERVICE_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_OPENAI_SERVICE_NAME=$($DEPLOY_OUTPUT.AZURE_OPENAI_SERVICE_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_OPENAI_SERVICE_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_OPENAI_SERVICE_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_COSMOSDB_NAME=$($DEPLOY_OUTPUT.AZURE_COSMOSDB_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZ_GPT4O_MODEL_NAME=$($DEPLOY_OUTPUT.AZ_GPT4O_MODEL_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZ_GPT4O_MODEL_ID=$($DEPLOY_OUTPUT.AZ_GPT4O_MODEL_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZ_GPT_EMBEDDING_MODEL_NAME=$($DEPLOY_OUTPUT.AZ_GPT_EMBEDDING_MODEL_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZ_GPT_EMBEDDING_MODEL_ID=$($DEPLOY_OUTPUT.AZ_GPT_EMBEDDING_MODEL_ID)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_APP_CONFIG_ENDPOINT=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_ENDPOINT)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "AZURE_APP_CONFIG_NAME=$($DEPLOY_OUTPUT.AZURE_APP_CONFIG_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "โœ… azd deployment completed" - # Get AKS managed resource group (node resource group) and save for later use - Write-Host "Retrieving AKS managed resource group..." - $AKS_NAME = $DEPLOY_OUTPUT.AZURE_AKS_NAME - $RESOURCE_GROUP = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME - $AKS_NODE_RG = az aks show --name $AKS_NAME --resource-group $RESOURCE_GROUP --query "nodeResourceGroup" -o tsv - Write-Host "AKS node resource group: $AKS_NODE_RG" - "krg_name=$AKS_NODE_RG" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Get Deployment Outputs + id: get_output + run: | + # Get outputs from azd + azd env get-values --output json > /tmp/azd_output.json + cat /tmp/azd_output.json + + # Extract values and write to GITHUB_ENV using bash + while IFS='=' read -r key value; do + # Remove quotes from value + value=$(echo "$value" | tr -d '"') + echo "${key}=${value}" >> $GITHUB_ENV + done < <(jq -r 'to_entries[] | "\(.key)=\(.value)"' /tmp/azd_output.json) + + # Get AKS node resource group if AKS exists + if [ -n "$AZURE_AKS_NAME" ]; then + krg_name=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "$RESOURCE_GROUP_NAME" --query "nodeResourceGroup" -o tsv || echo "") + if [ -n "$krg_name" ]; then + echo "krg_name=$krg_name" >> $GITHUB_ENV + echo "AKS node resource group: $krg_name" + fi + fi - name: Run Deployment Script with Input shell: pwsh run: | - $ErrorActionPreference = "Stop" - - # Verify Docker is still running - Write-Host "Verifying Docker before deployment..." - docker ps - cd Deployment $input = @" ${{ secrets.EMAIL }} yes "@ - - Write-Host "Starting resourcedeployment.ps1..." $input | pwsh ./resourcedeployment.ps1 - - if ($LASTEXITCODE -ne 0) { - Write-Host "โŒ resourcedeployment.ps1 failed with exit code: $LASTEXITCODE" - exit 1 - } - - Write-Host "โœ… resourcedeployment.ps1 completed successfully" Write-Host "Resource Group Name is ${{ env.RESOURCE_GROUP_NAME }}" Write-Host "Kubernetes resource group is ${{ env.AZURE_AKS_NAME }}" - - # Verify pods are created - Write-Host "Checking pod status..." - kubectl get pods -n ns-km env: # From GitHub secrets (for login) AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} @@ -286,151 +189,32 @@ jobs: - name: Retrieve Web App URL id: get_webapp_url - shell: pwsh - run: | - Write-Host "Retrieving Web App URL from AKS..." - Write-Host "Kubernetes resource group: $env:krg_name" - - # Get Web App URL from AKS public IP with retry logic - $maxAttempts = 12 - $attempt = 1 - $PUBLIC_IP_NAME = $null - - while ($attempt -le $maxAttempts) { - Write-Host "Attempt $attempt/$maxAttempts : Checking for public IP..." - - # List all public IPs in the resource group for debugging - $allIPs = az network public-ip list --resource-group $env:krg_name --query "[].name" -o tsv - if ($allIPs) { - Write-Host "Available public IPs: $($allIPs -join ', ')" - } else { - Write-Host "No public IPs found yet in resource group $env:krg_name" - } - - # Try to find kubernetes public IP - $PUBLIC_IP_NAME = az network public-ip list --resource-group $env:krg_name --query "[?contains(name, 'kubernetes-')].name" -o tsv | Select-Object -First 1 - - if (-not [string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { - Write-Host "โœ… Found public IP: $PUBLIC_IP_NAME" - break - } - - if ($attempt -lt $maxAttempts) { - Write-Host "Public IP not found yet, waiting 30 seconds..." - Start-Sleep -Seconds 30 - } - $attempt++ - } - - if ([string]::IsNullOrWhiteSpace($PUBLIC_IP_NAME)) { - Write-Host "โŒ Error: Could not find public IP after $maxAttempts attempts in resource group $env:krg_name" - exit 1 - } - - # Get FQDN with retry - Write-Host "Retrieving FQDN for public IP: $PUBLIC_IP_NAME" - $FQDN = $null - $fqdnAttempts = 5 - $fqdnAttempt = 1 - - while ($fqdnAttempt -le $fqdnAttempts) { - Write-Host "Attempt $fqdnAttempt/$fqdnAttempts : Getting FQDN..." - $FQDN = az network public-ip show --resource-group $env:krg_name --name $PUBLIC_IP_NAME --query "dnsSettings.fqdn" -o tsv - - if (-not [string]::IsNullOrWhiteSpace($FQDN)) { - Write-Host "โœ… Found FQDN: $FQDN" - break - } - - if ($fqdnAttempt -lt $fqdnAttempts) { - Write-Host "FQDN not available yet, waiting 15 seconds..." - Start-Sleep -Seconds 15 - } - $fqdnAttempt++ - } - - if ([string]::IsNullOrWhiteSpace($FQDN)) { - Write-Host "โŒ Error: Could not retrieve FQDN for public IP $PUBLIC_IP_NAME after $fqdnAttempts attempts" - exit 1 - } - - $WEB_APP_URL = "https://$FQDN" - Write-Host "โœ… Web App URL: $WEB_APP_URL" - - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - - name: Verify ACR Images shell: bash run: | - echo "๐Ÿ” Checking if Docker images exist in ACR..." - ACR_NAME="${{ env.AZURE_CONTAINER_REGISTRY_NAME }}" - - echo "Listing all repositories in ACR: $ACR_NAME" - az acr repository list --name "$ACR_NAME" --output table || echo "No repositories found" - - echo "" - echo "Checking for required images (kmgs namespace)..." - for repo in aiservice kernelmemory frontapp; do - echo "Checking kmgs/$repo..." - tags=$(az acr repository show-tags --name "$ACR_NAME" --repository "kmgs/$repo" --output table 2>/dev/null || echo "NOT FOUND") - if [ "$tags" = "NOT FOUND" ]; then - echo "โŒ Image kmgs/$repo not found in ACR!" - else - echo "โœ… Found tags: $tags" - fi - done + if az account show &> /dev/null; then + echo "Azure CLI is authenticated." + else + echo "Azure CLI is not authenticated. Logging in..." + az login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + fi + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - name: Check Pod Status and Logs - shell: bash - run: | - echo "๐Ÿ” Checking Kubernetes pod status..." - kubectl get pods -n ns-km -o wide - - echo "" - echo "๐Ÿ“Š Checking pod events..." - kubectl get events -n ns-km --sort-by='.lastTimestamp' | tail -20 - - # Check if any pods are in ImagePullBackOff or Error state - failed_pods=$(kubectl get pods -n ns-km -o json | jq -r '.items[] | select(.status.phase != "Running") | .metadata.name') - - if [ -n "$failed_pods" ]; then - echo "โš ๏ธ Found pods not in Running state:" - echo "$failed_pods" - - # Describe each failed pod for detailed error information - for pod in $failed_pods; do - echo "" - echo "๐Ÿ“‹ Describing pod: $pod" - kubectl describe pod "$pod" -n ns-km | tail -30 - - echo "" - echo "๐Ÿ“„ Checking pod logs (if available):" - kubectl logs "$pod" -n ns-km --tail=50 || echo "No logs available yet" - done - - # Check if ImagePullBackOff is the issue - image_pull_errors=$(kubectl get pods -n ns-km -o json | jq -r '.items[] | select(.status.containerStatuses[].state.waiting.reason == "ImagePullBackOff") | .metadata.name') - - if [ -n "$image_pull_errors" ]; then - echo "" - echo "โŒ ERROR: Pods are failing to pull Docker images!" - echo "This usually means:" - echo "1. Docker images weren't built/pushed to ACR" - echo "2. AKS doesn't have permission to pull from ACR" - echo "3. Image tags are incorrect" - echo "" - echo "Failing pods: $image_pull_errors" - exit 1 - fi + # Get the Web App URL and save it to GITHUB_OUTPUT + echo "Retrieving Web App URL..." + public_ip_name=$(az network public-ip list --resource-group ${{ env.krg_name }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) + fqdn=$(az network public-ip show --resource-group ${{ env.krg_name }} --name $public_ip_name --query "dnsSettings.fqdn" -o tsv) + if [ -n "$fqdn" ]; then + echo "WEB_APPURL=https://$fqdn" >> $GITHUB_OUTPUT + echo "Web App URL is https://$fqdn" else - echo "โœ… All pods are running successfully" + echo "Failed to retrieve Web App URL." + exit 1 fi - name: Validate Deployment shell: bash run: | - webapp_url="${{ env.WEB_APPURL }}" + webapp_url="${{ steps.get_webapp_url.outputs.WEB_APPURL }}" echo "Validating web app at: $webapp_url" # Enhanced health check with retry logic @@ -471,29 +255,20 @@ jobs: shell: pwsh run: | Write-Host "Running post deployment script to upload files..." - Write-Host "WEB_APPURL: $env:WEB_APPURL" - - if ([string]::IsNullOrWhiteSpace($env:WEB_APPURL)) { - Write-Host "โŒ Error: WEB_APPURL is empty" - exit 1 - } - cd Deployment try { - .\uploadfiles.ps1 -EndpointUrl $env:WEB_APPURL + .\uploadfiles.ps1 -EndpointUrl ${{ steps.get_webapp_url.outputs.WEB_APPURL }} Write-Host "ExitCode: $LASTEXITCODE" if ($LASTEXITCODE -eq $null -or $LASTEXITCODE -eq 0) { Write-Host "โœ… Post deployment script completed successfully." } else { - Write-Host "โš ๏ธ Post deployment script failed with exit code: $LASTEXITCODE" - Write-Host "โš ๏ธ This is non-critical - deployment will continue" - exit 0 + Write-Host "โŒ Post deployment script failed with exit code: $LASTEXITCODE" + exit 1 } } catch { - Write-Host "โš ๏ธ Post deployment script failed with error: $($_.Exception.Message)" - Write-Host "โš ๏ธ This is non-critical - deployment will continue" - exit 0 + Write-Host "โŒ Post deployment script failed with error: $($_.Exception.Message)" + exit 1 } - name: Generate Deploy Job Summary From 7750aa45224341b11a34b181b29bc56aa68b292c Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 11:15:08 +0530 Subject: [PATCH 19/37] updated tokens --- .github/workflows/job-deploy-windows.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index e40a6222..e2e3835b 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -121,6 +121,10 @@ jobs: azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}" + # Set AI model capacity parameters + azd env set AZURE_ENV_MODEL_CAPACITY="150" + azd env set AZURE_ENV_EMBEDDING_MODEL_CAPACITY="200" + # Deploy azd up --no-prompt From da53491f23c94e9537bcb0f955f1a2b635a4f205 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 13:42:42 +0530 Subject: [PATCH 20/37] added exp and waf support --- .github/workflows/job-deploy-windows.yml | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index e2e3835b..533b4486 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -50,6 +50,16 @@ jobs: - 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: Install Azure CLI shell: bash run: | @@ -124,6 +134,22 @@ jobs: # Set AI model capacity parameters azd env set AZURE_ENV_MODEL_CAPACITY="150" azd env set AZURE_ENV_EMBEDDING_MODEL_CAPACITY="200" + + 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 }}" + } + + Write-Host "AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: $EXP_LOG_ANALYTICS_ID" + azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID="$EXP_LOG_ANALYTICS_ID" + } else { + Write-Host "โŒ EXP DISABLED - Skipping EXP parameters" + } # Deploy azd up --no-prompt From 59fb40edb8c733a323cca23676ea4ef7166b550b Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 13:54:28 +0530 Subject: [PATCH 21/37] fix v1 --- .github/workflows/job-deploy-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 533b4486..94156674 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -119,6 +119,7 @@ jobs: - name: Deploy using azd up id: azd_deploy + shell: pwsh run: | # Create azd environment azd env new ${{ inputs.ENV_NAME }} --no-prompt From 601b650b529a3383c944ec0a7b1308eb5a9aeddc Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 14:24:33 +0530 Subject: [PATCH 22/37] code cleanup --- .github/workflows/deploy-orchestrator.yml | 6 ------ .github/workflows/deploy-windows.yml | 3 +-- .github/workflows/job-cleanup-deployment.yml | 6 +----- .github/workflows/job-deploy-windows.yml | 2 +- .github/workflows/job-deploy.yml | 11 +++-------- 5 files changed, 6 insertions(+), 22 deletions(-) diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 9e99cec1..1eeb3875 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -3,10 +3,6 @@ name: Deployment orchestrator 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 @@ -79,7 +75,6 @@ jobs: uses: ./.github/workflows/job-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 }} @@ -126,7 +121,6 @@ jobs: needs: [docker-build, deploy, e2e-test] uses: ./.github/workflows/job-cleanup-deployment.yml with: - runner_os: ${{ inputs.runner_os }} trigger_type: ${{ inputs.trigger_type }} cleanup_resources: ${{ inputs.cleanup_resources }} existing_webapp_url: ${{ inputs.existing_webapp_url }} diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml index 2e96c838..795daae3 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-windows.yml @@ -1,4 +1,4 @@ -name: Deploy-Test-Cleanup (v2) Windows +name: Deploy-Test-Cleanup (v2) on: push: branches: @@ -85,7 +85,6 @@ 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' }} diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml index 6b920a4e..d1e7d311 100644 --- a/.github/workflows/job-cleanup-deployment.yml +++ b/.github/workflows/job-cleanup-deployment.yml @@ -2,10 +2,6 @@ name: Cleanup Deployment Job 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 @@ -43,7 +39,7 @@ on: jobs: cleanup-deployment: - runs-on: ${{ inputs.runner_os }} + runs-on: ubuntu-latest continue-on-error: true env: RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 94156674..d1d618a3 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -1,4 +1,4 @@ -name: Deploy Steps - Windows +name: Deploy Steps on: workflow_call: diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index bc422bc1..0c40e35e 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -7,10 +7,6 @@ on: 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 @@ -315,7 +311,6 @@ jobs: 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 @@ -340,10 +335,10 @@ jobs: echo "โ„น๏ธ **Note:** Manual Trigger - Using user-specified configuration" >> $GITHUB_STEP_SUMMARY fi - deploy-windows: - name: Deploy on Windows + deploy-linux: + name: Deploy needs: azure-setup - if: inputs.runner_os == 'windows-latest' && always() && needs.azure-setup.result == 'success' + if: "!Cancelled() && needs.azure-setup.result == 'success'" uses: ./.github/workflows/job-deploy-windows.yml with: ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }} From 1231dbbdc20954b21434da7efdd5e7e56e3df7b8 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 16:09:19 +0530 Subject: [PATCH 23/37] code cleanup v2 --- .github/workflows/deploy-orchestrator.yml | 2 +- .github/workflows/job-deploy-windows.yml | 2 +- .github/workflows/job-send-notification.yml | 2 +- .github/workflows/test-automation-v2.yml | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 1eeb3875..66d070e1 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -93,7 +93,7 @@ jobs: needs: [docker-build, deploy] uses: ./.github/workflows/test-automation-v2.yml with: - DOCGEN_URL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_url }} + Test_URL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_url }} TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }} secrets: inherit diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index d1d618a3..45610392 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -319,7 +319,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY if [[ "${{ job.status }}" == "success" ]]; then echo "### โœ… Deployment Details" >> $GITHUB_STEP_SUMMARY - echo "- **Web App URL**: [${{ steps.get_output_windows.outputs.WEB_APPURL }}](${{ steps.get_output_windows.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY + echo "- **Web App URL**: [${{ steps.get_output.outputs.WEB_APPURL }}](${{ steps.get_output.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY else diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml index 87baad34..89189fa4 100644 --- a/.github/workflows/job-send-notification.yml +++ b/.github/workflows/job-send-notification.yml @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: true env: - accelerator_name: "DocGen" + accelerator_name: "DKM" steps: - name: Determine Test Suite Display Name id: test_suite diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml index 085693ba..23e9d611 100644 --- a/.github/workflows/test-automation-v2.yml +++ b/.github/workflows/test-automation-v2.yml @@ -1,12 +1,12 @@ -name: Test Automation DocGen-v2 +name: Test Automation Dkm-v2 on: workflow_call: inputs: - DOCGEN_URL: + Test_URL: required: true type: string - description: "Web URL for DocGen" + description: "Web URL for Dkm" TEST_SUITE: required: false type: string @@ -21,8 +21,8 @@ on: value: ${{ jobs.test.outputs.TEST_REPORT_URL }} env: - url: ${{ inputs.DOCGEN_URL }} - accelerator_name: "DocGen" + url: ${{ inputs.Test_URL }} + accelerator_name: "Dkm" test_suite: ${{ inputs.TEST_SUITE }} jobs: From 4b1fa16333e1441e84675bb7f25589bd50b1e24c Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 16:54:29 +0530 Subject: [PATCH 24/37] removed docker build file and code cleanup --- .github/workflows/deploy-orchestrator.yml | 27 +------ .github/workflows/deploy-windows.yml | 12 --- .github/workflows/job-deploy-windows.yml | 6 -- .github/workflows/job-deploy.yml | 50 +++--------- .github/workflows/job-docker-build.yml | 99 ----------------------- 5 files changed, 14 insertions(+), 180 deletions(-) delete mode 100644 .github/workflows/job-docker-build.yml diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 66d070e1..880e94e6 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -23,11 +23,6 @@ on: 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 @@ -43,11 +38,6 @@ on: 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 @@ -62,16 +52,8 @@ 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: inherit - deploy: if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null) - needs: docker-build uses: ./.github/workflows/job-deploy.yml with: trigger_type: ${{ inputs.trigger_type }} @@ -79,18 +61,15 @@ jobs: 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_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} - AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} - docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }} 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.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] + needs: [deploy] uses: ./.github/workflows/test-automation-v2.yml with: Test_URL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_url }} @@ -99,7 +78,7 @@ jobs: send-notification: if: always() - needs: [docker-build, deploy, e2e-test] + needs: [deploy, e2e-test] uses: ./.github/workflows/job-send-notification.yml with: trigger_type: ${{ inputs.trigger_type }} @@ -118,7 +97,7 @@ jobs: 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) - needs: [docker-build, deploy, e2e-test] + needs: [deploy, e2e-test] uses: ./.github/workflows/job-cleanup-deployment.yml with: trigger_type: ${{ inputs.trigger_type }} diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml index 795daae3..7aff690b 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-windows.yml @@ -40,11 +40,6 @@ on: 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' @@ -67,11 +62,6 @@ on: 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 WebApp URL (Skips Deployment)' required: false @@ -89,11 +79,9 @@ jobs: 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_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_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 diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 45610392..8d8b6aac 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -18,9 +18,6 @@ on: IMAGE_TAG: required: true type: string - BUILD_DOCKER_IMAGE: - required: true - type: string EXP: required: true type: string @@ -31,9 +28,6 @@ on: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: required: false type: string - AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: - required: false - type: string outputs: WEB_APPURL: description: "Container Web App URL" diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 0c40e35e..b3500b45 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -27,11 +27,6 @@ on: 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 @@ -52,16 +47,6 @@ on: 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 outputs: RESOURCE_GROUP_NAME: description: "Resource Group Name" @@ -93,7 +78,7 @@ env: EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.EXP || false) || false }} 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 }} + jobs: azure-setup: @@ -115,12 +100,11 @@ jobs: echo "๐Ÿ” Validating EXP configuration..." if [[ "${{ inputs.EXP }}" != "true" ]]; then - if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] || [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then + if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_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_ANALYTICS_WORKSPACE_ID }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.AZURE_ENV_LOG_ANALYTICS_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 @@ -213,7 +197,7 @@ jobs: echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV else echo "Generating a unique resource group name..." - ACCL_NAME="dkmv2" # Account name as specified + ACCL_NAME="dkm" # 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 @@ -256,23 +240,14 @@ jobs: - name: Determine Docker Image Tag id: determine_image_tag 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" - - # Determine image tag based on branch - if [[ "$BRANCH_NAME" == "main" ]]; then - IMAGE_TAG="latest_waf" - echo "Using main branch - image tag: latest_waf" + echo "๐Ÿท๏ธ Using existing Docker image based on branch..." + BRANCH_NAME="${{ env.BRANCH_NAME }}" + echo "Current branch: $BRANCH_NAME" + + # Determine image tag based on branch + if [[ "$BRANCH_NAME" == "main" ]]; then + IMAGE_TAG="latest_waf" + echo "Using main branch - image tag: latest_waf" elif [[ "$BRANCH_NAME" == "dev" ]]; then IMAGE_TAG="dev" echo "Using dev branch - image tag: dev" @@ -315,7 +290,6 @@ jobs: 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 @@ -346,9 +320,7 @@ jobs: 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: ${{ inputs.build_docker_image || 'false' }} EXP: ${{ inputs.EXP || 'false' }} WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} - AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} secrets: inherit diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml deleted file mode 100644 index 62956a43..00000000 --- a/.github/workflows/job-docker-build.yml +++ /dev/null @@ -1,99 +0,0 @@ -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 - 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 Docker Image - id: build_push_image - uses: docker/build-push-action@v6 - env: - DOCKER_BUILD_SUMMARY: false - with: - context: ./src - file: ./src/WebApp.Dockerfile - push: true - tags: | - ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} - ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ 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 one Docker image to ACR:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY - echo "- \`${ACR_NAME}.azurecr.io/webapp:${{ 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 From bf2f244c28ba8aa33ab36b2554ab1813337b1bc9 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 16:58:03 +0530 Subject: [PATCH 25/37] fix v1 --- .github/workflows/job-deploy.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index b3500b45..8f9c3d38 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -260,7 +260,6 @@ jobs: fi echo "Using existing Docker image tag: $IMAGE_TAG" - fi echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT From 0c282949d66f48847454b694333e61b280461a83 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 17:53:44 +0530 Subject: [PATCH 26/37] e to e step fix --- .github/workflows/job-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 8f9c3d38..de052305 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -53,7 +53,7 @@ on: value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} WEB_APPURL: description: "Container Web App URL" - value: ${{ jobs.deploy-windows.outputs.WEB_APPURL }} + value: ${{ jobs.deploy-linux.outputs.WEB_APPURL }} ENV_NAME: description: "Environment Name" value: ${{ jobs.azure-setup.outputs.ENV_NAME }} From 54f9fe93b86b6b9f26271ac29e37a134927b8a91 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 18 Dec 2025 20:22:25 +0530 Subject: [PATCH 27/37] updated output params --- .github/workflows/job-deploy-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 8d8b6aac..646ca426 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -313,7 +313,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY if [[ "${{ job.status }}" == "success" ]]; then echo "### โœ… Deployment Details" >> $GITHUB_STEP_SUMMARY - echo "- **Web App URL**: [${{ steps.get_output.outputs.WEB_APPURL }}](${{ steps.get_output.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY + echo "- **Web App URL**: [${{ steps.get_webapp_url.outputs.WEB_APPURL }}](${{ steps.get_webapp_url.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY else From e75ff5f991c12c306824a418769c7a385333d859 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Fri, 19 Dec 2025 11:58:46 +0530 Subject: [PATCH 28/37] added ai location param --- docs/CustomizingAzdParameters.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md index 15625e6b..8756c99f 100644 --- a/docs/CustomizingAzdParameters.md +++ b/docs/CustomizingAzdParameters.md @@ -10,6 +10,7 @@ By default this template will use the environment name as the prefix to prevent | ------------------------------- | ------ | ----------------- | --------------------------------------------------------------------------------------------------- | | `AZURE_ENV_NAME` | string | `dkm` | Used as a prefix for all resource names to ensure uniqueness across environments. | | `AZURE_LOCATION` | string | `` | Location of the Azure resources. Controls where the infrastructure will be deployed. | +| `AZURE_ENV_OPENAI_LOCATION` | string | `` | Location for Azure OpenAI resources. Can be different from AZURE_LOCATION for optimized AI service placement. | | `AZURE_ENV_MODEL_DEPLOYMENT_TYPE` | string | `GlobalStandard` | Defines the deployment type for the AI model (e.g., Standard, GlobalStandard). | | `AZURE_ENV_MODEL_NAME` | string | `gpt-4.1` | Specifies the name of the GPT model to be deployed. | | `AZURE_ENV_MODEL_CAPACITY` | int | `100` | Sets the GPT model capacity. | From 8e85a0dbffe1e8f1bbb8251790bac4a0911fd22f Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 22 Dec 2025 11:58:43 +0530 Subject: [PATCH 29/37] fixed copilot suggested fixes --- .../{deploy-windows.yml => deploy-linux.yml} | 3 -- .github/workflows/deploy-orchestrator.yml | 8 ++--- .github/workflows/job-cleanup-deployment.yml | 2 +- ...eploy-windows.yml => job-deploy-linux.yml} | 30 +++++++------------ .github/workflows/job-deploy.yml | 21 +++++++------ .github/workflows/test-automation-v2.yml | 8 +++-- 6 files changed, 32 insertions(+), 40 deletions(-) rename .github/workflows/{deploy-windows.yml => deploy-linux.yml} (96%) rename .github/workflows/{job-deploy-windows.yml => job-deploy-linux.yml} (91%) diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-linux.yml similarity index 96% rename from .github/workflows/deploy-windows.yml rename to .github/workflows/deploy-linux.yml index 7aff690b..7fd7462f 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-linux.yml @@ -67,9 +67,6 @@ on: required: false default: '' type: string - - # schedule: - # - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT jobs: Run: diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 880e94e6..6f0de5d4 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -53,7 +53,7 @@ env: jobs: deploy: - if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null) + if: "!cancelled() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)" uses: ./.github/workflows/job-deploy.yml with: trigger_type: ${{ inputs.trigger_type }} @@ -68,7 +68,7 @@ jobs: secrets: inherit e2e-test: - if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.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: "!cancelled() && ((needs.deploy.result == 'success' && needs.deploy.outputs.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: [deploy] uses: ./.github/workflows/test-automation-v2.yml with: @@ -77,7 +77,7 @@ jobs: secrets: inherit send-notification: - if: always() + if: "!cancelled()" needs: [deploy, e2e-test] uses: ./.github/workflows/job-send-notification.yml with: @@ -96,7 +96,7 @@ jobs: 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) + if: "!cancelled() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)" needs: [deploy, e2e-test] uses: ./.github/workflows/job-cleanup-deployment.yml with: diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml index d1e7d311..b8a911c9 100644 --- a/.github/workflows/job-cleanup-deployment.yml +++ b/.github/workflows/job-cleanup-deployment.yml @@ -59,7 +59,7 @@ jobs: - 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 login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Delete Resource Group (Optimized Cleanup) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-linux.yml similarity index 91% rename from .github/workflows/job-deploy-windows.yml rename to .github/workflows/job-deploy-linux.yml index 646ca426..b5126253 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -31,10 +31,10 @@ on: outputs: WEB_APPURL: description: "Container Web App URL" - value: ${{ jobs.deploy-windows.outputs.WEB_APPURL }} + value: ${{ jobs.deploy-linux.outputs.WEB_APPURL }} jobs: - deploy-windows: + deploy-linux: runs-on: ubuntu-latest env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} @@ -70,10 +70,10 @@ jobs: shell: bash run: | # If helm is already available on the runner, print version and skip installation - if command -v helm >/dev/null 2>&1; then - echo "helm already installed: $(helm version --short 2>/dev/null || true)" - exit 0 - fi + if command -v helm >/dev/null 2>&1; then + echo "helm already installed: $(helm version --short 2>/dev/null || true)" + exit 0 + fi # Ensure prerequisites are present sudo apt-get update @@ -106,7 +106,7 @@ jobs: - name: Login to Azure run: | - az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ 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 }} @@ -124,7 +124,7 @@ jobs: 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 }}" + azd env set AZURE_ENV_IMAGE_TAG="${{ inputs.IMAGE_TAG }}" # Set AI model capacity parameters azd env set AZURE_ENV_MODEL_CAPACITY="150" @@ -167,7 +167,7 @@ jobs: # Get AKS node resource group if AKS exists if [ -n "$AZURE_AKS_NAME" ]; then - krg_name=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "$RESOURCE_GROUP_NAME" --query "nodeResourceGroup" -o tsv || echo "") + krg_name=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "${{ inputs.RESOURCE_GROUP_NAME }}" --query "nodeResourceGroup" -o tsv || echo "") if [ -n "$krg_name" ]; then echo "krg_name=$krg_name" >> $GITHUB_ENV echo "AKS node resource group: $krg_name" @@ -216,14 +216,6 @@ jobs: id: get_webapp_url shell: bash run: | - if az account show &> /dev/null; then - echo "Azure CLI is authenticated." - else - echo "Azure CLI is not authenticated. Logging in..." - az login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} - fi - az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} - # Get the Web App URL and save it to GITHUB_OUTPUT echo "Retrieving Web App URL..." public_ip_name=$(az network public-ip list --resource-group ${{ env.krg_name }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) @@ -300,7 +292,7 @@ jobs: if: always() shell: bash run: | - echo "## ๐Ÿš€ Deploy Job Summary (Windows)" >> $GITHUB_STEP_SUMMARY + echo "## ๐Ÿš€ Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY @@ -308,7 +300,7 @@ jobs: 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_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 diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index de052305..3415210f 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -118,7 +118,7 @@ jobs: - 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 login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Run Quota Check @@ -130,21 +130,20 @@ jobs: # Path to the PowerShell script for quota check $quotaCheckScript = "Deployment/checkquota.ps1" - # Check if the script exists and is executable (not needed for PowerShell like chmod) + # Check if the script exists if (-not (Test-Path $quotaCheckScript)) { Write-Host "โŒ Error: Quota check script not found." exit 1 } - # Run the script - .\Deployment\checkquota.ps1 + # Run the script and capture its output (stdout and stderr) + $output = & $quotaCheckScript 2>&1 + $exitCode = $LASTEXITCODE - # If the script fails, check for the failure message + # Check the execution output for the quota failure message $quotaFailedMessage = "No region with sufficient quota found" - $output = Get-Content "Deployment/checkquota.ps1" - - if ($output -contains $quotaFailedMessage) { - echo "QUOTA_FAILED=true" >> $GITHUB_ENV + if ($output -match [Regex]::Escape($quotaFailedMessage) -or $exitCode -ne 0) { + echo "QUOTA_FAILED=true" >> $env:GITHUB_ENV } env: AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} @@ -311,8 +310,8 @@ jobs: deploy-linux: name: Deploy needs: azure-setup - if: "!Cancelled() && needs.azure-setup.result == 'success'" - uses: ./.github/workflows/job-deploy-windows.yml + if: "!cancelled() && 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 }} diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml index 23e9d611..5bc9f857 100644 --- a/.github/workflows/test-automation-v2.yml +++ b/.github/workflows/test-automation-v2.yml @@ -22,7 +22,7 @@ on: env: url: ${{ inputs.Test_URL }} - accelerator_name: "Dkm" + accelerator_name: "DKM" test_suite: ${{ inputs.TEST_SUITE }} jobs: @@ -41,8 +41,12 @@ jobs: python-version: '3.13' - name: Login to Azure + env: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} run: | - az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az login --service-principal --username "$AZURE_CLIENT_ID" --password "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID" az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Install dependencies From d0cda0af822c11fb920c5bf053c3ac1fdde276d2 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 22 Dec 2025 14:23:25 +0530 Subject: [PATCH 30/37] copilot fixes --- .github/workflows/deploy-orchestrator.yml | 2 +- .github/workflows/job-deploy-linux.yml | 23 +++++----- .github/workflows/job-deploy.yml | 49 +++++++++++---------- .github/workflows/job-send-notification.yml | 2 +- .github/workflows/test-automation-v2.yml | 4 +- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 6f0de5d4..1582dc9d 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -72,7 +72,7 @@ jobs: needs: [deploy] uses: ./.github/workflows/test-automation-v2.yml with: - Test_URL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_url }} + TEST_URL: ${{ needs.deploy.outputs.WEB_APPURL || inputs.existing_webapp_url }} TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }} secrets: inherit diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index b5126253..321ac1d7 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -149,7 +149,7 @@ jobs: # Deploy azd up --no-prompt - echo "โœ… azd deployment completed" + echo "โœ… Azure Developer CLI (azd) deployment completed" - name: Get Deployment Outputs id: get_output @@ -167,10 +167,10 @@ jobs: # Get AKS node resource group if AKS exists if [ -n "$AZURE_AKS_NAME" ]; then - krg_name=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "${{ inputs.RESOURCE_GROUP_NAME }}" --query "nodeResourceGroup" -o tsv || echo "") - if [ -n "$krg_name" ]; then - echo "krg_name=$krg_name" >> $GITHUB_ENV - echo "AKS node resource group: $krg_name" + aks_node_resource_group=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "${{ inputs.RESOURCE_GROUP_NAME }}" --query "nodeResourceGroup" -o tsv || echo "") + if [ -n "$aks_node_resource_group" ]; then + echo "aks_node_resource_group=$aks_node_resource_group" >> $GITHUB_ENV + echo "AKS node resource group: $aks_node_resource_group" fi fi @@ -183,8 +183,9 @@ jobs: yes "@ $input | pwsh ./resourcedeployment.ps1 - Write-Host "Resource Group Name is ${{ env.RESOURCE_GROUP_NAME }}" - Write-Host "Kubernetes resource group is ${{ env.AZURE_AKS_NAME }}" + Write-Host "Resource Group: ${{ inputs.RESOURCE_GROUP_NAME }}" + Write-Host "AKS Cluster Name: ${{ env.AZURE_AKS_NAME }}" + Write-Host "AKS Node Resource Group: ${{ env.aks_node_resource_group }}" env: # From GitHub secrets (for login) AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} @@ -192,8 +193,8 @@ jobs: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - # From deployment outputs step (these come from $GITHUB_ENV) - RESOURCE_GROUP_NAME: ${{ env.RESOURCE_GROUP_NAME }} + # From workflow inputs and deployment outputs + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} AZURE_RESOURCE_GROUP_ID: ${{ env.AZURE_RESOURCE_GROUP_ID }} STORAGE_ACCOUNT_NAME: ${{ env.STORAGE_ACCOUNT_NAME }} AZURE_SEARCH_SERVICE_NAME: ${{ env.AZURE_SEARCH_SERVICE_NAME }} @@ -218,8 +219,8 @@ jobs: run: | # Get the Web App URL and save it to GITHUB_OUTPUT echo "Retrieving Web App URL..." - public_ip_name=$(az network public-ip list --resource-group ${{ env.krg_name }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) - fqdn=$(az network public-ip show --resource-group ${{ env.krg_name }} --name $public_ip_name --query "dnsSettings.fqdn" -o tsv) + public_ip_name=$(az network public-ip list --resource-group ${{ env.aks_node_resource_group }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) + fqdn=$(az network public-ip show --resource-group ${{ env.aks_node_resource_group }} --name $public_ip_name --query "dnsSettings.fqdn" -o tsv) if [ -n "$fqdn" ]; then echo "WEB_APPURL=https://$fqdn" >> $GITHUB_OUTPUT echo "Web App URL is https://$fqdn" diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 3415210f..561e4bd6 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -94,22 +94,23 @@ jobs: QUOTA_FAILED: ${{ steps.quota_failure_output.outputs.QUOTA_FAILED }} steps: - - name: Validate and Auto-Configure EXP + - name: Validate EXP Configuration shell: bash run: | echo "๐Ÿ” Validating EXP configuration..." - if [[ "${{ inputs.EXP }}" != "true" ]]; then - if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_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_ANALYTICS_WORKSPACE_ID }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_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 + if [[ "${{ inputs.EXP }}" == "false" && -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then + echo "โš ๏ธ WARNING: EXP is disabled but Log Analytics Workspace ID was provided." + echo "The provided workspace ID will be ignored unless EXP is enabled." + echo "" + echo "Provided but unused:" + echo " - Azure Log Analytics Workspace ID: '${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}'" + echo "" + echo "To use these values, set EXP=true in your workflow dispatch." + elif [[ "${{ inputs.EXP }}" == "true" ]]; then + echo "โœ… EXP is enabled" + else + echo "โ„น๏ธ EXP is disabled" fi - name: Checkout Code @@ -247,18 +248,18 @@ jobs: if [[ "$BRANCH_NAME" == "main" ]]; then IMAGE_TAG="latest_waf" echo "Using main branch - image tag: latest_waf" - 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" - else - IMAGE_TAG="latest_waf" - echo "Using default for branch '$BRANCH_NAME' - image tag: latest_waf" - fi - - echo "Using existing Docker image tag: $IMAGE_TAG" + 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" + else + IMAGE_TAG="latest_waf" + echo "Using default for branch '$BRANCH_NAME' - image tag: latest_waf" + fi + + echo "Using existing Docker image tag: $IMAGE_TAG" echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml index 89189fa4..5ca35243 100644 --- a/.github/workflows/job-send-notification.yml +++ b/.github/workflows/job-send-notification.yml @@ -182,7 +182,7 @@ jobs: -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 == '') + if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'success' shell: bash run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml index 5bc9f857..8f48ed19 100644 --- a/.github/workflows/test-automation-v2.yml +++ b/.github/workflows/test-automation-v2.yml @@ -3,7 +3,7 @@ name: Test Automation Dkm-v2 on: workflow_call: inputs: - Test_URL: + TEST_URL: required: true type: string description: "Web URL for Dkm" @@ -21,7 +21,7 @@ on: value: ${{ jobs.test.outputs.TEST_REPORT_URL }} env: - url: ${{ inputs.Test_URL }} + url: ${{ inputs.TEST_URL }} accelerator_name: "DKM" test_suite: ${{ inputs.TEST_SUITE }} From 52bfbca4770567693149749c4c99e3cc1f512a82 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Mon, 22 Dec 2025 14:31:39 +0530 Subject: [PATCH 31/37] renamed a param back to original --- .github/workflows/job-deploy-linux.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 321ac1d7..af54b815 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -167,10 +167,10 @@ jobs: # Get AKS node resource group if AKS exists if [ -n "$AZURE_AKS_NAME" ]; then - aks_node_resource_group=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "${{ inputs.RESOURCE_GROUP_NAME }}" --query "nodeResourceGroup" -o tsv || echo "") - if [ -n "$aks_node_resource_group" ]; then - echo "aks_node_resource_group=$aks_node_resource_group" >> $GITHUB_ENV - echo "AKS node resource group: $aks_node_resource_group" + krg_name=$(az aks show --name "$AZURE_AKS_NAME" --resource-group "${{ inputs.RESOURCE_GROUP_NAME }}" --query "nodeResourceGroup" -o tsv || echo "") + if [ -n "$krg_name" ]; then + echo "krg_name=$krg_name" >> $GITHUB_ENV + echo "AKS node resource group: $krg_name" fi fi @@ -185,7 +185,7 @@ jobs: $input | pwsh ./resourcedeployment.ps1 Write-Host "Resource Group: ${{ inputs.RESOURCE_GROUP_NAME }}" Write-Host "AKS Cluster Name: ${{ env.AZURE_AKS_NAME }}" - Write-Host "AKS Node Resource Group: ${{ env.aks_node_resource_group }}" + Write-Host "AKS Node Resource Group: ${{ env.krg_name }}" env: # From GitHub secrets (for login) AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} @@ -219,8 +219,8 @@ jobs: run: | # Get the Web App URL and save it to GITHUB_OUTPUT echo "Retrieving Web App URL..." - public_ip_name=$(az network public-ip list --resource-group ${{ env.aks_node_resource_group }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) - fqdn=$(az network public-ip show --resource-group ${{ env.aks_node_resource_group }} --name $public_ip_name --query "dnsSettings.fqdn" -o tsv) + public_ip_name=$(az network public-ip list --resource-group ${{ env.krg_name }} --query "[?contains(name, 'kubernetes-')].name" -o tsv) + fqdn=$(az network public-ip show --resource-group ${{ env.krg_name }} --name $public_ip_name --query "dnsSettings.fqdn" -o tsv) if [ -n "$fqdn" ]; then echo "WEB_APPURL=https://$fqdn" >> $GITHUB_OUTPUT echo "Web App URL is https://$fqdn" From 2e9759e4ce78f5022bd4ebb4eebdd86531355ce8 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 28 Jan 2026 12:27:24 +0530 Subject: [PATCH 32/37] copilot suggested changes --- .github/workflows/deploy-linux.yml | 8 ++++---- .github/workflows/deploy-orchestrator.yml | 2 +- .github/workflows/job-cleanup-deployment.yml | 1 - .github/workflows/job-deploy-linux.yml | 4 ++-- .github/workflows/job-deploy.yml | 16 ++++------------ .github/workflows/test-automation-v2.yml | 8 ++++++++ 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 7fd7462f..1ef85eda 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -6,7 +6,7 @@ on: - dev - demo schedule: - - cron: "0 10,22 * * *" # Runs at 10:00 AM and 10:00 PM GMT + - cron: "0 10,22 * * *" # Runs at 10:00 AM and 10:00 PM UTC workflow_dispatch: inputs: @@ -74,9 +74,9 @@ jobs: with: 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' }} - cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} + waf_enabled: ${{ github.event.inputs.waf_enabled }} + EXP: ${{ github.event.inputs.EXP }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }} existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 1582dc9d..b42ca2b8 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -68,7 +68,7 @@ jobs: secrets: inherit e2e-test: - if: "!cancelled() && ((needs.deploy.result == 'success' && needs.deploy.outputs.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: "!cancelled() && ((needs.deploy.outputs.WEB_APPURL != '' && needs.deploy.outputs.WEB_APPURL != null) || (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: [deploy] uses: ./.github/workflows/test-automation-v2.yml with: diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml index b8a911c9..30e518e3 100644 --- a/.github/workflows/job-cleanup-deployment.yml +++ b/.github/workflows/job-cleanup-deployment.yml @@ -82,7 +82,6 @@ jobs: if: always() shell: bash run: | - azd auth logout || true az logout || echo "Warning: Failed to logout from Azure CLI" echo "Logged out from Azure." diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index af54b815..b8066ec5 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -76,8 +76,8 @@ jobs: fi # Ensure prerequisites are present - sudo apt-get update - sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release + sudo apt-get update + sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release # Ensure keyrings dir exists sudo mkdir -p /usr/share/keyrings diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 561e4bd6..40be0127 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -172,6 +172,10 @@ jobs: id: set_region shell: bash run: | + if [[ -z "$VALID_REGION" ]]; then + echo "โŒ ERROR: VALID_REGION is not set. The quota check script (Deployment/checkquota.ps1) must set this variable before this step runs." >&2 + exit 1 + fi 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 @@ -225,18 +229,6 @@ jobs: 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 run: | diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml index 8f48ed19..a3a87299 100644 --- a/.github/workflows/test-automation-v2.yml +++ b/.github/workflows/test-automation-v2.yml @@ -63,6 +63,14 @@ jobs: echo "ERROR: No URL provided for testing" exit 1 fi + + # Validate test suite is implemented + if [ "${{ env.test_suite }}" == "Smoke-Testing" ]; then + echo "ERROR: Smoke-Testing is not yet implemented" + echo "Available test suites: GoldenPath-Testing" + exit 1 + fi + echo "Testing URL: ${{ env.url }}" echo "Test Suite: ${{ env.test_suite }}" From 61739e9d7712a8247b44ea287405bbc68093258e Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Wed, 28 Jan 2026 13:23:33 +0530 Subject: [PATCH 33/37] boolean values fix --- .github/workflows/deploy-linux.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 1ef85eda..93b5ae00 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -74,9 +74,9 @@ jobs: with: azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} - waf_enabled: ${{ github.event.inputs.waf_enabled }} - EXP: ${{ github.event.inputs.EXP }} - cleanup_resources: ${{ github.event.inputs.cleanup_resources }} + waf_enabled: ${{ github.event.inputs.waf_enabled || false }} + EXP: ${{ github.event.inputs.EXP || false }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources || false }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }} existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} From 26f1c1671886d158559a6b260fa2490804c4958f Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Thu, 29 Jan 2026 10:12:04 +0530 Subject: [PATCH 34/37] fixes v1 --- .github/workflows/deploy-linux.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 93b5ae00..392fcc08 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -74,9 +74,9 @@ jobs: with: azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} - waf_enabled: ${{ github.event.inputs.waf_enabled || false }} - EXP: ${{ github.event.inputs.EXP || false }} - cleanup_resources: ${{ github.event.inputs.cleanup_resources || false }} + waf_enabled: ${{ github.event.inputs.waf_enabled == true }} + EXP: ${{ github.event.inputs.EXP == true }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources == true }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }} existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} From 8033a84a4db8811c3d6ee9d3b3a4aa1112a47f1b Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 30 Jan 2026 16:08:33 +0530 Subject: [PATCH 35/37] Integrated GP and Smoke Testing --- .github/workflows/test-automation-v2.yml | 13 +++--- tests/e2e-test/pytest.ini | 3 ++ tests/e2e-test/tests/test_dkm_functional.py | 48 ++++++++++----------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml index a3a87299..fe64a1ec 100644 --- a/.github/workflows/test-automation-v2.yml +++ b/.github/workflows/test-automation-v2.yml @@ -64,13 +64,6 @@ jobs: exit 1 fi - # Validate test suite is implemented - if [ "${{ env.test_suite }}" == "Smoke-Testing" ]; then - echo "ERROR: Smoke-Testing is not yet implemented" - echo "Available test suites: GoldenPath-Testing" - exit 1 - fi - echo "Testing URL: ${{ env.url }}" echo "Test Suite: ${{ env.test_suite }}" @@ -103,6 +96,8 @@ jobs: id: test1 run: | if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest -m goldenpath --headed --html=report/report.html --self-contained-html + else xvfb-run pytest --headed --html=report/report.html --self-contained-html fi working-directory: tests/e2e-test @@ -118,6 +113,8 @@ jobs: if: ${{ steps.test1.outcome == 'failure' }} run: | if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest -m goldenpath --headed --html=report/report.html --self-contained-html + else xvfb-run pytest --headed --html=report/report.html --self-contained-html fi working-directory: tests/e2e-test @@ -133,6 +130,8 @@ jobs: if: ${{ steps.test2.outcome == 'failure' }} run: | if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + xvfb-run pytest -m goldenpath --headed --html=report/report.html --self-contained-html + else xvfb-run pytest --headed --html=report/report.html --self-contained-html fi working-directory: tests/e2e-test diff --git a/tests/e2e-test/pytest.ini b/tests/e2e-test/pytest.ini index 76eb64fc..a18b0949 100644 --- a/tests/e2e-test/pytest.ini +++ b/tests/e2e-test/pytest.ini @@ -4,3 +4,6 @@ log_cli_level = INFO log_file = logs/tests.log log_file_level = INFO addopts = -p no:warnings + +markers = + goldenpath: Golden Path tests \ No newline at end of file diff --git a/tests/e2e-test/tests/test_dkm_functional.py b/tests/e2e-test/tests/test_dkm_functional.py index fd068d76..0bad5f00 100644 --- a/tests/e2e-test/tests/test_dkm_functional.py +++ b/tests/e2e-test/tests/test_dkm_functional.py @@ -42,7 +42,7 @@ def capture_screenshot(page, step_name, test_prefix="test"): pass -@pytest.mark.smoke +@pytest.mark.goldenpath def test_golden_path_dkm(login_logout, request): """ Test Case 10591: Golden Path-DKM-test golden path demo script works properly @@ -283,7 +283,7 @@ def test_golden_path_dkm(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_upload_default_github_data(login_logout, request): """ Test Case 10661: DKM-Upload default GitHub repo sample data @@ -350,7 +350,7 @@ def test_upload_default_github_data(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_search_functionality(login_logout, request): """ Test Case 10671: DKM-Verify the search functionality @@ -416,7 +416,7 @@ def test_search_functionality(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_chat_selected_document(login_logout, request): """ Test Case 10704: DKM-Test chat selected document @@ -496,7 +496,7 @@ def test_chat_selected_document(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_chat_multiple_selected_documents(login_logout, request): """ Test Case 10705: DKM-Test chat multiple selected documents @@ -575,7 +575,7 @@ def test_chat_multiple_selected_documents(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_chat_all_documents(login_logout, request): """ Test Case 10706: DKM-Test chat all documents @@ -634,7 +634,7 @@ def test_chat_all_documents(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_jailbreak_questions(login_logout, request): """ Test Case 10707: DKM-Test questions to jailbreak @@ -702,7 +702,7 @@ def test_jailbreak_questions(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_web_knowledge_questions(login_logout, request): """ Test Case 10708: DKM-Test questions to ask web knowledge @@ -761,7 +761,7 @@ def test_web_knowledge_questions(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_send_button_disabled_by_default(login_logout, request): """ Test Case 14111: Bug-13861-DKM - Send prompt icon should be disabled by default @@ -827,7 +827,7 @@ def test_send_button_disabled_by_default(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_validate_empty_spaces_chat_input(login_logout, request): """ Test Case 26217: DKM - Validate chat input handling for Empty / only-spaces @@ -899,7 +899,7 @@ def test_validate_empty_spaces_chat_input(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_upload_different_file_types(login_logout, request): """ Test Case 10664: DKM-Upload one file of each supported filetype @@ -964,7 +964,7 @@ def test_upload_different_file_types(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_upload_large_file(login_logout, request): """ Test Case 10665: OOS_DKM-Upload very large file size @@ -1030,7 +1030,7 @@ def test_upload_large_file(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_upload_zero_byte_file(login_logout, request): """ Test Case 10666: DKM-Upload zero byte file @@ -1085,7 +1085,7 @@ def test_upload_zero_byte_file(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_upload_unsupported_file(login_logout, request): """ Test Case 10667: DKM-Upload unsupported file @@ -1140,7 +1140,7 @@ def test_upload_unsupported_file(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_documents_scrolling_pagination(login_logout, request): """ Test Case 10670: DKM-test documents section scrolling and pagination @@ -1201,7 +1201,7 @@ def test_documents_scrolling_pagination(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_search_with_time_filter(login_logout, request): """ Test Case 10672: DKM-Test search documents with time filter @@ -1272,7 +1272,7 @@ def test_search_with_time_filter(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_left_pane_filters(login_logout, request): """ Test Case 10700: DKM-Test left pane filters @@ -1341,7 +1341,7 @@ def test_left_pane_filters(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_left_pane_and_search_filters(login_logout, request): """ Test Case 10702: DKM-Test left pane filters collision with search filters @@ -1412,7 +1412,7 @@ def test_left_pane_and_search_filters(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_document_details_preview(login_logout, request): """ Test Case 10703: DKM-Test document details preview @@ -1492,7 +1492,7 @@ def test_document_details_preview(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_confirm_references_citations(login_logout, request): """ Test Case 10710: DKM-Confirm references or citations in response @@ -1564,7 +1564,7 @@ def test_confirm_references_citations(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_bug_sensitive_question_stuck(login_logout, request): """ Test Case 13539: Bug 12794 - Response Not Generated for Sensitive Question @@ -1630,7 +1630,7 @@ def test_bug_sensitive_question_stuck(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_bug_chat_session_cleared(login_logout, request): """ Test Case 14704: Bug-13797-DKM-Chat session cleared when switch tabs @@ -1706,7 +1706,7 @@ def test_bug_chat_session_cleared(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_bug_text_file_download(login_logout, request): """ Test Case 16787: Bug 16600 - Text file getting downloaded on click @@ -1768,7 +1768,7 @@ def test_bug_text_file_download(login_logout, request): logger.removeHandler(handler) -@pytest.mark.smoke + def test_bug_clear_all_button(login_logout, request): """ Test Case 16788: Bug 16599 - Clear All Button should reset search box From e79a5fdf480c8c355f1c95df8455de5643e8df36 Mon Sep 17 00:00:00 2001 From: Rafi-Microsoft Date: Fri, 30 Jan 2026 16:34:18 +0530 Subject: [PATCH 36/37] updated the post deployment script --- Deployment/send-filestoendpoint.psm1 | 101 ++++++++++++++++++++------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/Deployment/send-filestoendpoint.psm1 b/Deployment/send-filestoendpoint.psm1 index e7964467..05a2fe55 100644 --- a/Deployment/send-filestoendpoint.psm1 +++ b/Deployment/send-filestoendpoint.psm1 @@ -27,6 +27,10 @@ function Send-FilesToEndpoint { $totalFiles = $files.Count $currentFileIndex = 0 + $maxRetries = 3 + $retryDelaySeconds = 5 + $failedFiles = @() + $successfulFiles = 0 foreach ($file in $files) { $currentFileIndex++ @@ -35,43 +39,70 @@ function Send-FilesToEndpoint { # Check file size if ($file.Length -eq 0) { - Write-Host "File cannot be uploaded: $($file.Name) (File size is 0)" + Write-Host "โš ๏ธ File cannot be uploaded: $($file.Name) (File size is 0)" -ForegroundColor Yellow + $failedFiles += @{FileName = $file.Name; Reason = "File size is 0"} continue } # Check file type $allowedExtensions = @(".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".tif", ".tiff", ".jpg", ".jpeg", ".png", ".bmp", ".txt") if (-Not ($allowedExtensions -contains $file.Extension.ToLower())) { - Write-Host "File cannot be uploaded: $($file.Name) (Unsupported file type)" + Write-Host "โš ๏ธ File cannot be uploaded: $($file.Name) (Unsupported file type)" -ForegroundColor Yellow + $failedFiles += @{FileName = $file.Name; Reason = "Unsupported file type"} continue } - try { - # Read the file content as byte array - $fileContent = [System.IO.File]::ReadAllBytes($file.FullName) + # Retry logic for file upload + $uploadSuccess = $false + $attempt = 0 + + while ($attempt -lt $maxRetries -and -not $uploadSuccess) { + $attempt++ + try { + if ($attempt -gt 1) { + Write-Host "๐Ÿ”„ Retry attempt $attempt of $maxRetries for file: $($file.Name)" -ForegroundColor Cyan + Start-Sleep -Seconds $retryDelaySeconds + } + + # Read the file content as byte array + $fileContent = [System.IO.File]::ReadAllBytes($file.FullName) - # Create the multipart form data content - $content = [System.Net.Http.MultipartFormDataContent]::new() - $fileContentByteArray = [System.Net.Http.ByteArrayContent]::new($fileContent) - $fileContentByteArray.Headers.ContentDisposition = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") - $fileContentByteArray.Headers.ContentDisposition.Name = '"file"' - $fileContentByteArray.Headers.ContentDisposition.FileName = '"' + $file.Name + '"' - $content.Add($fileContentByteArray) + # Create the multipart form data content + $content = [System.Net.Http.MultipartFormDataContent]::new() + $fileContentByteArray = [System.Net.Http.ByteArrayContent]::new($fileContent) + $fileContentByteArray.Headers.ContentDisposition = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") + $fileContentByteArray.Headers.ContentDisposition.Name = '"file"' + $fileContentByteArray.Headers.ContentDisposition.FileName = '"' + $file.Name + '"' + $content.Add($fileContentByteArray) - # Upload the file content to the HTTP endpoint - $response = $httpClient.PostAsync($EndpointUrl, $content).GetAwaiter().GetResult() - - - # Check the response status - if ($response.IsSuccessStatusCode) { - Write-Host "File uploaded successfully: $($file.Name)" - } - else { - Write-Error "Failed to upload file: $($file.Name). Status code: $($response.StatusCode)" + # Upload the file content to the HTTP endpoint + $response = $httpClient.PostAsync($EndpointUrl, $content).GetAwaiter().GetResult() + + + # Check the response status + if ($response.IsSuccessStatusCode) { + Write-Host "โœ… File uploaded successfully: $($file.Name)" -ForegroundColor Green + $uploadSuccess = $true + $successfulFiles++ + } + else { + $statusCode = $response.StatusCode + if ($attempt -lt $maxRetries) { + Write-Host "โš ๏ธ Failed to upload file: $($file.Name). Status code: $statusCode. Will retry..." -ForegroundColor Yellow + } else { + Write-Host "โŒ Failed to upload file: $($file.Name). Status code: $statusCode. Max retries reached." -ForegroundColor Red + $failedFiles += @{FileName = $file.Name; Reason = "HTTP Status: $statusCode"} + } + } + } + catch { + if ($attempt -lt $maxRetries) { + Write-Host "โš ๏ธ Error uploading file: $($file.Name). Error: $($_.Exception.Message). Will retry..." -ForegroundColor Yellow + } else { + Write-Host "โŒ Error uploading file: $($file.Name). Error: $($_.Exception.Message). Max retries reached." -ForegroundColor Red + $failedFiles += @{FileName = $file.Name; Reason = $_.Exception.Message} + } } - } - catch { - Write-Error "An error occurred while uploading the file: $($file.Name). Error: $_" } } # Dispose HttpClient @@ -79,6 +110,26 @@ function Send-FilesToEndpoint { # Clear the progress bar Write-Progress -Activity "Uploading Files" -Status "Completed" -PercentComplete 100 + + # Print summary report + Write-Host "`n========================================" -ForegroundColor Cyan + Write-Host "๐Ÿ“Š File Upload Summary" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "Total files processed: $totalFiles" -ForegroundColor White + Write-Host "โœ… Successfully uploaded: $successfulFiles" -ForegroundColor Green + Write-Host "โŒ Failed uploads: $($failedFiles.Count)" -ForegroundColor Red + + if ($failedFiles.Count -gt 0) { + Write-Host "`nโŒ Failed Files Details:" -ForegroundColor Red + foreach ($failed in $failedFiles) { + Write-Host " โ€ข $($failed.FileName) - Reason: $($failed.Reason)" -ForegroundColor Yellow + } + Write-Host "`nโš ๏ธ Warning: Some files failed to upload after $maxRetries retry attempts." -ForegroundColor Yellow + Write-Host "You can manually retry uploading the failed files later." -ForegroundColor Yellow + } else { + Write-Host "`nโœ… All files uploaded successfully!" -ForegroundColor Green + } + Write-Host "========================================`n" -ForegroundColor Cyan } Export-ModuleMember -Function Send-FilesToEndpoint \ No newline at end of file From 4c773f0d2697a947d4ab1755a3a94da9b847a932 Mon Sep 17 00:00:00 2001 From: Kanchan-Microsoft Date: Sat, 31 Jan 2026 13:41:26 +0530 Subject: [PATCH 37/37] fixed for waf and cleanup --- .github/workflows/deploy-linux.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 392fcc08..64c8ce29 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -74,9 +74,9 @@ jobs: with: 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 }} - cleanup_resources: ${{ github.event.inputs.cleanup_resources == true }} + waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} + EXP: ${{ github.event.inputs.EXP == 'true' }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }} existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}