diff --git a/.github/workflows/deploy-Parameterized.yml b/.github/workflows/deploy-Parameterized.yml new file mode 100644 index 000000000..bbb769b48 --- /dev/null +++ b/.github/workflows/deploy-Parameterized.yml @@ -0,0 +1,625 @@ +name: Deploy-Test-Cleanup (Parameterized) +on: + pull_request: + branches: + - main + workflow_run: + workflows: ["Build Docker and Optional Push"] + types: + - completed + branches: + - main + - dev + - demo + workflow_dispatch: + inputs: + run_e2e_tests: + description: 'Run end-to-end tests' + required: false + default: true + type: boolean + cleanup_resources: + description: 'Cleanup deployed resources' + required: false + default: false + type: boolean + waf_enabled: + description: 'Enable WAF' + required: false + default: false + type: boolean + EXP: + description: 'Enable EXP' + required: false + default: false + type: boolean + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + description: 'Log Analytics Workspace ID (optional)' + required: false + default: '' + type: string + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: + description: 'AI Project Resource ID (optional)' + required: false + default: '' + type: string + existing_webapp_url: + description: 'Existing WebApp URL' + required: false + default: '' + type: string + build_docker_image: + description: 'Build and push Docker image' + required: false + default: false + type: boolean + schedule: + - cron: "0 6,18 * * *" # Runs at 6:00 AM and 6:00 PM GMT + + + +env: + GPT_MIN_CAPACITY: 150 + TEXT_EMBEDDING_MIN_CAPACITY: 80 + BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} + # For automatic triggers (pull_request, workflow_run, schedule): force Non-WAF + Non-EXP + # For manual dispatch: use input values or defaults + WAF_ENABLED: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.waf_enabled || false) || false }} + EXP: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.EXP || false) || false }} + CLEANUP_RESOURCES: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.cleanup_resources || true) || true }} + RUN_E2E_TESTS: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.run_e2e_tests || true) || true }} + BUILD_DOCKER_IMAGE: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.build_docker_image || false) || false }} + +jobs: + deploy: + # Skip deployment if an existing webapp URL is provided + if: github.event_name != 'workflow_dispatch' || github.event.inputs.existing_webapp_url == '' || github.event.inputs.existing_webapp_url == null + runs-on: ubuntu-latest + outputs: + RESOURCE_GROUP_NAME: ${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }} + WEBAPP_URL: ${{ steps.get_output.outputs.WEBAPP_URL }} + ENV_NAME: ${{ steps.generate_env_name.outputs.ENV_NAME }} + AZURE_LOCATION: ${{ steps.set_region.outputs.AZURE_LOCATION }} + IMAGE_TAG: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + env: + # For automatic triggers: force Non-WAF + Non-EXP, for manual dispatch: use inputs + WAF_ENABLED: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.waf_enabled || false) || false }} + EXP: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.EXP || false) || false }} + CLEANUP_RESOURCES: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.cleanup_resources || true) || true }} + + steps: + - name: Display Workflow Configuration + run: | + echo "🚀 ===================================" + echo "📋 WORKFLOW CONFIGURATION SUMMARY" + echo "🚀 ===================================" + echo "Trigger Type: ${{ github.event_name }}" + echo "Branch: ${{ env.BRANCH_NAME }}" + echo "" + echo "Configuration Settings:" + echo " â€ĸ WAF Enabled: ${{ env.WAF_ENABLED }}" + echo " â€ĸ EXP Enabled: ${{ env.EXP }}" + echo " â€ĸ Run E2E Tests: ${{ env.RUN_E2E_TESTS }}" + echo " â€ĸ Cleanup Resources: ${{ env.CLEANUP_RESOURCES }}" + echo " â€ĸ Build Docker Image: ${{ env.BUILD_DOCKER_IMAGE }}" + if [[ "${{ github.event.inputs.existing_webapp_url }}" != "" ]]; then + echo " â€ĸ Using Existing Webapp URL: ${{ github.event.inputs.existing_webapp_url }}" + echo " â€ĸ Skip Deployment: Yes" + else + echo " â€ĸ Skip Deployment: No" + fi + echo "" + if [[ "${{ github.event_name }}" != "workflow_dispatch" ]]; then + echo "â„šī¸ Automatic Trigger: Using Non-WAF + Non-EXP configuration" + else + echo "â„šī¸ Manual Trigger: Using user-specified configuration" + # Check if EXP was auto-enabled after user input validation + if [[ "${{ env.EXP }}" == "true" && "${{ github.event.inputs.EXP }}" != "true" ]]; then + echo "🔧 Note: EXP was automatically enabled due to provided parameter values" + fi + fi + echo "🚀 ===================================" + + - name: Validate and Auto-Configure EXP + run: | + echo "🔍 Validating EXP configuration..." + + # Check if EXP values were provided but EXP is disabled + if [[ "${{ github.event.inputs.EXP }}" != "true" ]]; then + if [[ -n "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] || [[ -n "${{ github.event.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 "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}'" + [[ -n "${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]] && echo " - Azure AI Project Resource ID: '${{ github.event.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 + + echo "✅ EXP configuration is valid" + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Azure CLI + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version # Verify installation + + - name: Run Quota Check + id: quota-check + run: | + export AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }} + export AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }} + export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }} + export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" + export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }} + export TEXT_EMBEDDING_MIN_CAPACITY=${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} + export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}" + + chmod +x scripts/checkquota.sh + if ! scripts/checkquota.sh; then + # If quota check fails due to insufficient quota, set the flag + if grep -q "No region with sufficient quota found" scripts/checkquota.sh; then + echo "QUOTA_FAILED=true" >> $GITHUB_ENV + fi + exit 1 # Fail the pipeline if any other failure occurs + fi + + + - name: Send Notification on Quota Failure + if: env.QUOTA_FAILED == 'true' + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + EMAIL_BODY=$(cat <Dear Team,

The quota check has failed, and the pipeline cannot proceed.

Build URL: ${RUN_URL}

Please take necessary action.

Best regards,
Your Automation Team

" + } + EOF + ) + + curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send notification" + + - name: Fail Pipeline if Quota Check Fails + if: env.QUOTA_FAILED == 'true' + run: exit 1 + + - name: Set Deployment Region + id: set_region + run: | + echo "Selected Region: $VALID_REGION" + echo "AZURE_AI_LOCATION=$VALID_REGION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT + if [ "$VALID_REGION" == "eastus" ] || [ "$VALID_REGION" == "westus3" ]; then + echo "AZURE_LOCATION=uksouth" >> $GITHUB_ENV + echo "AZURE_LOCATION=uksouth" >> $GITHUB_OUTPUT + fi + + - name: Generate Resource Group Name + id: generate_rg_name + run: | + echo "Generating a unique resource group name..." + ACCL_NAME="docgen" # 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}" + + - name: Setup Azure Developer CLI + run: | + curl -fsSL https://aka.ms/install-azd.sh | sudo bash + azd version + + - name: Login to Azure + id: login-azure + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }} + + - name: Install Bicep CLI + run: az bicep install + + - name: Check and Create Resource Group + id: check_create_rg + run: | + set -e + echo "Checking if resource group exists..." + rg_exists=$(az group exists --name $RESOURCE_GROUP_NAME) + if [ "$rg_exists" = "false" ]; then + echo "Resource group does not exist. Creating..." + az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION || { echo "Error creating resource group"; exit 1; } + else + echo "Resource group already exists." + fi + echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT + + - name: Generate Unique Solution Prefix + id: generate_solution_prefix + 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: Generate Unique Docker Image Tag + id: generate_docker_tag + run: | + if [[ "${{ env.BUILD_DOCKER_IMAGE }}" == "true" ]]; then + echo "🔨 Building new Docker image - generating unique tag..." + # Generate unique tag for manual deployment runs + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + RUN_ID="${{ github.run_id }}" + BRANCH_NAME="${{ env.BRANCH_NAME }}" + # Sanitize branch name for Docker tag (replace invalid characters with hyphens) + 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" + else + echo "đŸˇī¸ Using existing Docker image based on branch..." + BRANCH_NAME="${{ env.BRANCH_NAME }}" + echo "Current branch: $BRANCH_NAME" + + # Determine image tag based on branch + if [[ "$BRANCH_NAME" == "main" ]]; then + IMAGE_TAG="latest_waf" + echo "Using main branch - image tag: latest_waf" + elif [[ "$BRANCH_NAME" == "dev" ]]; then + IMAGE_TAG="dev" + echo "Using dev branch - image tag: dev" + elif [[ "$BRANCH_NAME" == "demo" ]]; then + IMAGE_TAG="demo" + echo "Using demo branch - image tag: demo" + else + IMAGE_TAG="latest_waf" + echo "Using default for branch '$BRANCH_NAME' - image tag: latest_waf" + fi + + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT + echo "Using existing Docker image tag: $IMAGE_TAG" + fi + + - name: Set up Docker Buildx + if: env.BUILD_DOCKER_IMAGE == true + uses: docker/setup-buildx-action@v3 + + - name: Log in to Azure Container Registry + if: env.BUILD_DOCKER_IMAGE == true + uses: azure/docker-login@v2 + with: + login-server: ${{ secrets.ACR_DEV_LOGIN_SERVER }} + username: ${{ secrets.ACR_DEV_USERNAME }} + password: ${{ secrets.ACR_DEV_PASSWORD }} + + - name: Build and Push Docker Image + if: env.BUILD_DOCKER_IMAGE == true + id: build_push_image + uses: docker/build-push-action@v6 + with: + context: ./src + file: ./src/WebApp.Dockerfile + push: true + tags: | + ${{ secrets.ACR_DEV_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} + ${{ secrets.ACR_DEV_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }} + + - name: Verify Docker Image Build + if: env.BUILD_DOCKER_IMAGE == true + run: | + echo "✅ Docker image successfully built and pushed" + echo "Image tag: ${{ env.IMAGE_TAG }}" + echo "Run number: ${{ github.run_number }}" + + - name: Verify Docker Image Selection + if: env.BUILD_DOCKER_IMAGE == false + run: | + echo "✅ Using existing Docker image: latest_waf" + echo "Image tag: ${{ env.IMAGE_TAG }}" + + - name: Generate Unique Environment Name + id: generate_env_name + 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: Configure Parameters Based on WAF Setting + run: | + if [[ "${{ env.WAF_ENABLED }}" == "true" ]]; then + echo "🔧 Configuring WAF deployment - copying main.waf.parameters.json to main.parameters.json..." + 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..." + # Ensure we have the original parameters file if it was overwritten + if [[ -f infra/main.waf.parameters.json ]] && [[ ! -f infra/main.parameters.json.backup ]]; then + echo "Backing up original parameters file..." + git checkout HEAD -- infra/main.parameters.json || echo "Using existing main.parameters.json" + fi + fi + + - name: Display Docker Image Tag + run: | + echo "=== Docker Image Information ===" + echo "Docker Image Tag: ${{ env.IMAGE_TAG }}" + echo "Registry: ${{ secrets.ACR_DEV_LOGIN_SERVER }}" + echo "Full Image: ${{ secrets.ACR_DEV_LOGIN_SERVER }}/webapp:${{ env.IMAGE_TAG }}" + echo "================================" + + - name: Deploy using azd up and extract values (${{ env.WAF_ENABLED == 'true' && 'WAF' || 'Non-WAF' }}+${{ env.EXP == 'true' && 'EXP' || 'Non-EXP' }}) + id: get_output + run: | + set -e + echo "Starting azd deployment..." + echo "WAF Enabled: ${{ env.WAF_ENABLED }}" + echo "EXP: ${{ env.EXP }}" + echo "Using Docker Image Tag: ${{ env.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 $ENV_NAME --no-prompt + echo "Environment created: $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="$AZURE_LOCATION" + azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME" + azd env set AZURE_ENV_IMAGETAG="${{ env.IMAGE_TAG }}" + azd env set AZURE_DEV_COLLECT_TELEMETRY="no" + + # Set ACR name only when building Docker image + if [[ "${{ env.BUILD_DOCKER_IMAGE }}" == "true" ]]; then + # Extract ACR name from login server and set as environment variable + ACR_NAME=$(echo "${{ secrets.ACR_DEV_LOGIN_SERVER }}" | cut -d'.' -f1) + azd env set AZURE_ENV_ACR_NAME="$ACR_NAME" + echo "Set ACR name to: $ACR_NAME" + else + echo "Skipping ACR name configuration (using existing image)" + fi + + if [[ "${{ env.EXP }}" == "true" ]]; then + echo "✅ EXP ENABLED - Setting EXP parameters..." + + # Set EXP variables dynamically + if [[ -n "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then + EXP_LOG_ANALYTICS_ID="${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" + else + EXP_LOG_ANALYTICS_ID="${{ secrets.EXP_LOG_ANALYTICS_WORKSPACE_ID }}" + fi + + if [[ -n "${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then + EXP_AI_PROJECT_ID="${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" + else + EXP_AI_PROJECT_ID="${{ secrets.EXP_AI_PROJECT_RESOURCE_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" + if [[ -n "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] || [[ -n "${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then + echo "âš ī¸ Warning: EXP parameter values provided but EXP is disabled. These values will be ignored." + fi + fi + + # Deploy using azd up + azd up --no-prompt + + # Get deployment outputs using azd + 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 + + # Extract values from azd output (adjust these based on actual output variable names) + export AI_FOUNDRY_RESOURCE_ID=$(echo "$DEPLOY_OUTPUT" | jq -r '.AI_FOUNDRY_RESOURCE_ID // empty') + echo "AI_FOUNDRY_RESOURCE_ID=$AI_FOUNDRY_RESOURCE_ID" >> $GITHUB_ENV + export AI_SEARCH_SERVICE_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.AI_SEARCH_SERVICE_NAME // empty') + echo "AI_SEARCH_SERVICE_NAME=$AI_SEARCH_SERVICE_NAME" >> $GITHUB_ENV + export COSMOS_DB_ACCOUNT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.COSMOS_DB_ACCOUNT_NAME // empty') + echo "COSMOS_DB_ACCOUNT_NAME=$COSMOS_DB_ACCOUNT_NAME" >> $GITHUB_ENV + export STORAGE_ACCOUNT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.STORAGE_ACCOUNT_NAME // empty') + echo "STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME" >> $GITHUB_ENV + export STORAGE_CONTAINER_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.STORAGE_CONTAINER_NAME // empty') + echo "STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME" >> $GITHUB_ENV + export KEY_VAULT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.KEY_VAULT_NAME // empty') + echo "KEY_VAULT_NAME=$KEY_VAULT_NAME" >> $GITHUB_ENV + export SQL_SERVER_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.SQLDB_SERVER_NAME // empty') + echo "SQL_SERVER_NAME=$SQL_SERVER_NAME" >> $GITHUB_ENV + export SQL_DATABASE=$(echo "$DEPLOY_OUTPUT" | jq -r '.SQLDB_DATABASE // empty') + echo "SQL_DATABASE=$SQL_DATABASE" >> $GITHUB_ENV + export CLIENT_ID=$(echo "$DEPLOY_OUTPUT" | jq -r '.MANAGEDIDENTITY_SQL_CLIENTID // empty') + echo "CLIENT_ID=$CLIENT_ID" >> $GITHUB_ENV + export CLIENT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.MANAGEDIDENTITY_SQL_NAME // empty') + echo "CLIENT_NAME=$CLIENT_NAME" >> $GITHUB_ENV + export MANAGEDIDENTITY_WEBAPP_CLIENTID=$(echo "$DEPLOY_OUTPUT" | jq -r '.MANAGEDIDENTITY_WEBAPP_CLIENTID // empty') + echo "MANAGEDIDENTITY_WEBAPP_CLIENTID=$MANAGEDIDENTITY_WEBAPP_CLIENTID" >> $GITHUB_ENV + export RESOURCE_GROUP_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.RESOURCE_GROUP_NAME // .AZURE_RESOURCE_GROUP // empty') + [[ -z "$RESOURCE_GROUP_NAME" ]] && export RESOURCE_GROUP_NAME="$RESOURCE_GROUP_NAME" + echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV + WEBAPP_URL=$(echo "$DEPLOY_OUTPUT" | jq -r '.WEB_APP_URL // .SERVICE_BACKEND_ENDPOINT_URL // empty') + echo "WEBAPP_URL=$WEBAPP_URL" >> $GITHUB_OUTPUT + WEB_APP_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.WEB_APP_NAME // .SERVICE_BACKEND_NAME // empty') + echo "WEB_APP_NAME=$WEB_APP_NAME" >> $GITHUB_ENV + + # echo "🔧 Disabling AUTH_ENABLED for the web app..." + # if [[ -n "$WEB_APP_NAME" && -n "$RESOURCE_GROUP_NAME" ]]; then + # az webapp config appsettings set -g "$RESOURCE_GROUP_NAME" -n "$WEB_APP_NAME" --settings AUTH_ENABLED=false + # else + # echo "Warning: Could not disable AUTH_ENABLED - WEB_APP_NAME or RESOURCE_GROUP_NAME not found" + # fi + + sleep 30 + + - name: Run Post-Deployment Script + id: post_deploy + env: + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + run: | + set -e + az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + + echo "Running post-deployment script..." + + bash ./infra/scripts/process_sample_data.sh \ + "$STORAGE_ACCOUNT_NAME" \ + "$STORAGE_CONTAINER_NAME" \ + "$KEY_VAULT_NAME" \ + "$COSMOS_DB_ACCOUNT_NAME" \ + "$RESOURCE_GROUP_NAME" \ + "$AI_SEARCH_SERVICE_NAME" \ + "${{ secrets.AZURE_CLIENT_ID }}" \ + "$AI_FOUNDRY_RESOURCE_ID" + + - name: Logout from Azure + if: always() + run: | + az logout + echo "Logged out from Azure." + + e2e-test: + # Run e2e tests for automatic triggers, when manually enabled, or when existing webapp URL is provided + if: always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.run_e2e_tests == true || github.event.inputs.run_e2e_tests == null || github.event.inputs.existing_webapp_url != '') + needs: [deploy] + uses: ./.github/workflows/test-automation.yml + with: + DOCGEN_URL: ${{ github.event.inputs.existing_webapp_url || needs.deploy.outputs.WEBAPP_URL }} + secrets: inherit + + cleanup-deployment: + # Cleanup for automatic triggers or when manually enabled (skip cleanup when using existing webapp URL) + if: always() && needs.deploy.result != 'skipped' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && (github.event_name != 'workflow_dispatch' || (github.event.inputs.cleanup_resources == true && github.event.inputs.existing_webapp_url == '')) + needs: [deploy] + runs-on: ubuntu-latest + env: + RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }} + ENV_NAME: ${{ needs.deploy.outputs.ENV_NAME }} + IMAGE_TAG: ${{ needs.deploy.outputs.IMAGE_TAG }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Azure Developer CLI + run: | + curl -fsSL https://aka.ms/install-azd.sh | sudo bash + azd version + + - name: Login to Azure + run: | + azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} --tenant-id ${{ secrets.AZURE_TENANT_ID }} + azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Setup Azure CLI for Docker cleanup + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version + + - name: Login to Azure CLI for Docker cleanup + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + + - name: Delete Docker Images from ACR + run: | + set -e + echo "đŸ—‘ī¸ Cleaning up Docker images from Azure Container Registry..." + + if [[ -n "${{ env.IMAGE_TAG }}" && "${{ env.IMAGE_TAG }}" != "latest_waf" ]]; then + echo "Deleting Docker images with tag: ${{ env.IMAGE_TAG }}" + + # Delete the main image + echo "Deleting image: ${{ secrets.ACR_DEV_LOGIN_SERVER }}/webapp:${{ env.IMAGE_TAG }}" + az acr repository delete --name $(echo "${{ secrets.ACR_DEV_LOGIN_SERVER }}" | cut -d'.' -f1) \ + --image webapp:${{ env.IMAGE_TAG }} --yes || echo "Warning: Failed to delete main image or image not found" + + # Delete the image with run number suffix + echo "Deleting image: ${{ secrets.ACR_DEV_LOGIN_SERVER }}/webapp:${{ env.IMAGE_TAG }}_${{ github.run_number }}" + az acr repository delete --name $(echo "${{ secrets.ACR_DEV_LOGIN_SERVER }}" | cut -d'.' -f1) \ + --image webapp:${{ env.IMAGE_TAG }}_${{ github.run_number }} --yes || echo "Warning: Failed to delete run-numbered image or image not found" + + echo "✅ Docker images cleanup completed" + else + echo "âš ī¸ Skipping Docker image cleanup (using latest_waf or no custom image tag)" + fi + + - name: Select Environment + run: | + # Try to select the environment if it exists, otherwise create a minimal environment for cleanup + azd env list + if azd env list | grep -q "${{ env.ENV_NAME }}"; then + echo "Environment ${{ env.ENV_NAME }} found, selecting it..." + azd env select ${{ env.ENV_NAME }} + else + echo "Environment ${{ env.ENV_NAME }} not found, creating minimal environment for cleanup..." + azd env new ${{ env.ENV_NAME }} --no-prompt + azd env set AZURE_RESOURCE_GROUP "${{ env.RESOURCE_GROUP_NAME }}" + azd env set AZURE_SUBSCRIPTION_ID "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + azd env set AZURE_ENV_OPENAI_LOCATION="${{ env.AZURE_LOCATION }}" + azd env set AZURE_LOCATION="${{ env.AZURE_LOCATION }}" + fi + + - name: Delete deployment using azd + run: | + set -e + echo "Deleting deployment..." + azd down --purge --force --no-prompt + echo "Deployment deleted successfully." + + - name: Send Notification on Failure + if: always() && (failure() || needs.deploy.result == 'failure') + run: | + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Get deployment configuration for notification + WAF_STATUS="${{ github.event.inputs.waf_enabled || true }}" + EXP_STATUS="${{ env.EXP || false }}" + CLEANUP_STATUS="${{ github.event.inputs.cleanup_resources || true }}" + + # Construct the email body + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the document-generation-solution-accelerator Unified Deployment process has encountered an issue and has failed to complete successfully.

Configuration:
- WAF Enabled: ${WAF_STATUS}
- EXP: ${EXP_STATUS}
- Cleanup: ${CLEANUP_STATUS}

Build URL: ${RUN_URL}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

" + } + EOF + ) + + # Send the notification + curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send notification" + + - name: Logout from Azure + if: always() + run: | + azd auth logout + az logout || echo "Warning: Failed to logout from Azure CLI" + echo "Logged out from Azure." diff --git a/docker-workflow-test.md b/docker-workflow-test.md new file mode 100644 index 000000000..5ef531955 --- /dev/null +++ b/docker-workflow-test.md @@ -0,0 +1,9 @@ +# Docker Workflow Test + +This file is created to trigger the "Build Docker and Optional Push" workflow, which should then trigger the "Deploy-Test-Cleanup (Parameterized)" workflow via workflow_run. + +**Chain of events expected:** +1. Push this file → triggers "Build Docker and Optional Push" +2. "Build Docker and Optional Push" completes → triggers "Deploy-Test-Cleanup (Parameterized)" + +Test timestamp: October 23, 2025 \ No newline at end of file diff --git a/infra/main.bicep b/infra/main.bicep index 56e68a3ae..52c304da3 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -623,7 +623,7 @@ module aiSearch 'br/public:avm/res/search/search-service:0.11.1' = { diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null disableLocalAuth: false hostingMode: 'default' - sku: enableScalability ? 'standard' : 'basic' + sku: enableScalability ? 'standard' : 'standard' managedIdentities: { systemAssigned: true } networkRuleSet: { bypass: 'AzureServices' diff --git a/infra/main.parameters.json b/infra/main.parameters.json index b84739b81..c8b86c4cc 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -40,6 +40,9 @@ }, "azureExistingAIProjectResourceId":{ "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" + }, + "acrName": { + "value": "${AZURE_ENV_ACR_NAME}" } } } diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index ab91c89cf..b65a3ccb7 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -58,6 +58,9 @@ }, "azureExistingAIProjectResourceId":{ "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" + }, + "acrName": { + "value": "${AZURE_ENV_ACR_NAME}" } } } diff --git a/pr-test-trigger.md b/pr-test-trigger.md new file mode 100644 index 000000000..215cd82b4 --- /dev/null +++ b/pr-test-trigger.md @@ -0,0 +1,17 @@ +# PR Workflow Test + +This is a test file created to trigger the pull request workflow. + +**Test Details:** +- Date: October 23, 2025 +- Purpose: Testing the pull request trigger in deploy-Parameterized.yml workflow +- Expected outcome: Workflow should run with PR-specific configuration (WAF_ENABLED=false, EXP=false, etc.) + +## What the workflow should do: +1. Trigger on PR to main branch +2. Set automatic configuration for PR triggers +3. Deploy resources to Azure +4. Run E2E tests +5. Clean up resources after testing + +This file can be safely deleted after testing is complete. \ No newline at end of file