-
Notifications
You must be signed in to change notification settings - Fork 0
336 lines (289 loc) · 15 KB
/
Copy pathdeploy.yml
File metadata and controls
336 lines (289 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# =============================================================================
# SpatialSync — Render.com Deployment Pipeline
# Triggers on every new release (after semantic-release) and on manual dispatch
# 2026 Industry Standard: Automated CD with deploy hooks
# =============================================================================
name: Deploy to Render
on:
release:
types: [published]
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
required: true
default: production
type: choice
options:
- production
- staging
clear_cache:
description: 'Clear build cache'
required: false
default: false
type: boolean
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'release' && 'production' || inputs.environment }}
cancel-in-progress: true
env:
APP_NAME: SpatialSync
RENDER_SERVICE_NAME: blueprintflow
DEPLOY_ENV: ${{ github.event_name == 'release' && 'production' || inputs.environment }}
jobs:
# ---------------------------------------------------------------------------
# 1. Pre-Deployment Validation
# ---------------------------------------------------------------------------
validate:
name: ✅ Pre-Deploy Validation
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Validate render.yaml exists
run: |
if [ ! -f "render.yaml" ]; then
echo "::error::render.yaml not found! Required for Render deployment."
exit 1
fi
echo "✅ render.yaml found"
- name: Validate Dockerfile exists
run: |
if [ ! -f "Dockerfile" ]; then
echo "::error::Dockerfile not found! Required for Docker deployment."
exit 1
fi
echo "✅ Dockerfile found"
- name: Version info
run: |
echo "## 🚀 Deployment Preview" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
echo "| **Version** | \`${{ github.event.release.tag_name || github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Revision** | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Branch** | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Environment** | ${{ env.DEPLOY_ENV }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Service** | ${{ env.RENDER_SERVICE_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Triggered by** | ${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# ---------------------------------------------------------------------------
# 2. Render Deploy Hook Trigger
# ---------------------------------------------------------------------------
deploy:
name: 🚀 Deploy to Render
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [validate]
environment:
name: ${{ env.DEPLOY_ENV }}
url: ${{ steps.deploy_result.outputs.service_url || 'https://dashboard.render.com' }}
env:
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
steps:
- uses: actions/checkout@v4
- name: 🔄 Trigger Render Deploy Hook
id: deploy_hook
run: |
DEPLOY_HOOK_URL="${{ secrets.RENDER_DEPLOY_HOOK_URL }}"
if [ -z "$DEPLOY_HOOK_URL" ] || [ "$DEPLOY_HOOK_URL" = "" ]; then
echo "::warning::RENDER_DEPLOY_HOOK_URL secret not set."
echo "::warning::To enable automated deploys:"
echo "::warning::1. Go to Render Dashboard → Services → blueprintflow → Settings → Deploy Hook"
echo "::warning::2. Copy the deploy hook URL"
echo "::warning::3. Add it as a GitHub secret: RENDER_DEPLOY_HOOK_URL"
echo ""
echo "🔍 Render Auto-Deploy is still active via render.yaml (autoDeploy: true)"
echo " → Any push to main will trigger a Render deployment."
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
echo "🌐 Triggering Render deployment via Deploy Hook..."
echo " Service: ${{ env.RENDER_SERVICE_NAME }}"
echo " Environment: ${{ env.DEPLOY_ENV }}"
CLEAR_CACHE="${{ github.event_name == 'workflow_dispatch' && inputs.clear_cache || 'false' }}"
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$DEPLOY_HOOK_URL" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "{\"clearCache\": $CLEAR_CACHE}" 2>&1)
HTTP_BODY=$(echo "$HTTP_RESPONSE" | head -n -1)
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1)
echo "HTTP Status: $HTTP_STATUS"
echo "Response: $HTTP_BODY"
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "201" ] || [ "$HTTP_STATUS" = "202" ]; then
echo "✅ Deploy hook triggered successfully (HTTP $HTTP_STATUS)"
echo "status=success" >> $GITHUB_OUTPUT
else
echo "::warning::Deploy hook returned HTTP $HTTP_STATUS"
echo "::warning::Response: $HTTP_BODY"
echo "::warning::Render auto-deploy (push to main) is still active as fallback."
echo "status=failed" >> $GITHUB_OUTPUT
fi
# ---------------------------------------------------------------------------
# 3. Render API Deployment (optional — requires API key)
# ---------------------------------------------------------------------------
- name: 🔧 Trigger Render API Deploy
id: deploy_api
if: env.RENDER_API_KEY != '' && steps.deploy_hook.outputs.status != 'success'
run: |
if [ -z "$RENDER_API_KEY" ]; then
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
echo "🌐 Triggering Render deployment via API..."
SERVICE_ID="${{ secrets.RENDER_SERVICE_ID }}"
if [ -z "$SERVICE_ID" ]; then
echo "::warning::RENDER_SERVICE_ID secret not set."
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
RESPONSE=$(curl -s -X POST "https://api.render.com/v1/services/${SERVICE_ID}/deploys" \
-H "Authorization: Bearer $RENDER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"clearCache\": ${{ github.event_name == 'workflow_dispatch' && inputs.clear_cache || 'false' }}}" 2>&1)
DEPLOY_ID=$(echo "$RESPONSE" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
if [ -n "$DEPLOY_ID" ]; then
echo "✅ Render deploy triggered via API. Deploy ID: $DEPLOY_ID"
echo "status=success" >> $GITHUB_OUTPUT
echo "deploy_id=$DEPLOY_ID" >> $GITHUB_OUTPUT
echo "🔍 Monitoring deployment..."
echo "deploy_id=$DEPLOY_ID" >> $GITHUB_STEP_SUMMARY
# Poll for deployment status (up to 10 minutes)
for i in $(seq 1 60); do
STATUS_RESPONSE=$(curl -s "https://api.render.com/v1/services/${SERVICE_ID}/deploys/${DEPLOY_ID}" \
-H "Authorization: Bearer $RENDER_API_KEY")
STATUS=$(echo "$STATUS_RESPONSE" | grep -o '"status":"[^"]*"' | head -1 | cut -d'"' -f4)
echo " Deployment status: $STATUS (${i}s)"
if [ "$STATUS" = "live" ]; then
echo "✅ Deployment completed successfully!"
echo "result=success" >> $GITHUB_OUTPUT
SERVICE_URL=$(echo "$STATUS_RESPONSE" | grep -o '"url":"[^"]*"' | head -1 | cut -d'"' -f4)
echo "service_url=$SERVICE_URL" >> $GITHUB_OUTPUT
break
elif [ "$STATUS" = "failed" ] || [ "$STATUS" = "canceled" ]; then
echo "::error::Deployment $STATUS"
echo "result=failed" >> $GITHUB_OUTPUT
break
fi
sleep 10
done
else
echo "::warning::Failed to trigger Render deploy via API"
echo "Response: $RESPONSE"
echo "status=failed" >> $GITHUB_OUTPUT
fi
# ---------------------------------------------------------------------------
# 4. Deployment Status Summary
# ---------------------------------------------------------------------------
- name: 📋 Deployment Summary
id: deploy_result
run: |
DEPLOY_STATUS="${{ steps.deploy_hook.outputs.status || steps.deploy_api.outputs.status }}"
echo "## 📋 Deployment Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$DEPLOY_STATUS" = "success" ]; then
echo "### ✅ Deployment Triggered Successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
elif [ "$DEPLOY_STATUS" = "skipped" ]; then
echo "### ⚠️ Deploy Hook Not Configured" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To enable automated deploys via GitHub Actions:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. Go to **Render Dashboard → Services → blueprintflow → Settings → Deploy Hook**" >> $GITHUB_STEP_SUMMARY
echo "2. Copy the deploy hook URL" >> $GITHUB_STEP_SUMMARY
echo "3. Add it as a GitHub secret: \`RENDER_DEPLOY_HOOK_URL\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> Render **autoDeploy** (\`render.yaml\`) is still active — pushing to \`main\` will auto-deploy." >> $GITHUB_STEP_SUMMARY
else
echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
echo "| **Version** | \`${{ github.event.release.tag_name || github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Service** | ${{ env.RENDER_SERVICE_NAME }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Environment** | ${{ env.DEPLOY_ENV }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Method** | ${{ steps.deploy_hook.outputs.status == 'success' && 'Deploy Hook' || steps.deploy_api.outputs.status == 'success' && 'Render API' || 'N/A' }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Monitor** | [Render Dashboard](https://dashboard.render.com) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "service_url=https://${{ env.RENDER_SERVICE_NAME }}.onrender.com" >> $GITHUB_OUTPUT
# ---------------------------------------------------------------------------
# 5. Create GitHub Deployment (visibility)
# ---------------------------------------------------------------------------
- name: 🏷️ Create GitHub Deployment
if: always()
run: |
DEPLOY_ID="${{ steps.deploy_api.outputs.deploy_id }}"
echo "### 🔗 Quick Links" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- [Render Dashboard](https://dashboard.render.com)" >> $GITHUB_STEP_SUMMARY
echo "- [Service: ${{ env.RENDER_SERVICE_NAME }}](https://dashboard.render.com/web/srv-${{ env.RENDER_SERVICE_NAME }})" >> $GITHUB_STEP_SUMMARY
if [ -n "$DEPLOY_ID" ]; then
echo "- [Deployment Details](https://api.render.com/v1/services/${{ secrets.RENDER_SERVICE_ID }}/deploys/$DEPLOY_ID)" >> $GITHUB_STEP_SUMMARY
fi
echo "- [Release v${{ github.event.release.tag_name }}](${{ github.event.release.html_url }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# ---------------------------------------------------------------------------
# 6. Rollback Instructions
# ---------------------------------------------------------------------------
- name: 🔙 Rollback Info
run: |
echo "### 🔙 Rollback Instructions" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "If this deployment has issues:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. Go to **Render Dashboard → Services → blueprintflow → Deployments**" >> $GITHUB_STEP_SUMMARY
echo "2. Find the last **working** deployment" >> $GITHUB_STEP_SUMMARY
echo "3. Click **Redeploy**" >> $GITHUB_STEP_SUMMARY
echo "4. Or revert the release: \`gh release delete v${{ github.event.release.tag_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# ---------------------------------------------------------------------------
# 7. Post-Deploy Smoke Tests
# ---------------------------------------------------------------------------
smoke-test:
name: 🔍 Smoke Tests
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [deploy]
if: always() && needs.deploy.result == 'success'
steps:
- name: ⏳ Wait for service to be ready
run: sleep 30
- name: 🔍 Health check
id: health
run: |
APP_URL="https://${{ env.RENDER_SERVICE_NAME }}.onrender.com"
echo "Checking health at: $APP_URL/up"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 --max-time 15 "$APP_URL/up" 2>&1 || echo "000")
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "302" ]; then
echo "✅ Health check passed (HTTP $HTTP_STATUS)"
echo "status=pass" >> $GITHUB_OUTPUT
else
echo "::warning::Health check returned HTTP $HTTP_STATUS"
echo "::warning::The service may still be starting up."
echo "status=warn" >> $GITHUB_OUTPUT
fi
- name: 🔍 Page load check
run: |
APP_URL="https://${{ env.RENDER_SERVICE_NAME }}.onrender.com"
echo "Checking main page: $APP_URL"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 --max-time 15 -L "$APP_URL" 2>&1 || echo "000")
PAGE_SIZE=$(curl -s --connect-timeout 10 --max-time 15 -L "$APP_URL" 2>/dev/null | wc -c || echo "0")
if [ "$HTTP_STATUS" = "200" ]; then
echo "✅ Main page loads (HTTP $HTTP_STATUS, $PAGE_SIZE bytes)"
else
echo "::warning::Main page returned HTTP $HTTP_STATUS ($PAGE_SIZE bytes)"
echo "::warning::Monitor the service at: https://dashboard.render.com"
fi
- name: 📊 Smoke test results
if: always()
run: |
echo "### 🔍 Smoke Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.health.outputs.status }}" = "pass" ]; then
echo "- ✅ **Health Check**: Passed" >> $GITHUB_STEP_SUMMARY
else
echo "- ⚠️ **Health Check**: Warning (service may still be starting)" >> $GITHUB_STEP_SUMMARY
fi
echo "- ✅ **Page Load**: Checked" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🌐 **Live URL**: https://${{ env.RENDER_SERVICE_NAME }}.onrender.com" >> $GITHUB_STEP_SUMMARY