Deploy-Test-Cleanup (v2) #370
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy-Test-Cleanup (v2) | |
| permissions: | |
| id-token: write | |
| contents: read | |
| actions: read | |
| on: | |
| workflow_run: | |
| workflows: ["Build Docker and Optional Push v4"] | |
| types: | |
| - completed | |
| branches: | |
| - main | |
| - dev-v4 | |
| - hotfix | |
| workflow_dispatch: | |
| inputs: | |
| runner_os: | |
| description: 'Deployment Environment' | |
| required: false | |
| type: choice | |
| options: | |
| - 'codespace' | |
| - 'Local' | |
| default: 'codespace' | |
| azure_location: | |
| description: 'Azure Region (Non-AI Services)' | |
| required: false | |
| default: 'australiaeast' | |
| type: choice | |
| options: | |
| - 'australiaeast' | |
| - 'centralus' | |
| - 'eastasia' | |
| - 'eastus2' | |
| - 'japaneast' | |
| - 'northeurope' | |
| - 'southeastasia' | |
| - 'uksouth' | |
| resource_group_name: | |
| description: 'Resource Group Name (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| build_docker_image: | |
| description: 'Build & Use Custom Images (Optional)' | |
| required: false | |
| default: false | |
| type: boolean | |
| waf_enabled: | |
| description: 'Deploy WAF' | |
| required: false | |
| default: false | |
| type: boolean | |
| EXP: | |
| description: 'Deploy EXP' | |
| required: false | |
| default: false | |
| type: boolean | |
| enable_scalability: | |
| description: 'Enable Scalability (WAF only)' | |
| required: false | |
| default: false | |
| type: boolean | |
| cleanup_resources: | |
| description: 'Auto Delete RG' | |
| required: false | |
| default: false | |
| type: boolean | |
| run_e2e_tests: | |
| description: 'Run End-to-End Tests' | |
| required: false | |
| default: 'GoldenPath-Testing' | |
| type: choice | |
| options: | |
| - 'GoldenPath-Testing' | |
| - 'Smoke-Testing' | |
| - 'None' | |
| AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: | |
| description: 'Existing Log Analytics Workspace Resource ID (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| AZURE_EXISTING_AIPROJECT_RESOURCE_ID: | |
| description: 'Existing AI Project Resource ID (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| existing_webapp_url: | |
| description: 'Run Tests Against Existing RG (Provide Web App URL)' | |
| required: false | |
| default: '' | |
| type: string | |
| schedule: | |
| - cron: "0 11,23 * * *" # Runs at 11:00 AM and 11:00 PM GMT | |
| jobs: | |
| validate-inputs: | |
| 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 }} | |
| enable_scalability: ${{ steps.validate.outputs.enable_scalability }} | |
| exp: ${{ steps.validate.outputs.exp }} | |
| build_docker_image: ${{ steps.validate.outputs.build_docker_image }} | |
| cleanup_resources: ${{ steps.validate.outputs.cleanup_resources }} | |
| run_e2e_tests: ${{ steps.validate.outputs.run_e2e_tests }} | |
| azure_env_existing_log_analytics_workspace_rid: ${{ steps.validate.outputs.azure_env_existing_log_analytics_workspace_rid }} | |
| azure_existing_aiproject_resource_id: ${{ steps.validate.outputs.azure_existing_aiproject_resource_id }} | |
| existing_webapp_url: ${{ steps.validate.outputs.existing_webapp_url }} | |
| steps: | |
| - name: Validate Workflow Input Parameters | |
| 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 }} | |
| INPUT_ENABLE_SCALABILITY: ${{ github.event.inputs.enable_scalability }} | |
| INPUT_EXP: ${{ github.event.inputs.EXP }} | |
| INPUT_BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image }} | |
| INPUT_CLEANUP_RESOURCES: ${{ github.event.inputs.cleanup_resources }} | |
| INPUT_RUN_E2E_TESTS: ${{ github.event.inputs.run_e2e_tests }} | |
| INPUT_AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: ${{ github.event.inputs.AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID }} | |
| INPUT_AZURE_EXISTING_AIPROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AIPROJECT_RESOURCE_ID }} | |
| INPUT_EXISTING_WEBAPP_URL: ${{ github.event.inputs.existing_webapp_url }} | |
| run: | | |
| echo "🔍 Validating workflow input parameters..." | |
| VALIDATION_FAILED=false | |
| # Resolve runner_os from Deployment Environment selection | |
| DEPLOY_ENV="${INPUT_RUNNER_OS:-codespace}" | |
| if [[ "$DEPLOY_ENV" == "codespace" ]]; then | |
| RUNNER_OS="ubuntu-latest" | |
| echo "✅ Deployment Environment: 'codespace' → runner: ubuntu-latest" | |
| elif [[ "$DEPLOY_ENV" == "Local" ]]; then | |
| RUNNER_OS="windows-latest" | |
| echo "✅ Deployment Environment: 'Local' → runner: windows-latest" | |
| else | |
| echo "❌ ERROR: Deployment Environment must be 'codespace' or 'Local', got: '$DEPLOY_ENV'" | |
| VALIDATION_FAILED=true | |
| RUNNER_OS="ubuntu-latest" | |
| fi | |
| # Validate azure_location (Azure region format) | |
| LOCATION="${INPUT_AZURE_LOCATION:-australiaeast}" | |
| if [[ ! "$LOCATION" =~ ^[a-z0-9]+$ ]]; then | |
| echo "❌ ERROR: azure_location '$LOCATION' is invalid. Must contain only lowercase letters and numbers" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ azure_location: '$LOCATION' is valid" | |
| fi | |
| # Validate resource_group_name (Azure naming convention, optional) | |
| if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then | |
| if [[ ! "$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 (length: ${#INPUT_RESOURCE_GROUP_NAME})" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ resource_group_name: '$INPUT_RESOURCE_GROUP_NAME' is valid" | |
| fi | |
| else | |
| echo "✅ resource_group_name: Not provided (will be auto-generated)" | |
| fi | |
| # Validate waf_enabled (boolean) | |
| WAF_ENABLED="${INPUT_WAF_ENABLED:-false}" | |
| if [[ "$WAF_ENABLED" != "true" && "$WAF_ENABLED" != "false" ]]; then | |
| echo "❌ ERROR: waf_enabled must be 'true' or 'false', got: '$WAF_ENABLED'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ waf_enabled: '$WAF_ENABLED' is valid" | |
| fi | |
| # Validate enable_scalability (boolean, opt-in for WAF deployments) | |
| ENABLE_SCALABILITY="${INPUT_ENABLE_SCALABILITY:-false}" | |
| if [[ "$ENABLE_SCALABILITY" != "true" && "$ENABLE_SCALABILITY" != "false" ]]; then | |
| echo "❌ ERROR: enable_scalability must be 'true' or 'false', got: '$ENABLE_SCALABILITY'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ enable_scalability: '$ENABLE_SCALABILITY' is valid" | |
| fi | |
| # Validate EXP (boolean) | |
| EXP_ENABLED="${INPUT_EXP:-false}" | |
| if [[ "$EXP_ENABLED" != "true" && "$EXP_ENABLED" != "false" ]]; then | |
| echo "❌ ERROR: EXP must be 'true' or 'false', got: '$EXP_ENABLED'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ EXP: '$EXP_ENABLED' is valid" | |
| fi | |
| # Validate build_docker_image (boolean) | |
| BUILD_DOCKER="${INPUT_BUILD_DOCKER_IMAGE:-false}" | |
| if [[ "$BUILD_DOCKER" != "true" && "$BUILD_DOCKER" != "false" ]]; then | |
| echo "❌ ERROR: build_docker_image must be 'true' or 'false', got: '$BUILD_DOCKER'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ build_docker_image: '$BUILD_DOCKER' is valid" | |
| fi | |
| # Validate cleanup_resources (boolean) | |
| CLEANUP_RESOURCES="${INPUT_CLEANUP_RESOURCES:-false}" | |
| if [[ "$CLEANUP_RESOURCES" != "true" && "$CLEANUP_RESOURCES" != "false" ]]; then | |
| echo "❌ ERROR: cleanup_resources must be 'true' or 'false', got: '$CLEANUP_RESOURCES'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ cleanup_resources: '$CLEANUP_RESOURCES' is valid" | |
| fi | |
| # Validate run_e2e_tests (specific allowed values) | |
| TEST_OPTION="${INPUT_RUN_E2E_TESTS:-GoldenPath-Testing}" | |
| if [[ "$TEST_OPTION" != "GoldenPath-Testing" && "$TEST_OPTION" != "Smoke-Testing" && "$TEST_OPTION" != "None" ]]; then | |
| echo "❌ ERROR: run_e2e_tests must be one of: GoldenPath-Testing, Smoke-Testing, None, got: '$TEST_OPTION'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ run_e2e_tests: '$TEST_OPTION' is valid" | |
| fi | |
| # Validate AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID (optional, Azure Resource ID format) | |
| if [[ -n "$INPUT_AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID" ]]; then | |
| if [[ ! "$INPUT_AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then | |
| echo "❌ ERROR: AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID 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_EXISTING_LOG_ANALYTICS_WORKSPACE_RID'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: Valid Resource ID format" | |
| fi | |
| else | |
| echo "✅ AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: Not provided (optional)" | |
| fi | |
| # Validate AZURE_EXISTING_AIPROJECT_RESOURCE_ID (optional, Azure Resource ID format) | |
| if [[ -n "$INPUT_AZURE_EXISTING_AIPROJECT_RESOURCE_ID" ]]; then | |
| if [[ ! "$INPUT_AZURE_EXISTING_AIPROJECT_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_AIPROJECT_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_AIPROJECT_RESOURCE_ID'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ AZURE_EXISTING_AIPROJECT_RESOURCE_ID: Valid Resource ID format" | |
| fi | |
| else | |
| echo "✅ AZURE_EXISTING_AIPROJECT_RESOURCE_ID: Not provided (optional)" | |
| fi | |
| # Validate existing_webapp_url (optional, must start with https) | |
| if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then | |
| if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then | |
| echo "❌ ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'" | |
| VALIDATION_FAILED=true | |
| else | |
| echo "✅ existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid" | |
| fi | |
| else | |
| echo "✅ existing_webapp_url: Not provided (will perform deployment)" | |
| 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!" | |
| # 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 | |
| echo "enable_scalability=$ENABLE_SCALABILITY" >> $GITHUB_OUTPUT | |
| echo "exp=$EXP_ENABLED" >> $GITHUB_OUTPUT | |
| echo "build_docker_image=$BUILD_DOCKER" >> $GITHUB_OUTPUT | |
| echo "cleanup_resources=$CLEANUP_RESOURCES" >> $GITHUB_OUTPUT | |
| echo "run_e2e_tests=$TEST_OPTION" >> $GITHUB_OUTPUT | |
| echo "azure_env_existing_log_analytics_workspace_rid=$INPUT_AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID" >> $GITHUB_OUTPUT | |
| echo "azure_existing_aiproject_resource_id=$INPUT_AZURE_EXISTING_AIPROJECT_RESOURCE_ID" >> $GITHUB_OUTPUT | |
| echo "existing_webapp_url=$INPUT_EXISTING_WEBAPP_URL" >> $GITHUB_OUTPUT | |
| Run: | |
| needs: validate-inputs | |
| if: needs.validate-inputs.outputs.validation_passed == 'true' | |
| uses: ./.github/workflows/deploy-orchestrator.yml | |
| with: | |
| 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' }} | |
| enable_scalability: ${{ needs.validate-inputs.outputs.enable_scalability == 'true' }} | |
| EXP: ${{ needs.validate-inputs.outputs.exp == 'true' }} | |
| build_docker_image: ${{ needs.validate-inputs.outputs.build_docker_image == 'true' }} | |
| cleanup_resources: ${{ needs.validate-inputs.outputs.cleanup_resources == 'true' }} | |
| run_e2e_tests: ${{ needs.validate-inputs.outputs.run_e2e_tests || 'GoldenPath-Testing' }} | |
| AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID: ${{ needs.validate-inputs.outputs.azure_env_existing_log_analytics_workspace_rid || '' }} | |
| AZURE_EXISTING_AIPROJECT_RESOURCE_ID: ${{ needs.validate-inputs.outputs.azure_existing_aiproject_resource_id || '' }} | |
| existing_webapp_url: ${{ needs.validate-inputs.outputs.existing_webapp_url || '' }} | |
| trigger_type: ${{ github.event_name }} | |
| secrets: inherit |