Skip to content

Implement Clean Architecture and enhance documentation #1

Implement Clean Architecture and enhance documentation

Implement Clean Architecture and enhance documentation #1

Workflow file for this run

name: Build and Deploy to Azure App Service
# ===================================================================
# WORKFLOW TRIGGER CONFIGURATION
# ===================================================================
# This workflow triggers on:
# 1. Push to Master: Builds, tests, and DEPLOYS to Azure (Production)
# 2. Push to Dev: Builds and tests only (NO deployment)
# 3. Pull Requests to Master/Dev: Builds, tests, and runs security scan (NO deployment)
# 4. For more details, see the JOB comments below and visit documentation at: Docs/Deployment/AzureAppService/DEPLOYMENT_GUIDE.md and Docs/CICD/CICD_PIPELINE_GUIDE.md
on:
push:
branches:
- Master # Production deployment
- Dev # Build/test only, no deployment
pull_request:
branches:
- Master
- Dev
env:
DOTNET_VERSION: '8.0.x'
AZURE_WEBAPP_PACKAGE_PATH: './publish'
# ===================================================================
# JOB 1: BUILD AND TEST
# ===================================================================
# Purpose: Compiles the application and runs tests
# Runs on: All branches (Master, Dev) and all pull requests
# Output: Build artifact uploaded for deployment job
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
# ===== Cache NuGet packages for faster builds =====
# Caches packages to reduce build time from ~3min to ~1.5min (50% faster)
- name: Cache NuGet packages
uses: actions/cache@v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
# ===== Run tests only if test projects exist =====
# continue-on-error: true allows workflow to succeed even without test projects
# Remove this flag once unit tests are added to make tests required
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
continue-on-error: true
- name: Publish
run: dotnet publish -c Release -o ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
# ===== Upload build artifacts for debugging =====
# Artifacts can be downloaded from GitHub Actions UI for troubleshooting
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v3
with:
name: dotnet-app
path: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
# ===================================================================
# JOB 2: DEPLOY TO AZURE
# ===================================================================
# Purpose: Deploys the application to Azure App Service (Production)
#
# *** 1. DEPLOY JOB CONDITION ***
# This job ONLY runs when:
# - Event is a 'push' (not a pull request)
# - AND branch is 'Master' (production branch)
#
# Result:
# ✅ Master push → Deploys to Azure
# ❌ Dev push → Builds only, NO deployment
# ❌ Pull Request → Builds only, NO deployment
#
# This ensures only production-ready code from Master reaches Azure.
deploy:
name: Deploy to Azure
runs-on: ubuntu-latest
needs: build # Waits for build job to succeed
if: github.event_name == 'push' && github.ref == 'refs/heads/Master' # Deploy ONLY on push to Master
# *** 2. ENVIRONMENT CONFIGURATION ***
# GitHub Environment: 'production'
# - Can be configured in GitHub repo settings to require manual approval
# - Provides deployment history and protection rules
# - URL displays the deployed application URL in GitHub Actions UI
environment:
name: 'production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v3
with:
name: dotnet-app
path: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: ${{ secrets.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
# ===== Configure App Settings in Azure =====
# Sets configuration values directly in Azure App Service
# These persist across deployments and override appsettings.json
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
continue-on-error: true # Optional: if service principal not configured yet
# *** 3. ASPNETCORE_ENVIRONMENT CONFIGURATION ***
# Sets ASPNETCORE_ENVIRONMENT to "Production" in Azure App Service
# This determines which appsettings file is loaded:
# - appsettings.json (base)
# - appsettings.Production.json (overrides for production)
#
# Effects in application:
# - Production: Uses Azure Key Vault for secrets, production logging
# - Development: Uses local appsettings.Development.json
#
# Since only Master deploys, this is always "Production"
- name: Set Azure App Settings
uses: azure/appservice-settings@v1
with:
app-name: ${{ secrets.AZURE_WEBAPP_NAME }}
app-settings-json: |
[
{
"name": "ThirdPartyApi__BaseUrl",
"value": "${{ secrets.THIRDPARTY_API_BASEURL }}",
"slotSetting": false
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production",
"slotSetting": false
}
]
continue-on-error: true # Optional: if service principal not configured yet
# ===== Health Check =====
# Verifies the deployed application is running by calling /health endpoint
# Waits 30 seconds for application startup before checking
- name: Health Check
run: |
echo "Waiting 30 seconds for app to start..."
sleep 30
curl -f https://${{ secrets.AZURE_WEBAPP_NAME }}.azurewebsites.net/health || echo "Health check failed, but deployment completed"
continue-on-error: true
# ===================================================================
# JOB 3: SECURITY SCAN (OPTIONAL)
# ===================================================================
# Purpose: Scans for security vulnerabilities using Trivy
# Runs on: Pull requests only (not on direct pushes)
# Output: Security report uploaded to GitHub Security tab
security-scan:
name: Security Scan
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' # Only run on PRs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
continue-on-error: true
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
continue-on-error: true
# ===================================================================
# *** WORKFLOW BEHAVIOR SUMMARY ***
# ===================================================================
#
# ┌─────────────────┬───────┬───────┬────────┬─────────────┐
# │ Trigger │ Build │ Test │ Deploy │ Environment │
# ├─────────────────┼───────┼───────┼────────┼─────────────┤
# │ Push to Master │ ✅ │ ✅ │ ✅ │ Production │
# │ Push to Dev │ ✅ │ ✅ │ ❌ │ N/A │
# │ PR to Master │ ✅ │ ✅ │ ❌ │ N/A │
# │ PR to Dev │ ✅ │ ✅ │ ❌ │ N/A │
# └─────────────────┴───────┴───────┴────────┴─────────────┘
#
# DEPLOYMENT FLOW (Master branch only):
# 1. Developer pushes to Master
# 2. Build job: Restore → Build → Test → Publish → Upload artifact
# 3. Deploy job: Download artifact → Deploy to Azure → Configure settings
# 4. Health check verifies deployment success
# 5. Application runs with ASPNETCORE_ENVIRONMENT=Production
#
# DEVELOPMENT FLOW (Dev branch):
# 1. Developer pushes to Dev
# 2. Build job: Restore → Build → Test → Publish → Upload artifact
# 3. Deploy job: SKIPPED (does not run)
# 4. Artifact available for manual inspection if needed
#
# PULL REQUEST FLOW:
# 1. Developer opens PR
# 2. Build job: Restore → Build → Test → Publish
# 3. Security scan job: Runs Trivy vulnerability scanner
# 4. Deploy job: SKIPPED (does not run)
# 5. Results available for review before merging
#
# ===================================================================