|
1 | 1 | # --------------------------------------------------------------------------- |
2 | 2 | # CD Pipeline — deploy backend + frontend to Azure on push to main |
3 | 3 | # --------------------------------------------------------------------------- |
4 | | -# Phase 7.5/7.6: Triggered after CI passes on main branch. |
| 4 | +# Triggered after CI passes on main branch. |
5 | 5 | # |
6 | 6 | # Jobs: |
7 | 7 | # 1. backend — publish .NET 8 app → Azure App Service (zip deploy) |
8 | | -# 2. frontend — build Vite app → Azure Static Web Apps |
| 8 | +# 2. frontend — build Vite app → Azure App Service (static host w/ SPA fallback) |
| 9 | +# |
| 10 | +# Why App Service for frontend instead of Static Web Apps? |
| 11 | +# The Azure subscription is region-locked (israelcentral / swedencentral / etc.) |
| 12 | +# and SWA is not available in those regions. App Service is, so we host the |
| 13 | +# built `dist/` on a Linux App Service using the built-in `pm2 serve` command |
| 14 | +# with `--spa` so client-side routes fall back to index.html. |
9 | 15 | # |
10 | 16 | # Required GitHub Secrets: |
11 | | -# - AZURE_WEBAPP_PUBLISH_PROFILE (App Service publish profile XML) |
12 | | -# - AZURE_STATIC_WEB_APPS_API_TOKEN (SWA deployment token) |
| 17 | +# - AZURE_WEBAPP_PUBLISH_PROFILE (backend App Service publish profile XML) |
| 18 | +# - AZURE_WEBAPP_FRONTEND_PUBLISH_PROFILE (frontend App Service publish profile XML) |
13 | 19 | # |
14 | 20 | # Gating via GitHub Repository Variables (Settings > Secrets and variables > |
15 | 21 | # Actions > Variables tab): |
@@ -108,12 +114,35 @@ jobs: |
108 | 114 | env: |
109 | 115 | VITE_API_BASE_URL: https://app-groundshare-api.azurewebsites.net/api |
110 | 116 |
|
111 | | - - name: Deploy to Azure Static Web Apps |
112 | | - uses: Azure/static-web-apps-deploy@v1 |
| 117 | + # Zip only the built dist/ so the App Service wwwroot contains the SPA |
| 118 | + # files at its root. The App Service Startup Command serves them via: |
| 119 | + # pm2 serve /home/site/wwwroot --no-daemon --spa |
| 120 | + # `--spa` makes unmatched routes fall back to index.html so client-side |
| 121 | + # routing (React Router) works on deep links and page refreshes. |
| 122 | + - name: Package dist |
| 123 | + working-directory: 03-Client |
| 124 | + run: | |
| 125 | + cd dist |
| 126 | + zip -r ../deploy-frontend.zip . |
| 127 | +
|
| 128 | + - name: Deploy to Azure App Service (frontend) |
| 129 | + uses: azure/webapps-deploy@v3 |
113 | 130 | with: |
114 | | - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} |
115 | | - repo_token: ${{ secrets.GITHUB_TOKEN }} |
116 | | - action: upload |
117 | | - app_location: 03-Client/dist |
118 | | - skip_app_build: true |
119 | | - skip_api_build: true |
| 131 | + app-name: app-groundshare-web |
| 132 | + publish-profile: ${{ secrets.AZURE_WEBAPP_FRONTEND_PUBLISH_PROFILE }} |
| 133 | + package: 03-Client/deploy-frontend.zip |
| 134 | + |
| 135 | + - name: Health check |
| 136 | + run: | |
| 137 | + sleep 30 |
| 138 | + for i in 1 2 3 4 5; do |
| 139 | + STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://app-groundshare-web.azurewebsites.net/ || true) |
| 140 | + if [ "$STATUS" = "200" ]; then |
| 141 | + echo "Health check passed" |
| 142 | + exit 0 |
| 143 | + fi |
| 144 | + echo "Attempt $i: status $STATUS, retrying in 15s..." |
| 145 | + sleep 15 |
| 146 | + done |
| 147 | + echo "Health check failed after 5 attempts" |
| 148 | + exit 1 |
0 commit comments