ci: Added Deploy-Test-Cleanup v2 Pipeline #2
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) | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| paths: | |
| - '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"] | |
| types: | |
| - completed | |
| branches: | |
| - main | |
| - dev | |
| - 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 | |
| default: 'australiaeast' | |
| type: choice | |
| options: | |
| - 'australiaeast' | |
| - 'centralus' | |
| - 'eastasia' | |
| - 'eastus' | |
| - 'japaneast' | |
| - 'northeurope' | |
| - 'southeastasia' | |
| - 'swedencentral' | |
| - 'uksouth' | |
| - 'westus' | |
| - 'westus3' | |
| resource_group_name: | |
| description: 'Resource Group Name (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| waf_enabled: | |
| description: 'Enable WAF' | |
| required: false | |
| default: false | |
| type: boolean | |
| EXP: | |
| description: 'Enable EXP' | |
| required: false | |
| default: false | |
| type: boolean | |
| build_docker_image: | |
| description: 'Build And Push Docker Image (Optional)' | |
| required: false | |
| default: false | |
| type: boolean | |
| cleanup_resources: | |
| description: 'Cleanup Deployed Resources' | |
| 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_LOG_ANALYTICS_WORKSPACE_ID: | |
| description: 'Log Analytics Workspace ID (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: | |
| description: 'AI Project Resource ID (Optional)' | |
| required: false | |
| default: '' | |
| type: string | |
| existing_webapp_url: | |
| description: 'Existing WebApp URL (Skips Deployment)' | |
| required: false | |
| default: '' | |
| type: string | |
| 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: '30 4 * * *' # Runs at 10:00 AM IST (4:30 AM UTC) | |
| 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 | |
| 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 }} | |
| 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_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 | |
| 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_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_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 | |
| # 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}" | |
| 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 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_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, Azure Resource ID format) | |
| 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 | |
| # 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 "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_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 | |
| 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' }} | |
| 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_LOG_ANALYTICS_WORKSPACE_ID: ${{ needs.validate-inputs.outputs.azure_env_log_analytics_workspace_id || '' }} | |
| 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 |