diff --git a/.github/workflows/deploy-KMGeneric.yml b/.github/workflows/deploy-KMGeneric.yml index a870194df..4088ece94 100644 --- a/.github/workflows/deploy-KMGeneric.yml +++ b/.github/workflows/deploy-KMGeneric.yml @@ -96,14 +96,18 @@ jobs: - name: Check and Create Resource Group id: check_create_rg run: | - set -e - echo "Checking if resource group exists..." + set -e + OWNER_TAG_VALUE="${{ github.actor }}" + echo "🔍 Checking if resource group '${{ env.RESOURCE_GROUP_NAME }}' exists..." rg_exists=$(az group exists --name ${{ env.RESOURCE_GROUP_NAME }}) if [ "$rg_exists" = "false" ]; then - echo "Resource group does not exist. Creating..." - az group create --name ${{ env.RESOURCE_GROUP_NAME }} --location ${{ env.AZURE_LOCATION }} || { echo "Error creating resource group"; exit 1; } + echo "📦 Resource group does not exist. Creating..." + echo "🏷️ Adding Owner tag: Owner=${OWNER_TAG_VALUE}" + az group create --name ${{ env.RESOURCE_GROUP_NAME }} --location ${{ env.AZURE_LOCATION }} --tags "Owner=${OWNER_TAG_VALUE}" || { echo "❌ Error creating resource group"; exit 1; } else - echo "Resource group already exists." + echo "✅ Resource group already exists." + echo "🏷️ Adding Owner tag on existing resource group: Owner=${OWNER_TAG_VALUE}" + az group update --name "${{ env.RESOURCE_GROUP_NAME }}" --set tags.Owner="${OWNER_TAG_VALUE}" --output none || echo "⚠️ Warning: failed to update Owner tag on existing resource group '${{ env.RESOURCE_GROUP_NAME }}'." fi echo "RESOURCE_GROUP_NAME=${{ env.RESOURCE_GROUP_NAME }}" >> $GITHUB_OUTPUT - name: Generate Unique Solution Prefix diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 3d00e9630..46e669159 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -22,6 +22,11 @@ on: required: false default: false type: boolean + enable_scalability: + description: 'Enable scalability features for WAF deployments (opt-in)' + required: false + default: false + type: boolean exp: description: 'Enable EXP' required: false @@ -88,6 +93,7 @@ jobs: azure_location: ${{ inputs.azure_location }} resource_group_name: ${{ inputs.resource_group_name }} waf_enabled: ${{ inputs.waf_enabled }} + enable_scalability: ${{ inputs.enable_scalability }} exp: ${{ inputs.exp }} build_docker_image: ${{ inputs.build_docker_image }} existing_webapp_url: ${{ inputs.existing_webapp_url }} diff --git a/.github/workflows/deploy-v2.yml b/.github/workflows/deploy-v2.yml index 33aa0adec..f235a2421 100644 --- a/.github/workflows/deploy-v2.yml +++ b/.github/workflows/deploy-v2.yml @@ -31,41 +31,46 @@ on: default: 'codespace' azure_location: - description: 'Azure Location For Deployment' + description: 'Azure Region (Non-AI Services)' required: false default: 'australiaeast' type: choice options: - 'australiaeast' - - 'eastus' + - 'centralus' + - 'eastasia' - 'eastus2' - 'japaneast' - - 'swedencentral' + - 'northeurope' + - 'southeastasia' - 'uksouth' - - 'westus' - - 'westus2' resource_group_name: description: 'Resource Group Name (Optional)' required: false default: '' type: string + build_docker_image: + description: 'Build & Use Custom Images (Optional)' + required: false + default: false + type: boolean waf_enabled: - description: 'Enable WAF' + description: 'Deploy WAF' required: false default: false type: boolean - EXP: - description: 'Enable EXP' + enable_scalability: + description: 'Enable Scalability (WAF only)' required: false default: false type: boolean - build_docker_image: - description: 'Build And Push Docker Image (Optional)' + EXP: + description: 'Deploy EXP' required: false default: false type: boolean cleanup_resources: - description: 'Cleanup Deployed Resources' + description: 'Auto Delete RG' required: false default: false type: boolean @@ -87,17 +92,17 @@ on: - 'Smoke-Testing' - 'None' AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: - description: 'Log Analytics Workspace ID (Optional)' + description: 'Existing Log Analytics Workspace Resource ID (Optional)' required: false default: '' type: string AZURE_EXISTING_AIPROJECT_RESOURCE_ID: - description: 'AI Project Resource ID (Optional)' + description: 'Existing AI Project Resource ID (Optional)' required: false default: '' type: string existing_webapp_url: - description: 'Existing WebApp URL (Skips Deployment)' + description: 'Run Tests Against Existing RG (Provide Web App URL)' required: false default: '' type: string @@ -117,6 +122,7 @@ jobs: azure_location: ${{ steps.validate.outputs.azure_location }} resource_group_name: ${{ steps.validate.outputs.resource_group_name }} waf_enabled: ${{ steps.validate.outputs.waf_enabled }} + enable_scalability: ${{ steps.validate.outputs.enable_scalability }} exp: ${{ steps.validate.outputs.exp }} build_docker_image: ${{ steps.validate.outputs.build_docker_image }} cleanup_resources: ${{ steps.validate.outputs.cleanup_resources }} @@ -135,6 +141,7 @@ jobs: INPUT_AZURE_LOCATION: ${{ github.event.inputs.azure_location }} INPUT_RESOURCE_GROUP_NAME: ${{ github.event.inputs.resource_group_name }} INPUT_WAF_ENABLED: ${{ github.event.inputs.waf_enabled }} + INPUT_ENABLE_SCALABILITY: ${{ github.event.inputs.enable_scalability }} INPUT_EXP: ${{ github.event.inputs.EXP }} INPUT_BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image }} INPUT_CLEANUP_RESOURCES: ${{ github.event.inputs.cleanup_resources }} @@ -197,6 +204,15 @@ jobs: echo "✅ waf_enabled: '$WAF_ENABLED' is valid" fi + # Validate enable_scalability (boolean) + ENABLE_SCALABILITY="${INPUT_ENABLE_SCALABILITY:-false}" + if [[ "$ENABLE_SCALABILITY" != "true" && "$ENABLE_SCALABILITY" != "false" ]]; then + echo "❌ ERROR: enable_scalability must be 'true' or 'false', got: '$ENABLE_SCALABILITY'" + VALIDATION_FAILED=true + else + echo "✅ enable_scalability: '$ENABLE_SCALABILITY' is valid" + fi + # Validate EXP (boolean) EXP_ENABLED="${INPUT_EXP:-false}" if [[ "$EXP_ENABLED" != "true" && "$EXP_ENABLED" != "false" ]]; then @@ -297,6 +313,7 @@ jobs: echo "azure_location=$LOCATION" >> $GITHUB_OUTPUT echo "resource_group_name=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT echo "waf_enabled=$WAF_ENABLED" >> $GITHUB_OUTPUT + echo "enable_scalability=$ENABLE_SCALABILITY" >> $GITHUB_OUTPUT echo "exp=$EXP_ENABLED" >> $GITHUB_OUTPUT echo "build_docker_image=$BUILD_DOCKER" >> $GITHUB_OUTPUT echo "cleanup_resources=$CLEANUP_RESOURCES" >> $GITHUB_OUTPUT @@ -317,6 +334,7 @@ jobs: azure_location: ${{ needs.validate-inputs.outputs.azure_location || 'australiaeast' }} resource_group_name: ${{ needs.validate-inputs.outputs.resource_group_name || '' }} waf_enabled: ${{ needs.validate-inputs.outputs.waf_enabled == 'true' }} + enable_scalability: ${{ needs.validate-inputs.outputs.enable_scalability == 'true' }} exp: ${{ needs.validate-inputs.outputs.exp == 'true' }} build_docker_image: ${{ needs.validate-inputs.outputs.build_docker_image == 'true' }} cleanup_resources: ${{ needs.validate-inputs.outputs.cleanup_resources == 'true' }} diff --git a/.github/workflows/job-azure-deploy.yml b/.github/workflows/job-azure-deploy.yml index 3bcd2b046..e4b64838f 100644 --- a/.github/workflows/job-azure-deploy.yml +++ b/.github/workflows/job-azure-deploy.yml @@ -26,6 +26,11 @@ on: required: false default: false type: boolean + enable_scalability: + description: 'Enable scalability features for WAF deployments (opt-in)' + required: false + default: false + type: boolean exp: description: 'Enable EXP' required: false @@ -412,15 +417,19 @@ jobs: id: check_create_rg shell: bash run: | - set -e + set -e + OWNER_TAG_VALUE="${{ github.actor }}" 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 --tags ${{ env.RG_TAGS }} || { echo "❌ Error creating resource group"; exit 1; } + echo "🏷️ Adding Owner tag: Owner=${OWNER_TAG_VALUE}" + az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION --tags ${{ env.RG_TAGS }} "Owner=${OWNER_TAG_VALUE}" || { 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." + echo "🏷️ Adding Owner tag on existing resource group: Owner=${OWNER_TAG_VALUE}" + az group update --name "$RESOURCE_GROUP_NAME" --set tags.Owner="${OWNER_TAG_VALUE}" --output none || echo "⚠️ Warning: failed to update Owner tag on existing resource group '$RESOURCE_GROUP_NAME'." fi echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV @@ -551,6 +560,7 @@ jobs: BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }} EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }} WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + ENABLE_SCALABILITY: ${{ inputs.enable_scalability == true && 'true' || 'false' }} AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: ${{ inputs.azure_env_existing_log_analytics_workspace_rid }} AZURE_EXISTING_AIPROJECT_RESOURCE_ID: ${{ inputs.azure_existing_aiproject_resource_id }} USE_CASE: ${{ inputs.use_case }} @@ -570,6 +580,7 @@ jobs: BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image || 'false' }} EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }} WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + ENABLE_SCALABILITY: ${{ inputs.enable_scalability == true && 'true' || 'false' }} AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: ${{ inputs.azure_env_existing_log_analytics_workspace_rid }} AZURE_EXISTING_AIPROJECT_RESOURCE_ID: ${{ inputs.azure_existing_aiproject_resource_id }} USE_CASE: ${{ inputs.use_case }} diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 343e40820..3ece58123 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -28,6 +28,11 @@ on: required: false type: string default: 'false' + ENABLE_SCALABILITY: + required: false + type: string + default: 'false' + description: 'Enable scalability features for WAF deployments (true|false)' AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: required: false type: string @@ -206,11 +211,27 @@ jobs: - name: Configure Parameters Based on WAF Setting shell: bash env: - WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + INPUT_ENABLE_SCALABILITY: ${{ inputs.ENABLE_SCALABILITY }} run: | - if [[ "$WAF_ENABLED" == "true" ]]; then + set -euo pipefail + if [[ "$INPUT_WAF_ENABLED" == "true" ]]; then cp infra/main.waf.parameters.json infra/main.parameters.json echo "✅ Successfully copied WAF parameters to main parameters file" + SCALABILITY_VALUE="${INPUT_ENABLE_SCALABILITY:-false}" + if [[ "$SCALABILITY_VALUE" != "true" && "$SCALABILITY_VALUE" != "false" ]]; then + echo "❌ ERROR: ENABLE_SCALABILITY must be 'true' or 'false', got: '$SCALABILITY_VALUE'" + exit 1 + fi + echo "🔧 Setting enableScalability=${SCALABILITY_VALUE}" + tmpfile=$(mktemp) + if ! jq --argjson v "$SCALABILITY_VALUE" '.parameters.enableScalability.value = $v' infra/main.parameters.json > "$tmpfile"; then + echo "❌ ERROR: jq failed to update enableScalability in infra/main.parameters.json" + rm -f "$tmpfile" + exit 1 + fi + mv "$tmpfile" infra/main.parameters.json + echo "✅ enableScalability set to ${SCALABILITY_VALUE}" else echo "🔧 Configuring Non-WAF deployment - using default main.parameters.json..." fi diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index f406e4922..e63c84851 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -28,6 +28,11 @@ on: required: false type: string default: 'false' + ENABLE_SCALABILITY: + required: false + type: string + default: 'false' + description: 'Enable scalability features for WAF deployments (true|false)' AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: required: false type: string @@ -210,10 +215,26 @@ jobs: shell: bash env: INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + INPUT_ENABLE_SCALABILITY: ${{ inputs.ENABLE_SCALABILITY }} run: | + set -euo pipefail if [[ "$INPUT_WAF_ENABLED" == "true" ]]; then cp infra/main.waf.parameters.json infra/main.parameters.json echo "✅ Successfully copied WAF parameters to main parameters file" + SCALABILITY_VALUE="${INPUT_ENABLE_SCALABILITY:-false}" + if [[ "$SCALABILITY_VALUE" != "true" && "$SCALABILITY_VALUE" != "false" ]]; then + echo "❌ ERROR: ENABLE_SCALABILITY must be 'true' or 'false', got: '$SCALABILITY_VALUE'" + exit 1 + fi + echo "🔧 Setting enableScalability=${SCALABILITY_VALUE}" + tmpfile=$(mktemp) + if ! jq --argjson v "$SCALABILITY_VALUE" '.parameters.enableScalability.value = $v' infra/main.parameters.json > "$tmpfile"; then + echo "❌ ERROR: jq failed to update enableScalability in infra/main.parameters.json" + rm -f "$tmpfile" + exit 1 + fi + mv "$tmpfile" infra/main.parameters.json + echo "✅ enableScalability set to ${SCALABILITY_VALUE}" else echo "🔧 Configuring Non-WAF deployment - using default main.parameters.json..." fi diff --git a/.github/workflows/job-send-notifications.yml b/.github/workflows/job-send-notifications.yml index eeba13fa7..80be5d1e7 100644 --- a/.github/workflows/job-send-notifications.yml +++ b/.github/workflows/job-send-notifications.yml @@ -99,17 +99,25 @@ jobs: echo "TEST_SUITE_NAME=$TEST_SUITE_NAME" >> $GITHUB_OUTPUT echo "Test Suite: $TEST_SUITE_NAME" - - name: Determine Cleanup Status + - name: Determine Cleanup Pill id: cleanup shell: bash env: CLEANUP_RESULT: ${{ inputs.cleanup_result }} run: | + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" case "$CLEANUP_RESULT" in - success) echo "CLEANUP_STATUS=✅ SUCCESS" >> $GITHUB_OUTPUT ;; - failure) echo "CLEANUP_STATUS=❌ FAILED (Needs Manual Cleanup)" >> $GITHUB_OUTPUT ;; - *) echo "CLEANUP_STATUS=⏭️ SKIPPED (Needs Manual Cleanup)" >> $GITHUB_OUTPUT ;; + success) + CLEANUP_PILL="✅ SUCCESS" + ;; + failure) + CLEANUP_PILL="❌ FAILED" + ;; + *) + CLEANUP_PILL="⏭️ SKIPPED" + ;; esac + echo "CLEANUP_PILL=$CLEANUP_PILL" >> $GITHUB_OUTPUT - name: Determine Configuration Label id: config @@ -122,6 +130,9 @@ jobs: EXP_LABEL=$( [ "$EXP" = "true" ] && echo "EXP" || echo "Non-EXP" ) echo "CONFIG_LABEL=${WAF_LABEL} + ${EXP_LABEL}" >> $GITHUB_OUTPUT + # ------------------------------------------------------------------ + # Quota failure + # ------------------------------------------------------------------ - name: Send Quota Failure Notification if: inputs.deploy_result == 'failure' && inputs.quota_failed == 'true' shell: bash @@ -130,51 +141,156 @@ jobs: GITHUB_RUN_ID: ${{ github.run_id }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} 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 ${ACCELERATOR_NAME} deployment has failed due to insufficient quota.

Status Summary:
StageStatus
Deployment❌ FAILED (Insufficient Quota)
E2E Tests⏭️ SKIPPED
Cleanup${CLEANUP_STATUS}

Configuration: ${CONFIG_LABEL}

Run URL: ${RUN_URL}

Please resolve the quota issue and retry the deployment.

Best regards,
Your Automation Team

", - "subject": "❌[CI/CD-Automation] [${ACCELERATOR_NAME}] Insufficient Quota" - } - EOF + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="❌ FAILED" + E2E_PILL="⏭️ SKIPPED" + + BODY_HTML=$(cat < + + + + + +
+ + + +

Pipeline Failed — Insufficient Quota

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
The ${ACCELERATOR_NAME} deployment has failed due to insufficient quota.

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+
+ Please resolve the quota issue and retry the deployment. +
+

Deployment Details

+ + + + + +
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
+
+ VIEW PIPELINE RUN +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML ) + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u274C[CI/CD-Automation] [${ACCELERATOR_NAME}] Insufficient Quota\",\"body\":${BODY_JSON}}" curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send quota failure notification" + -d "$PAYLOAD" || echo "Failed to send quota failure notification" + # ------------------------------------------------------------------ + # Deployment failure (non-quota) + # ------------------------------------------------------------------ - name: Send Deployment Failure Notification if: inputs.deploy_result == 'failure' && inputs.quota_failed != 'true' shell: bash env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_RUN_ID: ${{ github.run_id }} INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} run: | - RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" - - EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${ACCELERATOR_NAME} deployment has failed.

Status Summary:
StageStatus
Deployment❌ FAILED (Deployment Issue)
E2E Tests⏭️ SKIPPED
Cleanup${CLEANUP_STATUS}

Deployment Details:
• Resource Group: ${RESOURCE_GROUP}

Configuration: ${CONFIG_LABEL}

Run URL: ${RUN_URL}

Please investigate the deployment failure at your earliest convenience.

Best regards,
Your Automation Team

", - "subject": "❌[CI/CD-Automation] [${ACCELERATOR_NAME}] Deployment-Failed" - } - EOF + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="❌ FAILED" + E2E_PILL="⏭️ SKIPPED" + + BODY_HTML=$(cat < + + + + + +
+ + + +

Pipeline Failed

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
The ${ACCELERATOR_NAME} deployment has failed. Please investigate at your earliest convenience.

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+
+ Please investigate the deployment failure at your earliest convenience. +
+

Deployment Details

+ + + + + + + +
Resource Group${RESOURCE_GROUP}
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
+
+ INVESTIGATE FAILURE +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML ) - + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u274C[CI/CD-Automation] [${ACCELERATOR_NAME}] Deployment-Failed\",\"body\":${BODY_JSON}}" + curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send deployment failure notification" + -d "$PAYLOAD" || echo "Failed to send deployment failure notification" + # ------------------------------------------------------------------ + # Success (deploy + optional E2E) + # ------------------------------------------------------------------ - name: Send Success Notification if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.test_success == 'true') shell: bash env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_RUN_ID: ${{ github.run_id }} INPUT_WEB_APPURL: ${{ inputs.web_app_url }} INPUT_EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }} INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }} @@ -182,41 +298,91 @@ jobs: INPUT_E2E_TEST_RESULT: ${{ inputs.e2e_test_result }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} - GITHUB_REPOSITORY: ${{ github.repository }} - GITHUB_RUN_ID: ${{ github.run_id }} CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} - RUN_E2E_TESTS: ${{ env.RUN_E2E_TESTS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }} - run: | + # HTML-escape values that get embedded into the email template to avoid HTML/attribute injection from workflow inputs. + html_escape() { + printf '%s' "$1" | sed -e 's/&/\&/g' -e 's//\>/g' -e 's/"/\"/g' -e "s/'/\'/g" + } RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - WEBAPP_URL="${INPUT_WEB_APPURL:-$INPUT_EXISTING_WEBAPP_URL}" - RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" - TEST_REPORT_URL="$INPUT_TEST_REPORT_URL" - + WEBAPP_URL="$(html_escape "${INPUT_WEB_APPURL:-$INPUT_EXISTING_WEBAPP_URL}")" + RESOURCE_GROUP="$(html_escape "$INPUT_RESOURCE_GROUP_NAME")" + TEST_REPORT_URL="$(html_escape "$INPUT_TEST_REPORT_URL")" + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="✅ SUCCESS" + if [ "$INPUT_E2E_TEST_RESULT" = "skipped" ]; then - EMAIL_BODY=$(cat <Dear Team,

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

Status Summary:
StageStatus
Deployment✅ SUCCESS
E2E Tests⏭️ SKIPPED
Cleanup${CLEANUP_STATUS}

Deployment Details:
• Resource Group: ${RESOURCE_GROUP}
• Web App URL: ${WEBAPP_URL}

Configuration: ${CONFIG_LABEL}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", - "subject": "✅[CI/CD-Automation] [${ACCELERATOR_NAME}] Success" - } - EOF - ) + E2E_PILL="⏭️ SKIPPED" + INTRO="The ${ACCELERATOR_NAME} deployment has completed successfully." + TEST_DETAIL_ROWS="" else - EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the ${ACCELERATOR_NAME} deployment and test automation has completed successfully.

Status Summary:
StageStatus
Deployment✅ SUCCESS
E2E Tests✅ SUCCESS
Cleanup${CLEANUP_STATUS}

Deployment Details:
• Resource Group: ${RESOURCE_GROUP}
• Web App URL: ${WEBAPP_URL}
• Test Suite: ${TEST_SUITE_NAME}
• Test Report: View Report

Configuration: ${CONFIG_LABEL}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", - "subject": "✅[CI/CD-Automation] [${ACCELERATOR_NAME}] Success" - } - EOF - ) + E2E_PILL="✅ SUCCESS" + INTRO="The ${ACCELERATOR_NAME} deployment and test automation has completed successfully." + TEST_DETAIL_ROWS="Test Suite${TEST_SUITE_NAME}Test Report📄 View Report" fi - + + BODY_HTML=$(cat < + + + + + +
+ + + +

Pipeline Succeeded

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
${INTRO}

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+

Deployment Details

+ + + + + + + + + + ${TEST_DETAIL_ROWS} +
Resource Group${RESOURCE_GROUP}
Web App URL${WEBAPP_URL}
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
+
+ VIEW PIPELINE RUN +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML + ) + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u2705[CI/CD-Automation] [${ACCELERATOR_NAME}] Success\",\"body\":${BODY_JSON}}" + curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send success notification" + -d "$PAYLOAD" || echo "Failed to send success notification" + # ------------------------------------------------------------------ + # E2E test failure (deploy succeeded) + # ------------------------------------------------------------------ - name: Send Test Failure Notification if: inputs.deploy_result == 'success' && inputs.e2e_test_result != 'skipped' && inputs.test_success != 'true' shell: bash @@ -226,31 +392,88 @@ jobs: INPUT_WEB_APPURL: ${{ inputs.web_app_url }} INPUT_EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }} INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }} + INPUT_TEST_REPORT_URL: ${{ inputs.test_report_url }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} - RUN_E2E_TESTS: ${{ env.RUN_E2E_TESTS }} TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }} - INPUT_TEST_REPORT_URL: ${{ inputs.test_report_url }} run: | - RUN_URL="https://github.com/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }}" - TEST_REPORT_URL="$INPUT_TEST_REPORT_URL" - WEBAPP_URL="${INPUT_WEB_APPURL:-$INPUT_EXISTING_WEBAPP_URL}" - RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" - - EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that ${ACCELERATOR_NAME} test automation has failed.

Status Summary:
StageStatus
Deployment✅ SUCCESS
E2E Tests❌ FAILED
Cleanup${CLEANUP_STATUS}

Deployment Details:
• Resource Group: ${RESOURCE_GROUP}
• Web App URL: ${WEBAPP_URL}
• Test Suite: ${TEST_SUITE_NAME}
• Test Report: View Report

Configuration: ${CONFIG_LABEL}

Run URL: ${RUN_URL}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

", - "subject": "❌[CI/CD-Automation] [${ACCELERATOR_NAME}] E2E Test-Failed" + # HTML-escape values that get embedded into the email template to avoid HTML/attribute injection from workflow inputs. + html_escape() { + printf '%s' "$1" | sed -e 's/&/\&/g' -e 's//\>/g' -e 's/"/\"/g' -e "s/'/\'/g" } - EOF + RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + WEBAPP_URL="$(html_escape "${INPUT_WEB_APPURL:-$INPUT_EXISTING_WEBAPP_URL}")" + RESOURCE_GROUP="$(html_escape "$INPUT_RESOURCE_GROUP_NAME")" + TEST_REPORT_URL="$(html_escape "$INPUT_TEST_REPORT_URL")" + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="✅ SUCCESS" + E2E_PILL="❌ FAILED" + + BODY_HTML=$(cat < + + + + + +
+ + + +

E2E Tests Failed

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
The ${ACCELERATOR_NAME} test automation has failed. Please investigate at your earliest convenience.

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+

Deployment Details

+ + + + + + + + + + + + + +
Resource Group${RESOURCE_GROUP}
Web App URL${WEBAPP_URL}
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
Test Suite${TEST_SUITE_NAME}
Test Report📄 View Report
+
+ INVESTIGATE FAILURE +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML ) + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u274C[CI/CD-Automation] [${ACCELERATOR_NAME}] E2E Test-Failed\",\"body\":${BODY_JSON}}" curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send test failure notification" + -d "$PAYLOAD" || echo "Failed to send test failure notification" + # ------------------------------------------------------------------ + # Existing URL: success + # ------------------------------------------------------------------ - 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 @@ -261,26 +484,86 @@ jobs: INPUT_TEST_REPORT_URL: ${{ inputs.test_report_url }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} - RUN_E2E_TESTS: ${{ env.RUN_E2E_TESTS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} + CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }} run: | - RUN_URL="https://github.com/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }}" - EXISTING_URL="$INPUT_EXISTING_WEBAPP_URL" - TEST_REPORT_URL="$INPUT_TEST_REPORT_URL" - - EMAIL_BODY=$(cat <Dear Team,

The ${ACCELERATOR_NAME} pipeline executed against the specified Target URL and test automation has completed successfully.

Status Summary:
StageStatus
Deployment⏭️ SKIPPED (Tests executed on Pre-deployed RG)
E2E Tests✅ SUCCESS
Cleanup${CLEANUP_STATUS}

Test Results:
• Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+• Test Report: View Report}
• Target URL: ${EXISTING_URL}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", - "subject": "✅[CI/CD-Automation] [${ACCELERATOR_NAME}] Success" + # HTML-escape values that get embedded into the email template to avoid HTML/attribute injection from workflow inputs. + html_escape() { + printf '%s' "$1" | sed -e 's/&/\&/g' -e 's//\>/g' -e 's/"/\"/g' -e "s/'/\'/g" } - EOF + RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + EXISTING_URL="$(html_escape "$INPUT_EXISTING_WEBAPP_URL")" + TEST_REPORT_URL="$(html_escape "$INPUT_TEST_REPORT_URL")" + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="⏭️ SKIPPED" + E2E_PILL="✅ SUCCESS" + if [ -n "$TEST_REPORT_URL" ]; then + REPORT_ROW="Test Report📄 View Report" + else + REPORT_ROW="" + fi + + BODY_HTML=$(cat < + + + + + +
+ + + +

Pipeline Succeeded

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
The ${ACCELERATOR_NAME} pipeline executed against the specified Target URL and test automation has completed successfully.

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+

Test Results

+ + + + + + + + + + ${REPORT_ROW} +
Target URL${EXISTING_URL}
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
Test Suite${TEST_SUITE_NAME}
+
+ VIEW PIPELINE RUN +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML ) + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u2705[CI/CD-Automation] [${ACCELERATOR_NAME}] Success\",\"body\":${BODY_JSON}}" curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send existing URL success notification" + -d "$PAYLOAD" || echo "Failed to send existing URL success notification" + # ------------------------------------------------------------------ + # Existing URL: test failure + # ------------------------------------------------------------------ - name: Send Existing URL Test Failure Notification if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'failure' shell: bash @@ -291,22 +574,79 @@ jobs: INPUT_TEST_REPORT_URL: ${{ inputs.test_report_url }} ACCELERATOR_NAME: ${{ env.accelerator_name }} LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }} - CLEANUP_STATUS: ${{ steps.cleanup.outputs.CLEANUP_STATUS }} - RUN_E2E_TESTS: ${{ env.RUN_E2E_TESTS }} + CLEANUP_PILL: ${{ steps.cleanup.outputs.CLEANUP_PILL }} + CONFIG_LABEL: ${{ steps.config.outputs.CONFIG_LABEL }} TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }} run: | - RUN_URL="https://github.com/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }}" - EXISTING_URL="$INPUT_EXISTING_WEBAPP_URL" - TEST_REPORT_URL="$INPUT_TEST_REPORT_URL" - - EMAIL_BODY=$(cat <Dear Team,

The ${ACCELERATOR_NAME} pipeline executed against the specified Target URL and test automation has failed.

Status Summary:
StageStatus
Deployment⏭️ SKIPPED (Tests executed on Pre-deployed RG)
E2E Tests❌ FAILED
Cleanup${CLEANUP_STATUS}

Failure Details:
• Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+• Test Report: View Report}
• Test Suite: ${TEST_SUITE_NAME}

Run URL: ${RUN_URL}

Best regards,
Your Automation Team

", - "subject": "❌[CI/CD-Automation] [${ACCELERATOR_NAME}] E2E Test-Failed" + # HTML-escape values that get embedded into the email template to avoid HTML/attribute injection from workflow inputs. + html_escape() { + printf '%s' "$1" | sed -e 's/&/\&/g' -e 's//\>/g' -e 's/"/\"/g' -e "s/'/\'/g" } - EOF + RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + EXISTING_URL="$(html_escape "$INPUT_EXISTING_WEBAPP_URL")" + TEST_REPORT_URL="$(html_escape "$INPUT_TEST_REPORT_URL")" + PILL_BASE="display:inline-block; min-width:70px; text-align:center; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; line-height:1.4;" + DEPLOY_PILL="⏭️ SKIPPED" + E2E_PILL="❌ FAILED" + if [ -n "$TEST_REPORT_URL" ]; then + REPORT_ROW="Test Report📄 View Report" + else + REPORT_ROW="" + fi + + BODY_HTML=$(cat < + + + + + +
+ + + +

E2E Tests Failed

+

${ACCELERATOR_NAME} Accelerator • CI/CD Automation

+ ${CONFIG_LABEL} +
+
+

Dear Team,
The ${ACCELERATOR_NAME} pipeline executed against the specified Target URL and test automation has failed.

+
+

Status Summary

+ + + + +
Deployment${DEPLOY_PILL}
E2E Tests${E2E_PILL}
Cleanup${CLEANUP_PILL}
+
+

Failure Details

+ + + + + + + + + + ${REPORT_ROW} +
Target URL${EXISTING_URL}
Triggered By${{ github.actor }}
Branch${{ env.BRANCH_NAME }}
Test Suite${TEST_SUITE_NAME}
+
+ INVESTIGATE FAILURE +
+
+ + + +
CI/CD Automation Pipeline${ACCELERATOR_NAME} Accelerator
+
+ + + HTML ) + BODY_JSON=$(printf '%s' "$BODY_HTML" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') + PAYLOAD="{\"subject\":\"\u274C[CI/CD-Automation] [${ACCELERATOR_NAME}] E2E Test-Failed\",\"body\":${BODY_JSON}}" curl -X POST "${LOGICAPP_URL}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send existing URL test failure notification" \ No newline at end of file + -d "$PAYLOAD" || echo "Failed to send existing URL test failure notification"