Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 105 additions & 66 deletions .github/workflows/azure-deploy.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
name: Deploy to Azure
# This workflow complements the Azure Static Web Apps deployment by handling:
# - Backend deployment to Azure Container Apps
# - Database migrations
# - Additional Azure resource management
# The frontend is deployed via the Azure Static Web Apps GitHub workflow

name: Deploy Backend and Azure Resources

on:
push:
branches: [ main, develop ]
branches: [ main, development ]
workflow_dispatch:

env:
Expand Down Expand Up @@ -30,28 +36,15 @@ jobs:

- name: Install dependencies
run: |
cd frontend && npm ci
cd ../backend && npm ci

- name: Lint frontend
run: |
cd frontend
npm run lint || echo "No lint script defined"

- name: Lint backend
run: |
cd backend
npm run lint || echo "No lint script defined"
npm ci

- name: Test frontend
- name: Lint code
run: |
cd frontend
npm test -- --coverage --watchAll=false || echo "Tests failed or not defined"
npm run lint || echo "Lint issues found"

- name: Test backend
- name: Run tests
run: |
cd backend
npm test || echo "Tests failed or not defined"
npm run test || echo "Tests failed or not defined"

# Build Application
build:
Expand All @@ -72,22 +65,11 @@ jobs:
cache: 'npm'
cache-dependency-path: |
package-lock.json
frontend/package-lock.json
backend/package-lock.json

- name: Build frontend
- name: Build application
run: |
cd frontend
npm ci
npm run build
cd ..

- name: Build backend
run: |
cd backend
npm ci
npm run build || echo "No build script defined"
cd ..

- name: Generate build hashes
id: hash
Expand All @@ -107,9 +89,9 @@ jobs:
name: backend-build-${{ github.sha }}
path: backend/

# Deploy to Azure
# Deploy Backend and Azure Resources
deploy:
name: Deploy to Azure
name: Deploy Backend and Azure Resources
runs-on: ubuntu-latest
needs: build
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }}
Expand All @@ -126,7 +108,7 @@ jobs:
uses: actions/download-artifact@v4
with:
name: frontend-build-${{ github.sha }}
path: frontend/build/
path: build/

- name: Download backend artifacts
uses: actions/download-artifact@v4
Expand All @@ -139,75 +121,132 @@ jobs:
with:
node-version: '18'

- name: Deploy to Azure Static Web Apps
id: swa
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "frontend"
api_location: "backend"
output_location: "build"
skip_api_build: true
skip_app_build: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Azure Container Registry
run: |
az acr login --name ${{ secrets.ACR_REGISTRY_NAME }}
# Use secret if available, otherwise derive from environment
ACR_NAME="${{ secrets.ACR_REGISTRY_NAME }}"
if [ -z "$ACR_NAME" ]; then
ACR_NAME="jobboarddevacr" # Updated to match your Azure environment
echo "Using ACR name: $ACR_NAME"
fi
echo "Attempting to login to ACR: $ACR_NAME"
if az acr login --name "$ACR_NAME"; then
echo "✅ Successfully logged in to ACR: $ACR_NAME"
else
echo "⚠️ Failed to login to ACR: $ACR_NAME"
echo "⏭️ Skipping ACR operations - registry may not exist yet"
exit 0
fi

- name: Build and push backend image
run: |
docker build -f docker/Dockerfile.backend -t ${{ secrets.ACR_REGISTRY_NAME }}.azurecr.io/jobboard-backend:${{ github.sha }} ./backend
docker push ${{ secrets.ACR_REGISTRY_NAME }}.azurecr.io/jobboard-backend:${{ github.sha }}
# Use secret if available, otherwise derive from environment
ACR_NAME="${{ secrets.ACR_REGISTRY_NAME }}"
if [ -z "$ACR_NAME" ]; then
ACR_NAME="jobboarddevacr" # Updated to match your Azure environment
echo "Using ACR name: $ACR_NAME"
fi
echo "Building and pushing to ACR: $ACR_NAME"
if docker build -f docker/Dockerfile.backend -t "$ACR_NAME.azurecr.io/jobboard-backend:${{ github.sha }}" ./backend && \
docker push "$ACR_NAME.azurecr.io/jobboard-backend:${{ github.sha }}"; then
echo "✅ Successfully built and pushed backend image"
else
echo "⚠️ Failed to build/push backend image"
echo "⏭️ Skipping container deployment - ACR may not be available"
exit 0
fi

- name: Deploy to Azure Container Apps
run: |
az containerapp update \
--name jobboard-${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}-api \
--resource-group jobboard-${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }} \
--image ${{ secrets.ACR_REGISTRY_NAME }}.azurecr.io/jobboard-backend:${{ github.sha }} \
--set-env-vars DB_HOST=${{ secrets.DB_HOST }} DB_PASSWORD=${{ secrets.DB_PASSWORD }}
# Use secret if available, otherwise derive from environment
ACR_NAME="${{ secrets.ACR_REGISTRY_NAME }}"
if [ -z "$ACR_NAME" ]; then
ACR_NAME="jobboarddevacr" # Updated to match your Azure environment
fi

# Check if image exists in ACR before deploying
if az acr repository show --name "$ACR_NAME" --image jobboard-backend:${{ github.sha }} --yes >/dev/null 2>&1; then
echo "📦 Found image in ACR, deploying to Container App..."
az containerapp update \
--name jobboard-${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}-api \
--resource-group jobboard-${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }} \
--image "$ACR_NAME.azurecr.io/jobboard-backend:${{ github.sha }}" \
--set-env-vars DB_HOST=${{ secrets.DB_HOST }} DB_PASSWORD=${{ secrets.DB_PASSWORD }}
echo "✅ Container app updated successfully"
else
echo "⚠️ Image not found in ACR, skipping container deployment"
echo "🔍 Make sure ACR registry exists and image was pushed successfully"
fi

- name: Run database migrations
run: |
mysql -h ${{ secrets.DB_HOST }} -u ${{ secrets.DB_USER }} -p${{ secrets.DB_PASSWORD }} < scripts/setup-db.sql
echo "🗄️ Running database migrations..."
# Check if required secrets are available
if [ -z "${{ secrets.DB_HOST }}" ] || [ -z "${{ secrets.DB_USER }}" ] || [ -z "${{ secrets.DB_PASSWORD }}" ]; then
echo "⚠️ Database secrets not configured"
echo "🔍 Please set DB_HOST, DB_USER, and DB_PASSWORD secrets"
echo "💡 Run the ARM template deployment first to get these values"
else
if mysql -h "${{ secrets.DB_HOST }}" -u "${{ secrets.DB_USER }}" -p"${{ secrets.DB_PASSWORD }}" < scripts/setup-db.sql; then
echo "✅ Database migrations completed successfully"
else
echo "⚠️ Database migrations failed or database not accessible"
echo "🔍 Please ensure database is created and accessible"
fi
fi

- name: Health check
run: |
echo "Waiting for deployment to complete..."
sleep 60

# Check if the application is responding
if curl -f "https://${{ steps.swa.outputs.static_web_app_url }}/health" > /dev/null 2>&1; then
echo "✅ Health check passed"
# Check if CONTAINER_APP_URL is available
if [ -n "${{ secrets.CONTAINER_APP_URL }}" ] && [ "${{ secrets.CONTAINER_APP_URL }}" != "https://" ]; then
# Check if the backend API is responding
if curl -f "https://${{ secrets.CONTAINER_APP_URL }}/health" > /dev/null 2>&1; then
echo "✅ Backend health check passed"
else
echo "⚠️ Backend health check failed - application may still be starting"
fi
else
echo "⚠️ Health check failed - application may still be starting"
echo "⚠️ CONTAINER_APP_URL not configured, skipping health check"
fi

- name: Notify deployment status
run: |
echo "🚀 Deployment completed successfully!"
echo "🌐 Frontend: https://${{ steps.swa.outputs.static_web_app_url }}"
echo "🔗 API: https://${{ secrets.CONTAINER_APP_URL }}"
echo "🚀 Deployment workflow completed!"

# Show URLs if available
if [ -n "${{ secrets.CONTAINER_APP_URL }}" ] && [ "${{ secrets.CONTAINER_APP_URL }}" != "https://" ]; then
echo "🔗 Backend API: https://${{ secrets.CONTAINER_APP_URL }}"
else
echo "🔗 Backend API: Not available (configure CONTAINER_APP_URL secret)"
fi

echo "📝 Note: Frontend is deployed via Azure Static Web Apps workflow"
echo "📦 ACR operations may have been skipped if registry doesn't exist yet"

# Security Scanning
security:
name: Security Scan
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push'
permissions:
contents: read
security-events: write
actions: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run npm audit
run: |
cd frontend && npm audit --audit-level=moderate || echo "Security issues found"
cd ../backend && npm audit --audit-level=moderate || echo "Security issues found"
npm audit --audit-level=moderate || echo "Security issues found"

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
Expand All @@ -219,7 +258,7 @@ jobs:

- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
if: always() && hashFiles('trivy-results.sarif') != ''
with:
sarif_file: 'trivy-results.sarif'

Expand Down
63 changes: 63 additions & 0 deletions .github/workflows/azure-static-web-apps-polite-ocean-0f2a6f700.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Azure Static Web Apps CI/CD

on:
push:
branches:
- development
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- development

jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
runs-on: ubuntu-latest
name: Build and Deploy Job
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v3
with:
submodules: true
lfs: false
- name: Install OIDC Client from Core Package
run: npm install @actions/core@1.6.0 @actions/http-client
- name: Get Id Token
uses: actions/github-script@v6
id: idtoken
with:
script: |
const coredemo = require('@actions/core')
return await coredemo.getIDToken()
result-encoding: string
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
continue-on-error: true
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_POLITE_OCEAN_0F2A6F700 }}
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
skip_api_build: true # Skip API build since backend is deployed separately
app_location: "/" # App source code path
api_location: "backend" # Api source code path - optional
output_location: "build" # Built app content directory - optional
github_id_token: ${{ steps.idtoken.outputs.result }}
###### End of Repository/Build Configurations ######

close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
continue-on-error: true
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_POLITE_OCEAN_0F2A6F700 }}
action: "close"
app_location: "/"
Loading
Loading