Skip to content

chore: dev to main merge #75

chore: dev to main merge

chore: dev to main merge #75

Workflow file for this run

name: CI/CD Azure - Real-Time Intelligence Operations
# Trigger the workflow on manual dispatch
on:
workflow_dispatch:
push:
branches:
- main
- dev
paths:
- 'infra/**'
- 'src/**'
- 'azure.yaml'
- 'requirements.txt'
- '.github/workflows/azure-dev.yml'
pull_request:
branches:
- main
paths:
- 'infra/**'
- 'src/**'
- 'azure.yaml'
- 'requirements.txt'
- '.github/workflows/azure-dev.yml'
# Set up permissions for deploying with secretless Azure federated credentials
permissions:
id-token: write
contents: read
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
AZURE_LOCATION: 'westus3'
PYTHONIOENCODING: utf-8
RG_TAGS: ${{ vars.RG_TAGS }}
TEMPLATE_USE_DEV_CONTAINER: ${{ vars.TEMPLATE_USE_DEV_CONTAINER }}
TEMPLATE_VALIDATE_AZD: ${{ vars.TEMPLATE_VALIDATE_AZD }}
TEMPLATE_VALIDATE_TESTS: ${{ vars.TEMPLATE_VALIDATE_TESTS }}
AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
jobs:
build:
runs-on: ubuntu-latest
name: Build and Static Analysis
environment: 'rti-build'
outputs:
RESOURCE_GROUP_NAME: ${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }}
ENV_NAME: ${{ steps.generate_env_name.outputs.ENV_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Azure CLI
uses: azure/login@v3
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Install Bicep CLI
run: |
curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64
chmod +x ./bicep
sudo mv ./bicep /usr/local/bin/bicep
- name: Generate Resource Group Name
id: generate_rg_name
shell: bash
run: |
echo "Generating a unique resource group name..."
ACCL_NAME="rti"
SHORT_UUID=$(uuidgen | cut -d'-' -f1)
UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}"
echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV
echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}"
- name: Check and Create Resource Group
id: check_create_rg
shell: bash
run: |
set -e
echo "🔍 Checking if resource group '$RESOURCE_GROUP_NAME' exists..."
rg_exists=$(az group exists --name $RESOURCE_GROUP_NAME)
if [ "$rg_exists" = "false" ]; then
echo "📦 Resource group does not exist. Creating new resource group '$RESOURCE_GROUP_NAME' in location '$AZURE_LOCATION'..."
az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION --tags ${{ env.RG_TAGS }} || { echo "❌ Error creating resource group"; exit 1; }
echo "✅ Resource group '$RESOURCE_GROUP_NAME' created successfully."
else
echo "✅ Resource group '$RESOURCE_GROUP_NAME' already exists. Deploying to existing resource group."
fi
echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT
echo "RESOURCE_GROUP_NAME=$RESOURCE_GROUP_NAME" >> $GITHUB_ENV
- name: Generate Unique Environment Name
id: generate_env_name
shell: bash
run: |
COMMON_PART="rtio"
HHMM=$(date -u +'%H%M')
TIMESTAMP=$(date +%s)
UPDATED_TIMESTAMP=$(echo "$TIMESTAMP" | tail -c 6)
UNIQUE_ENV_NAME="${COMMON_PART}${HHMM}${UPDATED_TIMESTAMP}"
echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_ENV
echo "Generated Environment Name: ${UNIQUE_ENV_NAME}"
echo "ENV_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_OUTPUT
- name: Bicep Static Code Analysis
run: |
echo "Running Bicep static code analysis on main.bicep..."
bicep build infra/main.bicep --outfile infra/main.json
echo "✅ Bicep compilation successful"
# Run bicep linter
bicep lint infra/main.bicep
echo "✅ Bicep linting completed"
- name: Validate Bicep Template
run: |
echo "Validating Bicep template..."
az deployment group validate \
--resource-group ${{ env.RESOURCE_GROUP_NAME }} \
--template-file infra/main.json \
--parameters infra/main.parameters.json \
--parameters solutionName=${{ env.ENV_NAME }} \
--parameters location=${{ env.AZURE_LOCATION }} || true
echo "✅ Bicep template validation completed"
deploy:
runs-on: ubuntu-latest
name: Deploy
environment: 'rti-dev'
needs: build
outputs:
SOLUTION_SUFFIX: ${{ steps.azd_params.outputs.SOLUTION_SUFFIX }}
AZURE_FABRIC_CAPACITY_NAME: ${{ steps.azd_params.outputs.AZURE_FABRIC_CAPACITY_NAME }}
env:
RESOURCE_GROUP_NAME: ${{ needs.build.outputs.RESOURCE_GROUP_NAME }}
ENV_NAME: ${{ needs.build.outputs.ENV_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Azure CLI login
uses: azure/login@v3
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Install azd
uses: Azure/setup-azd@v2
- name: Azure Developer CLI login
shell: bash
run: |
azd auth login \
--client-id "${{ env.AZURE_CLIENT_ID }}" \
--federated-credential-provider "github" \
--tenant-id "${{ env.AZURE_TENANT_ID }}"
- name: Deploy using azd up and Run Fabric provisioning script
id: get_output_linux
shell: bash
env:
ENV_NAME: ${{ env.ENV_NAME }}
AZURE_LOCATION: ${{ env.AZURE_LOCATION }}
RESOURCE_GROUP_NAME: ${{ env.RESOURCE_GROUP_NAME }}
run: |
set -e
echo "Creating environment..."
azd env new $ENV_NAME --no-prompt
echo "Environment created: $ENV_NAME"
echo "Setting default subscription..."
azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Set additional parameters
azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME"
# Set optional workspace administrators if provided via repository variable
FABRIC_WS_ADMINS="${{ vars.FABRIC_WORKSPACE_ADMINISTRATORS }}"
if [ -n "$FABRIC_WS_ADMINS" ]; then
azd env set FABRIC_WORKSPACE_ADMINISTRATORS "$FABRIC_WS_ADMINS"
echo "Workspace administrators set: $FABRIC_WS_ADMINS"
fi
# Deploy using azd up
azd up --no-prompt
- name: Get azd Environment Parameters
id: azd_params
shell: bash
run: |
echo "Extracting azd environment parameters..."
AZURE_FABRIC_CAPACITY_NAME=$(azd env get-value AZURE_FABRIC_CAPACITY_NAME 2>/dev/null || echo "")
echo "AZURE_FABRIC_CAPACITY_NAME=${AZURE_FABRIC_CAPACITY_NAME}" >> $GITHUB_OUTPUT
echo "AZURE_FABRIC_CAPACITY_NAME=${AZURE_FABRIC_CAPACITY_NAME}" >> $GITHUB_ENV
SOLUTION_SUFFIX=$(azd env get-value SOLUTION_SUFFIX 2>/dev/null || echo "")
echo "SOLUTION_SUFFIX=${SOLUTION_SUFFIX}" >> $GITHUB_OUTPUT
echo "SOLUTION_SUFFIX=${SOLUTION_SUFFIX}" >> $GITHUB_ENV
AZURE_RESOURCE_GROUP=$(azd env get-value AZURE_RESOURCE_GROUP 2>/dev/null || echo "")
echo "AZURE_RESOURCE_GROUP=${AZURE_RESOURCE_GROUP}" >> $GITHUB_OUTPUT
echo "AZURE_RESOURCE_GROUP=${AZURE_RESOURCE_GROUP}" >> $GITHUB_ENV
AZURE_FABRIC_CAPACITY_ADMINISTRATORS=$(azd env get-value AZURE_FABRIC_CAPACITY_ADMINISTRATORS 2>/dev/null || echo "")
echo "AZURE_FABRIC_CAPACITY_ADMINISTRATORS=${AZURE_FABRIC_CAPACITY_ADMINISTRATORS}" >> $GITHUB_OUTPUT
echo "AZURE_FABRIC_CAPACITY_ADMINISTRATORS=${AZURE_FABRIC_CAPACITY_ADMINISTRATORS}" >> $GITHUB_ENV
AZURE_EVENT_HUB_NAMESPACE_NAME=$(azd env get-value AZURE_EVENT_HUB_NAMESPACE_NAME 2>/dev/null || echo "")
echo "AZURE_EVENT_HUB_NAMESPACE_NAME=${AZURE_EVENT_HUB_NAMESPACE_NAME}" >> $GITHUB_OUTPUT
echo "AZURE_EVENT_HUB_NAMESPACE_NAME=${AZURE_EVENT_HUB_NAMESPACE_NAME}" >> $GITHUB_ENV
AZURE_EVENT_HUB_NAME=$(azd env get-value AZURE_EVENT_HUB_NAME 2>/dev/null || echo "")
echo "AZURE_EVENT_HUB_NAME=${AZURE_EVENT_HUB_NAME}" >> $GITHUB_OUTPUT
echo "AZURE_EVENT_HUB_NAME=${AZURE_EVENT_HUB_NAME}" >> $GITHUB_ENV
echo "✅ azd parameters extracted successfully"
- name: Output Deployment Summary
run: |
echo "## 🎉 Real-Time Intelligence Operations Deployment Complete!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📅 **Completed:** $(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_STEP_SUMMARY
echo "🏷️ **Environment:** ${{ env.ENV_NAME }}" >> $GITHUB_STEP_SUMMARY
echo "🔖 **Solution Suffix:** ${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🏢 Azure Resources Deployed" >> $GITHUB_STEP_SUMMARY
echo "| Resource | Name |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 📂 Resource Group | ${{ env.RESOURCE_GROUP_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "| ⚡ Fabric Capacity | ${{ env.AZURE_FABRIC_CAPACITY_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "| 📡 Event Hub Namespace | ${{ env.AZURE_EVENT_HUB_NAMESPACE_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "| 📨 Event Hub | ${{ env.AZURE_EVENT_HUB_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔗 Azure Portal Links" >> $GITHUB_STEP_SUMMARY
echo "- 📂 [Resource Group](https://portal.azure.com/#@${{ env.AZURE_TENANT_ID }}/resource/subscriptions/${{ env.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ env.RESOURCE_GROUP_NAME }}/overview)" >> $GITHUB_STEP_SUMMARY
echo "- ⚡ [Fabric Capacity](https://portal.azure.com/#@${{ env.AZURE_TENANT_ID }}/resource/subscriptions/${{ env.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ env.RESOURCE_GROUP_NAME }}/providers/Microsoft.Fabric/capacities/${{ env.AZURE_FABRIC_CAPACITY_NAME }}/overview)" >> $GITHUB_STEP_SUMMARY
echo "- 📡 [Event Hub Namespace](https://portal.azure.com/#@${{ env.AZURE_TENANT_ID }}/resource/subscriptions/${{ env.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ env.RESOURCE_GROUP_NAME }}/providers/Microsoft.EventHub/namespaces/${{ env.AZURE_EVENT_HUB_NAMESPACE_NAME }}/overview)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔧 Fabric Resources (Expected Names)" >> $GITHUB_STEP_SUMMARY
echo "The following Fabric resources should have been created with these naming patterns:" >> $GITHUB_STEP_SUMMARY
echo "- 🏠 **Workspace:** rti_workspace_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "- 🏛️ **Eventhouse:** rti_eventhouse_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "- 🗄️ **Database:** rti_kqldb_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "- 📊 **Dashboard:** rti_dashboard_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "- 🌊 **Eventstream:** rti_eventstream_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "- 🚨 **Activator:** rti_activator_${{ env.SOLUTION_SUFFIX }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🚀 Next Steps" >> $GITHUB_STEP_SUMMARY
echo "1. 📊 Access your Fabric workspace at [app.fabric.microsoft.com](https://app.fabric.microsoft.com)" >> $GITHUB_STEP_SUMMARY
echo "2. 🎯 Start the event simulator to generate sample data" >> $GITHUB_STEP_SUMMARY
echo "3. 📈 View real-time analytics in the dashboard" >> $GITHUB_STEP_SUMMARY
echo "4. 🔔 Configure alert recipients in the Activator" >> $GITHUB_STEP_SUMMARY
cleanup:
runs-on: ubuntu-latest
name: Cleanup Resources
environment: 'rti-dev'
needs: [build, deploy]
if: always() && needs.build.outputs.RESOURCE_GROUP_NAME != '' && needs.build.outputs.ENV_NAME != ''
env:
RESOURCE_GROUP_NAME: ${{ needs.build.outputs.RESOURCE_GROUP_NAME }}
ENV_NAME: ${{ needs.build.outputs.ENV_NAME }}
SOLUTION_SUFFIX: ${{ needs.deploy.outputs.SOLUTION_SUFFIX }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Azure CLI login
uses: azure/login@v3
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Install azd
uses: Azure/setup-azd@v2
- name: Azure Developer CLI login
shell: bash
run: |
azd auth login \
--client-id "${{ env.AZURE_CLIENT_ID }}" \
--federated-credential-provider "github" \
--tenant-id "${{ env.AZURE_TENANT_ID }}"
- name: Restore azd Environment and Run azd down
if: env.SOLUTION_SUFFIX != ''
shell: bash
run: |
set -e
echo "Restoring azd environment: ${{ env.ENV_NAME }}"
azd env new ${{ env.ENV_NAME }} --no-prompt || true
azd env select ${{ env.ENV_NAME }}
azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
azd env set AZURE_LOCATION="${{ env.AZURE_LOCATION }}"
azd env set AZURE_RESOURCE_GROUP="${{ env.RESOURCE_GROUP_NAME }}"
azd env set SOLUTION_SUFFIX="${{ env.SOLUTION_SUFFIX }}"
echo "✅ azd environment restored"
echo "🗑️ Running azd down to remove Fabric workspace and Azure resources..."
azd down --force --purge --no-prompt
echo "✅ azd down completed"
- name: Delete Resource Group (fallback)
if: always() && env.RESOURCE_GROUP_NAME != ''
shell: bash
run: |
echo "🗑️ Ensuring resource group '${{ env.RESOURCE_GROUP_NAME }}' is deleted..."
rg_exists=$(az group exists --name "${{ env.RESOURCE_GROUP_NAME }}")
if [ "$rg_exists" = "true" ]; then
echo "Resource group exists. Deleting '${{ env.RESOURCE_GROUP_NAME }}'..."
az group delete --name "${{ env.RESOURCE_GROUP_NAME }}" --yes --no-wait
echo "✅ Resource group deletion initiated."
else
echo "✅ Resource group '${{ env.RESOURCE_GROUP_NAME }}' does not exist or was already deleted."
fi
- name: Output Cleanup Summary
if: always()
run: |
CLEANUP_TIME=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
echo "# 🧹 Cleanup Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Cleanup completed at:** ${CLEANUP_TIME}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Resource | Status |" >> $GITHUB_STEP_SUMMARY
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` — deleted |" >> $GITHUB_STEP_SUMMARY
if [ -n "${{ env.SOLUTION_SUFFIX }}" ]; then
echo "| **Fabric Workspace** | Deleted via azd down |" >> $GITHUB_STEP_SUMMARY
fi