Skip to content

Commit 4dd4352

Browse files
Address PR review: eliminate duplication with matrix strategy and common values
- Refactor workflow to use matrix strategy (eliminates ~150 lines duplication) - Extract common staging config to envs/common/values.yaml - Slim down environment-specific values to only host/URL overrides - Remove unnecessary wrapper scripts (decrypt.sh, safe-apply-secrets.sh) - Update READMEs to document new structure Co-authored-by: openhands <openhands@all-hands.dev>
1 parent 34dedb7 commit 4dd4352

8 files changed

Lines changed: 387 additions & 852 deletions

File tree

Lines changed: 40 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: Deploy to Staging
22

33
on:
4-
# Manual trigger with options
54
workflow_dispatch:
65
inputs:
76
image_tag:
@@ -32,17 +31,26 @@ env:
3231
GCP_CLUSTER: staging-core-application
3332

3433
jobs:
35-
deploy-pathroute:
36-
name: Deploy to staging-pathroute
37-
if: ${{ inputs.environment == 'both' || inputs.environment == 'pathroute' }}
34+
deploy:
35+
name: Deploy to staging-${{ matrix.env.name }}
3836
runs-on: ubuntu-24.04
3937
permissions:
4038
contents: read
4139
id-token: write
42-
env:
43-
NAMESPACE: openhands-pathroute
44-
HELM_RELEASE: openhands-pathroute
45-
ENV_DIR: envs/staging-pathroute
40+
strategy:
41+
fail-fast: false
42+
matrix:
43+
env:
44+
- name: pathroute
45+
namespace: openhands-pathroute
46+
helm_release: openhands-pathroute
47+
env_dir: envs/staging-pathroute
48+
- name: subdomain
49+
namespace: openhands-subdomain
50+
helm_release: openhands-subdomain
51+
env_dir: envs/staging-subdomain
52+
# Only run for selected environment(s)
53+
if: ${{ inputs.environment == 'both' || inputs.environment == matrix.env.name }}
4654

4755
steps:
4856
- name: Checkout repository
@@ -69,149 +77,7 @@ jobs:
6977
uses: google-github-actions/setup-gcloud@v2
7078

7179
- name: Install gke-gcloud-auth-plugin
72-
run: |
73-
gcloud components install gke-gcloud-auth-plugin
74-
75-
- name: Configure kubectl
76-
run: |
77-
gcloud container clusters get-credentials ${{ env.GCP_CLUSTER }} \
78-
--zone ${{ env.GCP_ZONE }} \
79-
--project ${{ env.GCP_PROJECT }}
80-
81-
- name: Create namespace if not exists
82-
if: ${{ !inputs.dry_run }}
83-
run: |
84-
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
85-
86-
- name: Decrypt and apply secrets
87-
if: ${{ !inputs.skip_secrets && !inputs.dry_run }}
88-
run: |
89-
SECRETS_DIR="${{ env.ENV_DIR }}/secrets"
90-
91-
if [[ -d "$SECRETS_DIR" ]]; then
92-
echo "Applying secrets from $SECRETS_DIR"
93-
for file in "$SECRETS_DIR"/*.yaml; do
94-
# Skip .gitkeep or non-existent files
95-
[[ -e "$file" ]] || continue
96-
[[ "$(basename "$file")" == ".gitkeep" ]] && continue
97-
98-
echo "Decrypting and applying: $file"
99-
sops --decrypt "$file" | kubectl apply -n ${{ env.NAMESPACE }} -f -
100-
done
101-
echo "All secrets applied successfully"
102-
else
103-
echo "No secrets directory found at $SECRETS_DIR"
104-
fi
105-
106-
- name: Update Helm dependencies
107-
run: |
108-
helm dependency update charts/openhands
109-
110-
- name: Helm template (dry run)
111-
if: ${{ inputs.dry_run }}
112-
run: |
113-
helm template ${{ env.HELM_RELEASE }} charts/openhands \
114-
--namespace ${{ env.NAMESPACE }} \
115-
--values ${{ env.ENV_DIR }}/values.yaml \
116-
--set image.tag=${{ inputs.image_tag }} \
117-
--debug
118-
119-
- name: Deploy with Helm
120-
if: ${{ !inputs.dry_run }}
121-
run: |
122-
# Check current release status
123-
if helm status ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} &>/dev/null; then
124-
status=$(helm status ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} -o json | jq -r '.info.status')
125-
if [[ "$status" != "deployed" ]]; then
126-
echo "Found release in non-deployed state ($status). Attempting rollback..."
127-
helm rollback ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} || true
128-
fi
129-
fi
130-
131-
helm upgrade --install \
132-
--wait \
133-
--timeout 10m \
134-
${{ env.HELM_RELEASE }} \
135-
charts/openhands \
136-
--namespace ${{ env.NAMESPACE }} \
137-
--values ${{ env.ENV_DIR }}/values.yaml \
138-
--set image.tag=${{ inputs.image_tag }} \
139-
--debug
140-
141-
- name: Get deployment info
142-
if: ${{ !inputs.dry_run }}
143-
id: deployment_info
144-
run: |
145-
echo "## Deployment Summary (pathroute)" >> $GITHUB_STEP_SUMMARY
146-
echo "" >> $GITHUB_STEP_SUMMARY
147-
echo "- **Environment:** staging-pathroute" >> $GITHUB_STEP_SUMMARY
148-
echo "- **Namespace:** ${{ env.NAMESPACE }}" >> $GITHUB_STEP_SUMMARY
149-
echo "- **Image Tag:** ${{ inputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
150-
echo "" >> $GITHUB_STEP_SUMMARY
151-
152-
# Get ingress hostname
153-
hostname=$(kubectl get ing -n ${{ env.NAMESPACE }} -o jsonpath='{.items[0].spec.rules[0].host}' 2>/dev/null || echo "N/A")
154-
echo "- **Hostname:** https://$hostname" >> $GITHUB_STEP_SUMMARY
155-
echo "hostname=$hostname" >> $GITHUB_OUTPUT
156-
157-
echo "" >> $GITHUB_STEP_SUMMARY
158-
echo "### Pods Status" >> $GITHUB_STEP_SUMMARY
159-
echo '```' >> $GITHUB_STEP_SUMMARY
160-
kubectl get pods -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }} >> $GITHUB_STEP_SUMMARY
161-
echo '```' >> $GITHUB_STEP_SUMMARY
162-
163-
- name: Verify deployment health
164-
if: ${{ !inputs.dry_run }}
165-
run: |
166-
echo "Waiting for deployment to stabilize..."
167-
kubectl rollout status deployment -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }} --timeout=5m || true
168-
169-
echo ""
170-
echo "Current pod status:"
171-
kubectl get pods -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }}
172-
173-
outputs:
174-
hostname: ${{ steps.deployment_info.outputs.hostname }}
175-
176-
deploy-subdomain:
177-
name: Deploy to staging-subdomain
178-
if: ${{ inputs.environment == 'both' || inputs.environment == 'subdomain' }}
179-
runs-on: ubuntu-24.04
180-
permissions:
181-
contents: read
182-
id-token: write
183-
env:
184-
NAMESPACE: openhands-subdomain
185-
HELM_RELEASE: openhands-subdomain
186-
ENV_DIR: envs/staging-subdomain
187-
188-
steps:
189-
- name: Checkout repository
190-
uses: actions/checkout@v4
191-
192-
- name: Install SOPS
193-
run: |
194-
curl -L "https://github.com/mozilla/sops/releases/download/v3.9.1/sops-v3.9.1.linux.amd64" -o sops
195-
chmod +x sops
196-
sudo mv sops /usr/local/bin/sops
197-
sops --version
198-
199-
- name: Install Helm
200-
uses: azure/setup-helm@v3
201-
with:
202-
version: 'latest'
203-
204-
- name: Authenticate with Google Cloud
205-
uses: google-github-actions/auth@v2
206-
with:
207-
credentials_json: ${{ secrets.GCP_SERVICE_KEY }}
208-
209-
- name: Set up Google Cloud SDK
210-
uses: google-github-actions/setup-gcloud@v2
211-
212-
- name: Install gke-gcloud-auth-plugin
213-
run: |
214-
gcloud components install gke-gcloud-auth-plugin
80+
run: gcloud components install gke-gcloud-auth-plugin
21581

21682
- name: Configure kubectl
21783
run: |
@@ -222,94 +88,89 @@ jobs:
22288
- name: Create namespace if not exists
22389
if: ${{ !inputs.dry_run }}
22490
run: |
225-
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
91+
kubectl create namespace ${{ matrix.env.namespace }} --dry-run=client -o yaml | kubectl apply -f -
22692
22793
- name: Decrypt and apply secrets
22894
if: ${{ !inputs.skip_secrets && !inputs.dry_run }}
22995
run: |
230-
SECRETS_DIR="${{ env.ENV_DIR }}/secrets"
231-
96+
SECRETS_DIR="${{ matrix.env.env_dir }}/secrets"
23297
if [[ -d "$SECRETS_DIR" ]]; then
23398
echo "Applying secrets from $SECRETS_DIR"
23499
for file in "$SECRETS_DIR"/*.yaml; do
235-
# Skip .gitkeep or non-existent files
236100
[[ -e "$file" ]] || continue
237101
[[ "$(basename "$file")" == ".gitkeep" ]] && continue
238-
239102
echo "Decrypting and applying: $file"
240-
sops --decrypt "$file" | kubectl apply -n ${{ env.NAMESPACE }} -f -
103+
sops --decrypt "$file" | kubectl apply -n ${{ matrix.env.namespace }} -f -
241104
done
242-
echo "All secrets applied successfully"
243105
else
244106
echo "No secrets directory found at $SECRETS_DIR"
245107
fi
246108
247109
- name: Update Helm dependencies
248-
run: |
249-
helm dependency update charts/openhands
110+
run: helm dependency update charts/openhands
250111

251112
- name: Helm template (dry run)
252113
if: ${{ inputs.dry_run }}
253114
run: |
254-
helm template ${{ env.HELM_RELEASE }} charts/openhands \
255-
--namespace ${{ env.NAMESPACE }} \
256-
--values ${{ env.ENV_DIR }}/values.yaml \
115+
helm template ${{ matrix.env.helm_release }} charts/openhands \
116+
--namespace ${{ matrix.env.namespace }} \
117+
--values envs/common/values.yaml \
118+
--values ${{ matrix.env.env_dir }}/values.yaml \
257119
--set image.tag=${{ inputs.image_tag }} \
258120
--debug
259121
260122
- name: Deploy with Helm
261123
if: ${{ !inputs.dry_run }}
262124
run: |
263-
# Check current release status
264-
if helm status ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} &>/dev/null; then
265-
status=$(helm status ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} -o json | jq -r '.info.status')
125+
# Check current release status and rollback if needed
126+
if helm status ${{ matrix.env.helm_release }} -n ${{ matrix.env.namespace }} &>/dev/null; then
127+
status=$(helm status ${{ matrix.env.helm_release }} -n ${{ matrix.env.namespace }} -o json | jq -r '.info.status')
266128
if [[ "$status" != "deployed" ]]; then
267129
echo "Found release in non-deployed state ($status). Attempting rollback..."
268-
helm rollback ${{ env.HELM_RELEASE }} -n ${{ env.NAMESPACE }} || true
130+
helm rollback ${{ matrix.env.helm_release }} -n ${{ matrix.env.namespace }} || true
269131
fi
270132
fi
271133
272134
helm upgrade --install \
273135
--wait \
274136
--timeout 10m \
275-
${{ env.HELM_RELEASE }} \
137+
${{ matrix.env.helm_release }} \
276138
charts/openhands \
277-
--namespace ${{ env.NAMESPACE }} \
278-
--values ${{ env.ENV_DIR }}/values.yaml \
139+
--namespace ${{ matrix.env.namespace }} \
140+
--values envs/common/values.yaml \
141+
--values ${{ matrix.env.env_dir }}/values.yaml \
279142
--set image.tag=${{ inputs.image_tag }} \
280143
--debug
281144
282145
- name: Get deployment info
283146
if: ${{ !inputs.dry_run }}
284147
id: deployment_info
285148
run: |
286-
echo "## Deployment Summary (subdomain)" >> $GITHUB_STEP_SUMMARY
149+
echo "## Deployment Summary (${{ matrix.env.name }})" >> $GITHUB_STEP_SUMMARY
287150
echo "" >> $GITHUB_STEP_SUMMARY
288-
echo "- **Environment:** staging-subdomain" >> $GITHUB_STEP_SUMMARY
289-
echo "- **Namespace:** ${{ env.NAMESPACE }}" >> $GITHUB_STEP_SUMMARY
151+
echo "- **Environment:** staging-${{ matrix.env.name }}" >> $GITHUB_STEP_SUMMARY
152+
echo "- **Namespace:** ${{ matrix.env.namespace }}" >> $GITHUB_STEP_SUMMARY
290153
echo "- **Image Tag:** ${{ inputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
291154
echo "" >> $GITHUB_STEP_SUMMARY
292155
293-
# Get ingress hostname
294-
hostname=$(kubectl get ing -n ${{ env.NAMESPACE }} -o jsonpath='{.items[0].spec.rules[0].host}' 2>/dev/null || echo "N/A")
156+
hostname=$(kubectl get ing -n ${{ matrix.env.namespace }} -o jsonpath='{.items[0].spec.rules[0].host}' 2>/dev/null || echo "N/A")
295157
echo "- **Hostname:** https://$hostname" >> $GITHUB_STEP_SUMMARY
296158
echo "hostname=$hostname" >> $GITHUB_OUTPUT
297159
298160
echo "" >> $GITHUB_STEP_SUMMARY
299161
echo "### Pods Status" >> $GITHUB_STEP_SUMMARY
300162
echo '```' >> $GITHUB_STEP_SUMMARY
301-
kubectl get pods -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }} >> $GITHUB_STEP_SUMMARY
163+
kubectl get pods -n ${{ matrix.env.namespace }} -l app.kubernetes.io/instance=${{ matrix.env.helm_release }} >> $GITHUB_STEP_SUMMARY
302164
echo '```' >> $GITHUB_STEP_SUMMARY
303165
304166
- name: Verify deployment health
305167
if: ${{ !inputs.dry_run }}
306168
run: |
307169
echo "Waiting for deployment to stabilize..."
308-
kubectl rollout status deployment -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }} --timeout=5m || true
309-
170+
kubectl rollout status deployment -n ${{ matrix.env.namespace }} -l app.kubernetes.io/instance=${{ matrix.env.helm_release }} --timeout=5m || true
310171
echo ""
311172
echo "Current pod status:"
312-
kubectl get pods -n ${{ env.NAMESPACE }} -l app.kubernetes.io/instance=${{ env.HELM_RELEASE }}
173+
kubectl get pods -n ${{ matrix.env.namespace }} -l app.kubernetes.io/instance=${{ matrix.env.helm_release }}
313174
314175
outputs:
315176
hostname: ${{ steps.deployment_info.outputs.hostname }}

0 commit comments

Comments
 (0)