Skip to content

Commit 8ad64a1

Browse files
authored
chore(ci): enforce strict changed-app deploy scope (#188)
1 parent 96c98bc commit 8ad64a1

File tree

2 files changed

+60
-54
lines changed

2 files changed

+60
-54
lines changed

.github/workflows/deploy-azd.yml

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ on:
3939
type: boolean
4040
default: true
4141
deployChangedOnly:
42-
description: Deploy only services changed vs default branch
42+
description: Legacy flag (changed-app-only deployment is always enforced)
4343
required: true
4444
type: boolean
4545
default: true
@@ -75,65 +75,70 @@ jobs:
7575
7676
CHANGED_FILES=$(git diff --name-only "origin/$DEFAULT_BRANCH...HEAD")
7777
78-
mapfile -t AGENT_SERVICES <<'EOF'
79-
crm-campaign-intelligence
80-
crm-profile-aggregation
81-
crm-segmentation-personalization
82-
crm-support-assistance
83-
ecommerce-cart-intelligence
84-
ecommerce-catalog-search
85-
ecommerce-checkout-support
86-
ecommerce-order-status
87-
ecommerce-product-detail-enrichment
88-
inventory-alerts-triggers
89-
inventory-health-check
90-
inventory-jit-replenishment
91-
inventory-reservation-validation
92-
logistics-carrier-selection
93-
logistics-eta-computation
94-
logistics-returns-support
95-
logistics-route-issue-detection
96-
product-management-acp-transformation
97-
product-management-assortment-optimization
98-
product-management-consistency-validation
99-
product-management-normalization-classification
100-
truth-ingestion
101-
EOF
78+
mapfile -t AGENT_SERVICES < <(python3 - <<'PY'
79+
import re
10280
103-
SHARED_CHANGED=false
104-
if echo "$CHANGED_FILES" | grep -Eq '^(lib/|pyproject.toml|azure.yaml|\.infra/|\.kubernetes/)'; then
105-
SHARED_CHANGED=true
106-
fi
81+
with open('azure.yaml', encoding='utf-8') as f:
82+
lines = f.readlines()
83+
84+
in_services = False
85+
current_service = None
86+
current_host = None
87+
services = []
88+
89+
for raw in lines:
90+
line = raw.rstrip('\n')
91+
if not in_services:
92+
if re.match(r'^services:\s*$', line):
93+
in_services = True
94+
continue
95+
96+
if re.match(r'^[^\s]', line):
97+
break
98+
99+
service_match = re.match(r'^ ([a-z0-9\-]+):\s*$', line)
100+
if service_match:
101+
if current_service and current_host == 'aks' and current_service != 'crud-service':
102+
services.append(current_service)
103+
current_service = service_match.group(1)
104+
current_host = None
105+
continue
106+
107+
host_match = re.match(r'^ host:\s*(\S+)\s*$', line)
108+
if host_match:
109+
current_host = host_match.group(1)
110+
111+
if current_service and current_host == 'aks' and current_service != 'crud-service':
112+
services.append(current_service)
113+
114+
for service in services:
115+
print(service)
116+
PY
117+
)
107118
108119
CRUD_CHANGED=false
109-
if [ "$SHARED_CHANGED" = true ] || echo "$CHANGED_FILES" | grep -Eq '^apps/crud-service/'; then
120+
if echo "$CHANGED_FILES" | grep -Eq '^apps/crud-service/'; then
110121
CRUD_CHANGED=true
111122
fi
112123
113124
UI_CHANGED=false
114-
if [ "$SHARED_CHANGED" = true ] || echo "$CHANGED_FILES" | grep -Eq '^apps/ui/'; then
125+
if echo "$CHANGED_FILES" | grep -Eq '^apps/ui/'; then
115126
UI_CHANGED=true
116127
fi
117128
118129
AGENTS_CHANGED=false
119130
MATRIX='[]'
120131
CHANGED_AGENTS=()
121132
122-
if [ "$SHARED_CHANGED" = true ]; then
123-
AGENTS_CHANGED=true
124-
CHANGED_AGENTS=("${AGENT_SERVICES[@]}")
125-
MATRIX=$(printf '%s\n' "${AGENT_SERVICES[@]}" | jq -R . | jq -s 'map({service: .})')
126-
else
127-
for service in "${AGENT_SERVICES[@]}"; do
128-
if echo "$CHANGED_FILES" | grep -Eq "^apps/$service/"; then
129-
CHANGED_AGENTS+=("$service")
130-
fi
131-
done
132-
133-
if [ ${#CHANGED_AGENTS[@]} -gt 0 ]; then
134-
AGENTS_CHANGED=true
135-
MATRIX=$(printf '%s\n' "${CHANGED_AGENTS[@]}" | jq -R . | jq -s 'map({service: .})')
133+
for service in "${AGENT_SERVICES[@]}"; do
134+
if echo "$CHANGED_FILES" | grep -Eq "^apps/$service/"; then
135+
CHANGED_AGENTS+=("$service")
136136
fi
137+
done
138+
139+
if [ ${#CHANGED_AGENTS[@]} -gt 0 ]; then
140+
AGENTS_CHANGED=true
141+
MATRIX=$(printf '%s\n' "${CHANGED_AGENTS[@]}" | jq -R . | jq -s 'map({service: .})')
137142
fi
138143
139144
CHANGED_AGENT_SERVICES_CSV=""
@@ -369,7 +374,7 @@ jobs:
369374
needs:
370375
- provision
371376
- detect-changes
372-
if: ${{ !inputs.uiOnly && (!inputs.deployChangedOnly || needs.detect-changes.outputs.crud_changed == 'true') }}
377+
if: ${{ !inputs.uiOnly && needs.detect-changes.outputs.crud_changed == 'true' }}
373378
environment: ${{ inputs.environment }}
374379
env:
375380
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
@@ -474,7 +479,7 @@ jobs:
474479

475480
deploy-ui:
476481
runs-on: ubuntu-latest
477-
if: ${{ inputs.deployStatic && !inputs.uiOnly && (!inputs.deployChangedOnly || needs.detect-changes.outputs.ui_changed == 'true') }}
482+
if: ${{ inputs.deployStatic && !inputs.uiOnly && needs.detect-changes.outputs.ui_changed == 'true' }}
478483
needs:
479484
- provision
480485
- detect-changes
@@ -595,7 +600,7 @@ jobs:
595600

596601
deploy-agents:
597602
runs-on: ubuntu-latest
598-
if: ${{ !inputs.uiOnly && (!inputs.deployChangedOnly || needs.detect-changes.outputs.agents_changed == 'true') }}
603+
if: ${{ !inputs.uiOnly && needs.detect-changes.outputs.agents_changed == 'true' }}
599604
needs:
600605
- provision
601606
- deploy-crud
@@ -605,7 +610,7 @@ jobs:
605610
strategy:
606611
fail-fast: false
607612
matrix:
608-
include: ${{ inputs.deployChangedOnly && fromJSON(needs.detect-changes.outputs.changed_agents_matrix) || fromJSON('[{"service":"crm-campaign-intelligence"},{"service":"crm-profile-aggregation"},{"service":"crm-segmentation-personalization"},{"service":"crm-support-assistance"},{"service":"ecommerce-cart-intelligence"},{"service":"ecommerce-catalog-search"},{"service":"ecommerce-checkout-support"},{"service":"ecommerce-order-status"},{"service":"ecommerce-product-detail-enrichment"},{"service":"inventory-alerts-triggers"},{"service":"inventory-health-check"},{"service":"inventory-jit-replenishment"},{"service":"inventory-reservation-validation"},{"service":"logistics-carrier-selection"},{"service":"logistics-eta-computation"},{"service":"logistics-returns-support"},{"service":"logistics-route-issue-detection"},{"service":"product-management-acp-transformation"},{"service":"product-management-assortment-optimization"},{"service":"product-management-consistency-validation"},{"service":"product-management-normalization-classification"},{"service":"truth-ingestion"}]') }}
613+
include: ${{ fromJSON(needs.detect-changes.outputs.changed_agents_matrix) }}
609614
env:
610615
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
611616
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
@@ -669,7 +674,7 @@ jobs:
669674

670675
sync-apim:
671676
runs-on: ubuntu-latest
672-
if: ${{ !inputs.uiOnly && (!inputs.deployChangedOnly || needs.detect-changes.outputs.agents_changed == 'true' || needs.detect-changes.outputs.crud_changed == 'true') && (needs.deploy-crud.result == 'success' || needs.deploy-crud.result == 'skipped') && (needs.deploy-agents.result == 'success' || needs.deploy-agents.result == 'skipped') }}
677+
if: ${{ !inputs.uiOnly && (needs.detect-changes.outputs.agents_changed == 'true' || needs.detect-changes.outputs.crud_changed == 'true') && (needs.deploy-crud.result == 'success' || needs.deploy-crud.result == 'skipped') && (needs.deploy-agents.result == 'success' || needs.deploy-agents.result == 'skipped') }}
673678
needs:
674679
- deploy-crud
675680
- deploy-agents
@@ -679,7 +684,7 @@ jobs:
679684
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
680685
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
681686
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
682-
CHANGED_SERVICES: ${{ inputs.deployChangedOnly && needs.detect-changes.outputs.changed_aks_services_csv || '' }}
687+
CHANGED_SERVICES: ${{ needs.detect-changes.outputs.changed_aks_services_csv }}
683688
steps:
684689
- uses: actions/checkout@v4
685690

@@ -706,7 +711,7 @@ jobs:
706711

707712
ensure-foundry-agents:
708713
runs-on: ubuntu-latest
709-
if: ${{ !inputs.uiOnly && (!inputs.deployChangedOnly || needs.detect-changes.outputs.agents_changed == 'true') && (needs.deploy-agents.result == 'success' || needs.deploy-agents.result == 'skipped') }}
714+
if: ${{ !inputs.uiOnly && needs.detect-changes.outputs.agents_changed == 'true' && (needs.deploy-agents.result == 'success' || needs.deploy-agents.result == 'skipped') }}
710715
needs:
711716
- deploy-agents
712717
- detect-changes
@@ -715,7 +720,7 @@ jobs:
715720
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
716721
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
717722
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
718-
CHANGED_SERVICES: ${{ inputs.deployChangedOnly && needs.detect-changes.outputs.changed_agent_services_csv || '' }}
723+
CHANGED_SERVICES: ${{ needs.detect-changes.outputs.changed_agent_services_csv }}
719724
steps:
720725
- uses: actions/checkout@v4
721726

docs/implementation/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ Target: **100%**
152152
## Deployment Optimization
153153

154154
- `deploy-azd` changed-service detection now publishes changed agent and AKS service lists.
155-
- Post-deploy hooks (`sync-apim-agents` and `ensure-foundry-agents`) consume these lists through `CHANGED_SERVICES` and run only for changed services when `deployChangedOnly=true`.
155+
- App deployments in `deploy-azd` are now strictly changed-only (CRUD, UI, and agent matrix entries are deployed only when their app paths change).
156+
- Post-deploy hooks (`sync-apim-agents` and `ensure-foundry-agents`) consume these lists through `CHANGED_SERVICES` and run only for changed services.
156157
- Foundry readiness verification in deployment workflow is scoped to changed agent services under changed-only mode.
157158

158159
---

0 commit comments

Comments
 (0)