Skip to content

Commit b39d216

Browse files
feat(ci): add Windows build and test workflow (#1376)
1 parent 1de65f5 commit b39d216

6 files changed

Lines changed: 197 additions & 179 deletions

File tree

‎.github/workflows/Build-Test-And-Deploy.yml‎

Lines changed: 173 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,65 @@ name: Build, Test, and Deploy EssentialCSharp.Web
33
on:
44
push:
55
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
merge_group:
69
workflow_dispatch:
710

811
permissions:
9-
id-token: write
1012
contents: read
1113

14+
concurrency:
15+
group: ${{ github.event_name == 'pull_request' && format('build-test-deploy-pr-{0}', github.event.pull_request.number) || github.run_id }}
16+
cancel-in-progress: true
17+
1218
jobs:
19+
frontend-build:
20+
name: Build frontend (${{ matrix.runner }})
21+
runs-on: ${{ matrix.runner }}
22+
timeout-minutes: 20
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
runner:
27+
- ubuntu-latest
28+
- macos-latest
29+
- windows-latest
30+
31+
steps:
32+
- uses: actions/checkout@v7
33+
34+
- name: Verify Node version matches the Docker build
35+
shell: bash
36+
run: |
37+
expected_node_version="$(tr -d '[:space:]' < EssentialCSharp.Web/.nvmrc)"
38+
docker_node_version="$(sed -nE 's/^FROM node:([0-9]+)-.*/\1/p' EssentialCSharp.Web/Dockerfile | head -n 1)"
39+
if [[ "$expected_node_version" != "$docker_node_version" ]]; then
40+
echo "::error::EssentialCSharp.Web/.nvmrc specifies Node $expected_node_version, but the Dockerfile uses Node $docker_node_version."
41+
exit 1
42+
fi
43+
44+
- name: Set up Node.js
45+
uses: actions/setup-node@v7
46+
with:
47+
node-version-file: EssentialCSharp.Web/.nvmrc
48+
cache: npm
49+
cache-dependency-path: EssentialCSharp.Web/package-lock.json
50+
51+
- name: Install npm dependencies
52+
working-directory: EssentialCSharp.Web
53+
run: npm ci
54+
55+
- name: Build frontend
56+
working-directory: EssentialCSharp.Web
57+
run: npm run build
58+
1359
build-and-test:
60+
name: Build and test (Ubuntu)
61+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
62+
needs: frontend-build
1463
runs-on: ubuntu-latest
64+
timeout-minutes: 45
1565
environment: "BuildAndUploadImage"
1666

1767
steps:
@@ -25,13 +75,6 @@ jobs:
2575
env:
2676
NUGET_AUTH_TOKEN: ${{ secrets.AZURE_DEVOPS_PAT }}
2777

28-
- name: Set up Node.js
29-
uses: actions/setup-node@v7
30-
with:
31-
node-version: 24
32-
cache: npm
33-
cache-dependency-path: EssentialCSharp.Web/package-lock.json
34-
3578
- name: Set up dependency caching for faster builds
3679
uses: actions/cache@v6
3780
id: nuget-cache
@@ -48,7 +91,7 @@ jobs:
4891
run: dotnet restore
4992

5093
- name: Build with dotnet
51-
run: dotnet build -p:ContinuousIntegrationBuild=True -p:ReleaseDateAttribute=True --configuration Release --no-restore
94+
run: dotnet build -p:ContinuousIntegrationBuild=True -p:ReleaseDateAttribute=True -p:SkipFrontendBuild=true --configuration Release --no-restore
5295

5396
- name: Expose GitHub Actions Runtime
5497
uses: actions/github-script@v9
@@ -112,9 +155,127 @@ jobs:
112155
name: essentialcsharpwebimage
113156
path: ${{ github.workspace }}/essentialcsharpwebimage.tar
114157

158+
pr-build-and-test:
159+
name: Build and test (${{ matrix.runner }})
160+
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
161+
needs: frontend-build
162+
runs-on: ${{ matrix.runner }}
163+
timeout-minutes: 30
164+
strategy:
165+
fail-fast: false
166+
matrix:
167+
include:
168+
- runner: ubuntu-latest
169+
collect_coverage: true
170+
- runner: macos-latest
171+
collect_coverage: false
172+
- runner: windows-latest
173+
collect_coverage: false
174+
175+
steps:
176+
- uses: actions/checkout@v7
177+
178+
- name: Set up .NET
179+
uses: actions/setup-dotnet@v6
180+
with:
181+
global-json-file: global.json
182+
183+
- name: Set up NuGet cache
184+
uses: actions/cache@v6
185+
with:
186+
path: |
187+
~/.nuget/packages
188+
${{ github.workspace }}/**/obj/project.assets.json
189+
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
190+
restore-keys: |
191+
${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
192+
${{ runner.os }}-nuget-
193+
194+
- name: Restore .NET dependencies
195+
run: dotnet restore /p:AccessToNugetFeed=false
196+
197+
- name: Build .NET
198+
run: dotnet build --configuration Release --no-restore /p:AccessToNugetFeed=false /p:SkipFrontendBuild=true
199+
200+
- name: Restore local .NET tools
201+
if: matrix.collect_coverage
202+
run: dotnet tool restore
203+
204+
- name: Check for pending EF Core model changes
205+
if: matrix.collect_coverage
206+
run: dotnet tool run dotnet-ef -- migrations has-pending-model-changes --project EssentialCSharp.Web --configuration Release --no-build
207+
env:
208+
ASPNETCORE_ENVIRONMENT: Development
209+
210+
- name: Expose GitHub Actions Runtime
211+
if: matrix.collect_coverage
212+
uses: actions/github-script@v9
213+
with:
214+
script: |
215+
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN']);
216+
core.exportVariable('ACTIONS_RESULTS_URL', process.env['ACTIONS_RESULTS_URL']);
217+
218+
- name: Run .NET tests with coverage
219+
if: matrix.collect_coverage
220+
run: dotnet test --no-build --configuration Release --report-trx --coverage --results-directory ${{ runner.temp }}
221+
222+
- name: Run .NET tests
223+
if: ${{ !matrix.collect_coverage }}
224+
run: dotnet test --no-build --configuration Release
225+
226+
- name: Convert TRX to VS Playlist
227+
if: ${{ failure() && matrix.collect_coverage }}
228+
uses: BenjaminMichaelis/trx-to-vsplaylist@v4
229+
with:
230+
trx-file-path: '${{ runner.temp }}/*.trx'
231+
output-directory: '${{ runner.temp }}/vsplaylists'
232+
233+
container-validation:
234+
name: Build container image
235+
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
236+
needs: [frontend-build, pr-build-and-test]
237+
runs-on: ubuntu-latest
238+
timeout-minutes: 30
239+
240+
steps:
241+
- uses: actions/checkout@v7
242+
243+
- name: Set up Docker Buildx
244+
uses: docker/setup-buildx-action@v4
245+
id: buildx
246+
247+
- name: Restore BuildKit cache mounts
248+
uses: actions/cache@v6
249+
id: buildkit-cache
250+
with:
251+
path: buildkit-cache
252+
key: buildkit-cache-${{ hashFiles('EssentialCSharp.Web/Dockerfile', 'Directory.Packages.props', '**/*.csproj', 'EssentialCSharp.Web/package-lock.json') }}
253+
restore-keys: buildkit-cache-
254+
255+
- name: Inject BuildKit cache mounts
256+
uses: reproducible-containers/buildkit-cache-dance@v3
257+
with:
258+
builder: ${{ steps.buildx.outputs.name }}
259+
dockerfile: EssentialCSharp.Web/Dockerfile
260+
cache-dir: buildkit-cache
261+
skip-extraction: ${{ steps.buildkit-cache.outputs.cache-hit }}
262+
263+
- name: Build container image
264+
uses: docker/build-push-action@v7
265+
with:
266+
file: ./EssentialCSharp.Web/Dockerfile
267+
context: .
268+
push: false
269+
cache-from: |
270+
type=gha,scope=essentialcsharpweb-main
271+
type=gha,scope=essentialcsharpweb-pr
272+
cache-to: type=gha,mode=min,scope=essentialcsharpweb-pr
273+
build-args: ACCESS_TO_NUGET_FEED=false
274+
115275
deploy-development:
116-
if: github.event_name != 'pull_request_target' && github.event_name != 'pull_request'
276+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
117277
runs-on: ubuntu-latest
278+
timeout-minutes: 45
118279
needs: build-and-test
119280
concurrency:
120281
group: deploy-development
@@ -172,8 +333,9 @@ jobs:
172333
az account clear
173334
174335
deploy-production:
175-
if: github.event_name != 'pull_request_target' && github.event_name != 'pull_request'
336+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
176337
runs-on: ubuntu-latest
338+
timeout-minutes: 45
177339
needs: [deploy-development]
178340
concurrency:
179341
group: deploy-production

‎.github/workflows/PR-Build-And-Test.yml‎

Lines changed: 0 additions & 113 deletions
This file was deleted.

‎.github/workflows/codeql.yml‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ on:
55
branches: [ "main" ]
66
pull_request:
77
branches: [ "main" ]
8+
merge_group:
89
schedule:
910
- cron: '21 15 * * 5'
1011

12+
concurrency:
13+
group: codeql-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
14+
cancel-in-progress: true
15+
1116
jobs:
1217
analyze-csharp:
1318
name: Analyze C# (CodeQL)
1419
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
15-
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
20+
timeout-minutes: 60
1621
permissions:
1722
actions: read
1823
contents: read
@@ -36,6 +41,8 @@ jobs:
3641

3742
- name: Set up .NET Core
3843
uses: actions/setup-dotnet@v6
44+
with:
45+
global-json-file: global.json
3946

4047
- name: Set up dependency caching for faster builds
4148
uses: actions/cache@v6
@@ -52,7 +59,7 @@ jobs:
5259
- name: Restore with dotnet
5360
run: |
5461
dotnet restore /p:AccessToNugetFeed=false
55-
dotnet build --configuration Release --no-restore --no-incremental /p:AccessToNugetFeed=false
62+
dotnet build --configuration Release --no-restore --no-incremental /p:AccessToNugetFeed=false /p:SkipFrontendBuild=true
5663
5764
- name: Perform CodeQL Analysis
5865
uses: github/codeql-action/analyze@v4
@@ -62,7 +69,7 @@ jobs:
6269
analyze-non-compiled-languages:
6370
name: Analyze Non-Compiled Languages (CodeQL)
6471
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
65-
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
72+
timeout-minutes: 30
6673
permissions:
6774
actions: read
6875
contents: read

0 commit comments

Comments
 (0)