From e6c8695c61b3354b888808882715524e36fd549b Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Fri, 28 Nov 2025 10:56:17 +0530 Subject: [PATCH 1/4] Optimized Deployment workflow by separating jobs into individual workflows --- .github/workflows/deploy-linux.yml | 85 ++++ .github/workflows/deploy-orchestrator.yml | 180 +++++++++ .github/workflows/deploy-windows.yml | 85 ++++ .github/workflows/job-azure-deploy.yml | 400 +++++++++++++++++++ .github/workflows/job-cleanup-resources.yml | 125 ++++++ .github/workflows/job-docker-build.yml | 131 ++++++ .github/workflows/job-send-notifications.yml | 227 +++++++++++ .github/workflows/job-test-automation.yml | 185 +++++++++ 8 files changed, 1418 insertions(+) create mode 100644 .github/workflows/deploy-linux.yml create mode 100644 .github/workflows/deploy-orchestrator.yml create mode 100644 .github/workflows/deploy-windows.yml create mode 100644 .github/workflows/job-azure-deploy.yml create mode 100644 .github/workflows/job-cleanup-resources.yml create mode 100644 .github/workflows/job-docker-build.yml create mode 100644 .github/workflows/job-send-notifications.yml create mode 100644 .github/workflows/job-test-automation.yml diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml new file mode 100644 index 000000000..b6845dd41 --- /dev/null +++ b/.github/workflows/deploy-linux.yml @@ -0,0 +1,85 @@ +name: Deploy-Test-Cleanup Linux +on: + workflow_dispatch: + inputs: + azure_location: + description: 'Azure Location For Deployment' + required: false + default: 'australiaeast' + type: choice + options: + - 'australiaeast' + - 'centralus' + - 'eastasia' + - 'eastus2' + - 'japaneast' + - 'northeurope' + - 'southeastasia' + - 'uksouth' + resource_group_name: + description: 'Resource Group Name (Optional)' + required: false + default: '' + type: string + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + exp: + description: 'Enable EXP' + required: false + default: false + type: boolean + build_docker_image: + description: 'Build And Push Docker Image (Optional)' + required: false + default: false + type: boolean + cleanup_resources: + description: 'Cleanup Deployed Resources' + required: false + default: false + type: boolean + run_e2e_tests: + description: 'Run End-to-End Tests' + required: false + default: 'GoldenPath-Testing' + type: choice + options: + - 'GoldenPath-Testing' + - 'Smoke-Testing' + - 'None' + azure_env_log_anlytics_workspace_id: + description: 'Log Analytics Workspace ID (Optional)' + required: false + default: '' + type: string + azure_existing_ai_project_resource_id: + description: 'AI Project Resource ID (Optional)' + required: false + default: '' + type: string + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + +jobs: + Run: + uses: ./.github/workflows/deploy-orchestrator.yml + with: + runner_os: ubuntu-latest + azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} + resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} + waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} + EXP: ${{ github.event.inputs.EXP == 'true' }} + build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} + run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} + azure_env_log_anlytics_workspace_id: ${{ github.event.inputs.azure_env_log_anlytics_workspace_id || '' }} + azure_existing_ai_project_resource_id: ${{ github.event.inputs.azure_existing_ai_project_resource_id || '' }} + existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} + trigger_type: ${{ github.event_name }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml new file mode 100644 index 000000000..d2d5748d5 --- /dev/null +++ b/.github/workflows/deploy-orchestrator.yml @@ -0,0 +1,180 @@ +name: Deployment orchestrator v2 + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS (ubuntu-latest or windows-latest)' + required: true + type: string + azure_location: + description: 'Azure Location For Deployment' + required: false + default: 'australiaeast' + type: string + resource_group_name: + description: 'Resource Group Name (Optional)' + required: false + default: '' + type: string + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + exp: + description: 'Enable EXP' + required: false + default: false + type: boolean + build_docker_image: + description: 'Build And Push Docker Image (Optional)' + required: false + default: false + type: boolean + cleanup_resources: + description: 'Cleanup Deployed Resources' + required: false + default: false + type: boolean + run_e2e_tests: + description: 'Run End-to-End Tests' + required: false + default: 'GoldenPath-Testing' + type: string + azure_env_log_anlytics_workspace_id: + description: 'Log Analytics Workspace ID (Optional)' + required: false + default: '' + type: string + azure_existing_ai_project_resource_id: + description: 'AI Project Resource ID (Optional)' + required: false + default: '' + type: string + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + trigger_type: + description: 'Trigger type (workflow_dispatch, pull_request, schedule)' + required: true + type: string + secrets: + AZURE_CLIENT_ID: + required: true + AZURE_CLIENT_SECRET: + required: true + AZURE_TENANT_ID: + required: true + AZURE_SUBSCRIPTION_ID: + required: true + ACR_TEST_LOGIN_SERVER: + required: true + ACR_TEST_USERNAME: + required: true + ACR_TEST_PASSWORD: + required: true + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + required: false + AZURE_ENV_FOUNDRY_PROJECT_ID: + required: false + EMAILNOTIFICATION_LOGICAPP_URL_TA: + required: false + outputs: + CONTAINER_WEB_APPURL: + description: "Container Web App URL" + value: ${{ jobs.deploy.outputs.CONTAINER_WEB_APPURL }} + RESOURCE_GROUP_NAME: + description: "Resource Group Name" + value: ${{ jobs.deploy.outputs.RESOURCE_GROUP_NAME }} + +env: + AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + +jobs: + docker-build: + uses: ./.github/workflows/job-docker-build.yml + with: + trigger_type: ${{ inputs.trigger_type }} + build_docker_image: ${{ inputs.build_docker_image }} + secrets: + ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} + ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }} + ACR_TEST_PASSWORD: ${{ secrets.ACR_TEST_PASSWORD }} + + deploy: + if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null) + needs: docker-build + uses: ./.github/workflows/job-azure-deploy.yml + with: + trigger_type: ${{ inputs.trigger_type }} + runner_os: ${{ inputs.runner_os }} + azure_location: ${{ inputs.azure_location }} + resource_group_name: ${{ inputs.resource_group_name }} + waf_enabled: ${{ inputs.waf_enabled }} + EXP: ${{ inputs.exp }} + build_docker_image: ${{ inputs.build_docker_image }} + existing_webapp_url: ${{ inputs.existing_webapp_url }} + azure_env_log_anlytics_workspace_id: ${{ inputs.azure_env_log_anlytics_workspace_id }} + azure_existing_ai_project_resource_id: ${{ inputs.azure_existing_ai_project_resource_id }} + docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }} + secrets: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.azure_env_log_anlytics_workspace_id }} + AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} + + e2e-test: + if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null)) + needs: [docker-build, deploy] + uses: ./.github/workflows/job-test-automation.yml + with: + KMGENERIC_URL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }} + KMGENERIC_URL_API: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }} + TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }} + secrets: inherit + + send-notification: + if: always() + needs: [docker-build, deploy, e2e-test] + uses: ./.github/workflows/job-send-notifications.yml + with: + trigger_type: ${{ inputs.trigger_type }} + waf_enabled: ${{ inputs.waf_enabled }} + EXP: ${{ inputs.exp }} + run_e2e_tests: ${{ inputs.run_e2e_tests }} + existing_webapp_url: ${{ inputs.existing_webapp_url }} + deploy_result: ${{ needs.deploy.result }} + e2e_test_result: ${{ needs.e2e-test.result }} + CONTAINER_WEB_APPURL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL }} + RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + QUOTA_FAILED: ${{ needs.deploy.outputs.QUOTA_FAILED }} + TEST_SUCCESS: ${{ needs.e2e-test.outputs.TEST_SUCCESS }} + TEST_REPORT_URL: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }} + secrets: + EMAILNOTIFICATION_LOGICAPP_URL_TA: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} + + cleanup-deployment: + if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null) + needs: [docker-build, deploy, e2e-test] + uses: ./.github/workflows/job-cleanup-resources.yml + with: + runner_os: ${{ inputs.runner_os }} + trigger_type: ${{ inputs.trigger_type }} + cleanup_resources: ${{ inputs.cleanup_resources }} + existing_webapp_url: ${{ inputs.existing_webapp_url }} + RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }} + AZURE_ENV_OPENAI_LOCATION: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }} + ENV_NAME: ${{ needs.deploy.outputs.ENV_NAME }} + IMAGE_TAG: ${{ needs.deploy.outputs.IMAGE_TAG }} + secrets: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ No newline at end of file diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml new file mode 100644 index 000000000..538e53694 --- /dev/null +++ b/.github/workflows/deploy-windows.yml @@ -0,0 +1,85 @@ +name: Deploy-Test-Cleanup Windows +on: + workflow_dispatch: + inputs: + azure_location: + description: 'Azure Location For Deployment' + required: false + default: 'australiaeast' + type: choice + options: + - 'australiaeast' + - 'centralus' + - 'eastasia' + - 'eastus2' + - 'japaneast' + - 'northeurope' + - 'southeastasia' + - 'uksouth' + resource_group_name: + description: 'Resource Group Name (Optional)' + required: false + default: '' + type: string + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + exp: + description: 'Enable EXP' + required: false + default: false + type: boolean + build_docker_image: + description: 'Build And Push Docker Image (Optional)' + required: false + default: false + type: boolean + cleanup_resources: + description: 'Cleanup Deployed Resources' + required: false + default: false + type: boolean + run_e2e_tests: + description: 'Run End-to-End Tests' + required: false + default: 'GoldenPath-Testing' + type: choice + options: + - 'GoldenPath-Testing' + - 'Smoke-Testing' + - 'None' + azure_env_log_anlytics_workspace_id: + description: 'Log Analytics Workspace ID (Optional)' + required: false + default: '' + type: string + azure_existing_ai_project_resource_id: + description: 'AI Project Resource ID (Optional)' + required: false + default: '' + type: string + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + +jobs: + Run: + uses: ./.github/workflows/deploy-orchestrator.yml + with: + runner_os: windows-latest + azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} + resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} + waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} + EXP: ${{ github.event.inputs.exp == 'true' }} + build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }} + cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} + run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} + azure_env_log_anlytics_workspace_id: ${{ github.event.inputs.azure_env_log_anlytics_workspace_id || '' }} + azure_existing_ai_project_resource_id: ${{ github.event.inputs.azure_existing_ai_project_resource_id || '' }} + existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} + trigger_type: ${{ github.event_name }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/job-azure-deploy.yml b/.github/workflows/job-azure-deploy.yml new file mode 100644 index 000000000..ac3562b69 --- /dev/null +++ b/.github/workflows/job-azure-deploy.yml @@ -0,0 +1,400 @@ +name: Deploy Job v2 + +on: + workflow_call: + inputs: + trigger_type: + description: 'Trigger type (workflow_dispatch, pull_request, schedule)' + required: true + type: string + runner_os: + description: 'Runner OS (ubuntu-latest or windows-latest)' + required: true + type: string + azure_location: + description: 'Azure Location For Deployment' + required: false + default: 'australiaeast' + type: string + resource_group_name: + description: 'Resource Group Name (Optional)' + required: false + default: '' + type: string + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + exp: + description: 'Enable EXP' + required: false + default: false + type: boolean + build_docker_image: + description: 'Build And Push Docker Image (Optional)' + required: false + default: false + type: boolean + cleanup_resources: + description: 'Cleanup Deployed Resources' + required: false + default: false + type: boolean + run_e2e_tests: + description: 'Run End-to-End Tests' + required: false + default: 'GoldenPath-Testing' + type: string + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + azure_env_log_anlytics_workspace_id: + description: 'Log Analytics Workspace ID (Optional)' + required: false + default: '' + type: string + azure_existing_ai_project_resource_id: + description: 'AI Project Resource ID (Optional)' + required: false + default: '' + type: string + docker_image_tag: + description: 'Docker Image Tag from build job' + required: false + default: '' + type: string + secrets: + AZURE_CLIENT_ID: + required: true + AZURE_CLIENT_SECRET: + required: true + AZURE_TENANT_ID: + required: true + AZURE_SUBSCRIPTION_ID: + required: true + ACR_TEST_LOGIN_SERVER: + required: true + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + required: false + AZURE_ENV_FOUNDRY_PROJECT_ID: + required: false + outputs: + invoice_schema_id: + description: "Invoice Schema ID" + value: ${{ jobs.deploy-linux.outputs.invoice_schema_id || jobs.deploy-windows.outputs.invoice_schema_id }} + propertydamageclaimform_schema_id: + description: "Property Damage Claim Form Schema ID" + value: ${{ jobs.deploy-linux.outputs.propertydamageclaimform_schema_id || jobs.deploy-windows.outputs.propertydamageclaimform_schema_id }} + RESOURCE_GROUP_NAME: + description: "Resource Group Name" + value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} + CONTAINER_WEB_APPURL: + description: "Container Web App URL" + value: ${{ jobs.deploy-linux.outputs.CONTAINER_WEB_APPURL || jobs.deploy-windows.outputs.CONTAINER_WEB_APPURL }} + ENV_NAME: + description: "Environment Name" + value: ${{ jobs.azure-setup.outputs.ENV_NAME }} + AZURE_LOCATION: + description: "Azure Location" + value: ${{ jobs.azure-setup.outputs.AZURE_LOCATION }} + AZURE_ENV_OPENAI_LOCATION: + description: "Azure OpenAI Location" + value: ${{ jobs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }} + IMAGE_TAG: + description: "Docker Image Tag Used" + value: ${{ jobs.azure-setup.outputs.IMAGE_TAG }} + QUOTA_FAILED: + description: "Quota Check Failed Flag" + value: ${{ jobs.azure-setup.outputs.QUOTA_FAILED }} + +env: + GPT_MIN_CAPACITY: 100 + BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} + WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }} + EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }} + CLEANUP_RESOURCES: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.cleanup_resources || true) || true }} + RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }} + BUILD_DOCKER_IMAGE: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.build_docker_image || false) || false }} + +jobs: + azure-setup: + name: Azure Setup + if: inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null + runs-on: ubuntu-latest + outputs: + RESOURCE_GROUP_NAME: ${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }} + ENV_NAME: ${{ steps.generate_env_name.outputs.ENV_NAME }} + AZURE_LOCATION: ${{ steps.set_region.outputs.AZURE_LOCATION }} + AZURE_ENV_OPENAI_LOCATION: ${{ steps.set_region.outputs.AZURE_ENV_OPENAI_LOCATION }} + IMAGE_TAG: ${{ steps.determine_image_tag.outputs.IMAGE_TAG }} + QUOTA_FAILED: ${{ steps.quota_failure_output.outputs.QUOTA_FAILED }} + + steps: + - name: Validate and Auto-Configure EXP + shell: bash + run: | + echo "πŸ” Validating EXP configuration..." + + if [[ "${{ inputs.exp }}" != "true" ]]; then + if [[ -n "${{ inputs.azure_env_log_anlytics_workspace_id }}" ]] || [[ -n "${{ inputs.azure_existing_ai_project_resource_id }}" ]]; then + echo "πŸ”§ AUTO-ENABLING EXP: EXP parameter values were provided but EXP was not explicitly enabled." + echo "" + echo "You provided values for:" + [[ -n "${{ inputs.azure_env_log_anlytics_workspace_id }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.azure_env_log_anlytics_workspace_id }}'" + [[ -n "${{ inputs.azure_existing_ai_project_resource_id }}" ]] && echo " - Azure AI Project Resource ID: '${{ inputs.azure_existing_ai_project_resource_id }}'" + echo "" + echo "βœ… Automatically enabling EXP to use these values." + echo "EXP=true" >> $GITHUB_ENV + echo "πŸ“Œ EXP has been automatically enabled for this deployment." + fi + fi + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Login to Azure + shell: bash + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Run Quota Check + id: quota-check + shell: bash + run: | + export AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }} + export AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }} + export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }} + export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" + export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }} + export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}" + + chmod +x infra/scripts/checkquota.sh + if ! infra/scripts/checkquota.sh; then + if grep -q "No region with sufficient quota found" infra/scripts/checkquota.sh; then + echo "QUOTA_FAILED=true" >> $GITHUB_ENV + fi + exit 1 + fi + + - name: Set Quota Failure Output + id: quota_failure_output + if: env.QUOTA_FAILED == 'true' + shell: bash + run: | + echo "QUOTA_FAILED=true" >> $GITHUB_OUTPUT + echo "Quota check failed - will notify via separate notification job" + + - name: Fail Pipeline if Quota Check Fails + if: env.QUOTA_FAILED == 'true' + shell: bash + run: exit 1 + + - name: Set Deployment Region + id: set_region + shell: bash + run: | + echo "Selected Region from Quota Check: $VALID_REGION" + echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_ENV + echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT + + if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then + USER_SELECTED_LOCATION="${{ inputs.azure_location }}" + echo "Using user-selected Azure location: $USER_SELECTED_LOCATION" + echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_OUTPUT + else + echo "Using location from quota check for automatic triggers: $VALID_REGION" + echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT + fi + + - name: Generate Resource Group Name + id: generate_rg_name + shell: bash + run: | + # Check if a resource group name was provided as input + if [[ -n "${{ inputs.resource_group_name }}" ]]; then + echo "Using provided Resource Group name: ${{ inputs.resource_group_name }}" + echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV + else + echo "Generating a unique resource group name..." + ACCL_NAME="cp" # Account name as specified + SHORT_UUID=$(uuidgen | cut -d'-' -f1) + UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}" + echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV + echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}" + fi + + - name: Install Bicep CLI + shell: bash + run: az bicep install + + - name: Check and Create Resource Group + id: check_create_rg + shell: bash + run: | + set -e + echo "πŸ” Checking if resource group '$RESOURCE_GROUP_NAME' exists..." + rg_exists=$(az group exists --name $RESOURCE_GROUP_NAME) + if [ "$rg_exists" = "false" ]; then + echo "πŸ“¦ Resource group does not exist. Creating new resource group '$RESOURCE_GROUP_NAME' in location '$AZURE_LOCATION'..." + az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION || { echo "❌ Error creating resource group"; exit 1; } + echo "βœ… Resource group '$RESOURCE_GROUP_NAME' created successfully." + else + echo "βœ… Resource group '$RESOURCE_GROUP_NAME' already exists. Deploying to existing resource group." + fi + echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT + echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV + + - name: Generate Unique Solution Prefix + id: generate_solution_prefix + shell: bash + run: | + set -e + COMMON_PART="psldg" + TIMESTAMP=$(date +%s) + UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6) + UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}" + echo "SOLUTION_PREFIX=${UNIQUE_SOLUTION_PREFIX}" >> $GITHUB_ENV + echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}" + + - name: Determine Docker Image Tag + id: determine_image_tag + shell: bash + run: | + if [[ "${{ env.BUILD_DOCKER_IMAGE }}" == "true" ]]; then + if [[ -n "${{ inputs.docker_image_tag }}" ]]; then + IMAGE_TAG="${{ inputs.docker_image_tag }}" + echo "πŸ”— Using Docker image tag from build job: $IMAGE_TAG" + else + echo "❌ Docker build job failed or was skipped, but BUILD_DOCKER_IMAGE is true" + exit 1 + fi + else + echo "🏷️ Using existing Docker image based on branch..." + BRANCH_NAME="${{ env.BRANCH_NAME }}" + echo "Current branch: $BRANCH_NAME" + + if [[ "$BRANCH_NAME" == "main" ]]; then + IMAGE_TAG="latest" + echo "Using main branch - image tag: latest" + elif [[ "$BRANCH_NAME" == "dev" ]]; then + IMAGE_TAG="dev" + echo "Using dev branch - image tag: dev" + elif [[ "$BRANCH_NAME" == "demo" ]]; then + IMAGE_TAG="demo" + echo "Using demo branch - image tag: demo" + elif [[ "$BRANCH_NAME" == "hotfix" ]]; then + BASE_TAG="hotfix" + elif [[ "$BRANCH_NAME" == "dependabotchanges" ]]; then + BASE_TAG="dependabotchanges" + else + IMAGE_TAG="latest" + echo "Using default for branch '$BRANCH_NAME' - image tag: latest" + fi + + echo "Using existing Docker image tag: $IMAGE_TAG" + fi + + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT + + - name: Generate Unique Environment Name + id: generate_env_name + shell: bash + run: | + COMMON_PART="pslc" + TIMESTAMP=$(date +%s) + UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6) + UNIQUE_ENV_NAME="${COMMON_PART}${UPDATED_TIMESTAMP}" + echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_ENV + echo "Generated Environment Name: ${UNIQUE_ENV_NAME}" + echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_OUTPUT + + - name: Display Workflow Configuration to GitHub Summary + shell: bash + run: | + echo "## πŸ“‹ Workflow Configuration Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Configuration | Value |" >> $GITHUB_STEP_SUMMARY + echo "|---------------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| **Trigger Type** | \`${{ github.event_name }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Branch** | \`${{ env.BRANCH_NAME }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Runner OS** | \`${{ inputs.runner_os }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **WAF Enabled** | ${{ env.WAF_ENABLED == 'true' && 'βœ… Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **EXP Enabled** | ${{ env.EXP == 'true' && 'βœ… Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Run E2E Tests** | \`${{ env.RUN_E2E_TESTS }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Cleanup Resources** | ${{ env.CLEANUP_RESOURCES == 'true' && 'βœ… Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Build Docker Image** | ${{ env.BUILD_DOCKER_IMAGE == 'true' && 'βœ… Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY + + if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then + echo "| **Azure Location** | \`${{ inputs.azure_location }}\` (User Selected) |" >> $GITHUB_STEP_SUMMARY + fi + + if [[ -n "${{ inputs.resource_group_name }}" ]]; then + echo "| **Resource Group** | \`${{ inputs.resource_group_name }}\` (Pre-specified) |" >> $GITHUB_STEP_SUMMARY + else + echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` (Auto-generated) |" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + + if [[ "${{ inputs.trigger_type }}" != "workflow_dispatch" ]]; then + echo "ℹ️ **Note:** Automatic Trigger - Using Non-WAF + Non-EXP configuration" >> $GITHUB_STEP_SUMMARY + else + echo "ℹ️ **Note:** Manual Trigger - Using user-specified configuration" >> $GITHUB_STEP_SUMMARY + fi + + deploy-linux: + name: Deploy on Linux + needs: azure-setup + if: inputs.runner_os == 'ubuntu-latest' && always() && needs.azure-setup.result == 'success' + uses: ./.github/workflows/job-deploy-linux.yml + with: + ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }} + AZURE_ENV_OPENAI_LOCATION: ${{ needs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }} + AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }} + RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }} + IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }} + BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }} + EXP: ${{ github.event.inputs.exp || 'false' }} + WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }} + secrets: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} + + deploy-windows: + name: Deploy on Windows + needs: azure-setup + if: inputs.runner_os == 'windows-latest' && always() && needs.azure-setup.result == 'success' + uses: ./.github/workflows/job-deploy-windows.yml + with: + ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }} + AZURE_ENV_OPENAI_LOCATION: ${{ needs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }} + AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }} + RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }} + IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }} + BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }} + EXP: ${{ github.event.inputs.exp || 'false' }} + WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }} + secrets: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} \ No newline at end of file diff --git a/.github/workflows/job-cleanup-resources.yml b/.github/workflows/job-cleanup-resources.yml new file mode 100644 index 000000000..12e6a6cfc --- /dev/null +++ b/.github/workflows/job-cleanup-resources.yml @@ -0,0 +1,125 @@ +name: Cleanup Deployment Job v2 + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS (ubuntu-latest or windows-latest)' + required: true + type: string + trigger_type: + description: 'Trigger type (workflow_dispatch, pull_request, schedule)' + required: true + type: string + cleanup_resources: + description: 'Cleanup Deployed Resources' + required: false + default: false + type: boolean + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + RESOURCE_GROUP_NAME: + description: 'Resource Group Name to cleanup' + required: true + type: string + AZURE_LOCATION: + description: 'Azure Location' + required: true + type: string + AZURE_ENV_OPENAI_LOCATION: + description: 'Azure OpenAI Location' + required: true + type: string + ENV_NAME: + description: 'Environment Name' + required: true + type: string + IMAGE_TAG: + description: 'Docker Image Tag' + required: true + type: string + secrets: + AZURE_CLIENT_ID: + required: true + AZURE_CLIENT_SECRET: + required: true + AZURE_TENANT_ID: + required: true + AZURE_SUBSCRIPTION_ID: + required: true + +jobs: + cleanup-deployment: + if: inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null) + runs-on: ${{ inputs.runner_os }} + continue-on-error: true + env: + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} + AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} + ENV_NAME: ${{ inputs.ENV_NAME }} + IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + steps: + - name: Setup Azure CLI + shell: bash + run: | + if [[ "${{ runner.os }}" == "Linux" ]]; then + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + fi + az --version + + - name: Login to Azure + shell: bash + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Delete Resource Group (Optimized Cleanup) + id: delete_rg + shell: bash + run: | + set -e + echo "πŸ—‘οΈ Starting optimized resource cleanup..." + echo "Deleting resource group: ${{ env.RESOURCE_GROUP_NAME }}" + + az group delete \ + --name "${{ env.RESOURCE_GROUP_NAME }}" \ + --yes \ + --no-wait + + echo "βœ… Resource group deletion initiated (running asynchronously)" + echo "Note: Resources will be cleaned up in the background" + + - name: Logout from Azure + if: always() + shell: bash + run: | + azd auth logout || true + az logout || echo "Warning: Failed to logout from Azure CLI" + echo "Logged out from Azure." + + - name: Generate Cleanup Job Summary + if: always() + shell: bash + run: | + echo "## 🧹 Cleanup Job Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| **Resouce Group deletion Status** | ${{ steps.delete_rg.outcome == 'success' && 'βœ… Initiated' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ steps.delete_rg.outcome }}" == "success" ]]; then + echo "### βœ… Cleanup Details" >> $GITHUB_STEP_SUMMARY + echo "- Successfully initiated deletion for Resource Group \`${{ env.RESOURCE_GROUP_NAME }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Cleanup Failed" >> $GITHUB_STEP_SUMMARY + echo "- Cleanup process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Manual cleanup may be required for:" >> $GITHUB_STEP_SUMMARY + echo " - Resource Group: \`${{ env.RESOURCE_GROUP_NAME }}\`" >> $GITHUB_STEP_SUMMARY + echo "- Check the cleanup-deployment job logs for detailed error information" >> $GITHUB_STEP_SUMMARY + fi \ No newline at end of file diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml new file mode 100644 index 000000000..800dd5591 --- /dev/null +++ b/.github/workflows/job-docker-build.yml @@ -0,0 +1,131 @@ +name: Docker Build Job + +on: + workflow_call: + inputs: + trigger_type: + description: 'Trigger type (workflow_dispatch, pull_request, schedule)' + required: true + type: string + build_docker_image: + description: 'Build And Push Docker Image (Optional)' + required: false + default: false + type: boolean + secrets: + ACR_TEST_LOGIN_SERVER: + required: true + ACR_TEST_USERNAME: + required: true + ACR_TEST_PASSWORD: + required: true + outputs: + IMAGE_TAG: + description: "Generated Docker Image Tag" + value: ${{ jobs.docker-build.outputs.IMAGE_TAG }} + +env: + BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} + +jobs: + docker-build: + if: inputs.trigger_type == 'workflow_dispatch' && inputs.build_docker_image == true + runs-on: ubuntu-latest + outputs: + IMAGE_TAG: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Generate Unique Docker Image Tag + id: generate_docker_tag + shell: bash + run: | + echo "πŸ”¨ Building new Docker image - generating unique tag..." + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + RUN_ID="${{ github.run_id }}" + BRANCH_NAME="${{ github.head_ref || github.ref_name }}" + CLEAN_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9._-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + UNIQUE_TAG="${CLEAN_BRANCH_NAME}-${TIMESTAMP}-${RUN_ID}" + echo "IMAGE_TAG=$UNIQUE_TAG" >> $GITHUB_ENV + echo "IMAGE_TAG=$UNIQUE_TAG" >> $GITHUB_OUTPUT + echo "Generated unique Docker tag: $UNIQUE_TAG" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Azure Container Registry + uses: azure/docker-login@v2 + with: + login-server: ${{ secrets.ACR_TEST_LOGIN_SERVER }} + username: ${{ secrets.ACR_TEST_USERNAME }} + password: ${{ secrets.ACR_TEST_PASSWORD }} + + # - name: Build and Push ContentProcessor Docker image + # uses: docker/build-push-action@v6 + # env: + # DOCKER_BUILD_SUMMARY: false + # with: + # context: ./src/ContentProcessor + # file: ./src/ContentProcessor/Dockerfile + # push: true + # tags: | + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + + # - name: Build and Push ContentProcessorAPI Docker image + # uses: docker/build-push-action@v6 + # env: + # DOCKER_BUILD_SUMMARY: false + # with: + # context: ./src/ContentProcessorAPI + # file: ./src/ContentProcessorAPI/Dockerfile + # push: true + # tags: | + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + + # - name: Build and Push ContentProcessorWeb Docker image + # uses: docker/build-push-action@v6 + # env: + # DOCKER_BUILD_SUMMARY: false + # with: + # context: ./src/ContentProcessorWeb + # file: ./src/ContentProcessorWeb/Dockerfile + # push: true + # tags: | + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + + - name: Verify Docker Image Build + shell: bash + run: | + echo "βœ… Docker image successfully built and pushed" + echo "Image tag: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}" + + - name: Generate Docker Build Summary + if: always() + shell: bash + run: | + ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}") + echo "## 🐳 Docker Build Job Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| **Job Status** | ${{ job.status == 'success' && 'βœ… Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Image Tag** | \`${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Branch** | ${{ env.BRANCH_NAME }} |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ job.status }}" == "success" ]]; then + echo "### βœ… Build Details" >> $GITHUB_STEP_SUMMARY + echo "Successfully built and pushed three Docker images to ACR:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Build Failed" >> $GITHUB_STEP_SUMMARY + echo "- Docker build process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Check the docker-build job for detailed error information" >> $GITHUB_STEP_SUMMARY + fi \ No newline at end of file diff --git a/.github/workflows/job-send-notifications.yml b/.github/workflows/job-send-notifications.yml new file mode 100644 index 000000000..c1280cdac --- /dev/null +++ b/.github/workflows/job-send-notifications.yml @@ -0,0 +1,227 @@ +name: Send Notification Job v2 + +on: + workflow_call: + inputs: + trigger_type: + description: 'Trigger type (workflow_dispatch, pull_request, schedule)' + required: true + type: string + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + exp: + description: 'Enable EXP' + required: false + default: false + type: boolean + run_e2e_tests: + description: 'Run End-to-End Tests' + required: false + default: 'GoldenPath-Testing' + type: string + existing_webapp_url: + description: 'Existing Container WebApp URL (Skips Deployment)' + required: false + default: '' + type: string + deploy_result: + description: 'Deploy job result (success, failure, skipped)' + required: true + type: string + e2e_test_result: + description: 'E2E test job result (success, failure, skipped)' + required: true + type: string + CONTAINER_WEB_APPURL: + description: 'Container Web App URL' + required: false + default: '' + type: string + RESOURCE_GROUP_NAME: + description: 'Resource Group Name' + required: false + default: '' + type: string + QUOTA_FAILED: + description: 'Quota Check Failed Flag' + required: false + default: 'false' + type: string + TEST_SUCCESS: + description: 'Test Success Flag' + required: false + default: '' + type: string + TEST_REPORT_URL: + description: 'Test Report URL' + required: false + default: '' + type: string + secrets: + EMAILNOTIFICATION_LOGICAPP_URL_TA: + required: false + +env: + GPT_MIN_CAPACITY: 100 + BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} + WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }} + EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }} + RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }} + +jobs: + send-notification: + runs-on: ubuntu-latest + continue-on-error: true + env: + accelerator_name: "Content Processing" + steps: + - name: Determine Test Suite Display Name + id: test_suite + shell: bash + run: | + if [ "${{ env.RUN_E2E_TESTS }}" = "GoldenPath-Testing" ]; then + TEST_SUITE_NAME="Golden Path Testing" + elif [ "${{ env.RUN_E2E_TESTS }}" = "Smoke-Testing" ]; then + TEST_SUITE_NAME="Smoke Testing" + elif [ "${{ env.RUN_E2E_TESTS }}" = "None" ]; then + TEST_SUITE_NAME="None" + else + TEST_SUITE_NAME="${{ env.RUN_E2E_TESTS }}" + fi + echo "TEST_SUITE_NAME=$TEST_SUITE_NAME" >> $GITHUB_OUTPUT + echo "Test Suite: $TEST_SUITE_NAME" + + - name: Send Quota Failure Notification + if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED == 'true' + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${{ env.accelerator_name }} deployment has failed due to insufficient quota in the requested regions.

Issue Details:
β€’ Quota check failed for GPT model
β€’ Required GPT Capacity: ${{ env.GPT_MIN_CAPACITY }}
β€’ Checked Regions: ${{ vars.AZURE_REGIONS }}

Run URL: ${RUN_URL}

Please resolve the quota issue and retry the deployment.

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Failed (Insufficient Quota)" + } + EOF + ) + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send quota failure notification" + + - name: Send Deployment Failure Notification + if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED != 'true' + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" + + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${{ env.accelerator_name }} deployment process has encountered an issue and has failed to complete successfully.

Deployment Details:
β€’ Resource Group: ${RESOURCE_GROUP}
β€’ WAF Enabled: ${{ env.WAF_ENABLED }}
β€’ EXP Enabled: ${{ env.EXP }}

Run URL: ${RUN_URL}

Please investigate the deployment failure at your earliest convenience.

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Failed" + } + EOF + ) + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send deployment failure notification" + + - name: Send Success Notification + if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.TEST_SUCCESS == 'true') + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}" + RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" + TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" + + if [ "${{ inputs.e2e_test_result }}" = "skipped" ]; then + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${{ env.accelerator_name }} deployment has completed successfully.

Deployment Details:
β€’ Resource Group: ${RESOURCE_GROUP}
β€’ Web App URL: ${WEBAPP_URL}
β€’ E2E Tests: Skipped (as configured)

Configuration:
β€’ WAF Enabled: ${{ env.WAF_ENABLED }}
β€’ EXP Enabled: ${{ env.EXP }}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Deployment Success" + } + EOF + ) + else + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${{ env.accelerator_name }} deployment and testing process has completed successfully.

Deployment Details:
β€’ Resource Group: ${RESOURCE_GROUP}
β€’ Web App URL: ${WEBAPP_URL}
β€’ E2E Tests: Passed βœ…
β€’ Test Suite: ${TEST_SUITE_NAME}
β€’ Test Report: View Report

Configuration:
β€’ WAF Enabled: ${{ env.WAF_ENABLED }}
β€’ EXP Enabled: ${{ env.EXP }}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Success" + } + EOF + ) + fi + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send success notification" + + - name: Send Test Failure Notification + if: inputs.deploy_result == 'success' && inputs.e2e_test_result != 'skipped' && inputs.TEST_SUCCESS != 'true' + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" + WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}" + RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" + + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that ${{ env.accelerator_name }} accelerator test automation process has encountered issues and failed to complete successfully.

Deployment Details:
β€’ Resource Group: ${RESOURCE_GROUP}
β€’ Web App URL: ${WEBAPP_URL}
β€’ Deployment Status: βœ… Success
β€’ E2E Tests: ❌ Failed
β€’ Test Suite: ${TEST_SUITE_NAME}

Test Details:
β€’ Test Report: View Report

Run URL: ${RUN_URL}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Failed" + } + EOF + ) + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send test failure notification" + + - name: Send Existing URL Success Notification + if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'success' && (inputs.TEST_SUCCESS == 'true' || inputs.TEST_SUCCESS == '') + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + EXISTING_URL="${{ inputs.existing_webapp_url }}" + TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" + + EMAIL_BODY=$(cat <Dear Team,

The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and testing process has completed successfully.

Test Results:
β€’ Status: βœ… Passed
β€’ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+β€’ Test Report: View Report}
β€’ Target URL: ${EXISTING_URL}

Deployment: Skipped

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Passed (Existing URL)" + } + EOF + ) + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send existing URL success notification" + + - name: Send Existing URL Test Failure Notification + if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'failure' + shell: bash + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + EXISTING_URL="${{ inputs.existing_webapp_url }}" + TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" + + EMAIL_BODY=$(cat <Dear Team,

The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.

Failure Details:
β€’ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+β€’ Test Report: View Report}
β€’ Test Suite: ${TEST_SUITE_NAME}
β€’ Deployment: Skipped

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", + "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Failed (Existing URL)" + } + EOF + ) + + curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send existing URL test failure notification" \ No newline at end of file diff --git a/.github/workflows/job-test-automation.yml b/.github/workflows/job-test-automation.yml new file mode 100644 index 000000000..c0b9dca52 --- /dev/null +++ b/.github/workflows/job-test-automation.yml @@ -0,0 +1,185 @@ +name: Test Automation KMGeneric v2 + +on: + workflow_call: + inputs: + KMGENERIC_URL: + required: false + type: string + description: "Web URL for KMGeneric (overrides environment variable)" + KMGENERIC_URL_API: + required: false + type: string + description: "API URL for KMGeneric (overrides environment variable)" + TEST_SUITE: + required: false + type: string + default: "GoldenPath-Testing" + description: "Test suite to run: 'Smoke-Testing', 'GoldenPath-Testing' " + secrets: + EMAILNOTIFICATION_LOGICAPP_URL_TA: + required: false + description: "Logic App URL for email notifications" + outputs: + TEST_SUCCESS: + description: "Whether tests passed" + value: ${{ jobs.test.outputs.TEST_SUCCESS }} + TEST_REPORT_URL: + description: "URL to test report artifact" + value: ${{ jobs.test.outputs.TEST_REPORT_URL }} +env: + # Use input URL if provided (from deploy pipeline), otherwise fall back to vars + url: ${{ inputs.KMGENERIC_URL }} + api_url: ${{ inputs.KMGENERIC_URL_API}} + accelerator_name: "KMGeneric" + test_suite: ${{ inputs.TEST_SUITE }} + +jobs: + test: + runs-on: ubuntu-latest + outputs: + TEST_SUCCESS: ${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }} + TEST_REPORT_URL: ${{ steps.upload_report.outputs.artifact-url }} + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.13' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r tests/e2e-test/requirements.txt + + - name: Ensure browsers are installed + run: python -m playwright install --with-deps chromium + + - name: Validate URL + run: | + if [ -z "${{ env.url }}" ]; then + echo "ERROR: No URL provided for testing" + exit 1 + elif [ -z "${{ env.api_url }}" ]; then + echo "ERROR: No API URL provided for testing" + exit 1 + fi + echo "Testing URL: ${{ env.url }}" + echo "Testing API URL: ${{ env.api_url }}" + + - name: Wait for Application to be Ready + run: | + echo "Waiting for application to be ready at ${{ env.url }} " + max_attempts=10 + attempt=1 + + while [ $attempt -le $max_attempts ]; do + echo "Attempt $attempt: Checking if application is ready..." + if curl -f -s "${{ env.url }}" > /dev/null; then + echo "Application is ready!" + break + fi + + if [ $attempt -eq $max_attempts ]; then + echo "Application is not ready after $max_attempts attempts" + exit 1 + fi + + echo "Application not ready, waiting 30 seconds..." + sleep 30 + attempt=$((attempt + 1)) + done + + - name: Run tests(1) + id: test1 + run: | + xvfb-run pytest --headed --html=report/report.html --self-contained-html + working-directory: tests/e2e-test + continue-on-error: true + + - name: Sleep for 30 seconds + if: ${{ steps.test1.outcome == 'failure' }} + run: sleep 30s + shell: bash + + - name: Run tests(2) + if: ${{ steps.test1.outcome == 'failure' }} + id: test2 + run: | + xvfb-run pytest --headed --html=report/report.html --self-contained-html + working-directory: tests/e2e-test + continue-on-error: true + + - name: Sleep for 60 seconds + if: ${{ steps.test2.outcome == 'failure' }} + run: sleep 60s + shell: bash + + - name: Run tests(3) + if: ${{ steps.test2.outcome == 'failure' }} + id: test3 + run: | + xvfb-run pytest --headed --html=report/report.html --self-contained-html + working-directory: tests/e2e-test + + - name: Upload test report + id: upload_report + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + + name: test-report-${{ github.run_id }} + path: tests/e2e-test/report/* + + - name: Generate E2E Test Summary + if: always() + run: | + # Determine test suite type for title + if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then + echo "## πŸ§ͺ E2E Test Job Summary : Golden Path Testing" >> $GITHUB_STEP_SUMMARY + else + echo "## πŸ§ͺ E2E Test Job Summary : Smoke Testing" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + + # Determine overall test result + OVERALL_SUCCESS="${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}" + if [[ "$OVERALL_SUCCESS" == "true" ]]; then + echo "| **Job Status** | βœ… Success |" >> $GITHUB_STEP_SUMMARY + else + echo "| **Job Status** | ❌ Failed |" >> $GITHUB_STEP_SUMMARY + fi + + echo "| **Target URL** | [${{ env.url }}](${{ env.url }}) |" >> $GITHUB_STEP_SUMMARY + echo "| **Test Suite** | \`${{ env.test_suite }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Test Report** | [Download Artifact](${{ steps.upload_report.outputs.artifact-url }}) |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### πŸ“‹ Test Execution Details" >> $GITHUB_STEP_SUMMARY + echo "| Attempt | Status | Notes |" >> $GITHUB_STEP_SUMMARY + echo "|---------|--------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| **Test Run 1** | ${{ steps.test1.outcome == 'success' && 'βœ… Passed' || '❌ Failed' }} | Initial test execution |" >> $GITHUB_STEP_SUMMARY + + if [[ "${{ steps.test1.outcome }}" == "failure" ]]; then + echo "| **Test Run 2** | ${{ steps.test2.outcome == 'success' && 'βœ… Passed' || steps.test2.outcome == 'failure' && '❌ Failed' || '⏸️ Skipped' }} | Retry after 30s delay |" >> $GITHUB_STEP_SUMMARY + fi + + if [[ "${{ steps.test2.outcome }}" == "failure" ]]; then + echo "| **Test Run 3** | ${{ steps.test3.outcome == 'success' && 'βœ… Passed' || steps.test3.outcome == 'failure' && '❌ Failed' || '⏸️ Skipped' }} | Final retry after 60s delay |" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + + if [[ "$OVERALL_SUCCESS" == "true" ]]; then + echo "### βœ… Test Results" >> $GITHUB_STEP_SUMMARY + echo "- End-to-end tests completed successfully" >> $GITHUB_STEP_SUMMARY + echo "- Application is functioning as expected" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Test Results" >> $GITHUB_STEP_SUMMARY + echo "- All test attempts failed" >> $GITHUB_STEP_SUMMARY + echo "- Check the e2e-test/test job for detailed error information" >> $GITHUB_STEP_SUMMARY + fi \ No newline at end of file From c6f291d55d4e63d84524ccfea1d536315702c9e5 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Tue, 2 Dec 2025 16:59:15 +0530 Subject: [PATCH 2/4] Enhance Deployment Pipeline --- .github/workflows/deploy-linux.yml | 8 +- .github/workflows/deploy-orchestrator.yml | 89 +++----- .github/workflows/deploy-windows.yml | 8 +- .github/workflows/job-azure-deploy.yml | 88 +++----- .github/workflows/job-cleanup-resources.yml | 34 ++- .github/workflows/job-deploy-linux.yml | 206 +++++++++++++++++++ .github/workflows/job-deploy-windows.yml | 200 ++++++++++++++++++ .github/workflows/job-docker-build.yml | 64 ++---- .github/workflows/job-send-notifications.yml | 65 +++--- .github/workflows/job-test-automation.yml | 2 +- infra/main.parameters.json | 13 +- infra/main.waf.parameters.json | 13 +- 12 files changed, 557 insertions(+), 233 deletions(-) create mode 100644 .github/workflows/job-deploy-linux.yml create mode 100644 .github/workflows/job-deploy-windows.yml diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index b6845dd41..2a467e60c 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -1,5 +1,9 @@ name: Deploy-Test-Cleanup Linux on: + push: + branches: + - main + - dev workflow_dispatch: inputs: azure_location: @@ -61,7 +65,7 @@ on: default: '' type: string existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string @@ -74,7 +78,7 @@ jobs: azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} - EXP: ${{ github.event.inputs.EXP == 'true' }} + exp: ${{ github.event.inputs.exp == 'true' }} build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }} cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index d2d5748d5..daa6a5389 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -1,4 +1,4 @@ -name: Deployment orchestrator v2 +name: Deployment orchestrator on: workflow_call: @@ -53,7 +53,7 @@ on: default: '' type: string existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string @@ -61,34 +61,6 @@ on: description: 'Trigger type (workflow_dispatch, pull_request, schedule)' required: true type: string - secrets: - AZURE_CLIENT_ID: - required: true - AZURE_CLIENT_SECRET: - required: true - AZURE_TENANT_ID: - required: true - AZURE_SUBSCRIPTION_ID: - required: true - ACR_TEST_LOGIN_SERVER: - required: true - ACR_TEST_USERNAME: - required: true - ACR_TEST_PASSWORD: - required: true - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: - required: false - AZURE_ENV_FOUNDRY_PROJECT_ID: - required: false - EMAILNOTIFICATION_LOGICAPP_URL_TA: - required: false - outputs: - CONTAINER_WEB_APPURL: - description: "Container Web App URL" - value: ${{ jobs.deploy.outputs.CONTAINER_WEB_APPURL }} - RESOURCE_GROUP_NAME: - description: "Resource Group Name" - value: ${{ jobs.deploy.outputs.RESOURCE_GROUP_NAME }} env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} @@ -99,10 +71,7 @@ jobs: with: trigger_type: ${{ inputs.trigger_type }} build_docker_image: ${{ inputs.build_docker_image }} - secrets: - ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} - ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }} - ACR_TEST_PASSWORD: ${{ secrets.ACR_TEST_PASSWORD }} + secrets: inherit deploy: if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null) @@ -114,28 +83,23 @@ jobs: azure_location: ${{ inputs.azure_location }} resource_group_name: ${{ inputs.resource_group_name }} waf_enabled: ${{ inputs.waf_enabled }} - EXP: ${{ inputs.exp }} + exp: ${{ inputs.exp }} build_docker_image: ${{ inputs.build_docker_image }} existing_webapp_url: ${{ inputs.existing_webapp_url }} azure_env_log_anlytics_workspace_id: ${{ inputs.azure_env_log_anlytics_workspace_id }} azure_existing_ai_project_resource_id: ${{ inputs.azure_existing_ai_project_resource_id }} docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }} - secrets: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.azure_env_log_anlytics_workspace_id }} - AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} + run_e2e_tests: ${{ inputs.run_e2e_tests }} + cleanup_resources: ${{ inputs.cleanup_resources }} + secrets: inherit e2e-test: - if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null)) + if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.WEB_APP_URL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null)) needs: [docker-build, deploy] uses: ./.github/workflows/job-test-automation.yml with: - KMGENERIC_URL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }} - KMGENERIC_URL_API: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }} + KMGENERIC_URL: ${{ needs.deploy.outputs.WEB_APP_URL || inputs.existing_webapp_url }} + KMGENERIC_URL_API: ${{ needs.deploy.outputs.API_APP_URL || inputs.existing_webapp_url }} TEST_SUITE: ${{ inputs.trigger_type == 'workflow_dispatch' && inputs.run_e2e_tests || 'GoldenPath-Testing' }} secrets: inherit @@ -146,21 +110,20 @@ jobs: with: trigger_type: ${{ inputs.trigger_type }} waf_enabled: ${{ inputs.waf_enabled }} - EXP: ${{ inputs.exp }} + exp: ${{ inputs.exp }} run_e2e_tests: ${{ inputs.run_e2e_tests }} existing_webapp_url: ${{ inputs.existing_webapp_url }} deploy_result: ${{ needs.deploy.result }} e2e_test_result: ${{ needs.e2e-test.result }} - CONTAINER_WEB_APPURL: ${{ needs.deploy.outputs.CONTAINER_WEB_APPURL }} - RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} - QUOTA_FAILED: ${{ needs.deploy.outputs.QUOTA_FAILED }} - TEST_SUCCESS: ${{ needs.e2e-test.outputs.TEST_SUCCESS }} - TEST_REPORT_URL: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }} - secrets: - EMAILNOTIFICATION_LOGICAPP_URL_TA: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} + web_app_url: ${{ needs.deploy.outputs.WEB_APP_URL }} + resource_group_name: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + quota_failed: ${{ needs.deploy.outputs.QUOTA_FAILED }} + test_success: ${{ needs.e2e-test.outputs.TEST_SUCCESS }} + test_report_url: ${{ needs.e2e-test.outputs.TEST_REPORT_URL }} + secrets: inherit cleanup-deployment: - if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null) + if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources) needs: [docker-build, deploy, e2e-test] uses: ./.github/workflows/job-cleanup-resources.yml with: @@ -168,13 +131,9 @@ jobs: trigger_type: ${{ inputs.trigger_type }} cleanup_resources: ${{ inputs.cleanup_resources }} existing_webapp_url: ${{ inputs.existing_webapp_url }} - RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} - AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }} - AZURE_ENV_OPENAI_LOCATION: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }} - ENV_NAME: ${{ needs.deploy.outputs.ENV_NAME }} - IMAGE_TAG: ${{ needs.deploy.outputs.IMAGE_TAG }} - secrets: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ No newline at end of file + resource_group_name: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + azure_location: ${{ needs.deploy.outputs.AZURE_LOCATION }} + azure_env_openai_location: ${{ needs.deploy.outputs.AZURE_ENV_OPENAI_LOCATION }} + env_name: ${{ needs.deploy.outputs.ENV_NAME }} + image_tag: ${{ needs.deploy.outputs.IMAGE_TAG }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml index 538e53694..743125817 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-windows.yml @@ -1,5 +1,9 @@ name: Deploy-Test-Cleanup Windows on: + push: + branches: + - main + - dev workflow_dispatch: inputs: azure_location: @@ -61,7 +65,7 @@ on: default: '' type: string existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string @@ -74,7 +78,7 @@ jobs: azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} - EXP: ${{ github.event.inputs.exp == 'true' }} + exp: ${{ github.event.inputs.exp == 'true' }} build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }} cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} diff --git a/.github/workflows/job-azure-deploy.yml b/.github/workflows/job-azure-deploy.yml index ac3562b69..de04f4767 100644 --- a/.github/workflows/job-azure-deploy.yml +++ b/.github/workflows/job-azure-deploy.yml @@ -1,4 +1,4 @@ -name: Deploy Job v2 +name: Deploy Job on: workflow_call: @@ -47,7 +47,7 @@ on: default: 'GoldenPath-Testing' type: string existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string @@ -66,34 +66,16 @@ on: required: false default: '' type: string - secrets: - AZURE_CLIENT_ID: - required: true - AZURE_CLIENT_SECRET: - required: true - AZURE_TENANT_ID: - required: true - AZURE_SUBSCRIPTION_ID: - required: true - ACR_TEST_LOGIN_SERVER: - required: true - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: - required: false - AZURE_ENV_FOUNDRY_PROJECT_ID: - required: false outputs: - invoice_schema_id: - description: "Invoice Schema ID" - value: ${{ jobs.deploy-linux.outputs.invoice_schema_id || jobs.deploy-windows.outputs.invoice_schema_id }} - propertydamageclaimform_schema_id: - description: "Property Damage Claim Form Schema ID" - value: ${{ jobs.deploy-linux.outputs.propertydamageclaimform_schema_id || jobs.deploy-windows.outputs.propertydamageclaimform_schema_id }} RESOURCE_GROUP_NAME: description: "Resource Group Name" value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} - CONTAINER_WEB_APPURL: - description: "Container Web App URL" - value: ${{ jobs.deploy-linux.outputs.CONTAINER_WEB_APPURL || jobs.deploy-windows.outputs.CONTAINER_WEB_APPURL }} + WEB_APP_URL: + description: "Web App URL" + value: ${{ jobs.deploy-linux.outputs.WEB_APP_URL || jobs.deploy-windows.outputs.WEB_APP_URL }} + API_APP_URL: + description: "API App URL" + value: ${{ jobs.deploy-linux.outputs.API_APP_URL || jobs.deploy-windows.outputs.API_APP_URL }} ENV_NAME: description: "Environment Name" value: ${{ jobs.azure-setup.outputs.ENV_NAME }} @@ -112,10 +94,11 @@ on: env: GPT_MIN_CAPACITY: 100 + TEXT_EMBEDDING_MIN_CAPACITY: 80 BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }} EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.exp || false) || false }} - CLEANUP_RESOURCES: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.cleanup_resources || true) || true }} + CLEANUP_RESOURCES: ${{ inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources }} RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }} BUILD_DOCKER_IMAGE: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.build_docker_image || false) || false }} @@ -155,6 +138,11 @@ jobs: - name: Checkout Code uses: actions/checkout@v4 + - name: Setup Azure CLI + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version + - name: Login to Azure shell: bash run: | @@ -170,29 +158,25 @@ jobs: export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }} export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }} + export TEXT_EMBEDDING_MIN_CAPACITY=${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}" - chmod +x infra/scripts/checkquota.sh - if ! infra/scripts/checkquota.sh; then - if grep -q "No region with sufficient quota found" infra/scripts/checkquota.sh; then + chmod +x infra/scripts/checkquota_km.sh + if ! infra/scripts/checkquota_km.sh; then + if grep -q "No region with sufficient quota found" infra/scripts/checkquota_km.sh; then echo "QUOTA_FAILED=true" >> $GITHUB_ENV fi exit 1 fi - - - name: Set Quota Failure Output - id: quota_failure_output - if: env.QUOTA_FAILED == 'true' - shell: bash - run: | - echo "QUOTA_FAILED=true" >> $GITHUB_OUTPUT - echo "Quota check failed - will notify via separate notification job" - name: Fail Pipeline if Quota Check Fails if: env.QUOTA_FAILED == 'true' shell: bash run: exit 1 - + + - name: Install Bicep CLI + run: az bicep install + - name: Set Deployment Region id: set_region shell: bash @@ -222,17 +206,13 @@ jobs: echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV else echo "Generating a unique resource group name..." - ACCL_NAME="cp" # Account name as specified + ACCL_NAME="kmgeneric" # Account name as specified SHORT_UUID=$(uuidgen | cut -d'-' -f1) UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}" echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}" fi - - name: Install Bicep CLI - shell: bash - run: az bicep install - - name: Check and Create Resource Group id: check_create_rg shell: bash @@ -255,7 +235,7 @@ jobs: shell: bash run: | set -e - COMMON_PART="psldg" + COMMON_PART="pslkmg" TIMESTAMP=$(date +%s) UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 6) UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}" @@ -365,14 +345,7 @@ jobs: WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }} AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }} - secrets: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} - AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} + secrets: inherit deploy-windows: name: Deploy on Windows @@ -390,11 +363,4 @@ jobs: WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.azure_env_log_anlytics_workspace_id }} AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.azure_existing_ai_project_resource_id }} - secrets: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - ACR_TEST_LOGIN_SERVER: ${{ secrets.ACR_TEST_LOGIN_SERVER }} - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} - AZURE_ENV_FOUNDRY_PROJECT_ID: ${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }} \ No newline at end of file + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/job-cleanup-resources.yml b/.github/workflows/job-cleanup-resources.yml index 12e6a6cfc..6d3399776 100644 --- a/.github/workflows/job-cleanup-resources.yml +++ b/.github/workflows/job-cleanup-resources.yml @@ -1,4 +1,4 @@ -name: Cleanup Deployment Job v2 +name: Cleanup Deployment Resources on: workflow_call: @@ -17,51 +17,41 @@ on: default: false type: boolean existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string - RESOURCE_GROUP_NAME: + resource_group_name: description: 'Resource Group Name to cleanup' required: true type: string - AZURE_LOCATION: + azure_location: description: 'Azure Location' required: true type: string - AZURE_ENV_OPENAI_LOCATION: + azure_env_openai_location: description: 'Azure OpenAI Location' required: true type: string - ENV_NAME: + env_name: description: 'Environment Name' required: true type: string - IMAGE_TAG: + image_tag: description: 'Docker Image Tag' required: true type: string - secrets: - AZURE_CLIENT_ID: - required: true - AZURE_CLIENT_SECRET: - required: true - AZURE_TENANT_ID: - required: true - AZURE_SUBSCRIPTION_ID: - required: true jobs: cleanup-deployment: - if: inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources == true || inputs.cleanup_resources == null) runs-on: ${{ inputs.runner_os }} continue-on-error: true env: - RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} - AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} - AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} - ENV_NAME: ${{ inputs.ENV_NAME }} - IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }} + AZURE_LOCATION: ${{ inputs.azure_location }} + AZURE_ENV_OPENAI_LOCATION: ${{ inputs.azure_env_openai_location }} + ENV_NAME: ${{ inputs.env_name }} + IMAGE_TAG: ${{ inputs.image_tag }} steps: - name: Setup Azure CLI shell: bash diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml new file mode 100644 index 000000000..a8fd32fa3 --- /dev/null +++ b/.github/workflows/job-deploy-linux.yml @@ -0,0 +1,206 @@ +name: Deploy Steps - Linux + +on: + workflow_call: + inputs: + ENV_NAME: + required: true + type: string + AZURE_ENV_OPENAI_LOCATION: + required: true + type: string + AZURE_LOCATION: + required: true + type: string + RESOURCE_GROUP_NAME: + required: true + type: string + IMAGE_TAG: + required: true + type: string + BUILD_DOCKER_IMAGE: + required: true + type: string + EXP: + required: true + type: string + WAF_ENABLED: + required: false + type: string + default: 'false' + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + required: false + type: string + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: + required: false + type: string + outputs: + WEB_APP_URL: + description: "Web App URL" + value: ${{ jobs.deploy-linux.outputs.WEB_APP_URL }} + API_APP_URL: + description: "API App URL" + value: ${{ jobs.deploy-linux.outputs.API_APP_URL }} + +jobs: + deploy-linux: + runs-on: ubuntu-latest + env: + AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + outputs: + WEB_APP_URL: ${{ steps.get_output_linux.outputs.WEB_APP_URL }} + API_APP_URL: ${{ steps.get_output_linux.outputs.API_APP_URL }} + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Configure Parameters Based on WAF Setting + shell: bash + run: | + if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then + cp infra/main.waf.parameters.json infra/main.parameters.json + echo "βœ… Successfully copied WAF parameters to main parameters file" + else + echo "πŸ”§ Configuring Non-WAF deployment - using default main.parameters.json..." + fi + + - name: Setup Azure CLI + shell: bash + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + + - name: Setup Azure Developer CLI (Linux) + if: runner.os == 'Linux' + shell: bash + run: | + curl -fsSL https://aka.ms/install-azd.sh | sudo bash + azd version + + - name: Login to AZD + id: login-azure + shell: bash + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }} + + - name: Deploy using azd up and extract values (Linux) + id: get_output_linux + shell: bash + run: | + set -e + echo "Starting azd deployment..." + echo "EXP: ${{ inputs.EXP }}" + echo "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}" + + # Install azd (Azure Developer CLI) + curl -fsSL https://aka.ms/install-azd.sh | bash + + # Generate current timestamp in desired format: YYYY-MM-DDTHH:MM:SS.SSSSSSSZ + current_date=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ") + + echo "Creating environment..." + azd env new ${{ inputs.ENV_NAME }} --no-prompt + echo "Environment created: ${{ inputs.ENV_NAME }}" + + echo "Setting default subscription..." + azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + # Set additional parameters + azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" + azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}" + azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}" + azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" + azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}" + + if [[ "${{ inputs.BUILD_DOCKER_IMAGE }}" == "true" ]]; then + ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}") + azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME" + echo "Set ACR name to: $ACR_NAME" + else + echo "Skipping ACR name configuration (using existing image)" + fi + + if [[ "${{ inputs.EXP }}" == "true" ]]; then + echo "βœ… EXP ENABLED - Setting EXP parameters..." + + if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then + EXP_LOG_ANALYTICS_ID="${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" + else + EXP_LOG_ANALYTICS_ID="${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" + fi + + if [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then + EXP_AI_PROJECT_ID="${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" + else + EXP_AI_PROJECT_ID="${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}" + fi + + echo "AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: $EXP_LOG_ANALYTICS_ID" + echo "AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: $EXP_AI_PROJECT_ID" + azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID="$EXP_LOG_ANALYTICS_ID" + azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID="$EXP_AI_PROJECT_ID" + else + echo "❌ EXP DISABLED - Skipping EXP parameters" + fi + + # Set tags for deployment + echo "Setting deployment tags..." + azd env set AZURE_TAG_SECURITY_CONTROL="Ignore" + + azd up --no-prompt + + echo "βœ… Deployment succeeded." + echo "$DEPLOY_OUTPUT" + + echo "Extracting deployment outputs..." + DEPLOY_OUTPUT=$(azd env get-values --output json) + echo "Deployment output: $DEPLOY_OUTPUT" + + if [[ -z "$DEPLOY_OUTPUT" ]]; then + echo "Error: Deployment output is empty. Please check the deployment logs." + exit 1 + fi + + export API_APP_URL="$(echo "$DEPLOY_OUTPUT" | jq -r '.API_APP_URL // empty')" + echo "API_APP_URL=$API_APP_URL" >> $GITHUB_ENV + echo "API_APP_URL=$API_APP_URL" >> $GITHUB_OUTPUT + + export WEB_APP_URL="$(echo "$DEPLOY_OUTPUT" | jq -r '.WEB_APP_URL // empty')" + echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_ENV + echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT + + - name: Generate Deployment Summary + if: always() + shell: bash + run: | + echo "## πŸš€ Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| **Job Status** | ${{ job.status == 'success' && 'βœ… Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ job.status }}" == "success" ]]; then + echo "### βœ… Deployment Details" >> $GITHUB_STEP_SUMMARY + echo "- **Container Web App URL**: [${{ env.WEB_APP_URL }}](${{ env.WEB_APP_URL }})" >> $GITHUB_STEP_SUMMARY + echo "- **Container API App URL**: [${{ env.API_APP_URL }}](${{ env.API_APP_URL }})" >> $GITHUB_STEP_SUMMARY + echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY + echo "- Schemas registered and sample data uploaded successfully" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY + echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Check the deployment steps above for detailed error information" >> $GITHUB_STEP_SUMMARY + fi + + - name: Logout from Azure + if: always() + shell: bash + run: | + az logout || true + echo "Logged out from Azure." \ No newline at end of file diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml new file mode 100644 index 000000000..82738623a --- /dev/null +++ b/.github/workflows/job-deploy-windows.yml @@ -0,0 +1,200 @@ +name: Deploy Steps - Windows + +on: + workflow_call: + inputs: + ENV_NAME: + required: true + type: string + AZURE_ENV_OPENAI_LOCATION: + required: true + type: string + AZURE_LOCATION: + required: true + type: string + RESOURCE_GROUP_NAME: + required: true + type: string + IMAGE_TAG: + required: true + type: string + BUILD_DOCKER_IMAGE: + required: true + type: string + EXP: + required: true + type: string + WAF_ENABLED: + required: false + type: string + default: 'false' + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + required: false + type: string + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: + required: false + type: string + AZURE_TAGS: + required: false + type: string + description: 'Optional JSON string of tags to apply to Azure resources' + outputs: + WEB_APP_URL: + description: "Web App URL" + value: ${{ jobs.deploy-windows.outputs.WEB_APP_URL }} + API_APP_URL: + description: "API App URL" + value: ${{ jobs.deploy-windows.outputs.API_APP_URL }} + +jobs: + deploy-windows: + runs-on: windows-latest + env: + AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + outputs: + WEB_APP_URL: ${{ steps.get_output_windows.outputs.WEB_APP_URL }} + API_APP_URL: ${{ steps.get_output_windows.outputs.API_APP_URL }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Configure Parameters Based on WAF Setting + shell: bash + run: | + if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then + cp infra/main.waf.parameters.json infra/main.parameters.json + echo "βœ… Successfully copied WAF parameters to main parameters file" + else + echo "πŸ”§ Configuring Non-WAF deployment - using default main.parameters.json..." + fi + + - name: Setup Azure Developer CLI (Windows) + uses: Azure/setup-azd@v2 + + - name: Login to AZD + id: login-azure + shell: bash + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }} + + + - name: Deploy using azd up and extract values (Windows) + id: get_output_windows + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + Write-Host "Starting azd deployment..." + Write-Host "EXP: ${{ inputs.EXP }}" + Write-Host "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}" + + Write-Host "Creating environment..." + azd env new ${{ inputs.ENV_NAME }} --no-prompt + Write-Host "Environment created: ${{ inputs.ENV_NAME }}" + + Write-Host "Setting default subscription..." + azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + # Set additional parameters + azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" + azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}" + azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}" + azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" + azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}" + + # Set ACR name only when building Docker image + if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") { + # Extract ACR name from login server and set as environment variable + $ACR_NAME = "${{ secrets.ACR_TEST_LOGIN_SERVER }}" + azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME" + Write-Host "Set ACR name to: $ACR_NAME" + } else { + Write-Host "Skipping ACR name configuration (using existing image)" + } + + if ("${{ inputs.EXP }}" -eq "true") { + Write-Host "βœ… EXP ENABLED - Setting EXP parameters..." + + # Set EXP variables dynamically + if ("${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" -ne "") { + $EXP_LOG_ANALYTICS_ID = "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" + } else { + $EXP_LOG_ANALYTICS_ID = "${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" + } + + if ("${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" -ne "") { + $EXP_AI_PROJECT_ID = "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" + } else { + $EXP_AI_PROJECT_ID = "${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}" + } + + Write-Host "AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: $EXP_LOG_ANALYTICS_ID" + Write-Host "AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: $EXP_AI_PROJECT_ID" + azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID="$EXP_LOG_ANALYTICS_ID" + azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID="$EXP_AI_PROJECT_ID" + } else { + Write-Host "❌ EXP DISABLED - Skipping EXP parameters" + } + + # Set tags for deployment + Write-Host "Setting deployment tags..." + azd env set AZURE_TAG_SECURITY_CONTROL="Ignore" + + # Deploy using azd up + azd up --no-prompt + + Write-Host "βœ… Deployment succeeded." + + # Get deployment outputs using azd + Write-Host "Extracting deployment outputs..." + $DEPLOY_OUTPUT = azd env get-values --output json | ConvertFrom-Json + Write-Host "Deployment output: $($DEPLOY_OUTPUT | ConvertTo-Json -Depth 10)" + + if (-not $DEPLOY_OUTPUT) { + Write-Host "Error: Deployment output is empty. Please check the deployment logs." + exit 1 + } + + # Export variables only after successful deploy + $API_APP_URL = $DEPLOY_OUTPUT.API_APP_URL + "API_APP_URL=$API_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "API_APP_URL=$API_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL + "WEB_APP_URL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "WEB_APP_URL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + - name: Generate Deployment Summary + if: always() + shell: bash + run: | + echo "## πŸš€ Deploy Job Summary (Windows)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| **Job Status** | ${{ job.status == 'success' && 'βœ… Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ "${{ job.status }}" == "success" ]; then + echo "### βœ… Deployment Details" >> $GITHUB_STEP_SUMMARY + echo "- **Container Web App URL**: [${{ env.WEB_APP_URL }}](${{ env.WEB_APP_URL }})" >> $GITHUB_STEP_SUMMARY + echo "- **Container API App URL**: [${{ env.API_APP_URL }}](${{ env.API_APP_URL }})" >> $GITHUB_STEP_SUMMARY + echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY + echo "- Schemas registered and sample data uploaded successfully" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY + echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Check the deployment steps above for detailed error information" >> $GITHUB_STEP_SUMMARY + fi + + - name: Logout from Azure + if: always() + shell: bash + run: | + az logout || true + echo "Logged out from Azure." \ No newline at end of file diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml index 800dd5591..7f7d99902 100644 --- a/.github/workflows/job-docker-build.yml +++ b/.github/workflows/job-docker-build.yml @@ -12,13 +12,6 @@ on: required: false default: false type: boolean - secrets: - ACR_TEST_LOGIN_SERVER: - required: true - ACR_TEST_USERNAME: - required: true - ACR_TEST_PASSWORD: - required: true outputs: IMAGE_TAG: description: "Generated Docker Image Tag" @@ -61,41 +54,25 @@ jobs: username: ${{ secrets.ACR_TEST_USERNAME }} password: ${{ secrets.ACR_TEST_PASSWORD }} - # - name: Build and Push ContentProcessor Docker image - # uses: docker/build-push-action@v6 - # env: - # DOCKER_BUILD_SUMMARY: false - # with: - # context: ./src/ContentProcessor - # file: ./src/ContentProcessor/Dockerfile - # push: true - # tags: | - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} - - # - name: Build and Push ContentProcessorAPI Docker image - # uses: docker/build-push-action@v6 - # env: - # DOCKER_BUILD_SUMMARY: false - # with: - # context: ./src/ContentProcessorAPI - # file: ./src/ContentProcessorAPI/Dockerfile - # push: true - # tags: | - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + - name: Build and Push Docker Image for WebApp + uses: docker/build-push-action@v6 + with: + context: ./src/App + file: ./src/App/WebApp.Dockerfile + push: True + tags: | + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-app:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-app:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} - # - name: Build and Push ContentProcessorWeb Docker image - # uses: docker/build-push-action@v6 - # env: - # DOCKER_BUILD_SUMMARY: false - # with: - # context: ./src/ContentProcessorWeb - # file: ./src/ContentProcessorWeb/Dockerfile - # push: true - # tags: | - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} - # ${{ secrets.ACR_TEST_LOGIN_SERVER }}/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + - name: Build and Push Docker Image for API + uses: docker/build-push-action@v6 + with: + context: ./src/api + file: ./src/api/ApiApp.Dockerfile + push: True + tags: | + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + ${{ secrets.ACR_TEST_LOGIN_SERVER }}/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} - name: Verify Docker Image Build shell: bash @@ -121,9 +98,8 @@ jobs: echo "Successfully built and pushed three Docker images to ACR:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Built Images:**" >> $GITHUB_STEP_SUMMARY - echo "- \`${ACR_NAME}.azurecr.io/contentprocessor:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY - echo "- \`${ACR_NAME}.azurecr.io/contentprocessorapi:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY - echo "- \`${ACR_NAME}.azurecr.io/contentprocessorweb:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/km-api:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${ACR_NAME}.azurecr.io/km-web:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY else echo "### ❌ Build Failed" >> $GITHUB_STEP_SUMMARY echo "- Docker build process encountered an error" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/job-send-notifications.yml b/.github/workflows/job-send-notifications.yml index c1280cdac..1ad104360 100644 --- a/.github/workflows/job-send-notifications.yml +++ b/.github/workflows/job-send-notifications.yml @@ -1,4 +1,4 @@ -name: Send Notification Job v2 +name: Send Notification Job on: workflow_call: @@ -23,7 +23,7 @@ on: default: 'GoldenPath-Testing' type: string existing_webapp_url: - description: 'Existing Container WebApp URL (Skips Deployment)' + description: 'Existing WebApp URL (Skips Deployment)' required: false default: '' type: string @@ -35,34 +35,31 @@ on: description: 'E2E test job result (success, failure, skipped)' required: true type: string - CONTAINER_WEB_APPURL: - description: 'Container Web App URL' + web_app_url: + description: 'Web App URL' required: false default: '' type: string - RESOURCE_GROUP_NAME: + resource_group_name: description: 'Resource Group Name' required: false default: '' type: string - QUOTA_FAILED: + quota_failed: description: 'Quota Check Failed Flag' required: false default: 'false' type: string - TEST_SUCCESS: + test_success: description: 'Test Success Flag' required: false default: '' type: string - TEST_REPORT_URL: + test_report_url: description: 'Test Report URL' required: false default: '' type: string - secrets: - EMAILNOTIFICATION_LOGICAPP_URL_TA: - required: false env: GPT_MIN_CAPACITY: 100 @@ -76,7 +73,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: true env: - accelerator_name: "Content Processing" + accelerator_name: "KM Generic" steps: - name: Determine Test Suite Display Name id: test_suite @@ -95,7 +92,7 @@ jobs: echo "Test Suite: $TEST_SUITE_NAME" - name: Send Quota Failure Notification - if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED == 'true' + if: inputs.deploy_result == 'failure' && inputs.quota_failed == 'true' shell: bash run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" @@ -112,12 +109,12 @@ jobs: -d "$EMAIL_BODY" || echo "Failed to send quota failure notification" - name: Send Deployment Failure Notification - if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED != 'true' + if: inputs.deploy_result == 'failure' && inputs.quota_failed != 'true' shell: bash run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" - + RESOURCE_GROUP="${{ inputs.resource_group_name }}" + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${{ env.accelerator_name }} deployment process has encountered an issue and has failed to complete successfully.

Deployment Details:
β€’ Resource Group: ${RESOURCE_GROUP}
β€’ WAF Enabled: ${{ env.WAF_ENABLED }}
β€’ EXP Enabled: ${{ env.EXP }}

Run URL: ${RUN_URL}

Please investigate the deployment failure at your earliest convenience.

Best regards,
Your Automation Team

", @@ -131,15 +128,15 @@ jobs: -d "$EMAIL_BODY" || echo "Failed to send deployment failure notification" - name: Send Success Notification - if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.TEST_SUCCESS == 'true') + if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.test_success == 'true') shell: bash run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}" - RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}" - TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" - TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" - + WEBAPP_URL="${{ inputs.web_app_url || inputs.existing_webapp_url }}" + RESOURCE_GROUP="${{ inputs.resource_group_name }}" + TEST_REPORT_URL="${{ inputs.test_report_url }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.test_suite_name }}" + if [ "${{ inputs.e2e_test_result }}" = "skipped" ]; then EMAIL_BODY=$(cat <Dear Team,

The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and testing process has completed successfully.

Test Results:
β€’ Status: βœ… Passed
β€’ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+β€’ Test Report: View Report}
β€’ Target URL: ${EXISTING_URL}

Deployment: Skipped

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", @@ -211,9 +208,9 @@ jobs: run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" EXISTING_URL="${{ inputs.existing_webapp_url }}" - TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}" - TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}" - + TEST_REPORT_URL="${{ inputs.test_report_url }}" + TEST_SUITE_NAME="${{ steps.test_suite.outputs.test_suite_name }}" + EMAIL_BODY=$(cat <Dear Team,

The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.

Failure Details:
β€’ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+β€’ Test Report: View Report}
β€’ Test Suite: ${TEST_SUITE_NAME}
β€’ Deployment: Skipped

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", diff --git a/.github/workflows/job-test-automation.yml b/.github/workflows/job-test-automation.yml index c0b9dca52..80f1ad61a 100644 --- a/.github/workflows/job-test-automation.yml +++ b/.github/workflows/job-test-automation.yml @@ -1,4 +1,4 @@ -name: Test Automation KMGeneric v2 +name: Test Automation KMGeneric on: workflow_call: diff --git a/infra/main.parameters.json b/infra/main.parameters.json index aaf7a30a6..b120f5e39 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -14,7 +14,7 @@ "secondaryLocation": { "value": "${AZURE_SECONDARY_LOCATION}" }, - "azureAiServiceLocation": { + "aiServiceLocation": { "value": "${AZURE_ENV_OPENAI_LOCATION}" }, "gptModelDeploymentType": { @@ -44,6 +44,11 @@ "frontendContainerImageTag": { "value": "${AZURE_ENV_IMAGETAG=latest_waf}" }, + "tags": { + "value": { + "SecurityControl": "${AZURE_TAG_SECURITY_CONTROL=Ignore}" + } + }, "enableTelemetry": { "value": "${AZURE_ENV_ENABLE_TELEMETRY}" }, @@ -52,6 +57,12 @@ }, "existingAiFoundryAiProjectResourceId": { "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" + }, + "backendContainerRegistryHostname": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" + }, + "frontendContainerRegistryHostname": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" } } } \ No newline at end of file diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 866c4d330..7f312c4e8 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -14,7 +14,7 @@ "secondaryLocation": { "value": "${AZURE_SECONDARY_LOCATION}" }, - "azureAiServiceLocation": { + "aiServiceLocation": { "value": "${AZURE_ENV_OPENAI_LOCATION}" }, "gptModelDeploymentType": { @@ -44,6 +44,11 @@ "frontendContainerImageTag": { "value": "${AZURE_ENV_IMAGETAG=latest_waf}" }, + "tags": { + "value": { + "SecurityControl": "${AZURE_TAG_SECURITY_CONTROL=Ignore}" + } + }, "enableTelemetry": { "value": "${AZURE_ENV_ENABLE_TELEMETRY}" }, @@ -53,6 +58,12 @@ "existingAiFoundryAiProjectResourceId": { "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" }, + "backendContainerRegistryHostname": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" + }, + "frontendContainerRegistryHostname": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" + }, "enableMonitoring": { "value": true }, From 08c1f91ebedc86dfcc0e8065ddba9d0b332bb771 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Tue, 2 Dec 2025 17:00:55 +0530 Subject: [PATCH 3/4] minor update on pipeline --- .github/workflows/deploy-linux.yml | 1 - .github/workflows/deploy-windows.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 2a467e60c..309551b6f 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -3,7 +3,6 @@ on: push: branches: - main - - dev workflow_dispatch: inputs: azure_location: diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml index 743125817..1f587b2d0 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-windows.yml @@ -3,7 +3,6 @@ on: push: branches: - main - - dev workflow_dispatch: inputs: azure_location: From 4a7adb539582b03e11fb811331b4a4ffe2b5eea2 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Wed, 3 Dec 2025 13:08:39 +0530 Subject: [PATCH 4/4] updated parameter md file --- documents/CustomizingAzdParameters.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documents/CustomizingAzdParameters.md b/documents/CustomizingAzdParameters.md index 40e286049..3f8b15693 100644 --- a/documents/CustomizingAzdParameters.md +++ b/documents/CustomizingAzdParameters.md @@ -26,6 +26,7 @@ By default this template will use the environment name as the prefix to prevent | `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | `` | Reuses an existing AIFoundry and AIFoundryProject instead of creating a new one. | | `AZURE_ENV_VM_ADMIN_USERNAME` | string | `take(newGuid(), 20)` | The administrator username for the virtual machine. | | `AZURE_ENV_VM_ADMIN_PASSWORD` | string | `newGuid()` | The administrator password for the virtual machine. | +| `AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT` | string | `` | The hostname/endpoint for the container registry used by both backend and frontend containers. | ## How to Set a Parameter