-
Notifications
You must be signed in to change notification settings - Fork 0
135 lines (120 loc) · 6.35 KB
/
Copy pathdeploy.yml
File metadata and controls
135 lines (120 loc) · 6.35 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
name: Deploy to Azure App Service
# Trigger only on push to master and manual dispatch.
# This is the only workflow in this repo: it builds and deploys to Azure App Service.
on:
push:
branches: [master]
workflow_dispatch:
# Cancel in-progress runs of the same workflow on the same ref.
concurrency:
group: deploy-popunkoutersoftware-${{ github.ref }}
cancel-in-progress: true
# Minimum scopes for OIDC deployment; everything else is denied.
permissions:
id-token: write
contents: read
# Most values come from the GitHub Environment "production".
# Required environment secrets/vars (configure in Settings → Environments → production):
# AZURE_CLIENT_ID (secret) — User-assigned MI for OIDC
# AZURE_TENANT_ID (secret)
# AZURE_SUBSCRIPTION_ID (secret)
# AZURE_APP_NAME (variable, optional) — App Service name.
# Falls back to the known production app if unset.
# AZURE_RESOURCE_GROUP (variable, optional) — falls back to PoPunkouterSoftware.
# AZURE_WEBAPP_SLOT (variable, optional) — default 'production'
env:
DOTNET_VERSION: '10.0.x'
DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
DOTNET_NOLOGO: 'true'
# FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 keeps Azure actions on the maintained Node 24 runtime.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
# The live production targets. Used as the fallback when the matching
# "production" environment variables are unset or misconfigured, so the
# pipeline deploys to the right resource even without the GitHub vars.
DEFAULT_APP_NAME: 'app-popunkoutersoftware'
DEFAULT_RESOURCE_GROUP: 'PoPunkouterSoftware'
jobs:
build-and-deploy:
name: Build & Deploy
runs-on: ubuntu-latest
timeout-minutes: 20
# Pin to the production environment so its protection rules / approval gates apply.
environment: production
steps:
# Resolve the deploy targets once: prefer the production environment vars,
# fall back to the known live resources. A warning (not a hard failure) is
# emitted when a var is missing so the deploy still proceeds correctly.
- name: Resolve deploy targets
id: targets
run: |
APP_NAME="${{ vars.AZURE_APP_NAME || env.DEFAULT_APP_NAME }}"
RG="${{ vars.AZURE_RESOURCE_GROUP || env.DEFAULT_RESOURCE_GROUP }}"
if [ -z "${{ vars.AZURE_APP_NAME }}" ]; then
echo "::warning title=AZURE_APP_NAME unset::Using fallback app name '$APP_NAME'. Set AZURE_APP_NAME in Settings → Environments → production → Variables to make this explicit."
fi
echo "app_name=$APP_NAME" >> "$GITHUB_OUTPUT"
echo "resource_group=$RG" >> "$GITHUB_OUTPUT"
echo "Deploying '$APP_NAME' in resource group '$RG'."
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0 # full history so MinVer can compute the version from tags
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Cache NuGet packages
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }}
restore-keys: |
nuget-${{ runner.os }}-
- name: Restore
run: dotnet restore PoPunkouterSoftware.sln --nologo
- name: Build
run: dotnet build PoPunkouterSoftware.sln -c Release --no-restore --nologo
# ONE test tier runs here, and only one.
#
# Unit is the only tier that is hermetic enough to belong in a deploy pipeline: no
# Docker, no network, no live host, ~0.5s for 100 tests against an assembly this job
# has already built. Integration needs a Testcontainers Azurite instance; E2E-API and
# E2E-UI need a running app (and E2E-UI a browser download) and are pointed at a
# BASE_URL by hand. Adding any of those would trade a fast gate for a slow, flaky one
# and start blocking deploys on infrastructure rather than on code.
#
# This pipeline was build-and-deploy only until 2026-09-05, on the reasoning that the
# fast tier runs locally before every push. That holds right up until the once it
# does not, and the cost of the guard turned out to be under a second.
- name: Unit tests
run: dotnet test tests/PoPunkouterSoftware.Unit -c Release --no-build --nologo
- name: Publish
run: dotnet publish src/PoPunkouterSoftware.API/PoPunkouterSoftware.API.csproj -c Release --no-restore -o ./publish --nologo
# NOTE: 'secrets' is intentionally NOT referenced in any 'if:' expression —
# GitHub Actions blocks it there to avoid leaking secret existence.
# azure/login will fail with a clear error if the production environment
# is misconfigured (missing AZURE_CLIENT_ID / AZURE_TENANT_ID / AZURE_SUBSCRIPTION_ID).
- name: Azure Login (OIDC)
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Infrastructure is provisioned out-of-band (infra/main.bicep, applied
# locally or by a separately-privileged infra workflow) — deliberately NOT
# here. That keeps this deploy identity scoped to website-publish only,
# rather than the resource-group Contributor that provisioning requires.
#
# NOTE: azure/webapps-deploy (OneDeploy) started returning HTTP 500 from the
# App Service intake API on 2026-07-10 across three consecutive runs, while
# the site and Kudu stayed healthy. The legacy Kudu zipdeploy path is a
# separate endpoint and unaffected, so deploy through it via the CLI.
- name: Zip publish output
run: cd publish && zip -qr ../deploy.zip .
- name: Deploy to Azure App Service (zipdeploy)
run: |
az webapp deployment source config-zip \
--resource-group "${{ steps.targets.outputs.resource_group }}" \
--name "${{ steps.targets.outputs.app_name }}" \
--src deploy.zip \
--timeout 600