From 19ef66a9f40f7bcd9e585acd6feec5c2b3a05ef4 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Mon, 10 Nov 2025 14:56:40 +0530
Subject: [PATCH 01/17] Added Deploy-v2 pipeline with manual dispatch and input
parameter support
---
.github/workflows/deploy-v2.yml | 853 ++++++++++++++++++++++++++
.github/workflows/test-automation.yml | 77 ++-
infra/main.parameters.json | 6 +
infra/main.waf.parameters.json | 6 +
4 files changed, 917 insertions(+), 25 deletions(-)
create mode 100644 .github/workflows/deploy-v2.yml
diff --git a/.github/workflows/deploy-v2.yml b/.github/workflows/deploy-v2.yml
new file mode 100644
index 000000000..acb1d155c
--- /dev/null
+++ b/.github/workflows/deploy-v2.yml
@@ -0,0 +1,853 @@
+name: Deploy-Test-Cleanup (v2)
+on:
+ pull_request:
+ branches:
+ - main
+ workflow_run:
+ workflows: ["Build Docker and Optional Push"]
+ types:
+ - completed
+ branches:
+ - main
+ - dev
+ - demo
+ 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'
+ - 'eastus'
+ 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
+ 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
+
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID:
+ description: 'Log Analytics Workspace ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID:
+ description: 'AI Project Resource ID (Optional)'
+ required: false
+ default: ''
+ type: string
+ existing_webapp_url:
+ description: 'Existing WebApp URL (Skips Deployment)'
+ required: false
+ default: ''
+ type: string
+
+ schedule:
+ - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT
+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:
+ docker-build:
+ if: github.event_name == 'workflow_dispatch' && github.event.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
+ run: |
+ 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="${{ github.head_ref || github.ref_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"
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Azure Container Registry
+ uses: azure/docker-login@v2
+ with:
+ login-server: ${{ secrets.ACR_TEST_LOGIN_SERVER }}
+ username: ${{ secrets.ACR_TEST_USERNAME }}
+ password: ${{ secrets.ACR_TEST_PASSWORD }}
+
+ - name: Build and Push Docker Image
+ id: build_push_image
+ uses: docker/build-push-action@v6
+ env:
+ DOCKER_BUILD_SUMMARY: false
+ with:
+ context: ./src
+ file: ./src/WebApp.Dockerfile
+ push: true
+ tags: |
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}
+ ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}_${{ github.run_number }}
+
+ - name: Verify Docker Image Build
+ run: |
+ echo "β
Docker image successfully built and pushed"
+ echo "Image tag: ${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}"
+ echo "Run number: ${{ github.run_number }}"
+
+ - name: Generate Docker Build Summary
+ if: always()
+ run: |
+ # Extract ACR name from the secret
+ ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}" | cut -d'.' -f1)
+ 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 "| **Registry** | \`${ACR_NAME}.azurecr.io\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Full Image Path** | \`${ACR_NAME}.azurecr.io/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Trigger** | ${{ github.event_name }} |" >> $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 "- Docker image successfully built and pushed to ACR" >> $GITHUB_STEP_SUMMARY
+ echo "- Generated unique tag: \`${{ 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
+
+ deploy:
+ if: always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.existing_webapp_url == '' || github.event.inputs.existing_webapp_url == null)
+ needs: [docker-build]
+ 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 }}
+ 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 }}
+ 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_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.azure_location }}" ]]; then
+ echo " β’ Selected Azure Location: ${{ github.event.inputs.azure_location }}"
+ else
+ echo " β’ Azure Location: Will be determined by quota check"
+ fi
+ 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
+
+ - 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: Set Quota Failure Output
+ id: quota_failure_output
+ if: env.QUOTA_FAILED == 'true'
+ 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'
+ run: exit 1
+
+ - name: Set Deployment Region
+ id: set_region
+ run: |
+ # Set AZURE_ENV_OPENAI_LOCATION from quota check result
+ 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
+
+ # Set AZURE_LOCATION from user input (for manual dispatch) or default to quota check result (for automatic triggers)
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.azure_location }}" ]]; then
+ USER_SELECTED_LOCATION="${{ github.event.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
+ run: |
+ # Check if a resource group name was provided as input
+ if [[ -n "${{ github.event.inputs.resource_group_name }}" ]]; then
+ echo "Using provided Resource Group name: ${{ github.event.inputs.resource_group_name }}"
+ echo "RESOURCE_GROUP_NAME=${{ github.event.inputs.resource_group_name }}" >> $GITHUB_ENV
+ else
+ 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}"
+ fi
+
+ - 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 '$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
+
+ - 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: Determine Docker Image Tag
+ id: determine_image_tag
+ run: |
+ if [[ "${{ env.BUILD_DOCKER_IMAGE }}" == "true" ]]; then
+ # Use the tag from docker-build job if it was built
+ if [[ "${{ needs.docker-build.result }}" == "success" ]]; then
+ IMAGE_TAG="${{ needs.docker-build.outputs.IMAGE_TAG }}"
+ echo "π Using Docker image tag from build job: $IMAGE_TAG"
+ else
+ echo "β Docker build job failed or was skipped, but BUILD_DOCKER_IMAGE is true"
+ exit 1
+ fi
+ else
+ echo "π·οΈ Using existing Docker image based on branch..."
+ BRANCH_NAME="${{ env.BRANCH_NAME }}"
+ echo "Current branch: $BRANCH_NAME"
+
+ # Determine image tag based on branch
+ if [[ "$BRANCH_NAME" == "main" ]]; then
+ IMAGE_TAG="latest_waf"
+ echo "Using main branch - image tag: latest_waf"
+ elif [[ "$BRANCH_NAME" == "dev" ]]; then
+ IMAGE_TAG="dev"
+ echo "Using dev branch - image tag: dev"
+ elif [[ "$BRANCH_NAME" == "demo" ]]; then
+ IMAGE_TAG="demo"
+ echo "Using demo branch - image tag: demo"
+ else
+ IMAGE_TAG="latest_waf"
+ echo "Using default for branch '$BRANCH_NAME' - image tag: latest_waf"
+ fi
+
+ echo "Using existing Docker image tag: $IMAGE_TAG"
+ fi
+
+ echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
+ echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT
+
+ - name: Generate Unique Environment Name
+ id: generate_env_name
+ 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: ${{ steps.determine_image_tag.outputs.IMAGE_TAG }}"
+ echo "Registry: ${{ secrets.ACR_TEST_LOGIN_SERVER }}"
+ echo "Full Image: ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.determine_image_tag.outputs.IMAGE_TAG }}"
+ echo "================================"
+
+ - name: Deploy using azd up and extract values (${{ github.event.inputs.waf_enabled == 'true' && 'WAF' || 'Non-WAF' }}+${{ (github.event.inputs.EXP == 'true' || github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID != '' || github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID != '') && '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: ${{ steps.determine_image_tag.outputs.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_ENV_OPENAI_LOCATION"
+ azd env set AZURE_LOCATION="$AZURE_LOCATION"
+ azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME"
+ azd env set AZURE_ENV_IMAGETAG="${{ steps.determine_image_tag.outputs.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_TEST_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 AZURE_COSMOSDB_ACCOUNT=$(echo "$DEPLOY_OUTPUT" | jq -r '.AZURE_COSMOSDB_ACCOUNT // empty')
+ echo "AZURE_COSMOSDB_ACCOUNT=$AZURE_COSMOSDB_ACCOUNT" >> $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 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
+ 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" \
+ "$AZURE_COSMOSDB_ACCOUNT" \
+ "$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."
+
+
+
+ - name: Generate Deploy Job Summary
+ if: always()
+ run: |
+ echo "## π Deploy 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 "| **Environment Name** | \`${{ steps.generate_env_name.outputs.ENV_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`${{ steps.set_region.outputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`${{ steps.set_region.outputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`${{ steps.determine_image_tag.outputs.IMAGE_TAG }}\` |" >> $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 "| **Trigger** | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Branch** | ${{ env.BRANCH_NAME }} |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ job.status }}" == "success" ]]; then
+ echo "### β
Deployment Details" >> $GITHUB_STEP_SUMMARY
+ echo "- **Web App URL**: [${{ steps.get_output.outputs.WEBAPP_URL }}](${{ steps.get_output.outputs.WEBAPP_URL }})" >> $GITHUB_STEP_SUMMARY
+ echo "- **Configuration**: ${{ env.WAF_ENABLED == 'true' && 'WAF' || 'Non-WAF' }}+${{ env.EXP == 'true' && 'EXP' || 'Non-EXP' }}" >> $GITHUB_STEP_SUMMARY
+ echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY
+ echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "### β Deployment Failed" >> $GITHUB_STEP_SUMMARY
+ echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY
+ echo "- Check the deploy job for detailed error information" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ e2e-test:
+ if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.WEBAPP_URL != '') || (github.event.inputs.existing_webapp_url != '' && github.event.inputs.existing_webapp_url != null)) && (github.event_name != 'workflow_dispatch' || github.event.inputs.run_e2e_tests == 'true' || github.event.inputs.run_e2e_tests == null)
+ needs: [docker-build, 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:
+ if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && github.event.inputs.existing_webapp_url == '' && (github.event_name != 'workflow_dispatch' || github.event.inputs.cleanup_resources == 'true' || github.event.inputs.cleanup_resources == null)
+ needs: [docker-build, deploy, e2e-test]
+ runs-on: ubuntu-latest
+ env:
+ 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 }}
+ 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
+ if: github.event.inputs.existing_webapp_url == ''
+ run: |
+ set -e
+ echo "ποΈ Cleaning up Docker images from Azure Container Registry..."
+
+ # Determine the image tag to delete - check if docker-build job ran
+ if [[ "${{ needs.docker-build.result }}" == "success" ]]; then
+ IMAGE_TAG="${{ needs.docker-build.outputs.IMAGE_TAG }}"
+ echo "Using image tag from docker-build job: $IMAGE_TAG"
+ else
+ IMAGE_TAG="${{ needs.deploy.outputs.IMAGE_TAG }}"
+ echo "Using image tag from deploy job: $IMAGE_TAG"
+ fi
+
+ if [[ -n "$IMAGE_TAG" && "$IMAGE_TAG" != "latest_waf" && "$IMAGE_TAG" != "dev" && "$IMAGE_TAG" != "demo" ]]; then
+ echo "Deleting Docker images with tag: $IMAGE_TAG"
+
+ # Delete the main image
+ echo "Deleting image: ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:$IMAGE_TAG"
+ az acr repository delete --name $(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}" | cut -d'.' -f1) \
+ --image webapp:$IMAGE_TAG --yes || echo "Warning: Failed to delete main image or image not found"
+
+ echo "β
Docker images cleanup completed"
+ else
+ echo "β οΈ Skipping Docker image cleanup (using standard branch image: $IMAGE_TAG)"
+ fi
+
+ - name: Select Environment and Delete deployment using azd
+ run: |
+ set -e
+ # 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_ENV_OPENAI_LOCATION }}"
+ azd env set AZURE_LOCATION="${{ env.AZURE_LOCATION }}"
+ fi
+
+ echo "Deleting deployment..."
+ azd down --purge --force --no-prompt
+ echo "Deployment deleted successfully."
+
+
+
+ - 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."
+ - name: Generate Cleanup Job Summary
+ if: always()
+ run: |
+ echo "## π§Ή Cleanup 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 "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Environment Name** | \`${{ env.ENV_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`${{ env.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`${{ env.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`${{ env.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Trigger** | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Branch** | ${{ env.BRANCH_NAME }} |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ job.status }}" == "success" ]]; then
+ echo "### β
Cleanup Details" >> $GITHUB_STEP_SUMMARY
+ echo "- Successfully deleted Azure resource group: \`${{ env.RESOURCE_GROUP_NAME }}\`" >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ env.IMAGE_TAG }}" != "latest_waf" && "${{ env.IMAGE_TAG }}" != "dev" && "${{ env.IMAGE_TAG }}" != "demo" ]]; then
+ echo "- Removed custom Docker images from ACR with tag: \`${{ env.IMAGE_TAG }}\`" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "- Preserved standard Docker image (using branch tag: \`${{ env.IMAGE_TAG }}\`)" >> $GITHUB_STEP_SUMMARY
+ fi
+ echo "- All deployed resources have been successfully cleaned up" >> $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" >> $GITHUB_STEP_SUMMARY
+ echo "- β¬οΈ Check the cleanup-deployment job for detailed error information" >> $GITHUB_STEP_SUMMARY
+
+ fi
+
+ send-notification:
+ if: always()
+ needs: [docker-build, deploy, e2e-test]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Send Quota Failure Notification
+ if: needs.deploy.result == 'failure' && needs.deploy.outputs.QUOTA_FAILED == 'true'
+ 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 DocGen deployment has failed due to insufficient quota in the requested regions.
Issue Details:
β’ Quota check failed for GPT and Text Embedding models
β’ Required GPT Capacity: ${{ env.GPT_MIN_CAPACITY }}
β’ Required Text Embedding Capacity: ${{ env.TEXT_EMBEDDING_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": "DocGen 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: needs.deploy.result == 'failure' && needs.deploy.outputs.QUOTA_FAILED != 'true'
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ RESOURCE_GROUP="${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the DocGen 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": "DocGen 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: needs.deploy.result == 'success' && (needs.e2e-test.result == 'skipped' || needs.e2e-test.outputs.TEST_SUCCESS == 'true')
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ WEBAPP_URL="${{ needs.deploy.outputs.WEBAPP_URL || github.event.inputs.existing_webapp_url }}"
+ RESOURCE_GROUP="${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}"
+ TEST_REPORT_URL="${{ needs.e2e-test.outputs.TEST_REPORT_URL }}"
+
+ # Create email body based on test result
+ if [ "${{ needs.e2e-test.result }}" = "skipped" ]; then
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the DocGen 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": "DocGen Pipeline - Deployment Success"
+ }
+ EOF
+ )
+ else
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the DocGen deployment and testing process has completed successfully.
Deployment Details:
β’ Resource Group: ${RESOURCE_GROUP}
β’ Web App URL: ${WEBAPP_URL}
β’ E2E Tests: Passed
β’ Test Report: View Report
Configuration:
β’ WAF Enabled: ${{ env.WAF_ENABLED }}
β’ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "DocGen 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: needs.deploy.result == 'success' && needs.e2e-test.result != 'skipped' && needs.e2e-test.outputs.TEST_SUCCESS != 'true'
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ TEST_REPORT_URL="${{ needs.e2e-test.outputs.TEST_REPORT_URL }}"
+ WEBAPP_URL="${{ needs.deploy.outputs.WEBAPP_URL || github.event.inputs.existing_webapp_url }}"
+ RESOURCE_GROUP="${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }}"
+
+ EMAIL_BODY=$(cat <Dear Team,We would like to inform you that 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 Details:
β’ Test Report: View Report
Run URL: ${RUN_URL}
Please investigate the matter at your earliest convenience.
Best regards,
Your Automation Team
",
+ "subject": "DocGen 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
+ # Scenario: Deployment skipped (existing URL provided) AND e2e tests passed
+ if: needs.deploy.result == 'skipped' && github.event.inputs.existing_webapp_url != '' && needs.e2e-test.result == 'success' && (needs.e2e-test.outputs.TEST_SUCCESS == 'true' || needs.e2e-test.outputs.TEST_SUCCESS == '')
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ EXISTING_URL="${{ github.event.inputs.existing_webapp_url }}"
+ TEST_REPORT_URL="${{ needs.e2e-test.outputs.TEST_REPORT_URL }}"
+ EMAIL_BODY=$(cat <Dear Team,The DocGen pipeline executed against the existing WebApp URL and testing process has completed successfully.
Test Results:
β’ Status: β
Passed
${TEST_REPORT_URL:+β’ Test Report: View Report}
β’ Target URL: ${EXISTING_URL}
Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "DocGen 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
+ # Scenario: Deployment skipped (existing URL provided) AND e2e tests failed
+ if: needs.deploy.result == 'skipped' && github.event.inputs.existing_webapp_url != '' && needs.e2e-test.result == 'failure'
+ run: |
+ RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ EXISTING_URL="${{ github.event.inputs.existing_webapp_url }}"
+ TEST_REPORT_URL="${{ needs.e2e-test.outputs.TEST_REPORT_URL }}"
+ EMAIL_BODY=$(cat <Dear Team,The DocGen 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}
β’ Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "DocGen 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/test-automation.yml b/.github/workflows/test-automation.yml
index f602d4aea..a2581b9dc 100644
--- a/.github/workflows/test-automation.yml
+++ b/.github/workflows/test-automation.yml
@@ -11,6 +11,13 @@ on:
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:
url: ${{ inputs.DOCGEN_URL }}
@@ -19,6 +26,9 @@ env:
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
@@ -85,32 +95,49 @@ jobs:
name: test-report
path: tests/e2e-test/report/*
- - name: Send Notification
+
+
+ - name: Generate E2E Test Summary
if: always()
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- REPORT_URL=${{ steps.upload_report.outputs.artifact-url }}
- IS_SUCCESS=${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}
- # Construct the email body
- if [ "$IS_SUCCESS" = "true" ]; then
- EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} Test Automation process has completed successfully.
Run URL: ${RUN_URL}
Test Report: ${REPORT_URL}
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Test Automation - Success"
- }
- EOF
- )
+ echo "## π§ͺ E2E Test Job Summary" >> $GITHUB_STEP_SUMMARY
+ 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
- EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} Test Automation process has encountered an issue and has failed to complete successfully.
Run URL: ${RUN_URL}
${OUTPUT}
Test Report: ${REPORT_URL}
Please investigate the matter at your earliest convenience.
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Test Automation - Failure"
- }
- EOF
- )
+ echo "| **Job Status** | β Failed |" >> $GITHUB_STEP_SUMMARY
fi
-
- # Send the notification
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
- -H "Content-Type: application/json" \
- -d "$EMAIL_BODY" || echo "Failed to send notification"
\ No newline at end of file
+
+ echo "| **Target URL** | [${{ env.url }}](${{ env.url }}) |" >> $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
diff --git a/infra/main.parameters.json b/infra/main.parameters.json
index b84739b81..88bc053d4 100644
--- a/infra/main.parameters.json
+++ b/infra/main.parameters.json
@@ -40,6 +40,12 @@
},
"azureExistingAIProjectResourceId":{
"value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}"
+ },
+ "acrName": {
+ "value": "${AZURE_ENV_ACR_NAME}"
+ },
+ "azureAiServiceLocation": {
+ "value": "${AZURE_ENV_OPENAI_LOCATION}"
}
}
}
diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json
index ab91c89cf..da41c73dd 100644
--- a/infra/main.waf.parameters.json
+++ b/infra/main.waf.parameters.json
@@ -58,6 +58,12 @@
},
"azureExistingAIProjectResourceId":{
"value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}"
+ },
+ "acrName": {
+ "value": "${AZURE_ENV_ACR_NAME}"
+ },
+ "azureAiServiceLocation": {
+ "value": "${AZURE_ENV_OPENAI_LOCATION}"
}
}
}
From f0923b489d37897c8d0b97c92563fbce48fb7eff Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Tue, 11 Nov 2025 12:40:12 +0530
Subject: [PATCH 02/17] Update the ReadMe and Added role assignment for
Cognitive Services OpenAI User in create_index script
---
docs/CustomizingAzdParameters.md | 2 ++
infra/scripts/run_create_index_scripts.sh | 18 ++++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md
index dc1c99ccf..7345741a1 100644
--- a/docs/CustomizingAzdParameters.md
+++ b/docs/CustomizingAzdParameters.md
@@ -22,6 +22,8 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_EMBEDDING_MODEL_CAPACITY` | integer | `80` | Sets the capacity for the embedding model deployment. |
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of creating a new one. |
| `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | Guid to get your existing AI Foundry Project resource ID | Reuses an existing AIFoundry and AIFoundryProject instead of creating a new one. |
+| `AZURE_ENV_ACR_NAME` | string | `byocgacontainerreg` | Sets the Azure Container Registry name (allowed value: `byocgacontainerreg`)|
+| `AZURE_ENV_OPENAI_LOCATION` | string | `` | Sets the Azure region for OpenAI resource deployment. |
## How to Set a Parameter
diff --git a/infra/scripts/run_create_index_scripts.sh b/infra/scripts/run_create_index_scripts.sh
index a593c5cdc..c85c7cc78 100644
--- a/infra/scripts/run_create_index_scripts.sh
+++ b/infra/scripts/run_create_index_scripts.sh
@@ -83,6 +83,24 @@ fi
echo "User already has the Azure AI User role."
fi
+### Assign Cognitive Services OpenAI User role to the signed in user ###
+
+ # Check if the user has the Cognitive Services OpenAI User role
+ echo "Checking if user has the Cognitive Services OpenAI User role"
+ role_assignment=$(MSYS_NO_PATHCONV=1 az role assignment list --role 5e0bd9bd-7b93-4f28-af87-19fc36ad61bd --scope $aif_resource_id --assignee $signed_user_id --query "[].roleDefinitionId" -o tsv)
+ if [ -z "$role_assignment" ]; then
+ echo "User does not have the Cognitive Services OpenAI User role. Assigning the role."
+ MSYS_NO_PATHCONV=1 az role assignment create --assignee $signed_user_id --role 5e0bd9bd-7b93-4f28-af87-19fc36ad61bd --scope $aif_resource_id --output none
+ if [ $? -eq 0 ]; then
+ echo "Cognitive Services OpenAI User role assigned successfully."
+ else
+ echo "Failed to assign Cognitive Services OpenAI User role."
+ exit 1
+ fi
+ else
+ echo "User already has the Cognitive Services OpenAI User role."
+ fi
+
### Assign Search Index Data Contributor role to the signed in user ###
echo "Getting Azure Search resource id"
From de7b0cb98e4b9503cf5dd5562959484ee647e158 Mon Sep 17 00:00:00 2001
From: Prajwal-Microsoft
Date: Wed, 12 Nov 2025 10:28:06 +0530
Subject: [PATCH 03/17] refactor: Moved entry for AZURE_ENV_ACR_NAME
---
docs/CustomizingAzdParameters.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md
index 7345741a1..671848c5a 100644
--- a/docs/CustomizingAzdParameters.md
+++ b/docs/CustomizingAzdParameters.md
@@ -18,11 +18,11 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_OPENAI_API_VERSION` | string | `2025-01-01-preview` | Specifies the API version for Azure OpenAI. |
| `AZURE_ENV_MODEL_CAPACITY` | integer | `30` | Sets the GPT model capacity (based on what's available in your subscription). |
| `AZURE_ENV_EMBEDDING_MODEL_NAME` | string | `text-embedding-ada-002` | Sets the name of the embedding model to use. |
+| `AZURE_ENV_ACR_NAME` | string | `byocgacontainerreg` | Sets the Azure Container Registry name (allowed value: `byocgacontainerreg`)|
| `AZURE_ENV_IMAGETAG` | string | `latest_waf` | Set the Image tag Like (allowed values: latest_waf, dev, hotfix) |
| `AZURE_ENV_EMBEDDING_MODEL_CAPACITY` | integer | `80` | Sets the capacity for the embedding model deployment. |
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of creating a new one. |
| `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | Guid to get your existing AI Foundry Project resource ID | Reuses an existing AIFoundry and AIFoundryProject instead of creating a new one. |
-| `AZURE_ENV_ACR_NAME` | string | `byocgacontainerreg` | Sets the Azure Container Registry name (allowed value: `byocgacontainerreg`)|
| `AZURE_ENV_OPENAI_LOCATION` | string | `` | Sets the Azure region for OpenAI resource deployment. |
From d16a5a6ba03c01a610bc28f81cb55586795d9480 Mon Sep 17 00:00:00 2001
From: Atulku-Microsoft
Date: Fri, 14 Nov 2025 11:12:34 +0530
Subject: [PATCH 04/17] Add disclaimer for AI solutions in README
Added a disclaimer regarding AI solutions and associated risks.
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 616d9ccc9..6c49c9af4 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,10 @@ This example focuses on a generic use case - chat with your own data, generate a
-
+
+
+>β οΈ **Disclaimer:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
+
Solution overview
From 82ee8157523ddad43bbe8e41a913bf7157a22411 Mon Sep 17 00:00:00 2001
From: Harmanpreet-Microsoft
Date: Fri, 14 Nov 2025 20:02:22 +0530
Subject: [PATCH 05/17] Remove AI solutions disclaimer from README
Removed disclaimer about AI solutions and associated risks.
---
README.md | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 6c49c9af4..616d9ccc9 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,7 @@ This example focuses on a generic use case - chat with your own data, generate a
-
-
->β οΈ **Disclaimer:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
-
+
Solution overview
From 1437d6927f5f64c9cfc189e2dc7b6bf4dc4a239f Mon Sep 17 00:00:00 2001
From: Harmanpreet-Microsoft
Date: Fri, 14 Nov 2025 21:59:55 +0530
Subject: [PATCH 06/17] Add disclaimer for AI solutions and compliance
Added a disclaimer regarding AI solutions and associated risks.
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 616d9ccc9..e951595d6 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,10 @@ This example focuses on a generic use case - chat with your own data, generate a
+
+
+**Disclaimer:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
+
Solution overview
From 707caf84e02a08c23d43dc01a79e1d0df24d4280 Mon Sep 17 00:00:00 2001
From: Roopan-Microsoft <168007406+Roopan-Microsoft@users.noreply.github.com>
Date: Fri, 14 Nov 2025 22:21:28 +0530
Subject: [PATCH 07/17] Update README.md
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index e951595d6..d1d7cc816 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,6 @@ This example focuses on a generic use case - chat with your own data, generate a
-
**Disclaimer:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
From 50fd6b9332bb5331d53514efae76d7c3ea8dec6d Mon Sep 17 00:00:00 2001
From: Roopan-Microsoft <168007406+Roopan-Microsoft@users.noreply.github.com>
Date: Fri, 14 Nov 2025 23:45:53 +0530
Subject: [PATCH 08/17] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d1d7cc816..e36ca5758 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ This example focuses on a generic use case - chat with your own data, generate a
-**Disclaimer:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
+**Note:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
From 3068839111fad3bfa75f4eb745f93ee974287670 Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Thu, 20 Nov 2025 17:36:02 +0530
Subject: [PATCH 09/17] added files for vs code web
---
infra/vscode_web/.env | 7 ++
infra/vscode_web/.gitignore | 85 ++++++++++++++++++++++
infra/vscode_web/LICENSE | 21 ++++++
infra/vscode_web/README-noazd.md | 2 +
infra/vscode_web/README.md | 43 +++++++++++
infra/vscode_web/codeSample.py | 25 +++++++
infra/vscode_web/endpoint-requirements.txt | 3 +
infra/vscode_web/endpointCodeSample.py | 31 ++++++++
infra/vscode_web/index.json | 72 ++++++++++++++++++
infra/vscode_web/install.sh | 3 +
infra/vscode_web/requirements.txt | 3 +
11 files changed, 295 insertions(+)
create mode 100644 infra/vscode_web/.env
create mode 100644 infra/vscode_web/.gitignore
create mode 100644 infra/vscode_web/LICENSE
create mode 100644 infra/vscode_web/README-noazd.md
create mode 100644 infra/vscode_web/README.md
create mode 100644 infra/vscode_web/codeSample.py
create mode 100644 infra/vscode_web/endpoint-requirements.txt
create mode 100644 infra/vscode_web/endpointCodeSample.py
create mode 100644 infra/vscode_web/index.json
create mode 100644 infra/vscode_web/install.sh
create mode 100644 infra/vscode_web/requirements.txt
diff --git a/infra/vscode_web/.env b/infra/vscode_web/.env
new file mode 100644
index 000000000..d47886009
--- /dev/null
+++ b/infra/vscode_web/.env
@@ -0,0 +1,7 @@
+AZURE_EXISTING_AGENT_ID="<%= agentId %>"
+AZURE_ENV_NAME="<%= playgroundName %>"
+AZURE_LOCATION="<%= location %>"
+AZURE_SUBSCRIPTION_ID="<%= subscriptionId %>"
+AZURE_EXISTING_AIPROJECT_ENDPOINT="<%= endpoint %>"
+AZURE_EXISTING_AIPROJECT_RESOURCE_ID="<%= projectResourceId %>"
+AZD_ALLOW_NON_EMPTY_FOLDER=true
diff --git a/infra/vscode_web/.gitignore b/infra/vscode_web/.gitignore
new file mode 100644
index 000000000..23de01ef5
--- /dev/null
+++ b/infra/vscode_web/.gitignore
@@ -0,0 +1,85 @@
+# ========== .NET ========== #
+## Build results
+bin/
+obj/
+[Bb]uild/
+[Ll]ogs/
+*.log
+## User-specific files
+*.user
+*.suo
+*.userosscache
+*.sln.docstates
+*.vsp
+*.vspx
+*.vspscc
+## Rider / VS Code / Visual Studio
+.idea/
+.vscode/
+.vs/
+## NuGet packages
+*.nupkg
+packages/
+*.snupkg
+project.lock.json
+project.assets.json
+## Dotnet tools
+.tools/
+# ========== Java ========== #
+## Compiled class files
+*.class
+## Logs
+*.log
+## Maven
+target/
+## Gradle
+.gradle/
+build/
+## Eclipse
+.project
+.classpath
+.settings/
+.loadpath
+## IntelliJ IDEA
+*.iml
+*.ipr
+*.iws
+out/
+.idea/
+# ========== Python ========== #
+## Byte-compiled / cache
+__pycache__/
+*.py[cod]
+*$py.class
+## Virtual environment
+env/
+venv/
+ENV/
+.venv/
+.env*
+## PyInstaller
+*.spec
+dist/
+build/
+## Jupyter Notebook
+.ipynb_checkpoints/
+## Misc
+*.log
+*.pot
+*.pyc
+.DS_Store
+*.sqlite3
+# ========== General ========== #
+## OS generated
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+.DS_Store
+*.swp
+*.swo
+*.bak
+*.tmp
+*.old
+## Node (just in case mixed project)
+node_modules/
+# End
\ No newline at end of file
diff --git a/infra/vscode_web/LICENSE b/infra/vscode_web/LICENSE
new file mode 100644
index 000000000..22aed37e6
--- /dev/null
+++ b/infra/vscode_web/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) Microsoft Corporation.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/infra/vscode_web/README-noazd.md b/infra/vscode_web/README-noazd.md
new file mode 100644
index 000000000..1436b6150
--- /dev/null
+++ b/infra/vscode_web/README-noazd.md
@@ -0,0 +1,2 @@
+# VS Code for the Web - Azure AI Foundry Templates
+
diff --git a/infra/vscode_web/README.md b/infra/vscode_web/README.md
new file mode 100644
index 000000000..6ce5aedfa
--- /dev/null
+++ b/infra/vscode_web/README.md
@@ -0,0 +1,43 @@
+# VS Code for the Web - Azure AI Foundry Templates
+
+We've generated a simple development environment for you to deploy the templates.
+
+The Azure AI Foundry extension provides tools to help you build, test, and deploy AI models and AI Applications directly from VS Code. It offers simplified operations for interacting with your models, agents, and threads without leaving your development environment. Click on the Azure AI Foundry Icon on the left to see more.
+
+Follow the instructions below to get started!
+
+You should see a terminal opened with the template code already cloned.
+
+## Deploy the template
+
+You can provision and deploy this template using:
+
+```bash
+azd up
+```
+
+Follow any instructions from the deployment script and launch the application.
+
+
+If you need to delete the deployment and stop incurring any charges, run:
+
+```bash
+azd down
+```
+
+## Continuing on your local desktop
+
+You can keep working locally on VS Code Desktop by clicking "Continue On Desktop..." at the bottom left of this screen. Be sure to take the .env file with you using these steps:
+
+- Right-click the .env file
+- Select "Download"
+- Move the file from your Downloads folder to the local git repo directory
+- For Windows, you will need to rename the file back to .env using right-click "Rename..."
+
+## More examples
+
+Check out [Azure AI Projects client library for Python](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/README.md) for more information on using this SDK.
+
+## Troubleshooting
+
+- If you are instantiating your client via endpoint on an Azure AI Foundry project, ensure the endpoint is set in the `.env` as https://{your-foundry-resource-name}.services.ai.azure.com/api/projects/{your-foundry-project-name}`
\ No newline at end of file
diff --git a/infra/vscode_web/codeSample.py b/infra/vscode_web/codeSample.py
new file mode 100644
index 000000000..37224009c
--- /dev/null
+++ b/infra/vscode_web/codeSample.py
@@ -0,0 +1,25 @@
+from azure.ai.projects import AIProjectClient
+from azure.identity import DefaultAzureCredential
+
+project_client = AIProjectClient.from_connection_string(
+ credential=DefaultAzureCredential(),
+ conn_str="<%= connectionString %>")
+
+agent = project_client.agents.get_agent("<%= agentId %>")
+
+thread = project_client.agents.create_thread()
+print(f"Created thread, ID: {thread.id}")
+
+message = project_client.agents.create_message(
+ thread_id=thread.id,
+ role="user",
+ content="<%= userMessage %>"
+)
+
+run = project_client.agents.create_and_process_run(
+ thread_id=thread.id,
+ agent_id=agent.id)
+messages = project_client.agents.list_messages(thread_id=thread.id)
+
+for text_message in messages.text_messages:
+ print(text_message.as_dict())
diff --git a/infra/vscode_web/endpoint-requirements.txt b/infra/vscode_web/endpoint-requirements.txt
new file mode 100644
index 000000000..18d6803e8
--- /dev/null
+++ b/infra/vscode_web/endpoint-requirements.txt
@@ -0,0 +1,3 @@
+azure-ai-projects==1.0.0b12
+azure-identity==1.20.0
+ansible-core~=2.17.0
\ No newline at end of file
diff --git a/infra/vscode_web/endpointCodeSample.py b/infra/vscode_web/endpointCodeSample.py
new file mode 100644
index 000000000..227052773
--- /dev/null
+++ b/infra/vscode_web/endpointCodeSample.py
@@ -0,0 +1,31 @@
+from azure.ai.projects import AIProjectClient
+from azure.identity import DefaultAzureCredential
+from azure.ai.agents.models import ListSortOrder
+
+project = AIProjectClient(
+ credential=DefaultAzureCredential(),
+ endpoint="<%= endpoint %>")
+
+agent = project.agents.get_agent("<%= agentId %>")
+
+thread = project.agents.threads.create()
+print(f"Created thread, ID: {thread.id}")
+
+message = project.agents.messages.create(
+ thread_id=thread.id,
+ role="user",
+ content="<%= userMessage %>"
+)
+
+run = project.agents.runs.create_and_process(
+ thread_id=thread.id,
+ agent_id=agent.id)
+
+if run.status == "failed":
+ print(f"Run failed: {run.last_error}")
+else:
+ messages = project.agents.messages.list(thread_id=thread.id, order=ListSortOrder.ASCENDING)
+
+ for message in messages:
+ if message.text_messages:
+ print(f"{message.role}: {message.text_messages[-1].text.value}")
diff --git a/infra/vscode_web/index.json b/infra/vscode_web/index.json
new file mode 100644
index 000000000..55157c9da
--- /dev/null
+++ b/infra/vscode_web/index.json
@@ -0,0 +1,72 @@
+{
+ "ai-projects-sdk": {
+ "python": {
+ "default-azure-auth": {
+ "connectionString": [
+ {
+ "name": "run_agent.py",
+ "type": "code",
+ "path": "/codeSample.py"
+ },
+ {
+ "name": "INSTRUCTIONS.md",
+ "type": "readme",
+ "path": "/README-noazd.md"
+ },
+ {
+ "name": "requirements.txt",
+ "type": "dependencies",
+ "path": "/requirements.txt"
+ },
+ {
+ "name": ".env",
+ "type": "env",
+ "path": "/.env"
+ },
+ {
+ "name": "install.sh",
+ "type": "install",
+ "path": "/install.sh"
+ },
+ {
+ "name": ".gitignore",
+ "type": "code",
+ "path": "/.gitignore"
+ }
+ ],
+ "endpoint": [
+ {
+ "name": "run_agent.py",
+ "type": "code",
+ "path": "/endpointCodeSample.py"
+ },
+ {
+ "name": "INSTRUCTIONS.md",
+ "type": "readme",
+ "path": "/README.md"
+ },
+ {
+ "name": "requirements.txt",
+ "type": "dependencies",
+ "path": "/endpoint-requirements.txt"
+ },
+ {
+ "name": ".env",
+ "type": "env",
+ "path": "/.env"
+ },
+ {
+ "name": "install.sh",
+ "type": "install",
+ "path": "/install.sh"
+ },
+ {
+ "name": ".gitignore",
+ "type": "code",
+ "path": "/.gitignore"
+ }
+ ]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/infra/vscode_web/install.sh b/infra/vscode_web/install.sh
new file mode 100644
index 000000000..a5b72b48b
--- /dev/null
+++ b/infra/vscode_web/install.sh
@@ -0,0 +1,3 @@
+pip install -r requirements.txt --user -q
+
+azd init -t microsoft/document-generation-solution-accelerator
\ No newline at end of file
diff --git a/infra/vscode_web/requirements.txt b/infra/vscode_web/requirements.txt
new file mode 100644
index 000000000..18d6803e8
--- /dev/null
+++ b/infra/vscode_web/requirements.txt
@@ -0,0 +1,3 @@
+azure-ai-projects==1.0.0b12
+azure-identity==1.20.0
+ansible-core~=2.17.0
\ No newline at end of file
From 440df023440c87a51be9451b1ff05d2932f42358 Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Thu, 20 Nov 2025 19:46:56 +0530
Subject: [PATCH 10/17] add vscode web button in readme
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index e36ca5758..4740ff878 100644
--- a/README.md
+++ b/README.md
@@ -72,8 +72,8 @@ Follow the quick deploy steps on the deployment guide to deploy this solution to
[Click here to launch the deployment guide](./docs/DeploymentGuide.md)
-| [](https://codespaces.new/microsoft/document-generation-solution-accelerator) | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/document-generation-solution-accelerator) |
-|---|---|
+| [](https://codespaces.new/microsoft/document-generation-solution-accelerator) | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/document-generation-solution-accelerator) | [&message=Open&color=blue&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/azure/?vscode-azure-exp=foundry&agentPayload=eyJiYXNlVXJsIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9taWNyb3NvZnQvZG9jdW1lbnQtZ2VuZXJhdGlvbi1zb2x1dGlvbi1hY2NlbGVyYXRvci9yZWZzL2hlYWRzL21haW4vaW5mcmEvdnNjb2RlX3dlYiIsICJpbmRleFVybCI6ICIvaW5kZXguanNvbiIsICJ2YXJpYWJsZXMiOiB7ImFnZW50SWQiOiAiIiwgImNvbm5lY3Rpb25TdHJpbmciOiAiIiwgInRocmVhZElkIjogIiIsICJ1c2VyTWVzc2FnZSI6ICIiLCAicGxheWdyb3VuZE5hbWUiOiAiIiwgImxvY2F0aW9uIjogIiIsICJzdWJzY3JpcHRpb25JZCI6ICIiLCAicmVzb3VyY2VJZCI6ICIiLCAicHJvamVjdFJlc291cmNlSWQiOiAiIiwgImVuZHBvaW50IjogIiJ9LCAiY29kZVJvdXRlIjogWyJhaS1wcm9qZWN0cy1zZGsiLCAicHl0aG9uIiwgImRlZmF1bHQtYXp1cmUtYXV0aCIsICJlbmRwb2ludCJdfQ==) |
+|---|---|---|
From 0f9b7666af500535ca57e9c8ae60db9c3576b9a0 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 21 Nov 2025 10:44:44 +0530
Subject: [PATCH 11/17] chore: added AZURE_DEV_COLLECT_TELEMETRY environment
variable to pipeline
---
.github/workflows/deploy-v2.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy-v2.yml b/.github/workflows/deploy-v2.yml
index acb1d155c..555b7614b 100644
--- a/.github/workflows/deploy-v2.yml
+++ b/.github/workflows/deploy-v2.yml
@@ -89,6 +89,7 @@ env:
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 }}
+ AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
jobs:
docker-build:
@@ -456,14 +457,13 @@ jobs:
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_ENV_OPENAI_LOCATION"
azd env set AZURE_LOCATION="$AZURE_LOCATION"
azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME"
azd env set AZURE_ENV_IMAGETAG="${{ steps.determine_image_tag.outputs.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
From a2fa4147e4c1152b514a6a59017a717d3d654021 Mon Sep 17 00:00:00 2001
From: "Prekshith D J (Persistent Systems Inc)"
Date: Mon, 24 Nov 2025 12:36:04 +0530
Subject: [PATCH 12/17] Updated the code owners
---
.github/CODEOWNERS | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c67633667..1302d1455 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,5 +2,5 @@
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in the repo.
-* @toherman-msft @Avijit-Microsoft @Roopan-Microsoft @Prajwal-Microsoft @Vinay-Microsoft @malrose07 @aniaroramsft
+* @toherman-msft @Avijit-Microsoft @Roopan-Microsoft @Prajwal-Microsoft @Vinay-Microsoft @malrose07 @aniaroramsft @nchandhi
From c03ddc06d054b701a80c163de734870b357bcd22 Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Tue, 25 Nov 2025 11:24:55 +0530
Subject: [PATCH 13/17] commented Azure location env var in vs code web
---
infra/vscode_web/.env | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/infra/vscode_web/.env b/infra/vscode_web/.env
index d47886009..141104744 100644
--- a/infra/vscode_web/.env
+++ b/infra/vscode_web/.env
@@ -1,6 +1,6 @@
AZURE_EXISTING_AGENT_ID="<%= agentId %>"
AZURE_ENV_NAME="<%= playgroundName %>"
-AZURE_LOCATION="<%= location %>"
+# AZURE_LOCATION="<%= location %>"
AZURE_SUBSCRIPTION_ID="<%= subscriptionId %>"
AZURE_EXISTING_AIPROJECT_ENDPOINT="<%= endpoint %>"
AZURE_EXISTING_AIPROJECT_RESOURCE_ID="<%= projectResourceId %>"
From fe089e2c992232adc8f2a13123e59139a17f8820 Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Tue, 25 Nov 2025 11:28:03 +0530
Subject: [PATCH 14/17] added branch for validation
---
infra/vscode_web/install.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/infra/vscode_web/install.sh b/infra/vscode_web/install.sh
index a5b72b48b..b4ee8f623 100644
--- a/infra/vscode_web/install.sh
+++ b/infra/vscode_web/install.sh
@@ -1,3 +1,3 @@
pip install -r requirements.txt --user -q
-azd init -t microsoft/document-generation-solution-accelerator
\ No newline at end of file
+azd init -t microsoft/document-generation-solution-accelerator -b docgen-vscodeweb
\ No newline at end of file
From 255969f4d94f10e0ac7e2b424d709011303cc3fb Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Tue, 25 Nov 2025 12:09:10 +0530
Subject: [PATCH 15/17] Revert "added branch for validation"
This reverts commit fe089e2c992232adc8f2a13123e59139a17f8820.
---
infra/vscode_web/install.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/infra/vscode_web/install.sh b/infra/vscode_web/install.sh
index b4ee8f623..a5b72b48b 100644
--- a/infra/vscode_web/install.sh
+++ b/infra/vscode_web/install.sh
@@ -1,3 +1,3 @@
pip install -r requirements.txt --user -q
-azd init -t microsoft/document-generation-solution-accelerator -b docgen-vscodeweb
\ No newline at end of file
+azd init -t microsoft/document-generation-solution-accelerator
\ No newline at end of file
From 54190fce42623c92f9b74fe90666d9e39e170fce Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Thu, 27 Nov 2025 16:23:01 +0530
Subject: [PATCH 16/17] Update Deployment Guide to include Visual Studio Code
(WEB) deployment instructions
---
docs/DeploymentGuide.md | 40 ++++++++++++++++++++++++++++++++++++----
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/docs/DeploymentGuide.md b/docs/DeploymentGuide.md
index 879f84338..458792e23 100644
--- a/docs/DeploymentGuide.md
+++ b/docs/DeploymentGuide.md
@@ -64,10 +64,10 @@ azd env set AZURE_ENV_VM_ADMIN_PASSWORD
## Deployment Options & Steps
-Pick from the options below to see step-by-step instructions for GitHub Codespaces, VS Code Dev Containers, and Local Environments.
+Pick from the options below to see step-by-step instructions for GitHub Codespaces, VS Code Dev Containers, Visual Studio Code (WEB) and Local Environments.
-| [](https://codespaces.new/microsoft/document-generation-solution-accelerator) | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/document-generation-solution-accelerator) |
-|---|---|
+| [](https://codespaces.new/microsoft/document-generation-solution-accelerator) | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/document-generation-solution-accelerator) | [&message=Open&color=blue&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/azure/?vscode-azure-exp=foundry&agentPayload=eyJiYXNlVXJsIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9taWNyb3NvZnQvZG9jdW1lbnQtZ2VuZXJhdGlvbi1zb2x1dGlvbi1hY2NlbGVyYXRvci9yZWZzL2hlYWRzL21haW4vaW5mcmEvdnNjb2RlX3dlYiIsICJpbmRleFVybCI6ICIvaW5kZXguanNvbiIsICJ2YXJpYWJsZXMiOiB7ImFnZW50SWQiOiAiIiwgImNvbm5lY3Rpb25TdHJpbmciOiAiIiwgInRocmVhZElkIjogIiIsICJ1c2VyTWVzc2FnZSI6ICIiLCAicGxheWdyb3VuZE5hbWUiOiAiIiwgImxvY2F0aW9uIjogIiIsICJzdWJzY3JpcHRpb25JZCI6ICIiLCAicmVzb3VyY2VJZCI6ICIiLCAicHJvamVjdFJlc291cmNlSWQiOiAiIiwgImVuZHBvaW50IjogIiJ9LCAiY29kZVJvdXRlIjogWyJhaS1wcm9qZWN0cy1zZGsiLCAicHl0aG9uIiwgImRlZmF1bHQtYXp1cmUtYXV0aCIsICJlbmRwb2ludCJdfQ==) |
+|---|---|--|
Deploy in GitHub Codespaces
@@ -103,6 +103,38 @@ You can run this solution in VS Code Dev Containers, which will open the project
+
+ Deploy in Visual Studio Code (WEB)
+
+### Visual Studio Code (WEB)
+
+You can run this solution in VS Code Web. The button will open a web-based VS Code instance in your browser:
+
+1. Open the solution accelerator (this may take several minutes):
+
+ [&message=Open&color=blue&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/azure/?vscode-azure-exp=foundry&agentPayload=eyJiYXNlVXJsIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9taWNyb3NvZnQvZG9jdW1lbnQtZ2VuZXJhdGlvbi1zb2x1dGlvbi1hY2NlbGVyYXRvci9yZWZzL2hlYWRzL21haW4vaW5mcmEvdnNjb2RlX3dlYiIsICJpbmRleFVybCI6ICIvaW5kZXguanNvbiIsICJ2YXJpYWJsZXMiOiB7ImFnZW50SWQiOiAiIiwgImNvbm5lY3Rpb25TdHJpbmciOiAiIiwgInRocmVhZElkIjogIiIsICJ1c2VyTWVzc2FnZSI6ICIiLCAicGxheWdyb3VuZE5hbWUiOiAiIiwgImxvY2F0aW9uIjogIiIsICJzdWJzY3JpcHRpb25JZCI6ICIiLCAicmVzb3VyY2VJZCI6ICIiLCAicHJvamVjdFJlc291cmNlSWQiOiAiIiwgImVuZHBvaW50IjogIiJ9LCAiY29kZVJvdXRlIjogWyJhaS1wcm9qZWN0cy1zZGsiLCAicHl0aG9uIiwgImRlZmF1bHQtYXp1cmUtYXV0aCIsICJlbmRwb2ludCJdfQ==)
+
+2. When prompted, sign in using your Microsoft account linked to your Azure subscription.
+
+ Select the appropriate subscription to continue.
+
+3. Once the solution opens, the **AI Foundry terminal** will automatically start running the following command to install the required dependencies:
+
+ ```shell
+ sh install.sh
+ ```
+ During this process, youβll be prompted with the message:
+ ```
+ What would you like to do with these files?
+ - Overwrite with versions from template
+ - Keep my existing files unchanged
+ ```
+ Choose β**Overwrite with versions from template**β and provide a unique environment name when prompted.
+
+4. Continue with the [deploying steps](#deploying-with-azd).
+
+
+
Deploy in your local Environment
@@ -172,7 +204,7 @@ To adjust quota settings, follow these [steps](./AzureGPTQuotaSettings.md).
### Deploying with AZD
-Once you've opened the project in [Codespaces](#github-codespaces), [Dev Containers](#vs-code-dev-containers), or [locally](#local-environment), you can deploy it to Azure by following these steps:
+Once you've opened the project in [Codespaces](#github-codespaces), [Dev Containers](#vs-code-dev-containers), [Visual Studio Code (WEB)](#visual-studio-code-web) or [locally](#local-environment), you can deploy it to Azure by following these steps:
1. Login to Azure:
From de236260f858cfd250148628777b7e2325f7265a Mon Sep 17 00:00:00 2001
From: Ragini-Microsoft
Date: Thu, 27 Nov 2025 16:33:51 +0530
Subject: [PATCH 17/17] Update Azure CLI login method to use device code for
authentication
---
infra/scripts/process_sample_data.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/infra/scripts/process_sample_data.sh b/infra/scripts/process_sample_data.sh
index b5aece3f8..06cb81d44 100644
--- a/infra/scripts/process_sample_data.sh
+++ b/infra/scripts/process_sample_data.sh
@@ -251,7 +251,7 @@ else
else
# Use Azure CLI login if running locally
echo "Authenticating with Azure CLI..."
- az login
+ az login --use-device-code
fi
echo "Not authenticated with Azure. Attempting to authenticate..."
fi