Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 178 additions & 10 deletions .github/workflows/deploy-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,187 @@ permissions:
contents: read
actions: read
jobs:
validate-inputs:
runs-on: ubuntu-latest
outputs:
validation_passed: ${{ steps.validate.outputs.passed }}
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 }}
steps:
- name: Validate Workflow Input Parameters
id: validate
shell: bash
env:
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 }}
run: |
echo "🔍 Validating workflow input parameters..."
VALIDATION_FAILED=false

# 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 "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

Run:
needs: validate-inputs
if: needs.validate-inputs.outputs.validation_passed == 'true'
uses: ./.github/workflows/deploy-orchestrator.yml
with:
runner_os: ubuntu-latest
azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
EXP: ${{ github.event.inputs.EXP == 'true' }}
build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }}
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID || '' }}
existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}
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 }}
secrets: inherit
8 changes: 4 additions & 4 deletions .github/workflows/deploy-orchestrator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
secrets: inherit

deploy:
if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)
if: "!cancelled() && (needs.docker-build.result == 'success' || needs.docker-build.result == 'skipped') && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)"
needs: docker-build
uses: ./.github/workflows/job-deploy.yml
with:
Expand All @@ -96,7 +96,7 @@ jobs:
secrets: inherit

e2e-test:
if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_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.CONTAINER_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))"
needs: [docker-build, deploy]
uses: ./.github/workflows/test-automation-v2.yml
with:
Expand All @@ -105,7 +105,7 @@ jobs:
secrets: inherit

send-notification:
if: always()
if: "!cancelled()"
needs: [docker-build, deploy, e2e-test]
uses: ./.github/workflows/job-send-notification.yml
with:
Expand All @@ -124,7 +124,7 @@ jobs:
secrets: inherit

cleanup-deployment:
if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)
if: "!cancelled() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)"
needs: [docker-build, deploy, e2e-test]
uses: ./.github/workflows/job-cleanup-deployment.yml
with:
Expand Down
Loading