Skip to content

Bump dorny/paths-filter from 3 to 4 in the github-actions group #163

Bump dorny/paths-filter from 3 to 4 in the github-actions group

Bump dorny/paths-filter from 3 to 4 in the github-actions group #163

name: Build and Deploy
on:
push:
branches: [main]
paths-ignore:
- 'Infra/**'
- '.github/workflows/deploy-infrastructure.yml'
pull_request:
branches: [main]
paths-ignore:
- 'Infra/**'
workflow_dispatch:
permissions:
id-token: write
contents: read
defaults:
run:
shell: pwsh
env:
DOTNET_VERSION: '10.0.x'
NODE_VERSION: '22.x'
PNPM_VERSION: '11.1.1'
FRONTEND_PROJECT_PATH: 'GillyTracker.Web'
TERRAFORM_VERSION: '1.14.6'
jobs:
# Build and test backend and frontend
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
global-json-file: global.json
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
cache-dependency-path: ${{ env.FRONTEND_PROJECT_PATH }}/pnpm-lock.yaml
- name: Install frontend dependencies
working-directory: ${{ env.FRONTEND_PROJECT_PATH }}
run: pnpm install --frozen-lockfile
- name: Lint frontend
working-directory: ${{ env.FRONTEND_PROJECT_PATH }}
run: pnpm run lint
- name: Build frontend
working-directory: ${{ env.FRONTEND_PROJECT_PATH }}
run: pnpm run build
env:
BACKEND_URL: ''
- name: Restore .NET dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Restore dotnet tool
run: dotnet tool restore
- name: Check for Pending Database Changes
run: |
dotnet ef migrations has-pending-model-changes `
--configuration Release `
--project GillyTracker.Data/GillyTracker.Data.csproj `
--startup-project GillyTracker.AppHost/GillyTracker.AppHost.csproj
- name: Install Playwright browsers
run: pwsh GillyTracker.UITests/bin/Release/net10.0/playwright.ps1 install --with-deps
# Microsoft Testing Platform can stop the run once 10 tests fail in CI:
# https://learn.microsoft.com/dotnet/core/testing/microsoft-testing-platform-cli-options
# To enable retries, add Microsoft.Testing.Extensions.Retry to the test project, then pass
# --retry-failed-tests plus --retry-failed-tests-max-percentage <value> to skip reruns when too many tests fail:
# https://learn.microsoft.com/dotnet/core/testing/microsoft-testing-platform-retry#retry-1
- name: Test
run: dotnet test --no-build --configuration Release --verbosity normal --maximum-failed-tests 10
env:
DOTNET_BUILD_CONFIGURATION: Release
- name: Upload test failure screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: test-failure-screenshots
path: '**/TestResults/screenshots/*.png'
if-no-files-found: ignore
retention-days: 7
- name: Upload test failure logs
if: failure()
uses: actions/upload-artifact@v7
with:
name: test-failure-logs
path: '**/TestResults/logs/*.log'
if-no-files-found: ignore
retention-days: 7
- name: Publish
run: dotnet publish --configuration Release --no-build
- name: Build Database Bundle
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
run: |
dotnet ef migrations bundle `
--self-contained `
--no-build `
--configuration Release `
--project GillyTracker.Data/GillyTracker.Data.csproj `
--startup-project .\GillyTracker.AppHost\GillyTracker.AppHost.csproj `
--output efbundle
- name: Azure Login
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
uses: azure/login@v3
with:
client-id: ${{ secrets.ARM_CLIENT_ID }}
tenant-id: ${{ secrets.ARM_TENANT_ID }}
subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
- name: Upload DB Migration
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
uses: Keboo/sa-upload@v1
with:
name: efbundle
path: 'efbundle'
storage-account: keboogithub
container-name: gillytracker
create-container: true
- name: Upload frontend artifact
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v7
with:
name: frontend
path: ${{ env.FRONTEND_PROJECT_PATH }}/dist
retention-days: 1
automerge:
if: ${{ github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' }}
needs: [build]
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- name: Enable auto-merge for Dependabot PRs
run: gh pr merge --auto --squash "${{ github.event.pull_request.number }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
# Get infrastructure outputs from Terraform state
get-infrastructure-outputs:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
environment: production
outputs:
acr_login_server: ${{ steps.terraform-outputs.outputs.acr_login_server }}
backend_container_app_name: ${{ steps.terraform-outputs.outputs.backend_container_app_name }}
backend_url: ${{ steps.terraform-outputs.outputs.backend_url }}
resource_group_name: ${{ steps.terraform-outputs.outputs.resource_group_name }}
static_web_app_name: ${{ steps.terraform-outputs.outputs.static_web_app_name }}
static_web_app_api_key: ${{ steps.terraform-outputs.outputs.static_web_app_api_key }}
database_connection_string: ${{ steps.terraform-outputs.outputs.database_connection_string }}
applicationinsights_connection_string: ${{ steps.terraform-outputs.outputs.applicationinsights_connection_string }}
steps:
- uses: actions/checkout@v6
- name: Setup Terraform
uses: hashicorp/setup-terraform@v4
with:
terraform_version: ${{ env.TERRAFORM_VERSION }}
terraform_wrapper: false
- name: Azure Login
uses: azure/login@v3
with:
client-id: ${{ secrets.ARM_CLIENT_ID }}
tenant-id: ${{ secrets.ARM_TENANT_ID }}
subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
- name: Terraform Init
working-directory: Infra
run: terraform init
env:
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
ARM_USE_OIDC: true
- name: Get Terraform Outputs
id: terraform-outputs
working-directory: Infra
shell: bash
run: |
echo "acr_login_server=$(terraform output -raw acr_login_server)" >> $GITHUB_OUTPUT
echo "backend_container_app_name=$(terraform output -raw backend_container_app_name)" >> $GITHUB_OUTPUT
echo "resource_group_name=$(terraform output -raw resource_group_name)" >> $GITHUB_OUTPUT
echo "static_web_app_name=$(terraform output -raw static_web_app_name)" >> $GITHUB_OUTPUT
echo "static_web_app_api_key=$(terraform output -raw static_web_app_api_key)" >> $GITHUB_OUTPUT
echo "backend_url=$(terraform output -raw backend_url)" >> $GITHUB_OUTPUT
echo "database_connection_string=$(terraform output -raw database_connection_string)" >> $GITHUB_OUTPUT
echo "applicationinsights_connection_string=$(terraform output -raw applicationinsights_connection_string)" >> $GITHUB_OUTPUT
env:
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
ARM_USE_OIDC: true
deploy-database:
runs-on: ubuntu-latest
needs: [build, get-infrastructure-outputs]
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
environment: production
steps:
- name: Azure Login
uses: azure/login@v3
with:
client-id: ${{ secrets.ARM_CLIENT_ID }}
tenant-id: ${{ secrets.ARM_TENANT_ID }}
subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
- name: Download DB Migration Bundle
uses: Keboo/sa-download@v1
with:
name: efbundle
storage-account: keboogithub
container-name: gillytracker
- name: Apply Migration
run: |
chmod +x efbundle
$env:ConnectionStrings__Database = '${{ needs.get-infrastructure-outputs.outputs.database_connection_string }}'
./efbundle
if ($LASTEXITCODE -eq 0) {
rm efbundle
exit 0
}
rm efbundle
throw "Migration bundle failed."
# Build and push Docker image for backend
deploy-backend:
runs-on: ubuntu-latest
needs: [build, get-infrastructure-outputs]
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
environment: production
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
global-json-file: global.json
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
cache-dependency-path: ${{ env.FRONTEND_PROJECT_PATH }}/pnpm-lock.yaml
- name: Azure Login
uses: azure/login@v3
with:
client-id: ${{ secrets.ARM_CLIENT_ID }}
tenant-id: ${{ secrets.ARM_TENANT_ID }}
subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
- name: Log in to Azure Container Registry
run: |
az acr login --name ${{ needs.get-infrastructure-outputs.outputs.acr_login_server }}
- name: dotnet publish
run: dotnet publish .\GillyTracker\GillyTracker.csproj --configuration Release -r linux-x64 --self-contained -t:PublishContainer -p:ContainerRegistry=${{ needs.get-infrastructure-outputs.outputs.acr_login_server }} -p:ContainerImageTags="${{ github.sha }}"
- name: Update Container App
run: |
az containerapp update `
--name ${{ needs.get-infrastructure-outputs.outputs.backend_container_app_name }} `
--resource-group ${{ needs.get-infrastructure-outputs.outputs.resource_group_name }} `
--image ${{ needs.get-infrastructure-outputs.outputs.acr_login_server }}/gillytracker:${{ github.sha }}
# Deploy frontend to Azure Static Web Apps
deploy-frontend:
runs-on: ubuntu-latest
needs: [build, get-infrastructure-outputs]
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
environment: production
steps:
- uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
cache-dependency-path: ${{ env.FRONTEND_PROJECT_PATH }}/pnpm-lock.yaml
- name: Install frontend dependencies
working-directory: ${{ env.FRONTEND_PROJECT_PATH }}
run: pnpm install --frozen-lockfile
- name: Build frontend for production
working-directory: ${{ env.FRONTEND_PROJECT_PATH }}
run: pnpm run build
env:
BACKEND_URL: ${{ needs.get-infrastructure-outputs.outputs.backend_url }}
# BACKEND_URL: 'TODO' # This should be set to the backend_url, if you use the generated ACA endpoint you may run into issues with cross origin issues.
APPLICATIONINSIGHTS_CONNECTION_STRING: ${{ needs.get-infrastructure-outputs.outputs.applicationinsights_connection_string }}
- name: Deploy to Azure Static Web Apps
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ needs.get-infrastructure-outputs.outputs.static_web_app_api_key }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: 'upload'
app_location: '${{ env.FRONTEND_PROJECT_PATH }}/dist'
skip_app_build: true
skip_api_build: true