From a4806a48e7194ad2364267f17033d10dd9cf4f33 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 09:54:04 +0530 Subject: [PATCH 01/32] feat: Enhance deployment workflows with image model selection and quota checks --- .github/workflows/deploy-linux.yml | 37 +++- .github/workflows/deploy-orchestrator.yml | 6 + .github/workflows/job-deploy-linux.yml | 78 +------ .github/workflows/job-deploy-windows.yml | 64 +----- .github/workflows/job-deploy.yml | 74 ++++++- .github/workflows/job-docker-build.yml | 4 +- content-gen/infra/main.parameters.json | 12 -- content-gen/infra/main.waf.parameters.json | 66 ++++++ content-gen/scripts/checkquota.sh | 235 +++++++++++++++++++++ 9 files changed, 424 insertions(+), 152 deletions(-) create mode 100644 content-gen/infra/main.waf.parameters.json create mode 100644 content-gen/scripts/checkquota.sh diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index c45aae3f5..cad37465f 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -4,14 +4,12 @@ on: branches: - main paths: - - 'src/frontend/**' - - 'src/**/*.py' - - 'src/requirements*.txt' - - 'src/WebApp.Dockerfile' - - '!src/tests/**' - - 'infra/**/*.bicep' - - 'infra/**/*.json' - - '*.yaml' + - 'content-gen/src/**' + - '!content-gen/src/tests/**' + - 'content-gen/infra/**/*.bicep' + - 'content-gen/infra/**/*.json' + - 'content-gen/*.yaml' + - 'content-gen/scripts/**' - '.github/workflows/deploy-*.yml' workflow_run: workflows: ["Build Docker and Optional Push"] @@ -90,6 +88,16 @@ on: required: false default: '' type: string + image_model_choice: + description: 'Image Model to Deploy' + required: false + default: 'gpt-image-1' + type: choice + options: + - 'gpt-image-1' + - 'gpt-image-1.5' + - 'dall-e-3' + - 'none' schedule: - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT @@ -111,6 +119,7 @@ jobs: azure_env_log_analytics_workspace_id: ${{ steps.validate.outputs.azure_env_log_analytics_workspace_id }} azure_existing_ai_project_resource_id: ${{ steps.validate.outputs.azure_existing_ai_project_resource_id }} existing_webapp_url: ${{ steps.validate.outputs.existing_webapp_url }} + image_model_choice: ${{ steps.validate.outputs.image_model_choice }} steps: - name: Validate Workflow Input Parameters id: validate @@ -126,6 +135,7 @@ jobs: INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} INPUT_EXISTING_WEBAPP_URL: ${{ github.event.inputs.existing_webapp_url }} + INPUT_IMAGE_MODEL_CHOICE: ${{ github.event.inputs.image_model_choice }} run: | echo "🔍 Validating workflow input parameters..." VALIDATION_FAILED=false @@ -262,6 +272,16 @@ jobs: echo "azure_env_log_analytics_workspace_id=$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" >> $GITHUB_OUTPUT echo "azure_existing_ai_project_resource_id=$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" >> $GITHUB_OUTPUT echo "existing_webapp_url=$INPUT_EXISTING_WEBAPP_URL" >> $GITHUB_OUTPUT + + # Validate and output image_model_choice + IMAGE_MODEL="${INPUT_IMAGE_MODEL_CHOICE:-gpt-image-1}" + ALLOWED_MODELS=("gpt-image-1" "gpt-image-1.5" "dall-e-3" "none") + if [[ ! " ${ALLOWED_MODELS[@]} " =~ " ${IMAGE_MODEL} " ]]; then + echo "❌ ERROR: image_model_choice '$IMAGE_MODEL' is invalid. Allowed: ${ALLOWED_MODELS[*]}" + exit 1 + fi + echo "✅ image_model_choice: '$IMAGE_MODEL' is valid" + echo "image_model_choice=$IMAGE_MODEL" >> $GITHUB_OUTPUT Run: needs: validate-inputs @@ -280,4 +300,5 @@ jobs: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ needs.validate-inputs.outputs.azure_existing_ai_project_resource_id || '' }} existing_webapp_url: ${{ needs.validate-inputs.outputs.existing_webapp_url || '' }} trigger_type: ${{ github.event_name }} + image_model_choice: ${{ needs.validate-inputs.outputs.image_model_choice || 'gpt-image-1' }} secrets: inherit diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 31741f3b4..3b29968a0 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -61,6 +61,11 @@ on: description: 'Trigger type (workflow_dispatch, pull_request, schedule)' required: true type: string + image_model_choice: + description: 'Image model to deploy (gpt-image-1, gpt-image-1.5, dall-e-3, none)' + required: false + default: 'gpt-image-1' + type: string env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} @@ -94,6 +99,7 @@ jobs: docker_image_tag: ${{ needs.docker-build.outputs.IMAGE_TAG }} run_e2e_tests: ${{ inputs.run_e2e_tests }} cleanup_resources: ${{ inputs.cleanup_resources }} + image_model_choice: ${{ inputs.image_model_choice }} secrets: inherit e2e-test: diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 37d1b82a2..2438cc8a0 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -37,7 +37,7 @@ on: outputs: WEB_APPURL: description: "Container Web App URL" - value: ${{ jobs.deploy-linux.outputs.WEB_APPURL }} + value: ${{ jobs.deploy-linux.outputs.WEB_APP_URL }} permissions: contents: read actions: read @@ -48,7 +48,7 @@ jobs: env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} outputs: - WEB_APPURL: ${{ steps.get_output_linux.outputs.WEB_APPURL }} + WEB_APP_URL: ${{ steps.get_output_linux.outputs.WEB_APP_URL }} steps: - name: Validate Workflow Input Parameters shell: bash @@ -191,7 +191,7 @@ jobs: WAF_ENABLED: ${{ inputs.WAF_ENABLED }} run: | if [[ "$WAF_ENABLED" == "true" ]]; then - cp infra/main.waf.parameters.json infra/main.parameters.json + cp content-gen/infra/main.waf.parameters.json content-gen/infra/main.parameters.json echo "✅ Successfully copied WAF parameters to main parameters file" else echo "🔧 Configuring Non-WAF deployment - using default main.parameters.json..." @@ -275,72 +275,14 @@ jobs: fi fi - # Deploy using azd up + # Deploy using azd up (from content-gen directory where azure.yaml lives) + cd content-gen 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) - 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 - - 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 - - AZURE_COSMOSDB_ACCOUNT=$(echo "$DEPLOY_OUTPUT" | jq -r '.AZURE_COSMOSDB_ACCOUNT // empty') - echo "AZURE_COSMOSDB_ACCOUNT=$AZURE_COSMOSDB_ACCOUNT" >> $GITHUB_ENV - - STORAGE_ACCOUNT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.STORAGE_ACCOUNT_NAME // empty') - echo "STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME" >> $GITHUB_ENV - - STORAGE_CONTAINER_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.STORAGE_CONTAINER_NAME // empty') - echo "STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME" >> $GITHUB_ENV - - KEY_VAULT_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.KEY_VAULT_NAME // empty') - echo "KEY_VAULT_NAME=$KEY_VAULT_NAME" >> $GITHUB_ENV - - RESOURCE_GROUP_NAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.RESOURCE_GROUP_NAME // empty') - echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV - - WEB_APPURL=$(echo "$DEPLOY_OUTPUT" | jq -r '.WEB_APP_URL // .SERVICE_BACKEND_ENDPOINT_URL // empty') - echo "WEB_APPURL=$WEB_APPURL" >> $GITHUB_OUTPUT - sleep 30 - - - name: Run Post-Deployment Script - id: post_deploy - env: - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - STORAGE_ACCOUNT_NAME: ${{ env.STORAGE_ACCOUNT_NAME }} - STORAGE_CONTAINER_NAME: ${{ env.STORAGE_CONTAINER_NAME }} - KEY_VAULT_NAME: ${{ env.KEY_VAULT_NAME }} - AZURE_COSMOSDB_ACCOUNT: ${{ env.AZURE_COSMOSDB_ACCOUNT }} - RESOURCE_GROUP_NAME: ${{ env.RESOURCE_GROUP_NAME }} - AI_SEARCH_SERVICE_NAME: ${{ env.AI_SEARCH_SERVICE_NAME }} - AI_FOUNDRY_RESOURCE_ID: ${{ env.AI_FOUNDRY_RESOURCE_ID }} - run: | - set -e - az account set --subscription "$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" \ - "$AZURE_CLIENT_ID" \ - "$AI_FOUNDRY_RESOURCE_ID" + WEB_APP_URL=$(azd env get-value WEB_APP_URL) + echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_ENV + echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT - name: Generate Deploy Job Summary if: always() @@ -352,7 +294,7 @@ jobs: AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} IMAGE_TAG: ${{ inputs.IMAGE_TAG }} JOB_STATUS: ${{ job.status }} - WEB_APPURL: ${{ steps.get_output_linux.outputs.WEB_APPURL }} + WEB_APP_URL: ${{ steps.get_output_linux.outputs.WEB_APP_URL }} run: | echo "## 🚀 Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY @@ -386,7 +328,7 @@ jobs: if [[ "$JOB_STATUS" == "success" ]]; then echo "### ✅ Deployment Details" >> $GITHUB_STEP_SUMMARY - echo "- **Web App URL**: [$WEB_APPURL]($WEB_APPURL)" >> $GITHUB_STEP_SUMMARY + echo "- **Web App URL**: [$WEB_APP_URL]($WEB_APP_URL)" >> $GITHUB_STEP_SUMMARY echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY else diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index e9dda12d4..d83495d2e 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -192,7 +192,7 @@ jobs: WAF_ENABLED: ${{ inputs.WAF_ENABLED }} run: | if [[ "$WAF_ENABLED" == "true" ]]; then - cp infra/main.waf.parameters.json infra/main.parameters.json + cp content-gen/infra/main.waf.parameters.json content-gen/infra/main.parameters.json echo "✅ Successfully copied WAF parameters to main parameters file" else echo "🔧 Configuring Non-WAF deployment - using default main.parameters.json..." @@ -273,67 +273,17 @@ jobs: Write-Host "❌ EXP DISABLED - Skipping EXP parameters" } - # Deploy using azd up + # Deploy using azd up (from content-gen directory where azure.yaml lives) + Push-Location content-gen azd up --no-prompt - + Write-Host "✅ Deployment succeeded." # Get deployment outputs using azd Write-Host "Extracting deployment outputs..." - $DEPLOY_OUTPUT = azd env get-values --output json | ConvertFrom-Json - Write-Host "Deployment output: $($DEPLOY_OUTPUT | ConvertTo-Json -Depth 10)" - - if (-not $DEPLOY_OUTPUT) { - Write-Host "Error: Deployment output is empty. Please check the deployment logs." - exit 1 - } - - - $AI_FOUNDRY_RESOURCE_ID = $DEPLOY_OUTPUT.AI_FOUNDRY_RESOURCE_ID - "AI_FOUNDRY_RESOURCE_ID=$AI_FOUNDRY_RESOURCE_ID" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $AI_SEARCH_SERVICE_NAME = $DEPLOY_OUTPUT.AI_SEARCH_SERVICE_NAME - "AI_SEARCH_SERVICE_NAME=$AI_SEARCH_SERVICE_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $AZURE_COSMOSDB_ACCOUNT = $DEPLOY_OUTPUT.AZURE_COSMOSDB_ACCOUNT - "AZURE_COSMOSDB_ACCOUNT=$AZURE_COSMOSDB_ACCOUNT" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $STORAGE_ACCOUNT_NAME = $DEPLOY_OUTPUT.STORAGE_ACCOUNT_NAME - "STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $STORAGE_CONTAINER_NAME = $DEPLOY_OUTPUT.STORAGE_CONTAINER_NAME - "STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $KEY_VAULT_NAME = $DEPLOY_OUTPUT.KEY_VAULT_NAME - "KEY_VAULT_NAME=$KEY_VAULT_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $RESOURCE_GROUP_NAME = $DEPLOY_OUTPUT.RESOURCE_GROUP_NAME - "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - $WEB_APP_URL = $DEPLOY_OUTPUT.WEB_APP_URL - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "WEB_APPURL=$WEB_APP_URL" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - - name: Run Post-Deployment Script - id: post_deploy - env: - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - shell: bash - run: | - set -e - az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - echo "Running post-deployment script..." - - bash ./infra/scripts/process_sample_data.sh \ - "${{ env.STORAGE_ACCOUNT_NAME }}" \ - "${{ env.STORAGE_CONTAINER_NAME }}" \ - "${{ env.KEY_VAULT_NAME }}" \ - "${{ env.AZURE_COSMOSDB_ACCOUNT }}" \ - "${{ env.RESOURCE_GROUP_NAME }}" \ - "${{ env.AI_SEARCH_SERVICE_NAME }}" \ - "${{ secrets.AZURE_CLIENT_ID }}" \ - "${{ env.AI_FOUNDRY_RESOURCE_ID }}" + $webAppUrl = azd env get-value WEB_APP_URL + echo "WEB_APPURL=$webAppUrl" >> $GITHUB_ENV + echo "WEB_APPURL=$webAppUrl" >> $GITHUB_OUTPUT - name: Generate Deploy Job Summary if: always() diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index a54023768..a9d138e5c 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -66,6 +66,11 @@ on: required: false default: '' type: string + image_model_choice: + description: 'Image model to deploy (gpt-image-1, gpt-image-1.5, dall-e-3, none)' + required: false + default: 'gpt-image-1' + type: string outputs: RESOURCE_GROUP_NAME: description: "Resource Group Name" @@ -91,7 +96,7 @@ on: env: GPT_MIN_CAPACITY: 150 - TEXT_EMBEDDING_MIN_CAPACITY: 80 + IMAGE_MODEL_MIN_CAPACITY: 1 BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }} WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }} EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.EXP || false) || false }} @@ -333,13 +338,14 @@ jobs: AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} GPT_MIN_CAPACITY: ${{ env.GPT_MIN_CAPACITY }} - TEXT_EMBEDDING_MIN_CAPACITY: ${{ env.TEXT_EMBEDDING_MIN_CAPACITY }} + IMAGE_MODEL_CHOICE: ${{ inputs.image_model_choice || 'gpt-image-1' }} + IMAGE_MODEL_MIN_CAPACITY: ${{ env.IMAGE_MODEL_MIN_CAPACITY }} AZURE_REGIONS: ${{ vars.AZURE_REGIONS }} run: | - chmod +x scripts/checkquota.sh - if ! scripts/checkquota.sh; then + chmod +x content-gen/scripts/checkquota.sh + if ! content-gen/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 + if grep -q "No region with sufficient quota found" content-gen/scripts/checkquota.sh; then echo "QUOTA_FAILED=true" >> $GITHUB_ENV fi exit 1 # Fail the pipeline if any other failure occurs @@ -378,6 +384,64 @@ jobs: echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_ENV echo "AZURE_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT fi + + - name: Check Azure Search Service Quota + id: search-quota-check + shell: bash + run: | + # Determine search tier based on WAF (scalability) setting + # WAF enabled → standard tier, WAF disabled → basic tier + if [[ "${{ env.WAF_ENABLED }}" == "true" ]]; then + SEARCH_TIER="standard" + SEARCH_TIER_DISPLAY="Standard" + else + SEARCH_TIER="basic" + SEARCH_TIER_DISPLAY="Basic" + fi + + echo "🔍 Checking Azure Search $SEARCH_TIER_DISPLAY tier quota in region: ${{ env.AZURE_LOCATION }}" + + # Get current usage and limits for Azure Search in the selected region using REST API + SEARCH_USAGE=$(az rest --method get \ + --url "https://management.azure.com/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.Search/locations/${{ env.AZURE_LOCATION }}/usages?api-version=2024-03-01-preview" \ + -o json 2>/dev/null || echo '{"value":[]}') + + if [ "$(echo "$SEARCH_USAGE" | jq '.value | length')" -eq 0 ]; then + echo "âš ī¸ Could not retrieve Azure Search quota information. Proceeding with deployment..." + echo "SEARCH_QUOTA_CHECK=skipped" >> $GITHUB_OUTPUT + else + TIER_USAGE=$(echo "$SEARCH_USAGE" | jq -r --arg tier "$SEARCH_TIER" '.value[] | select(.name.value == $tier) | .currentValue // 0') + TIER_LIMIT=$(echo "$SEARCH_USAGE" | jq -r --arg tier "$SEARCH_TIER" '.value[] | select(.name.value == $tier) | .limit // 0') + TIER_AVAILABLE=$((TIER_LIMIT - TIER_USAGE)) + + echo "Azure Search $SEARCH_TIER_DISPLAY Tier Quota for ${{ env.AZURE_LOCATION }}:" + echo " Current Usage: $TIER_USAGE" + echo " Limit: $TIER_LIMIT" + echo " Available: $TIER_AVAILABLE" + + if [ "$TIER_AVAILABLE" -lt 1 ]; then + echo "" + echo "❌ ERROR: Insufficient Azure Search $SEARCH_TIER_DISPLAY tier quota in region: ${{ env.AZURE_LOCATION }}" + echo "Please select a different region." + + # Add error to GitHub Summary + echo "## ❌ Azure Search Quota Check Failed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Region:** \`${{ env.AZURE_LOCATION }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY + echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| **Tier** | $SEARCH_TIER_DISPLAY |" >> $GITHUB_STEP_SUMMARY + echo "| **Current Usage** | $TIER_USAGE |" >> $GITHUB_STEP_SUMMARY + echo "| **Limit** | $TIER_LIMIT |" >> $GITHUB_STEP_SUMMARY + echo "| **Available** | $TIER_AVAILABLE |" >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + echo "" + echo "✅ Azure Search $SEARCH_TIER_DISPLAY tier quota check passed." + echo "SEARCH_QUOTA_CHECK=passed" >> $GITHUB_OUTPUT + fi - name: Generate Resource Group Name id: generate_rg_name diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml index fc564ea3f..5c4fbed3d 100644 --- a/.github/workflows/job-docker-build.yml +++ b/.github/workflows/job-docker-build.yml @@ -63,8 +63,8 @@ jobs: env: DOCKER_BUILD_SUMMARY: false with: - context: ./src - file: ./src/WebApp.Dockerfile + context: ./content-gen/src + file: ./content-gen/src/WebApp.Dockerfile push: true tags: | ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} diff --git a/content-gen/infra/main.parameters.json b/content-gen/infra/main.parameters.json index 051635a50..05c294453 100644 --- a/content-gen/infra/main.parameters.json +++ b/content-gen/infra/main.parameters.json @@ -49,18 +49,6 @@ }, "imageTag": { "value": "${imageTag=latest}" - }, - "enablePrivateNetworking": { - "value": "${enablePrivateNetworking}" - }, - "enableMonitoring": { - "value": "${enableMonitoring}" - }, - "enableScalability": { - "value": "${enableScalability}" - }, - "enableRedundancy": { - "value": "${enableRedundancy}" } } } diff --git a/content-gen/infra/main.waf.parameters.json b/content-gen/infra/main.waf.parameters.json new file mode 100644 index 000000000..fb2ddf560 --- /dev/null +++ b/content-gen/infra/main.waf.parameters.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "solutionName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "gptModelName": { + "value": "${gptModelName}" + }, + "gptModelVersion": { + "value": "${gptModelVersion}" + }, + "gptModelDeploymentType": { + "value": "${gptModelDeploymentType}" + }, + "gptModelCapacity": { + "value": "${gptModelCapacity}" + }, + "imageModelChoice": { + "value": "${imageModelChoice}" + }, + "dalleModelCapacity": { + "value": "${dalleModelCapacity}" + }, + "embeddingModel": { + "value": "${embeddingModel}" + }, + "embeddingDeploymentCapacity": { + "value": "${embeddingDeploymentCapacity}" + }, + "azureOpenaiAPIVersion": { + "value": "${azureOpenaiAPIVersion}" + }, + "azureAiServiceLocation": { + "value": "${azureAiServiceLocation}" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "${existingLogAnalyticsWorkspaceId}" + }, + "azureExistingAIProjectResourceId": { + "value": "${azureExistingAIProjectResourceId}" + }, + "acrName": { + "value": "${acrName}" + }, + "imageTag": { + "value": "${imageTag=latest}" + }, + "enablePrivateNetworking": { + "value": true + }, + "enableMonitoring": { + "value": true + }, + "enableScalability": { + "value": true + }, + "enableRedundancy": { + "value": true + } + } +} diff --git a/content-gen/scripts/checkquota.sh b/content-gen/scripts/checkquota.sh new file mode 100644 index 000000000..c40592e5b --- /dev/null +++ b/content-gen/scripts/checkquota.sh @@ -0,0 +1,235 @@ +#!/bin/bash + +# ============================================================================= +# Quota Check Script for Content Generation Solution Accelerator +# Checks Azure OpenAI quota across regions for GPT and image models. +# Selects the first region with sufficient quota for ALL required models. +# +# Works in both CI (service principal) and local (existing az login) modes. +# Auto-detects mode based on environment variables. +# +# Usage (local): +# bash checkquota.sh [image_model_choice] +# bash checkquota.sh gpt-image-1 +# bash checkquota.sh dall-e-3 +# bash checkquota.sh none +# +# Usage (CI - via env vars): +# Set AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID, +# AZURE_SUBSCRIPTION_ID, GPT_MIN_CAPACITY, AZURE_REGIONS, IMAGE_MODEL_CHOICE +# ============================================================================= + +# ---- Determine run mode: CI (service principal) or Local (existing session) ---- +if [[ -n "$AZURE_CLIENT_ID" && -n "$AZURE_CLIENT_SECRET" && -n "$AZURE_TENANT_ID" ]]; then + RUN_MODE="ci" +else + RUN_MODE="local" +fi + +# ---- Configuration ---- +# In local mode, image model can be passed as first argument +if [[ "$RUN_MODE" == "local" ]]; then + IMAGE_MODEL_CHOICE="${1:-${IMAGE_MODEL_CHOICE:-gpt-image-1}}" +else + IMAGE_MODEL_CHOICE="${IMAGE_MODEL_CHOICE:-gpt-image-1}" +fi + +GPT_MIN_CAPACITY="${GPT_MIN_CAPACITY:-150}" +IMAGE_MODEL_MIN_CAPACITY="${IMAGE_MODEL_MIN_CAPACITY:-1}" + +# Regions to check +if [[ -n "$AZURE_REGIONS" ]]; then + IFS=', ' read -ra REGIONS <<< "$AZURE_REGIONS" +else + REGIONS=("westus3" "eastus2" "uaenorth" "polandcentral" "swedencentral" "australiaeast" "eastus" "uksouth" "japaneast") +fi + +# ---- Image Model Region Constraints ---- +# gpt-image-1 GlobalStandard: westus3, eastus2, uaenorth, polandcentral, swedencentral +# gpt-image-1.5 GlobalStandard: westus3, eastus2, uaenorth, polandcentral, swedencentral +# dall-e-3 Standard: available in most AI service regions (no extra restriction) +# none: no image model deployed + +declare -A IMAGE_MODEL_VALID_REGIONS +IMAGE_MODEL_VALID_REGIONS=( + ["gpt-image-1"]="westus3 eastus2 uaenorth polandcentral swedencentral" + ["gpt-image-1.5"]="westus3 eastus2 uaenorth polandcentral swedencentral" + ["dall-e-3"]="all" + ["none"]="all" +) + +# Map image model choice to Azure quota model name +declare -A IMAGE_MODEL_QUOTA_NAME +IMAGE_MODEL_QUOTA_NAME=( + ["gpt-image-1"]="OpenAI.GlobalStandard.gpt-image-1" + ["gpt-image-1.5"]="OpenAI.GlobalStandard.gpt-image-1.5" + ["dall-e-3"]="OpenAI.Standard.dall-e-3" + ["none"]="" +) + +# ---- Validate image model choice ---- +ALLOWED_MODELS=("gpt-image-1" "gpt-image-1.5" "dall-e-3" "none") +if [[ ! " ${ALLOWED_MODELS[@]} " =~ " ${IMAGE_MODEL_CHOICE} " ]]; then + echo "❌ ERROR: Invalid image model choice: '$IMAGE_MODEL_CHOICE'" + echo " Allowed values: ${ALLOWED_MODELS[*]}" + exit 1 +fi + +# ---- Authentication ---- +if [[ "$RUN_MODE" == "ci" ]]; then + echo "🔑 Authenticating using Service Principal (CI mode)..." + if ! az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID"; then + echo "❌ Error: Failed to login using Service Principal." + exit 1 + fi + + SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID}" + if [[ -z "$SUBSCRIPTION_ID" || -z "$GPT_MIN_CAPACITY" ]]; then + echo "❌ ERROR: Missing required environment variables." + echo " AZURE_SUBSCRIPTION_ID=${SUBSCRIPTION_ID:-(empty)}" + echo " GPT_MIN_CAPACITY=${GPT_MIN_CAPACITY:-(empty)}" + echo " AZURE_REGIONS=${AZURE_REGIONS:-(empty)}" + exit 1 + fi + + echo "🔄 Setting Azure subscription..." + if ! az account set --subscription "$SUBSCRIPTION_ID"; then + echo "❌ ERROR: Invalid subscription ID or insufficient permissions." + exit 1 + fi + echo "✅ Azure subscription set successfully." +else + echo "🔑 Using existing Azure CLI session (local mode)..." + if ! az account show &>/dev/null; then + echo "❌ Not logged in. Run 'az login' first." + exit 1 + fi + SUBSCRIPTION=$(az account show --query "name" -o tsv) + echo "✅ Using subscription: $SUBSCRIPTION" +fi + +echo "" +echo "📋 Configuration:" +echo " Mode: $RUN_MODE" +echo " Image Model Choice: $IMAGE_MODEL_CHOICE" +echo " GPT Min Capacity: $GPT_MIN_CAPACITY" +echo " Image Model Min Capacity: $IMAGE_MODEL_MIN_CAPACITY" +echo " Regions to check: ${REGIONS[*]}" +echo "" + +# ---- Build Model Capacity Map ---- +declare -A MIN_CAPACITY +MIN_CAPACITY=( + ["OpenAI.GlobalStandard.gpt-5.1"]=$GPT_MIN_CAPACITY +) + +# Add image model to quota check if not 'none' +IMAGE_QUOTA_NAME="${IMAGE_MODEL_QUOTA_NAME[$IMAGE_MODEL_CHOICE]}" +if [[ -n "$IMAGE_QUOTA_NAME" ]]; then + MIN_CAPACITY["$IMAGE_QUOTA_NAME"]=$IMAGE_MODEL_MIN_CAPACITY + echo "đŸ–ŧī¸ Image model '$IMAGE_MODEL_CHOICE' added to quota check (key: $IMAGE_QUOTA_NAME, min capacity: $IMAGE_MODEL_MIN_CAPACITY)" +else + echo "â„šī¸ Image model set to 'none' — skipping image model quota check." +fi +echo "" + +# ---- Helper: Check if region supports the selected image model ---- +is_region_valid_for_image_model() { + local region="$1" + local valid_regions="${IMAGE_MODEL_VALID_REGIONS[$IMAGE_MODEL_CHOICE]}" + + if [[ "$valid_regions" == "all" || "$IMAGE_MODEL_CHOICE" == "none" ]]; then + return 0 + fi + + for vr in $valid_regions; do + if [[ "$vr" == "$region" ]]; then + return 0 + fi + done + + return 1 +} + +# ---- Main Quota Check Loop ---- +VALID_REGION="" +for REGION in "${REGIONS[@]}"; do + echo "========================================" + echo "🔍 Checking region: $REGION" + + # First, check if this region supports the selected image model + if ! is_region_valid_for_image_model "$REGION"; then + echo " âš ī¸ Region '$REGION' does not support '$IMAGE_MODEL_CHOICE' (GlobalStandard). Skipping." + echo " Valid regions: ${IMAGE_MODEL_VALID_REGIONS[$IMAGE_MODEL_CHOICE]}" + continue + fi + + QUOTA_INFO=$(az cognitiveservices usage list --location "$REGION" --output json 2>/dev/null) + if [ -z "$QUOTA_INFO" ]; then + echo " âš ī¸ Failed to retrieve quota for region $REGION. Skipping." + continue + fi + + INSUFFICIENT_QUOTA=false + for MODEL in "${!MIN_CAPACITY[@]}"; do + MODEL_INFO=$(echo "$QUOTA_INFO" | awk -v model="\"value\": \"$MODEL\"" ' + BEGIN { RS="},"; FS="," } + $0 ~ model { print $0 } + ') + + if [ -z "$MODEL_INFO" ]; then + echo " âš ī¸ No quota info for: $MODEL in $REGION. Skipping." + INSUFFICIENT_QUOTA=true + continue + fi + + CURRENT_VALUE=$(echo "$MODEL_INFO" | awk -F': ' '/"currentValue"/ {print $2}' | tr -d ',' | tr -d ' ') + LIMIT=$(echo "$MODEL_INFO" | awk -F': ' '/"limit"/ {print $2}' | tr -d ',' | tr -d ' ') + + CURRENT_VALUE=${CURRENT_VALUE:-0} + LIMIT=${LIMIT:-0} + + CURRENT_VALUE=$(echo "$CURRENT_VALUE" | cut -d'.' -f1) + LIMIT=$(echo "$LIMIT" | cut -d'.' -f1) + + AVAILABLE=$((LIMIT - CURRENT_VALUE)) + + if [ "$AVAILABLE" -lt "${MIN_CAPACITY[$MODEL]}" ]; then + echo " ❌ $MODEL | Used: $CURRENT_VALUE | Limit: $LIMIT | Available: $AVAILABLE | Need: ${MIN_CAPACITY[$MODEL]}" + INSUFFICIENT_QUOTA=true + break + else + echo " ✅ $MODEL | Used: $CURRENT_VALUE | Limit: $LIMIT | Available: $AVAILABLE | Need: ${MIN_CAPACITY[$MODEL]}" + fi + done + + if [ "$INSUFFICIENT_QUOTA" = false ]; then + VALID_REGION="$REGION" + echo " 🎉 Region '$REGION' has sufficient quota for all models!" + break + fi + +done + +echo "" +echo "========================================" +if [ -z "$VALID_REGION" ]; then + echo "❌ No region with sufficient quota found!" + echo " Image Model: $IMAGE_MODEL_CHOICE" + echo " Checked regions: ${REGIONS[*]}" + + # In CI mode, set GITHUB_ENV variable instead of exiting with error + if [[ "$RUN_MODE" == "ci" ]]; then + echo "QUOTA_FAILED=true" >> "$GITHUB_ENV" + exit 0 + else + exit 1 + fi +else + echo "✅ Recommended Region: $VALID_REGION" + + if [[ "$RUN_MODE" == "ci" ]]; then + echo "VALID_REGION=$VALID_REGION" >> "$GITHUB_ENV" + fi + exit 0 +fi From bdc5267251eeb23f2f91cbcedeafebcc6b9ee4ed Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:11:57 +0530 Subject: [PATCH 02/32] feat: Add support for DevContainer deployment and enhance input validation --- .github/workflows/deploy-linux.yml | 34 +- .github/workflows/deploy-orchestrator.yml | 2 +- .github/workflows/job-deploy-devcontainer.yml | 432 ++++++++++++++++++ .github/workflows/job-deploy.yml | 21 +- 4 files changed, 485 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/job-deploy-devcontainer.yml diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index cad37465f..7972d8d06 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -21,6 +21,16 @@ on: - demo workflow_dispatch: inputs: + runner_os: + description: 'Deployment Environment' + required: false + type: choice + options: + - 'codespace' + - 'Devcontainer' + - 'Local' + default: 'codespace' + azure_location: description: 'Azure Location For Deployment' required: false @@ -109,6 +119,7 @@ jobs: runs-on: ubuntu-latest outputs: validation_passed: ${{ steps.validate.outputs.passed }} + runner_os: ${{ steps.validate.outputs.runner_os }} azure_location: ${{ steps.validate.outputs.azure_location }} resource_group_name: ${{ steps.validate.outputs.resource_group_name }} waf_enabled: ${{ steps.validate.outputs.waf_enabled }} @@ -125,6 +136,7 @@ jobs: id: validate shell: bash env: + INPUT_RUNNER_OS: ${{ github.event.inputs.runner_os }} INPUT_AZURE_LOCATION: ${{ github.event.inputs.azure_location }} INPUT_RESOURCE_GROUP_NAME: ${{ github.event.inputs.resource_group_name }} INPUT_WAF_ENABLED: ${{ github.event.inputs.waf_enabled }} @@ -140,6 +152,25 @@ jobs: echo "🔍 Validating workflow input parameters..." VALIDATION_FAILED=false + # Validate runner_os (specific allowed values) and derive actual runner + RUNNER_OS_INPUT="${INPUT_RUNNER_OS:-codespace}" + if [[ "$RUNNER_OS_INPUT" != "codespace" && "$RUNNER_OS_INPUT" != "Devcontainer" && "$RUNNER_OS_INPUT" != "Local" ]]; then + echo "❌ ERROR: runner_os must be one of: codespace, Devcontainer, Local, got: '$RUNNER_OS_INPUT'" + VALIDATION_FAILED=true + else + echo "✅ runner_os: '$RUNNER_OS_INPUT' is valid" + fi + + # Derive actual runner from runner_os input + if [[ "$RUNNER_OS_INPUT" == "codespace" ]]; then + RUNNER_OS="ubuntu-latest" + elif [[ "$RUNNER_OS_INPUT" == "Devcontainer" ]]; then + RUNNER_OS="devcontainer" + else + RUNNER_OS="windows-latest" + fi + echo "✅ runner_os derived as: '$RUNNER_OS'" + # Validate azure_location (Azure region format) LOCATION="${INPUT_AZURE_LOCATION:-australiaeast}" @@ -262,6 +293,7 @@ jobs: # Output validated values echo "passed=true" >> $GITHUB_OUTPUT + echo "runner_os=$RUNNER_OS" >> $GITHUB_OUTPUT echo "azure_location=$LOCATION" >> $GITHUB_OUTPUT echo "resource_group_name=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT echo "waf_enabled=$WAF_ENABLED" >> $GITHUB_OUTPUT @@ -288,7 +320,7 @@ jobs: if: needs.validate-inputs.outputs.validation_passed == 'true' uses: ./.github/workflows/deploy-orchestrator.yml with: - runner_os: ubuntu-latest + runner_os: ${{ needs.validate-inputs.outputs.runner_os || 'ubuntu-latest' }} azure_location: ${{ needs.validate-inputs.outputs.azure_location || 'australiaeast' }} resource_group_name: ${{ needs.validate-inputs.outputs.resource_group_name || '' }} waf_enabled: ${{ needs.validate-inputs.outputs.waf_enabled == 'true' }} diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 3b29968a0..b1234f60a 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -4,7 +4,7 @@ on: workflow_call: inputs: runner_os: - description: 'Runner OS (ubuntu-latest or windows-latest)' + description: 'Runner OS (ubuntu-latest, windows-latest, or devcontainer)' required: true type: string azure_location: diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml new file mode 100644 index 000000000..16b099693 --- /dev/null +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -0,0 +1,432 @@ +name: Deploy Steps - DevContainer + +# This workflow uses the same devcontainer as Codespaces. +# The devcontainer (Dockerfile + features + post-create script) installs everything: +# Python 3.11, Azure CLI + Bicep, azd, Node.js, Poetry, pip dependencies +# So the workflow simply: builds the container → logs in → runs azd up. + +on: + workflow_call: + inputs: + ENV_NAME: + required: true + type: string + AZURE_ENV_OPENAI_LOCATION: + required: true + type: string + AZURE_LOCATION: + required: true + type: string + RESOURCE_GROUP_NAME: + required: true + type: string + IMAGE_TAG: + required: true + type: string + EXP: + required: true + type: string + WAF_ENABLED: + required: false + type: string + default: 'false' + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: + required: false + type: string + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: + required: false + type: string + outputs: + WEB_APPURL: + description: "Container Web App URL" + value: ${{ jobs.deploy-devcontainer.outputs.WEB_APPURL }} + +permissions: + contents: read + packages: write # Required to push devcontainer image to GHCR (optional caching) + +jobs: + deploy-devcontainer: + runs-on: ubuntu-latest + env: + AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + outputs: + WEB_APPURL: ${{ steps.load_azd_outputs.outputs.WEB_APP_URL }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Validate Workflow Input Parameters + shell: bash + env: + INPUT_ENV_NAME: ${{ inputs.ENV_NAME }} + INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} + INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} + INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + INPUT_EXP: ${{ inputs.EXP }} + INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + run: | + echo "🔍 Validating workflow input parameters..." + VALIDATION_FAILED=false + + # Validate ENV_NAME (required, alphanumeric and hyphens) + if [[ -z "$INPUT_ENV_NAME" ]]; then + echo "❌ ERROR: ENV_NAME is required but not provided" + VALIDATION_FAILED=true + elif [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo "❌ ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must contain only alphanumerics, underscores, and hyphens" + VALIDATION_FAILED=true + else + echo "✅ ENV_NAME: '$INPUT_ENV_NAME' is valid" + fi + + # Validate AZURE_ENV_OPENAI_LOCATION (required, Azure region format) + if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then + echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided" + VALIDATION_FAILED=true + elif [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then + echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Must contain only lowercase letters and numbers" + VALIDATION_FAILED=true + else + echo "✅ AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid" + fi + + # Validate AZURE_LOCATION (required, Azure region format) + if [[ -z "$INPUT_AZURE_LOCATION" ]]; then + echo "❌ ERROR: AZURE_LOCATION is required but not provided" + VALIDATION_FAILED=true + elif [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then + echo "❌ ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers" + VALIDATION_FAILED=true + else + echo "✅ AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid" + fi + + # Validate RESOURCE_GROUP_NAME (required, Azure naming convention) + if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then + echo "❌ ERROR: RESOURCE_GROUP_NAME is required but not provided" + VALIDATION_FAILED=true + elif [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then + echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period." + VALIDATION_FAILED=true + elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then + echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters" + VALIDATION_FAILED=true + else + echo "✅ RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid" + fi + + # Validate IMAGE_TAG (required, Docker tag pattern) + if [[ -z "$INPUT_IMAGE_TAG" ]]; then + echo "❌ ERROR: IMAGE_TAG is required but not provided" + VALIDATION_FAILED=true + elif [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then + echo "❌ ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must start with alphanumeric or underscore, contain only alphanumerics, underscores, periods, hyphens, max 128 characters" + VALIDATION_FAILED=true + else + echo "✅ IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid" + fi + + # Validate EXP (required, boolean string) + if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then + echo "❌ ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'" + VALIDATION_FAILED=true + else + echo "✅ EXP: '$INPUT_EXP' is valid" + fi + + # Validate WAF_ENABLED (boolean string) + if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then + echo "❌ ERROR: WAF_ENABLED must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'" + VALIDATION_FAILED=true + else + echo "✅ WAF_ENABLED: '$INPUT_WAF_ENABLED' is valid" + fi + + # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, Azure Resource ID format) + if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then + if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then + echo "❌ ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:" + echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}" + echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'" + VALIDATION_FAILED=true + else + echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format" + fi + else + echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Not provided (optional)" + fi + + # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID) + if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then + if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then + echo "❌ ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:" + echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}" + echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'" + VALIDATION_FAILED=true + else + echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format" + fi + else + echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Not provided (optional)" + fi + + # Fail workflow if any validation failed + if [[ "$VALIDATION_FAILED" == "true" ]]; then + echo "" + echo "❌ Parameter validation failed. Please correct the errors above and try again." + exit 1 + fi + + echo "" + echo "✅ All input parameters validated successfully!" + + - name: Configure Parameters Based on WAF Setting + shell: bash + env: + WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + run: | + if [[ "$WAF_ENABLED" == "true" ]]; then + cp content-gen/infra/main.waf.parameters.json content-gen/infra/main.parameters.json + echo "✅ Successfully copied WAF parameters to main parameters file" + else + echo "🔧 Configuring Non-WAF deployment - using default main.parameters.json..." + fi + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set Lowercase Image Name + id: image_name + shell: bash + run: echo "IMAGE_NAME=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')/devcontainer" >> $GITHUB_ENV + + # Build devcontainer and run azd up inside it — identical to Codespaces + - name: Deploy with azd up in DevContainer + uses: devcontainers/ci@v0.3 + env: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + INPUT_ENV_NAME: ${{ inputs.ENV_NAME }} + INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} + INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} + INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + INPUT_EXP: ${{ inputs.EXP }} + INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + SECRET_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ secrets.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + SECRET_ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }} + with: + # Cache the built devcontainer image to GHCR to reuse across runs + imageName: ${{ env.IMAGE_NAME }} + cacheFrom: ${{ env.IMAGE_NAME }} + push: always + + # Explicitly forward env vars into the devcontainer + env: | + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET + AZURE_TENANT_ID + AZURE_SUBSCRIPTION_ID + INPUT_ENV_NAME + INPUT_AZURE_ENV_OPENAI_LOCATION + INPUT_AZURE_LOCATION + INPUT_RESOURCE_GROUP_NAME + INPUT_IMAGE_TAG + INPUT_EXP + INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID + INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID + EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID + SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID + SECRET_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID + SECRET_ACR_TEST_USERNAME + + runCmd: | + echo "đŸŗ Running inside devcontainer — same environment as Codespaces" + echo "Python: $(python3 --version)" + echo "Azure CLI: $(az version --query '"azure-cli"' -o tsv)" + echo "azd: $(azd version)" + echo "" + + set -e + + # 1. Authenticate Azure CLI and azd using client secret + echo "🔐 Logging in with Azure CLI (client secret)..." + az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID" + az account set --subscription "$AZURE_SUBSCRIPTION_ID" + + echo "🔐 Logging in with azd (client secret)..." + azd auth login \ + --client-id "$AZURE_CLIENT_ID" \ + --client-secret "$AZURE_CLIENT_SECRET" \ + --tenant-id "$AZURE_TENANT_ID" + + # 2. Initialize azd environment + echo "âš™ī¸ Creating azd environment: $INPUT_ENV_NAME" + azd env new "$INPUT_ENV_NAME" --no-prompt + + echo "Setting default subscription..." + azd config set defaults.subscription "$AZURE_SUBSCRIPTION_ID" + + # Set core parameters + azd env set AZURE_SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" + azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_LOCATION="$AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" + + # Set ACR name from secret + if [[ -n "$SECRET_ACR_TEST_USERNAME" ]]; then + azd env set AZURE_ENV_ACR_NAME="$SECRET_ACR_TEST_USERNAME" + echo "Set ACR name from secret" + fi + + # Set EXP parameters if enabled + if [[ "$INPUT_EXP" == "true" ]]; then + echo "✅ EXP ENABLED - Setting EXP parameters..." + + if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then + EXP_LOG_ANALYTICS_ID="$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" + elif [[ -n "$EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then + EXP_LOG_ANALYTICS_ID="$EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" + else + EXP_LOG_ANALYTICS_ID="$SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" + fi + + if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then + EXP_AI_PROJECT_ID="$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" + else + EXP_AI_PROJECT_ID="$SECRET_AZURE_EXISTING_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 "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] || [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then + echo "âš ī¸ Warning: EXP parameter values provided but EXP is disabled. These values will be ignored." + fi + fi + + # 3. Deploy using azd up (from content-gen directory where azure.yaml lives) + echo "🚀 Running azd up..." + cd content-gen + azd up --no-prompt + + # 4. Export azd env values to a file so the host can read them + echo "📝 Exporting azd environment values..." + azd env get-values > /tmp/azd-env-values.txt 2>/dev/null || true + cp /tmp/azd-env-values.txt "$PWD/.azd-env-output" || true + + # Also copy to the workspace root for the host step + cp /tmp/azd-env-values.txt "$GITHUB_WORKSPACE/.azd-env-output" || true + + echo "" + echo "✅ Deployment complete!" + + - name: Load azd Environment Outputs + id: load_azd_outputs + if: always() + shell: bash + run: | + # Read the azd env values exported from the devcontainer + AZD_OUTPUT_FILE="" + if [ -f .azd-env-output ]; then + AZD_OUTPUT_FILE=".azd-env-output" + elif [ -f content-gen/.azd-env-output ]; then + AZD_OUTPUT_FILE="content-gen/.azd-env-output" + fi + + if [ -n "$AZD_OUTPUT_FILE" ]; then + echo "📝 Loading azd environment values from $AZD_OUTPUT_FILE..." + + # Parse azd env output (format: KEY="value") + while IFS= read -r line; do + key=$(echo "$line" | cut -d'=' -f1) + value=$(echo "$line" | cut -d'=' -f2- | sed 's/^"//' | sed 's/"$//') + if [ -n "$key" ] && [ -n "$value" ]; then + echo "${key}=${value}" >> $GITHUB_ENV + fi + done < "$AZD_OUTPUT_FILE" + + echo "✅ Loaded azd environment values" + + # Extract Web App URL for downstream jobs + WEB_APP_URL=$(grep '^WEB_APP_URL=' "$AZD_OUTPUT_FILE" | cut -d'=' -f2- | sed 's/^"//' | sed 's/"$//') + echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT + else + echo "âš ī¸ No azd env output file found (.azd-env-output)" + fi + + - name: Generate Deploy Job Summary + if: always() + env: + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + WAF_ENABLED: ${{ inputs.WAF_ENABLED }} + EXP: ${{ inputs.EXP }} + AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} + AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }} + IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + JOB_STATUS: ${{ job.status }} + WEB_APP_URL: ${{ steps.load_azd_outputs.outputs.WEB_APP_URL }} + run: | + echo "## đŸŗ Deploy Job Summary (DevContainer)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY + + if [[ "$JOB_STATUS" == "success" ]]; then + echo "| **Job Status** | ✅ Success |" >> $GITHUB_STEP_SUMMARY + else + echo "| **Job Status** | ❌ Failed |" >> $GITHUB_STEP_SUMMARY + fi + + echo "| **Resource Group** | \`$RESOURCE_GROUP_NAME\` |" >> $GITHUB_STEP_SUMMARY + + # Determine configuration type + if [[ "$WAF_ENABLED" == "true" && "$EXP" == "true" ]]; then + CONFIG_TYPE="WAF + EXP" + elif [[ "$WAF_ENABLED" == "true" && "$EXP" != "true" ]]; then + CONFIG_TYPE="WAF + Non-EXP" + elif [[ "$WAF_ENABLED" != "true" && "$EXP" == "true" ]]; then + CONFIG_TYPE="Non-WAF + EXP" + else + CONFIG_TYPE="Non-WAF + Non-EXP" + fi + echo "| **Configuration Type** | \`$CONFIG_TYPE\` |" >> $GITHUB_STEP_SUMMARY + + echo "| **Azure Region (Infrastructure)** | \`$AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Azure OpenAI Region** | \`$AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Docker Image Tag** | \`$IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Deploy Method** | đŸŗ DevContainer (same as Codespaces) |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [[ "$JOB_STATUS" == "success" ]]; then + echo "### ✅ Deployment Details" >> $GITHUB_STEP_SUMMARY + echo "- **Web App URL**: [$WEB_APP_URL]($WEB_APP_URL)" >> $GITHUB_STEP_SUMMARY + echo "- Successfully deployed to Azure using devcontainer with all resources configured" >> $GITHUB_STEP_SUMMARY + else + echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY + echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY + echo "- Check the deploy job for detailed error information" >> $GITHUB_STEP_SUMMARY + fi + + - name: Logout from Azure + if: always() + shell: bash + run: | + az logout || true + echo "Logged out from Azure." diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index a9d138e5c..ac8b16e56 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -77,7 +77,7 @@ on: value: ${{ jobs.azure-setup.outputs.RESOURCE_GROUP_NAME }} WEB_APPURL: description: "Container Web App URL" - value: ${{ jobs.deploy-linux.outputs.WEB_APPURL || jobs.deploy-windows.outputs.WEB_APPURL }} + value: ${{ jobs.deploy-linux.outputs.WEB_APPURL || jobs.deploy-windows.outputs.WEB_APPURL || jobs.deploy-devcontainer.outputs.WEB_APPURL }} ENV_NAME: description: "Environment Name" value: ${{ jobs.azure-setup.outputs.ENV_NAME }} @@ -154,7 +154,7 @@ jobs: fi # Validate runner_os (required - must be specific values) - ALLOWED_RUNNER_OS=("ubuntu-latest" "windows-latest") + ALLOWED_RUNNER_OS=("ubuntu-latest" "windows-latest" "devcontainer") if [[ -z "$INPUT_RUNNER_OS" ]]; then echo "❌ ERROR: runner_os is required but was not provided" VALIDATION_FAILED=true @@ -616,3 +616,20 @@ jobs: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} secrets: inherit + + deploy-devcontainer: + name: Deploy on DevContainer + needs: azure-setup + if: inputs.runner_os == 'devcontainer' && !cancelled() && needs.azure-setup.result == 'success' + uses: ./.github/workflows/job-deploy-devcontainer.yml + with: + ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }} + AZURE_ENV_OPENAI_LOCATION: ${{ needs.azure-setup.outputs.AZURE_ENV_OPENAI_LOCATION }} + AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }} + RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }} + IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }} + EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }} + WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} + secrets: inherit From 8be055c47905c18bf8d9478bc786b9502e8ab7fe Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:19:43 +0530 Subject: [PATCH 03/32] Added azureAiServiceLocation to select the avaible region for Ai related service deployment --- .github/workflows/job-deploy-devcontainer.yml | 18 +++++++++++++----- .github/workflows/job-deploy-linux.yml | 2 +- .github/workflows/job-deploy-windows.yml | 4 ++-- .github/workflows/job-deploy.yml | 1 + 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 16b099693..dffcd06aa 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -23,6 +23,9 @@ on: IMAGE_TAG: required: true type: string + BUILD_DOCKER_IMAGE: + required: true + type: string EXP: required: true type: string @@ -221,6 +224,7 @@ jobs: INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }} INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }} + INPUT_BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }} INPUT_EXP: ${{ inputs.EXP }} INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} @@ -245,6 +249,7 @@ jobs: INPUT_AZURE_LOCATION INPUT_RESOURCE_GROUP_NAME INPUT_IMAGE_TAG + INPUT_BUILD_DOCKER_IMAGE INPUT_EXP INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID @@ -283,13 +288,16 @@ jobs: # Set core parameters azd env set AZURE_SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" - azd env set AZURE_LOCATION="$AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_LOCATION="$AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" - # Set ACR name from secret - if [[ -n "$SECRET_ACR_TEST_USERNAME" ]]; then - azd env set AZURE_ENV_ACR_NAME="$SECRET_ACR_TEST_USERNAME" - echo "Set ACR name from secret" + # Set ACR endpoint based on BUILD_DOCKER_IMAGE flag + if [[ "$INPUT_BUILD_DOCKER_IMAGE" == "true" ]]; then + ACR_NAME=$(echo "$SECRET_ACR_TEST_LOGIN_SERVER") + azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME" + echo "Set ACR name to: $ACR_NAME" + else + echo "Skipping ACR name configuration (using existing image)" fi # Set EXP parameters if enabled diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 2438cc8a0..2ac30327e 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -233,7 +233,7 @@ jobs: # 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 azureAiServiceLocation="$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="$IMAGE_TAG" diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index d83495d2e..302ff6f5e 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -235,8 +235,8 @@ jobs: # Set additional parameters 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" + azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_LOCATION="$AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$env:RESOURCE_GROUP_NAME" azd env set AZURE_ENV_IMAGETAG="$env:IMAGE_TAG" diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index ac8b16e56..9b703b025 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -628,6 +628,7 @@ jobs: AZURE_LOCATION: ${{ needs.azure-setup.outputs.AZURE_LOCATION }} RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }} IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }} + BUILD_DOCKER_IMAGE: ${{ inputs.build_docker_image || 'false' }} EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }} WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }} AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} From 4e85870587cb03ae1a377548d752b4332a150298 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:32:52 +0530 Subject: [PATCH 04/32] refactor: Remove image model region constraints and validation function from quota check script --- content-gen/scripts/checkquota.sh | 39 ------------------------------- 1 file changed, 39 deletions(-) diff --git a/content-gen/scripts/checkquota.sh b/content-gen/scripts/checkquota.sh index c40592e5b..8d91916b2 100644 --- a/content-gen/scripts/checkquota.sh +++ b/content-gen/scripts/checkquota.sh @@ -44,20 +44,6 @@ else REGIONS=("westus3" "eastus2" "uaenorth" "polandcentral" "swedencentral" "australiaeast" "eastus" "uksouth" "japaneast") fi -# ---- Image Model Region Constraints ---- -# gpt-image-1 GlobalStandard: westus3, eastus2, uaenorth, polandcentral, swedencentral -# gpt-image-1.5 GlobalStandard: westus3, eastus2, uaenorth, polandcentral, swedencentral -# dall-e-3 Standard: available in most AI service regions (no extra restriction) -# none: no image model deployed - -declare -A IMAGE_MODEL_VALID_REGIONS -IMAGE_MODEL_VALID_REGIONS=( - ["gpt-image-1"]="westus3 eastus2 uaenorth polandcentral swedencentral" - ["gpt-image-1.5"]="westus3 eastus2 uaenorth polandcentral swedencentral" - ["dall-e-3"]="all" - ["none"]="all" -) - # Map image model choice to Azure quota model name declare -A IMAGE_MODEL_QUOTA_NAME IMAGE_MODEL_QUOTA_NAME=( @@ -133,37 +119,12 @@ else fi echo "" -# ---- Helper: Check if region supports the selected image model ---- -is_region_valid_for_image_model() { - local region="$1" - local valid_regions="${IMAGE_MODEL_VALID_REGIONS[$IMAGE_MODEL_CHOICE]}" - - if [[ "$valid_regions" == "all" || "$IMAGE_MODEL_CHOICE" == "none" ]]; then - return 0 - fi - - for vr in $valid_regions; do - if [[ "$vr" == "$region" ]]; then - return 0 - fi - done - - return 1 -} - # ---- Main Quota Check Loop ---- VALID_REGION="" for REGION in "${REGIONS[@]}"; do echo "========================================" echo "🔍 Checking region: $REGION" - # First, check if this region supports the selected image model - if ! is_region_valid_for_image_model "$REGION"; then - echo " âš ī¸ Region '$REGION' does not support '$IMAGE_MODEL_CHOICE' (GlobalStandard). Skipping." - echo " Valid regions: ${IMAGE_MODEL_VALID_REGIONS[$IMAGE_MODEL_CHOICE]}" - continue - fi - QUOTA_INFO=$(az cognitiveservices usage list --location "$REGION" --output json 2>/dev/null) if [ -z "$QUOTA_INFO" ]; then echo " âš ī¸ Failed to retrieve quota for region $REGION. Skipping." From 4f41599c1de7ca59cbdff6a4b286e94498b63ec5 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:38:56 +0530 Subject: [PATCH 05/32] chore: Update permissions to allow package write access in deployment workflows --- .github/workflows/job-deploy.yml | 1 + archive-doc-gen/.github/workflows/deploy-orchestrator.yml | 1 + archive-doc-gen/.github/workflows/deploy-v2.yml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 9b703b025..289a9916d 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -106,6 +106,7 @@ env: permissions: contents: read actions: read + packages: write # Required by job-deploy-devcontainer to push devcontainer image to GHCR jobs: azure-setup: diff --git a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml index 31741f3b4..a8af0ec1c 100644 --- a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml +++ b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml @@ -67,6 +67,7 @@ env: permissions: contents: read actions: read + packages: write jobs: docker-build: diff --git a/archive-doc-gen/.github/workflows/deploy-v2.yml b/archive-doc-gen/.github/workflows/deploy-v2.yml index 555b7614b..7af3458f2 100644 --- a/archive-doc-gen/.github/workflows/deploy-v2.yml +++ b/archive-doc-gen/.github/workflows/deploy-v2.yml @@ -596,7 +596,7 @@ jobs: 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 + uses: ./.github/workflows/test-automation-v2.yml with: DOCGEN_URL: ${{ github.event.inputs.existing_webapp_url || needs.deploy.outputs.WEBAPP_URL }} secrets: inherit From f8b42b09853f7497e6263507cca4e409c2f73854 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:40:28 +0530 Subject: [PATCH 06/32] chore: Update permissions to allow package write access for devcontainer image deployment --- .github/workflows/deploy-orchestrator.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index b1234f60a..0f412ffe1 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -72,6 +72,7 @@ env: permissions: contents: read actions: read + packages: write # Required by job-deploy → job-deploy-devcontainer to push devcontainer image to GHCR jobs: docker-build: From 6e02aa9e159234ac0c7b6c94cb0a2125e2856278 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:41:55 +0530 Subject: [PATCH 07/32] chore: Add package write permission for deploy workflows --- .github/workflows/deploy-linux.yml | 1 + .github/workflows/deploy-windows.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml index 7972d8d06..741adb011 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-linux.yml @@ -114,6 +114,7 @@ on: permissions: contents: read actions: read + packages: write # Required by deploy-orchestrator → job-deploy → job-deploy-devcontainer for GHCR jobs: validate-inputs: runs-on: ubuntu-latest diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml index 9aec336a2..b2fe3dc3a 100644 --- a/.github/workflows/deploy-windows.yml +++ b/.github/workflows/deploy-windows.yml @@ -86,6 +86,7 @@ on: permissions: contents: read actions: read + packages: write # Required by deploy-orchestrator → job-deploy → job-deploy-devcontainer for GHCR jobs: validate-inputs: From ae3b3f105fad1c93e5b1b5c52b6cf4b1a2a2a2e7 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:48:03 +0530 Subject: [PATCH 08/32] Siwtch to content-gen directory --- .github/workflows/job-deploy-devcontainer.yml | 8 +++++--- .github/workflows/job-deploy-linux.yml | 6 ++++-- .github/workflows/job-deploy-windows.yml | 6 ++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index dffcd06aa..55964b269 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -278,7 +278,10 @@ jobs: --client-secret "$AZURE_CLIENT_SECRET" \ --tenant-id "$AZURE_TENANT_ID" - # 2. Initialize azd environment + # 2. Change to content-gen directory where azure.yaml lives + cd content-gen + + # Initialize azd environment echo "âš™ī¸ Creating azd environment: $INPUT_ENV_NAME" azd env new "$INPUT_ENV_NAME" --no-prompt @@ -329,9 +332,8 @@ jobs: fi fi - # 3. Deploy using azd up (from content-gen directory where azure.yaml lives) + # 3. Deploy using azd up echo "🚀 Running azd up..." - cd content-gen azd up --no-prompt # 4. Export azd env values to a file so the host can read them diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 2ac30327e..bc4d2385b 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -224,6 +224,9 @@ jobs: run: | set -e + # Change to content-gen directory where azure.yaml lives + cd content-gen + echo "Creating environment..." azd env new "$ENV_NAME" --no-prompt echo "Environment created: $ENV_NAME" @@ -275,8 +278,7 @@ jobs: fi fi - # Deploy using azd up (from content-gen directory where azure.yaml lives) - cd content-gen + # Deploy using azd up azd up --no-prompt # Get deployment outputs using azd diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 302ff6f5e..22a741e22 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -226,6 +226,9 @@ jobs: run: | $ErrorActionPreference = "Stop" + # Change to content-gen directory where azure.yaml lives + Push-Location content-gen + Write-Host "Creating environment..." azd env new $env:ENV_NAME --no-prompt Write-Host "Environment created: $env:ENV_NAME" @@ -273,8 +276,7 @@ jobs: Write-Host "❌ EXP DISABLED - Skipping EXP parameters" } - # Deploy using azd up (from content-gen directory where azure.yaml lives) - Push-Location content-gen + # Deploy using azd up azd up --no-prompt Write-Host "✅ Deployment succeeded." From 69ca6a229bdc4bcaab1d15ca14be9bf0ef5f0044 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:55:57 +0530 Subject: [PATCH 09/32] set acrName and image tags --- .github/workflows/job-deploy-devcontainer.yml | 2 +- .github/workflows/job-deploy-linux.yml | 4 ++-- .github/workflows/job-deploy-windows.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 55964b269..972723cf7 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -297,7 +297,7 @@ jobs: # Set ACR endpoint based on BUILD_DOCKER_IMAGE flag if [[ "$INPUT_BUILD_DOCKER_IMAGE" == "true" ]]; then ACR_NAME=$(echo "$SECRET_ACR_TEST_LOGIN_SERVER") - azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME" + azd env set acrName="$ACR_NAME" echo "Set ACR name to: $ACR_NAME" else echo "Skipping ACR name configuration (using existing image)" diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index bc4d2385b..9703f741f 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -239,13 +239,13 @@ jobs: azd env set azureAiServiceLocation="$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="$IMAGE_TAG" + azd env set imageTag="$IMAGE_TAG" # Set ACR name only when building Docker image if [[ "$BUILD_DOCKER_IMAGE" == "true" ]]; then # Extract ACR name from login server and set as environment variable ACR_NAME="${{ secrets.ACR_TEST_USERNAME }}" - azd env set AZURE_ENV_ACR_NAME="$ACR_NAME" + azd env set acrName="$ACR_NAME" echo "Set ACR name to: $ACR_NAME" else echo "Skipping ACR name configuration (using existing image)" diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 22a741e22..3ce078c5e 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -241,12 +241,12 @@ jobs: azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" azd env set AZURE_LOCATION="$AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$env:RESOURCE_GROUP_NAME" - azd env set AZURE_ENV_IMAGETAG="$env:IMAGE_TAG" + azd env set imageTag="$env:IMAGE_TAG" # Set ACR name only when building Docker image if ($env:BUILD_DOCKER_IMAGE -eq "true") { $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" - azd env set AZURE_ENV_ACR_NAME="$ACR_NAME" + azd env set acrName="$ACR_NAME" Write-Host "Set ACR name to: $ACR_NAME" } else { Write-Host "Skipping ACR name configuration (using existing image)" From 29a674d87c43866d8dc789e2b8413ab675cf2d7d Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 11:58:09 +0530 Subject: [PATCH 10/32] fix: Update account name in resource group generation --- .github/workflows/job-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 289a9916d..3348f0093 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -456,7 +456,7 @@ jobs: echo "RESOURCE_GROUP_NAME=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_ENV else echo "Generating a unique resource group name..." - ACCL_NAME="docgen" # Account name as specified + ACCL_NAME="cntgen" # Account name as specified SHORT_UUID=$(uuidgen | cut -d'-' -f1) UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}" echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV From c1f101b964578898da14dc3adfe56038c80ac937 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 12:09:29 +0530 Subject: [PATCH 11/32] changed tag --- .github/workflows/job-deploy.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 3348f0093..283044560 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -516,8 +516,8 @@ jobs: # Determine image tag based on branch if [[ "$BRANCH_NAME" == "main" ]]; then - IMAGE_TAG="latest_waf" - echo "Using main branch - image tag: latest_waf" + IMAGE_TAG="latest" + echo "Using main branch - image tag: latest" elif [[ "$BRANCH_NAME" == "dev" ]]; then IMAGE_TAG="dev" echo "Using dev branch - image tag: dev" @@ -525,8 +525,8 @@ jobs: 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" + IMAGE_TAG="latest" + echo "Using default for branch '$BRANCH_NAME' - image tag: latest" fi echo "Using existing Docker image tag: $IMAGE_TAG" From ef674ae8f8e16426bad3c3499dadedd47938e9fe Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 12:58:47 +0530 Subject: [PATCH 12/32] feat: Add role assignment step for deployment workflows --- .github/workflows/job-deploy-devcontainer.yml | 23 +++++++++++++++++++ .github/workflows/job-deploy-linux.yml | 23 +++++++++++++++++++ .github/workflows/job-deploy-windows.yml | 23 +++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 972723cf7..3b29e3836 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -381,6 +381,29 @@ jobs: echo "âš ī¸ No azd env output file found (.azd-env-output)" fi + - name: Assign Role Assignments + if: success() + shell: bash + env: + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + run: | + echo "🔐 Assigning role assignments to ACI managed identity..." + # Find the ACI container name in the resource group + ACI_NAME=$(az container list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[0].name" -o tsv 2>/dev/null) + + if [ -z "$ACI_NAME" ]; then + echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." + exit 0 + fi + + echo "Found ACI container: $ACI_NAME" + chmod +x content-gen/infra/scripts/assign_aci_roles.sh + bash content-gen/infra/scripts/assign_aci_roles.sh \ + -g "$RESOURCE_GROUP_NAME" \ + -c "$ACI_NAME" + - name: Generate Deploy Job Summary if: always() env: diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 9703f741f..44c5a90b9 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -286,6 +286,29 @@ jobs: echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_ENV echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT + - name: Assign Role Assignments + if: success() + shell: bash + env: + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + run: | + echo "🔐 Assigning role assignments to ACI managed identity..." + # Find the ACI container name in the resource group + ACI_NAME=$(az container list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[0].name" -o tsv 2>/dev/null) + + if [ -z "$ACI_NAME" ]; then + echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." + exit 0 + fi + + echo "Found ACI container: $ACI_NAME" + chmod +x content-gen/infra/scripts/assign_aci_roles.sh + bash content-gen/infra/scripts/assign_aci_roles.sh \ + -g "$RESOURCE_GROUP_NAME" \ + -c "$ACI_NAME" + - name: Generate Deploy Job Summary if: always() env: diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 3ce078c5e..40b6a8f38 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -287,6 +287,29 @@ jobs: echo "WEB_APPURL=$webAppUrl" >> $GITHUB_ENV echo "WEB_APPURL=$webAppUrl" >> $GITHUB_OUTPUT + - name: Assign Role Assignments + if: success() + shell: bash + env: + RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} + run: | + echo "🔐 Assigning role assignments to ACI managed identity..." + # Find the ACI container name in the resource group + ACI_NAME=$(az container list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[0].name" -o tsv 2>/dev/null) + + if [ -z "$ACI_NAME" ]; then + echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." + exit 0 + fi + + echo "Found ACI container: $ACI_NAME" + chmod +x content-gen/infra/scripts/assign_aci_roles.sh + bash content-gen/infra/scripts/assign_aci_roles.sh \ + -g "$RESOURCE_GROUP_NAME" \ + -c "$ACI_NAME" + - name: Generate Deploy Job Summary if: always() shell: bash From 63a819591111a29aab469ff8445415c7101b15a2 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 13:01:36 +0530 Subject: [PATCH 13/32] fix: Temporarily disable E2E tests in deployment workflow --- .github/workflows/deploy-orchestrator.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml index 0f412ffe1..a48f50aee 100644 --- a/.github/workflows/deploy-orchestrator.yml +++ b/.github/workflows/deploy-orchestrator.yml @@ -104,7 +104,8 @@ jobs: secrets: inherit e2e-test: - if: "!cancelled() && ((needs.deploy.result == 'success' && needs.deploy.outputs.WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))" + # if: "!cancelled() && ((needs.deploy.result == 'success' && needs.deploy.outputs.WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))" + if: false # Temporarily disable E2E tests needs: [docker-build, deploy] uses: ./.github/workflows/test-automation-v2.yml with: From a1305071c1686996b6efcd7d8745cae71069c576 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 13:25:05 +0530 Subject: [PATCH 14/32] fix: Remove role assignment steps from deployment workflows --- .github/workflows/job-deploy-devcontainer.yml | 23 ------------------- .github/workflows/job-deploy-linux.yml | 23 ------------------- .github/workflows/job-deploy-windows.yml | 23 ------------------- 3 files changed, 69 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 3b29e3836..972723cf7 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -381,29 +381,6 @@ jobs: echo "âš ī¸ No azd env output file found (.azd-env-output)" fi - - name: Assign Role Assignments - if: success() - shell: bash - env: - RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} - run: | - echo "🔐 Assigning role assignments to ACI managed identity..." - # Find the ACI container name in the resource group - ACI_NAME=$(az container list \ - --resource-group "$RESOURCE_GROUP_NAME" \ - --query "[0].name" -o tsv 2>/dev/null) - - if [ -z "$ACI_NAME" ]; then - echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." - exit 0 - fi - - echo "Found ACI container: $ACI_NAME" - chmod +x content-gen/infra/scripts/assign_aci_roles.sh - bash content-gen/infra/scripts/assign_aci_roles.sh \ - -g "$RESOURCE_GROUP_NAME" \ - -c "$ACI_NAME" - - name: Generate Deploy Job Summary if: always() env: diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 44c5a90b9..9703f741f 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -286,29 +286,6 @@ jobs: echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_ENV echo "WEB_APP_URL=$WEB_APP_URL" >> $GITHUB_OUTPUT - - name: Assign Role Assignments - if: success() - shell: bash - env: - RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} - run: | - echo "🔐 Assigning role assignments to ACI managed identity..." - # Find the ACI container name in the resource group - ACI_NAME=$(az container list \ - --resource-group "$RESOURCE_GROUP_NAME" \ - --query "[0].name" -o tsv 2>/dev/null) - - if [ -z "$ACI_NAME" ]; then - echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." - exit 0 - fi - - echo "Found ACI container: $ACI_NAME" - chmod +x content-gen/infra/scripts/assign_aci_roles.sh - bash content-gen/infra/scripts/assign_aci_roles.sh \ - -g "$RESOURCE_GROUP_NAME" \ - -c "$ACI_NAME" - - name: Generate Deploy Job Summary if: always() env: diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 40b6a8f38..3ce078c5e 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -287,29 +287,6 @@ jobs: echo "WEB_APPURL=$webAppUrl" >> $GITHUB_ENV echo "WEB_APPURL=$webAppUrl" >> $GITHUB_OUTPUT - - name: Assign Role Assignments - if: success() - shell: bash - env: - RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }} - run: | - echo "🔐 Assigning role assignments to ACI managed identity..." - # Find the ACI container name in the resource group - ACI_NAME=$(az container list \ - --resource-group "$RESOURCE_GROUP_NAME" \ - --query "[0].name" -o tsv 2>/dev/null) - - if [ -z "$ACI_NAME" ]; then - echo "âš ī¸ No ACI container found in resource group '$RESOURCE_GROUP_NAME'. Skipping role assignments." - exit 0 - fi - - echo "Found ACI container: $ACI_NAME" - chmod +x content-gen/infra/scripts/assign_aci_roles.sh - bash content-gen/infra/scripts/assign_aci_roles.sh \ - -g "$RESOURCE_GROUP_NAME" \ - -c "$ACI_NAME" - - name: Generate Deploy Job Summary if: always() shell: bash From f4b0703cfaeba1fa164b0a534f2334e6ae6e1041 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 13:47:52 +0530 Subject: [PATCH 15/32] Update location syntax for windows workflow --- .github/workflows/job-deploy-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index 3ce078c5e..bf5522813 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -238,8 +238,8 @@ jobs: # Set additional parameters azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" - azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" - azd env set AZURE_LOCATION="$AZURE_LOCATION" + azd env set azureAiServiceLocation="$env:AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_LOCATION="$env:AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$env:RESOURCE_GROUP_NAME" azd env set imageTag="$env:IMAGE_TAG" From a20ea2118e5ab4e28679bdd38ebbfb5f63352dfa Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 13:49:39 +0530 Subject: [PATCH 16/32] Changed workflow name --- .github/workflows/{deploy-linux.yml => deploy-ci.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{deploy-linux.yml => deploy-ci.yml} (99%) diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-ci.yml similarity index 99% rename from .github/workflows/deploy-linux.yml rename to .github/workflows/deploy-ci.yml index 741adb011..d2a18ce86 100644 --- a/.github/workflows/deploy-linux.yml +++ b/.github/workflows/deploy-ci.yml @@ -1,4 +1,4 @@ -name: Deploy-Test-Cleanup (v2) Linux +name: Deploy-Test-Cleanup (v2) on: pull_request: branches: From df66848c0b7a08357da9c7c6be762ebd52820b0e Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 14:12:24 +0530 Subject: [PATCH 17/32] fix: Set PYTHONUTF8 environment variable in Windows deployment job --- .github/workflows/job-deploy-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index bf5522813..c4e8862bf 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -47,6 +47,7 @@ jobs: runs-on: windows-latest env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} + PYTHONUTF8: 1 outputs: WEB_APPURL: ${{ steps.get_output_windows.outputs.WEB_APPURL }} steps: From b82ff6ef9c8b7e616f49aacb13bf57aed50d49b0 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 14:52:54 +0530 Subject: [PATCH 18/32] fix: Update environment variable references in deployment workflows --- .github/workflows/job-deploy-devcontainer.yml | 4 ++-- .github/workflows/job-deploy-windows.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 972723cf7..54594356e 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -290,8 +290,8 @@ jobs: # Set core parameters azd env set AZURE_SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" - azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" - azd env set AZURE_LOCATION="$AZURE_LOCATION" + azd env set azureAiServiceLocation="$INPUT_AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_LOCATION="$INPUT_AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" # Set ACR endpoint based on BUILD_DOCKER_IMAGE flag diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index c4e8862bf..bdd9e8b8c 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -285,8 +285,8 @@ jobs: # Get deployment outputs using azd Write-Host "Extracting deployment outputs..." $webAppUrl = azd env get-value WEB_APP_URL - echo "WEB_APPURL=$webAppUrl" >> $GITHUB_ENV - echo "WEB_APPURL=$webAppUrl" >> $GITHUB_OUTPUT + echo "WEB_APPURL=$webAppUrl" >> $env:GITHUB_ENV + echo "WEB_APPURL=$webAppUrl" >> $env:GITHUB_OUTPUT - name: Generate Deploy Job Summary if: always() From 07b4f39cf217803e4786137b1eabe3e3c9269a54 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 16:07:05 +0530 Subject: [PATCH 19/32] Minor fix --- .github/workflows/job-deploy-devcontainer.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 54594356e..0b8c9ce82 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -1,6 +1,5 @@ name: Deploy Steps - DevContainer -# This workflow uses the same devcontainer as Codespaces. # The devcontainer (Dockerfile + features + post-create script) installs everything: # Python 3.11, Azure CLI + Bicep, azd, Node.js, Poetry, pip dependencies # So the workflow simply: builds the container → logs in → runs azd up. @@ -211,7 +210,7 @@ jobs: shell: bash run: echo "IMAGE_NAME=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')/devcontainer" >> $GITHUB_ENV - # Build devcontainer and run azd up inside it — identical to Codespaces + # Build devcontainer and run azd up inside it - name: Deploy with azd up in DevContainer uses: devcontainers/ci@v0.3 env: @@ -421,7 +420,6 @@ jobs: echo "| **Azure Region (Infrastructure)** | \`$AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY echo "| **Azure OpenAI Region** | \`$AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY echo "| **Docker Image Tag** | \`$IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY - echo "| **Deploy Method** | đŸŗ DevContainer (same as Codespaces) |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "$JOB_STATUS" == "success" ]]; then From 5ea20f118679926df786b1235116d61bc6120a8f Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Wed, 11 Feb 2026 16:20:08 +0530 Subject: [PATCH 20/32] Changed main.paramter Names --- .github/workflows/job-deploy-devcontainer.yml | 8 ++------ .github/workflows/job-deploy-linux.yml | 6 +++--- .github/workflows/job-deploy-windows.yml | 6 +++--- content-gen/infra/main.parameters.json | 10 +++++----- content-gen/infra/main.waf.parameters.json | 10 +++++----- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index 0b8c9ce82..a481d5822 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -227,7 +227,6 @@ jobs: INPUT_EXP: ${{ inputs.EXP }} INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} - EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} SECRET_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ secrets.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} SECRET_ACR_TEST_USERNAME: ${{ secrets.ACR_TEST_USERNAME }} @@ -252,7 +251,6 @@ jobs: INPUT_EXP INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID - EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID SECRET_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID SECRET_ACR_TEST_USERNAME @@ -289,14 +287,14 @@ jobs: # Set core parameters azd env set AZURE_SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" - azd env set azureAiServiceLocation="$INPUT_AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_ENV_OPENAI_LOCATION="$INPUT_AZURE_ENV_OPENAI_LOCATION" azd env set AZURE_LOCATION="$INPUT_AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME" # Set ACR endpoint based on BUILD_DOCKER_IMAGE flag if [[ "$INPUT_BUILD_DOCKER_IMAGE" == "true" ]]; then ACR_NAME=$(echo "$SECRET_ACR_TEST_LOGIN_SERVER") - azd env set acrName="$ACR_NAME" + azd env set ACR_NAME="$ACR_NAME" echo "Set ACR name to: $ACR_NAME" else echo "Skipping ACR name configuration (using existing image)" @@ -308,8 +306,6 @@ jobs: if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then EXP_LOG_ANALYTICS_ID="$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" - elif [[ -n "$EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then - EXP_LOG_ANALYTICS_ID="$EVENT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" else EXP_LOG_ANALYTICS_ID="$SECRET_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" fi diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index 9703f741f..b691598ec 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -236,16 +236,16 @@ jobs: # Set additional parameters azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" - azd env set azureAiServiceLocation="$AZURE_ENV_OPENAI_LOCATION" + 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 imageTag="$IMAGE_TAG" + azd env set IMAGE_TAG="$IMAGE_TAG" # Set ACR name only when building Docker image if [[ "$BUILD_DOCKER_IMAGE" == "true" ]]; then # Extract ACR name from login server and set as environment variable ACR_NAME="${{ secrets.ACR_TEST_USERNAME }}" - azd env set acrName="$ACR_NAME" + azd env set ACR_NAME="$ACR_NAME" echo "Set ACR name to: $ACR_NAME" else echo "Skipping ACR name configuration (using existing image)" diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml index bdd9e8b8c..aba12f4d1 100644 --- a/.github/workflows/job-deploy-windows.yml +++ b/.github/workflows/job-deploy-windows.yml @@ -239,15 +239,15 @@ jobs: # Set additional parameters azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}" - azd env set azureAiServiceLocation="$env:AZURE_ENV_OPENAI_LOCATION" + azd env set AZURE_ENV_OPENAI_LOCATION="$env:AZURE_ENV_OPENAI_LOCATION" azd env set AZURE_LOCATION="$env:AZURE_LOCATION" azd env set AZURE_RESOURCE_GROUP="$env:RESOURCE_GROUP_NAME" - azd env set imageTag="$env:IMAGE_TAG" + azd env set IMAGE_TAG="$env:IMAGE_TAG" # Set ACR name only when building Docker image if ($env:BUILD_DOCKER_IMAGE -eq "true") { $ACR_NAME = "${{ secrets.ACR_TEST_USERNAME }}" - azd env set acrName="$ACR_NAME" + azd env set ACR_NAME="$ACR_NAME" Write-Host "Set ACR name to: $ACR_NAME" } else { Write-Host "Skipping ACR name configuration (using existing image)" diff --git a/content-gen/infra/main.parameters.json b/content-gen/infra/main.parameters.json index 05c294453..0f6336a1e 100644 --- a/content-gen/infra/main.parameters.json +++ b/content-gen/infra/main.parameters.json @@ -36,19 +36,19 @@ "value": "${azureOpenaiAPIVersion}" }, "azureAiServiceLocation": { - "value": "${azureAiServiceLocation}" + "value": "${AZURE_ENV_OPENAI_LOCATION}" }, "existingLogAnalyticsWorkspaceId": { - "value": "${existingLogAnalyticsWorkspaceId}" + "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" }, "azureExistingAIProjectResourceId": { - "value": "${azureExistingAIProjectResourceId}" + "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" }, "acrName": { - "value": "${acrName}" + "value": "${ACR_NAME}" }, "imageTag": { - "value": "${imageTag=latest}" + "value": "${IMAGE_TAG=latest}" } } } diff --git a/content-gen/infra/main.waf.parameters.json b/content-gen/infra/main.waf.parameters.json index fb2ddf560..be3e738ac 100644 --- a/content-gen/infra/main.waf.parameters.json +++ b/content-gen/infra/main.waf.parameters.json @@ -36,19 +36,19 @@ "value": "${azureOpenaiAPIVersion}" }, "azureAiServiceLocation": { - "value": "${azureAiServiceLocation}" + "value": "${AZURE_ENV_OPENAI_LOCATION}" }, "existingLogAnalyticsWorkspaceId": { - "value": "${existingLogAnalyticsWorkspaceId}" + "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" }, "azureExistingAIProjectResourceId": { - "value": "${azureExistingAIProjectResourceId}" + "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" }, "acrName": { - "value": "${acrName}" + "value": "${ACR_NAME}" }, "imageTag": { - "value": "${imageTag=latest}" + "value": "${IMAGE_TAG=latest}" }, "enablePrivateNetworking": { "value": true From c52964ddab2fa83d2db78a6f2b850fcb792547da Mon Sep 17 00:00:00 2001 From: Ragini-Microsoft Date: Wed, 11 Feb 2026 17:11:32 +0530 Subject: [PATCH 21/32] Update API version and payload for DALL-E 3 image generation --- content-gen/src/backend/orchestrator.py | 34 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/content-gen/src/backend/orchestrator.py b/content-gen/src/backend/orchestrator.py index 7677ca362..3e90b0471 100644 --- a/content-gen/src/backend/orchestrator.py +++ b/content-gen/src/backend/orchestrator.py @@ -1245,7 +1245,14 @@ async def _generate_foundry_image(self, image_prompt: str, results: dict) -> Non # The direct image API endpoint image_api_url = f"{image_endpoint}/openai/deployments/{image_deployment}/images/generations" - api_version = app_settings.azure_openai.image_api_version or "2025-04-01-preview" + + # Adapt API version and payload to the deployed image model + is_dalle3 = image_deployment.lower().startswith("dall-e") + + if is_dalle3: + api_version = app_settings.azure_openai.preview_api_version or "2024-02-01" + else: + api_version = app_settings.azure_openai.image_api_version or "2025-04-01-preview" logger.info(f"Calling Foundry direct image API: {image_api_url}") logger.info(f"Prompt: {image_prompt[:200]}...") @@ -1255,13 +1262,24 @@ async def _generate_foundry_image(self, image_prompt: str, results: dict) -> Non "Content-Type": "application/json", } - # gpt-image-1 parameters (no response_format parameter) - payload = { - "prompt": image_prompt, - "n": 1, - "size": "1024x1024", - "quality": "medium", # gpt-image-1 uses low/medium/high/auto - } + # Build model-appropriate payload + if is_dalle3: + # dall-e-3: quality must be "standard" or "hd"; needs response_format; 4000-char prompt limit + payload = { + "prompt": image_prompt[:4000], + "n": 1, + "size": app_settings.azure_openai.image_size or "1024x1024", + "quality": app_settings.azure_openai.image_quality or "hd", + "response_format": "b64_json", + } + else: + # gpt-image-1 / gpt-image-1.5: quality is low/medium/high/auto; no response_format + payload = { + "prompt": image_prompt, + "n": 1, + "size": "1024x1024", + "quality": "medium", + } async with httpx.AsyncClient(timeout=120.0) as client: response = await client.post( From 533d0a619fcf5db5f7c5d7d4587a9278c7031c69 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 09:57:56 +0530 Subject: [PATCH 22/32] Test --- .github/workflows/deploy-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-ci.yml b/.github/workflows/deploy-ci.yml index d2a18ce86..c099bfa90 100644 --- a/.github/workflows/deploy-ci.yml +++ b/.github/workflows/deploy-ci.yml @@ -110,7 +110,7 @@ on: - 'none' schedule: - - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT + - cron: '30 4 * * *' # Runs at 10:00 AM IST (4:30 AM UTC) permissions: contents: read actions: read From 9855cd9bcffbdc9a8fb9c38c17968dedf11228fc Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 10:13:10 +0530 Subject: [PATCH 23/32] fix: Remove 'eastus2' from the list as it has ResourcesForSkuUnavailable issue --- .github/workflows/deploy-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/deploy-ci.yml b/.github/workflows/deploy-ci.yml index c099bfa90..a9fe3d732 100644 --- a/.github/workflows/deploy-ci.yml +++ b/.github/workflows/deploy-ci.yml @@ -40,7 +40,6 @@ on: - 'australiaeast' - 'centralus' - 'eastasia' - - 'eastus2' - 'japaneast' - 'northeurope' - 'southeastasia' From c874150b973136aec2981e136facf7c74f480217 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 11:46:55 +0530 Subject: [PATCH 24/32] Added Quotacheck for Auto Triggers as well --- .github/workflows/deploy-ci.yml | 4 + .github/workflows/job-deploy.yml | 165 +++++++++++++++++++++---------- 2 files changed, 116 insertions(+), 53 deletions(-) diff --git a/.github/workflows/deploy-ci.yml b/.github/workflows/deploy-ci.yml index a9fe3d732..c8562fe08 100644 --- a/.github/workflows/deploy-ci.yml +++ b/.github/workflows/deploy-ci.yml @@ -40,10 +40,14 @@ on: - 'australiaeast' - 'centralus' - 'eastasia' + - 'eastus' - 'japaneast' - 'northeurope' - 'southeastasia' + - 'swedencentral' - 'uksouth' + - 'westus' + - 'westus3' resource_group_name: description: 'Resource Group Name (Optional)' required: false diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml index 283044560..37dfa8395 100644 --- a/.github/workflows/job-deploy.yml +++ b/.github/workflows/job-deploy.yml @@ -365,30 +365,12 @@ jobs: shell: bash run: exit 1 - - name: Set Deployment Region - id: set_region - shell: bash - env: - INPUT_AZURE_LOCATION: ${{ inputs.azure_location }} - run: | - echo "Selected Region from Quota Check: $VALID_REGION" - echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_ENV - echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT - - if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "$INPUT_AZURE_LOCATION" ]]; then - USER_SELECTED_LOCATION="$INPUT_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: Check Azure Search Service Quota id: search-quota-check shell: bash + env: + INPUT_AZURE_LOCATION: ${{ inputs.azure_location }} + TRIGGER_TYPE: ${{ inputs.trigger_type }} run: | # Determine search tier based on WAF (scalability) setting # WAF enabled → standard tier, WAF disabled → basic tier @@ -400,48 +382,125 @@ jobs: SEARCH_TIER_DISPLAY="Basic" fi - echo "🔍 Checking Azure Search $SEARCH_TIER_DISPLAY tier quota in region: ${{ env.AZURE_LOCATION }}" - - # Get current usage and limits for Azure Search in the selected region using REST API - SEARCH_USAGE=$(az rest --method get \ - --url "https://management.azure.com/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.Search/locations/${{ env.AZURE_LOCATION }}/usages?api-version=2024-03-01-preview" \ - -o json 2>/dev/null || echo '{"value":[]}') + # Valid deployment regions (must match Bicep @allowed list) + ALL_VALID_REGIONS=("australiaeast" "centralus" "eastasia" "eastus" "japaneast" "northeurope" "southeastasia" "swedencentral" "uksouth" "westus" "westus3") - if [ "$(echo "$SEARCH_USAGE" | jq '.value | length')" -eq 0 ]; then - echo "âš ī¸ Could not retrieve Azure Search quota information. Proceeding with deployment..." - echo "SEARCH_QUOTA_CHECK=skipped" >> $GITHUB_OUTPUT + # Build ordered list of regions to check: + # - Manual triggers: user's region first, then remaining valid regions + # - Automatic triggers: all valid regions (no user preference) + REGIONS_TO_CHECK=() + if [[ "$TRIGGER_TYPE" == "workflow_dispatch" && -n "$INPUT_AZURE_LOCATION" ]]; then + echo "📋 Manual trigger: checking user-selected region '$INPUT_AZURE_LOCATION' first" + REGIONS_TO_CHECK+=("$INPUT_AZURE_LOCATION") + for r in "${ALL_VALID_REGIONS[@]}"; do + if [[ "$r" != "$INPUT_AZURE_LOCATION" ]]; then + REGIONS_TO_CHECK+=("$r") + fi + done else + echo "📋 Automatic trigger: checking all valid regions for search quota" + REGIONS_TO_CHECK=("${ALL_VALID_REGIONS[@]}") + fi + + echo "🔍 Checking Azure Search $SEARCH_TIER_DISPLAY tier quota across regions: ${REGIONS_TO_CHECK[*]}" + echo "" + + SEARCH_VALID_REGION="" + CHECKED_REGIONS=() + for REGION in "${REGIONS_TO_CHECK[@]}"; do + echo "----------------------------------------" + echo "🔍 Checking region: $REGION" + + SEARCH_USAGE=$(az rest --method get \ + --url "https://management.azure.com/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.Search/locations/${REGION}/usages?api-version=2024-03-01-preview" \ + -o json 2>/dev/null || echo '{"value":[]}') + + if [ "$(echo "$SEARCH_USAGE" | jq '.value | length')" -eq 0 ]; then + echo " âš ī¸ Could not retrieve Azure Search quota for $REGION. Skipping." + CHECKED_REGIONS+=("$REGION: skipped") + continue + fi + TIER_USAGE=$(echo "$SEARCH_USAGE" | jq -r --arg tier "$SEARCH_TIER" '.value[] | select(.name.value == $tier) | .currentValue // 0') TIER_LIMIT=$(echo "$SEARCH_USAGE" | jq -r --arg tier "$SEARCH_TIER" '.value[] | select(.name.value == $tier) | .limit // 0') TIER_AVAILABLE=$((TIER_LIMIT - TIER_USAGE)) - echo "Azure Search $SEARCH_TIER_DISPLAY Tier Quota for ${{ env.AZURE_LOCATION }}:" - echo " Current Usage: $TIER_USAGE" - echo " Limit: $TIER_LIMIT" - echo " Available: $TIER_AVAILABLE" - - if [ "$TIER_AVAILABLE" -lt 1 ]; then - echo "" - echo "❌ ERROR: Insufficient Azure Search $SEARCH_TIER_DISPLAY tier quota in region: ${{ env.AZURE_LOCATION }}" - echo "Please select a different region." + echo " $SEARCH_TIER_DISPLAY Tier: Used=$TIER_USAGE | Limit=$TIER_LIMIT | Available=$TIER_AVAILABLE" - # Add error to GitHub Summary - echo "## ❌ Azure Search Quota Check Failed" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Region:** \`${{ env.AZURE_LOCATION }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY - echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY - echo "| **Tier** | $SEARCH_TIER_DISPLAY |" >> $GITHUB_STEP_SUMMARY - echo "| **Current Usage** | $TIER_USAGE |" >> $GITHUB_STEP_SUMMARY - echo "| **Limit** | $TIER_LIMIT |" >> $GITHUB_STEP_SUMMARY - echo "| **Available** | $TIER_AVAILABLE |" >> $GITHUB_STEP_SUMMARY - exit 1 + if [ "$TIER_AVAILABLE" -ge 1 ]; then + echo " ✅ Region '$REGION' has sufficient Azure Search $SEARCH_TIER_DISPLAY quota!" + SEARCH_VALID_REGION="$REGION" + CHECKED_REGIONS+=("$REGION: ✅ available=$TIER_AVAILABLE") + break + else + echo " ❌ Insufficient quota in $REGION" + CHECKED_REGIONS+=("$REGION: ❌ available=$TIER_AVAILABLE") fi + done + + echo "" + echo "========================================" + if [ -z "$SEARCH_VALID_REGION" ]; then + echo "❌ No region with sufficient Azure Search $SEARCH_TIER_DISPLAY tier quota found!" + echo "" + echo "Regions checked:" + for entry in "${CHECKED_REGIONS[@]}"; do + echo " - $entry" + done + + # Add error to GitHub Summary + echo "## ❌ Azure Search Quota Check Failed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "No region with sufficient Azure Search **$SEARCH_TIER_DISPLAY** tier quota was found." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Region | Status |" >> $GITHUB_STEP_SUMMARY + echo "|--------|--------|" >> $GITHUB_STEP_SUMMARY + for entry in "${CHECKED_REGIONS[@]}"; do + IFS=': ' read -r region status <<< "$entry" + echo "| \`$region\` | $status |" >> $GITHUB_STEP_SUMMARY + done + exit 1 + fi + + echo "✅ Selected region with Azure Search quota: $SEARCH_VALID_REGION" + echo "SEARCH_VALID_REGION=$SEARCH_VALID_REGION" >> $GITHUB_ENV + echo "SEARCH_VALID_REGION=$SEARCH_VALID_REGION" >> $GITHUB_OUTPUT + echo "SEARCH_QUOTA_CHECK=passed" >> $GITHUB_OUTPUT + if [[ "$TRIGGER_TYPE" == "workflow_dispatch" && "$SEARCH_VALID_REGION" != "$INPUT_AZURE_LOCATION" ]]; then echo "" - echo "✅ Azure Search $SEARCH_TIER_DISPLAY tier quota check passed." - echo "SEARCH_QUOTA_CHECK=passed" >> $GITHUB_OUTPUT + echo "âš ī¸ User-selected region '$INPUT_AZURE_LOCATION' had insufficient search quota." + echo " Falling back to region: $SEARCH_VALID_REGION" + fi + + - name: Set Deployment Region + id: set_region + shell: bash + env: + INPUT_AZURE_LOCATION: ${{ inputs.azure_location }} + run: | + echo "Selected Region from OpenAI Quota Check: $VALID_REGION" + echo "Selected Region from Search Quota Check: $SEARCH_VALID_REGION" + echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_ENV + echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT + + if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "$INPUT_AZURE_LOCATION" ]]; then + # Manual trigger: use user's region if it passed search quota, otherwise use search-validated region + if [[ "$INPUT_AZURE_LOCATION" == "$SEARCH_VALID_REGION" ]]; then + echo "✅ Using user-selected Azure location (search quota verified): $INPUT_AZURE_LOCATION" + echo "AZURE_LOCATION=$INPUT_AZURE_LOCATION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$INPUT_AZURE_LOCATION" >> $GITHUB_OUTPUT + else + echo "âš ī¸ User-selected region '$INPUT_AZURE_LOCATION' had insufficient search quota." + echo " Using fallback region from search quota check: $SEARCH_VALID_REGION" + echo "AZURE_LOCATION=$SEARCH_VALID_REGION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$SEARCH_VALID_REGION" >> $GITHUB_OUTPUT + fi + else + # Automatic trigger: use the search-quota-validated region + echo "Using region from search quota check for automatic triggers: $SEARCH_VALID_REGION" + echo "AZURE_LOCATION=$SEARCH_VALID_REGION" >> $GITHUB_ENV + echo "AZURE_LOCATION=$SEARCH_VALID_REGION" >> $GITHUB_OUTPUT fi - name: Generate Resource Group Name From de258f91b7fbb1bc18a66b2c0a6d96d0a06cd32f Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 11:51:23 +0530 Subject: [PATCH 25/32] minor fix --- content-gen/infra/main.waf.parameters.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/content-gen/infra/main.waf.parameters.json b/content-gen/infra/main.waf.parameters.json index be3e738ac..7da1297bf 100644 --- a/content-gen/infra/main.waf.parameters.json +++ b/content-gen/infra/main.waf.parameters.json @@ -58,9 +58,6 @@ }, "enableScalability": { "value": true - }, - "enableRedundancy": { - "value": true } } } From 616160188dac3b8e7ddd4de896a4c1102495a561 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 13:33:36 +0530 Subject: [PATCH 26/32] revert changes in old archived doc-gen --- archive-doc-gen/.github/workflows/deploy-orchestrator.yml | 4 +--- archive-doc-gen/.github/workflows/deploy-v2.yml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml index a8af0ec1c..4cffb3cc3 100644 --- a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml +++ b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml @@ -66,9 +66,7 @@ env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} permissions: contents: read - actions: read - packages: write - + actions: read jobs: docker-build: uses: ./.github/workflows/job-docker-build.yml diff --git a/archive-doc-gen/.github/workflows/deploy-v2.yml b/archive-doc-gen/.github/workflows/deploy-v2.yml index 7af3458f2..555b7614b 100644 --- a/archive-doc-gen/.github/workflows/deploy-v2.yml +++ b/archive-doc-gen/.github/workflows/deploy-v2.yml @@ -596,7 +596,7 @@ jobs: 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-v2.yml + uses: ./.github/workflows/test-automation.yml with: DOCGEN_URL: ${{ github.event.inputs.existing_webapp_url || needs.deploy.outputs.WEBAPP_URL }} secrets: inherit From 7f158927afb1f39402a68eba626829abf680f5b3 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 13:34:51 +0530 Subject: [PATCH 27/32] minor fix --- archive-doc-gen/.github/workflows/deploy-orchestrator.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml index 4cffb3cc3..e734acc91 100644 --- a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml +++ b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml @@ -66,7 +66,8 @@ env: AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }} permissions: contents: read - actions: read + actions: read + jobs: docker-build: uses: ./.github/workflows/job-docker-build.yml From 7ea4359117ddb669799a105fee8ad02bc1b36202 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 13:36:05 +0530 Subject: [PATCH 28/32] minor fix --- archive-doc-gen/.github/workflows/deploy-orchestrator.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml index e734acc91..31741f3b4 100644 --- a/archive-doc-gen/.github/workflows/deploy-orchestrator.yml +++ b/archive-doc-gen/.github/workflows/deploy-orchestrator.yml @@ -67,7 +67,7 @@ env: permissions: contents: read actions: read - + jobs: docker-build: uses: ./.github/workflows/job-docker-build.yml From 165e0cebb6d476a4b6781c1740aa12ce6c26ba9a Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 14:01:47 +0530 Subject: [PATCH 29/32] Update .github/workflows/job-docker-build.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/job-docker-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml index 5c4fbed3d..41e581966 100644 --- a/.github/workflows/job-docker-build.yml +++ b/.github/workflows/job-docker-build.yml @@ -63,8 +63,8 @@ jobs: env: DOCKER_BUILD_SUMMARY: false with: - context: ./content-gen/src - file: ./content-gen/src/WebApp.Dockerfile + context: ./content-gen/src/app + file: ./content-gen/src/app/WebApp.Dockerfile push: true tags: | ${{ secrets.ACR_TEST_LOGIN_SERVER }}/webapp:${{ steps.generate_docker_tag.outputs.IMAGE_TAG }} From 7032c975e3f22674d5274851c1288e0f546edcd6 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 14:11:49 +0530 Subject: [PATCH 30/32] Update content-gen/scripts/checkquota.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- content-gen/scripts/checkquota.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content-gen/scripts/checkquota.sh b/content-gen/scripts/checkquota.sh index 8d91916b2..9a798b297 100644 --- a/content-gen/scripts/checkquota.sh +++ b/content-gen/scripts/checkquota.sh @@ -41,7 +41,7 @@ IMAGE_MODEL_MIN_CAPACITY="${IMAGE_MODEL_MIN_CAPACITY:-1}" if [[ -n "$AZURE_REGIONS" ]]; then IFS=', ' read -ra REGIONS <<< "$AZURE_REGIONS" else - REGIONS=("westus3" "eastus2" "uaenorth" "polandcentral" "swedencentral" "australiaeast" "eastus" "uksouth" "japaneast") + REGIONS=("westus3" "eastus2" "uaenorth" "swedencentral" "australiaeast" "eastus" "uksouth" "japaneast") fi # Map image model choice to Azure quota model name From f15eba00318f41c52bbc0778cbf60f715eab3d2d Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 14:12:20 +0530 Subject: [PATCH 31/32] fixed Copilet suggestions --- .github/workflows/job-deploy-devcontainer.yml | 2 +- .github/workflows/job-deploy-linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-deploy-devcontainer.yml b/.github/workflows/job-deploy-devcontainer.yml index a481d5822..4a864f382 100644 --- a/.github/workflows/job-deploy-devcontainer.yml +++ b/.github/workflows/job-deploy-devcontainer.yml @@ -293,7 +293,7 @@ jobs: # Set ACR endpoint based on BUILD_DOCKER_IMAGE flag if [[ "$INPUT_BUILD_DOCKER_IMAGE" == "true" ]]; then - ACR_NAME=$(echo "$SECRET_ACR_TEST_LOGIN_SERVER") + ACR_NAME=$(echo "$SECRET_ACR_TEST_USERNAME") azd env set ACR_NAME="$ACR_NAME" echo "Set ACR name to: $ACR_NAME" else diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml index b691598ec..e4338572a 100644 --- a/.github/workflows/job-deploy-linux.yml +++ b/.github/workflows/job-deploy-linux.yml @@ -332,7 +332,7 @@ jobs: echo "### ✅ Deployment Details" >> $GITHUB_STEP_SUMMARY echo "- **Web App URL**: [$WEB_APP_URL]($WEB_APP_URL)" >> $GITHUB_STEP_SUMMARY echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY - echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY + echo "- All Deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY else echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY echo "- Deployment process encountered an error" >> $GITHUB_STEP_SUMMARY From 48d06b95c907d11f8899d7852c9ca87d9ff67ac0 Mon Sep 17 00:00:00 2001 From: Vamshi-Microsoft Date: Fri, 13 Feb 2026 14:46:06 +0530 Subject: [PATCH 32/32] Added CustomizingAzdParamters readme file --- content-gen/docs/AZD_DEPLOYMENT.md | 10 ++--- content-gen/docs/CustomizingAzdParameters.md | 43 ++++++++++++++++++++ content-gen/infra/main.parameters.json | 3 ++ content-gen/infra/main.waf.parameters.json | 3 ++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 content-gen/docs/CustomizingAzdParameters.md diff --git a/content-gen/docs/AZD_DEPLOYMENT.md b/content-gen/docs/AZD_DEPLOYMENT.md index 0348c9de6..693b888ba 100644 --- a/content-gen/docs/AZD_DEPLOYMENT.md +++ b/content-gen/docs/AZD_DEPLOYMENT.md @@ -81,7 +81,7 @@ The deployment has sensible defaults, but you can customize: azd env set AZURE_LOCATION swedencentral # Set AI Services region (must support your models) -azd env set azureAiServiceLocation swedencentral +azd env set AZURE_ENV_OPENAI_LOCATION swedencentral # GPT Model configuration azd env set gptModelName gpt-4o @@ -157,21 +157,21 @@ This single command will: ```bash # Set the resource ID of your existing AI Project -azd env set azureExistingAIProjectResourceId "/subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/" +azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID "/subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/" ``` ### Reuse Existing Log Analytics Workspace ```bash # Set the resource ID of your existing Log Analytics workspace -azd env set existingLogAnalyticsWorkspaceId "/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/" +azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID "/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/" ``` ### Use Existing Container Registry ```bash # Set the name of your existing ACR -azd env set acrName myexistingacr +azd env set ACR_NAME myexistingacr ``` ## Post-Deployment @@ -312,7 +312,7 @@ Error: The model 'gpt-4o' is not available in region 'westeurope' **Solution**: Set a different region for AI Services: ```bash -azd env set azureAiServiceLocation eastus +azd env set AZURE_ENV_OPENAI_LOCATION eastus ``` #### 3. Container Build Fails diff --git a/content-gen/docs/CustomizingAzdParameters.md b/content-gen/docs/CustomizingAzdParameters.md new file mode 100644 index 000000000..4198278e8 --- /dev/null +++ b/content-gen/docs/CustomizingAzdParameters.md @@ -0,0 +1,43 @@ +## [Optional]: Customizing resource names + +By default this template will use the environment name as the prefix to prevent naming collisions within Azure. The parameters below show the default values. You only need to run the statements below if you need to change the values. + +> To override any of the parameters, run `azd env set ` before running `azd up`. On the first azd command, it will prompt you for the environment name. Be sure to choose 3-15 characters alphanumeric unique name. + +## Parameters + +| Name | Type | Default Value | Purpose | +| -------------------------------------- | ------- | ---------------------------- | ----------------------------------------------------------------------------- | +| `AZURE_LOCATION` | string | `` | Sets the Azure region for resource deployment. Allowed: `australiaeast`, `centralus`, `eastasia`, `eastus`, `eastus2`, `japaneast`, `northeurope`, `southeastasia`, `swedencentral`, `uksouth`, `westus`, `westus3`. | +| `AZURE_ENV_NAME` | string | `contentgen` | Sets the environment name prefix for all Azure resources (3-15 characters). | +| `secondaryLocation` | string | `uksouth` | Specifies a secondary Azure region for database creation. | +| `gptModelName` | string | `gpt-5.1` | Specifies the GPT model name to deploy. | +| `gptModelVersion` | string | `2025-11-13` | Sets the GPT model version. | +| `gptModelDeploymentType` | string | `GlobalStandard` | Defines the model deployment type (allowed: `Standard`, `GlobalStandard`). | +| `gptModelCapacity` | integer | `150` | Sets the GPT model token capacity (minimum: `10`). | +| `imageModelChoice` | string | `gpt-image-1` | Image model to deploy (allowed: `gpt-image-1`, `gpt-image-1.5`, `dall-e-3`, `none`). | +| `dalleModelCapacity` | integer | `1` | Sets the image model deployment capacity in RPM (minimum: `1`). | +| `azureOpenaiAPIVersion` | string | `2025-01-01-preview` | Specifies the API version for Azure OpenAI service. | +| `AZURE_ENV_OPENAI_LOCATION` | string | `` | Sets the Azure region for OpenAI resource deployment. | +| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | `""` | Reuses an existing Log Analytics Workspace instead of creating a new one. | +| `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID`| string | `""` | Reuses an existing AI Foundry Project instead of creating a new one. | +| `ACR_NAME` | string | `contentgencontainerreg` | Sets the existing Azure Container Registry name (without `.azurecr.io`). | +| `IMAGE_TAG` | string | `latest` | Sets the container image tag (e.g., `latest`, `dev`, `hotfix`). | + +## How to Set a Parameter + +To customize any of the above values, run the following command **before** `azd up`: + +```bash +azd env set +``` + +**Examples:** + +```bash +azd env set AZURE_LOCATION westus2 +azd env set gptModelName gpt-5.1 +azd env set gptModelDeploymentType Standard +azd env set imageModelChoice dall-e-3 +azd env set ACR_NAME contentgencontainerreg +``` diff --git a/content-gen/infra/main.parameters.json b/content-gen/infra/main.parameters.json index 0f6336a1e..9370c6250 100644 --- a/content-gen/infra/main.parameters.json +++ b/content-gen/infra/main.parameters.json @@ -8,6 +8,9 @@ "location": { "value": "${AZURE_LOCATION}" }, + "secondaryLocation": { + "value": "${secondaryLocation}" + }, "gptModelName": { "value": "${gptModelName}" }, diff --git a/content-gen/infra/main.waf.parameters.json b/content-gen/infra/main.waf.parameters.json index 7da1297bf..d5d8438a2 100644 --- a/content-gen/infra/main.waf.parameters.json +++ b/content-gen/infra/main.waf.parameters.json @@ -8,6 +8,9 @@ "location": { "value": "${AZURE_LOCATION}" }, + "secondaryLocation": { + "value": "${secondaryLocation}" + }, "gptModelName": { "value": "${gptModelName}" },