-
Notifications
You must be signed in to change notification settings - Fork 0
187 lines (170 loc) · 9.63 KB
/
Copy pathci.yml
File metadata and controls
187 lines (170 loc) · 9.63 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
name: ci
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
# Cancel superseded runs on the same branch / PR.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Least privilege: this workflow only checks out and builds/tests, so the token
# needs nothing beyond read access to the repository contents.
permissions:
contents: read
env:
DOTNET_NOLOGO: 'true'
DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true'
jobs:
build-test:
name: Build & test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
# Fail a hung run fast instead of holding a runner to the 6-hour default; build+test finishes in ~2 min.
timeout-minutes: 15
strategy:
# Run both legs to completion so a platform-specific failure is always visible.
fail-fast: false
matrix:
# The doc generator spawns the worker as a separate process and manipulates
# file-system paths, so the whole solution is exercised on both platforms.
os: [ubuntu-latest, windows-latest]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: '10.0.x'
- name: Restore
run: dotnet restore FirstClassErrors.sln
- name: Build
run: dotnet build FirstClassErrors.sln -c Release --no-restore
- name: Test
# Collect OpenCover coverage via coverlet.collector (configured in coverage.runsettings).
# Reports land under artifacts/coverage/<guid>/coverage.opencover.xml, ready for a Sonar scan.
run: >-
dotnet test FirstClassErrors.sln -c Release --no-build
--collect:"XPlat Code Coverage"
--settings coverage.runsettings
--results-directory artifacts/coverage
--logger "console;verbosity=normal"
- name: Upload coverage report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
# Per-OS name so the two matrix legs do not clash when uploading.
name: coverage-${{ matrix.os }}
path: artifacts/coverage/**/coverage.opencover.xml
if-no-files-found: error
# build-test above runs the suite on the LATEST .NET (10). This job proves the LIBRARY's OTHER supported
# runtime: that the netstandard2.0 assemblies (FirstClassErrors, FirstClassErrors.Testing,
# FirstClassErrors.RequestBinder) actually load and pass their tests on .NET Framework 4.7.2 — the support
# floor recorded in doc/handwritten/for-maintainers/adr/0022-floor-the-library-on-net-framework-4-7-2.md.
# netstandard2.0 is only a COMPILE contract; running on the real .NET Framework CLR (NLS globalization, the
# netstandard.dll facade, its reflection stack) is what proves the library behaves there — the ordinary net10
# build cannot. .NET Framework tests run on Windows only (there is no Mono on the Linux legs), and the net472
# inner build is gated behind EnableNet472Floor (build/Net472TestFloor.props) so it never touches build-test.
framework-floor:
name: Library on the .NET Framework 4.7.2 floor
runs-on: windows-latest
# Restore + build + test of four small projects; cap a hung run like the other jobs.
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
# global.json pins the .NET 10 SDK; that SDK compiles the net472 target. The .NET Framework runtime that
# RUNS net472 assemblies ships on the windows-latest image, and the net472 targeting pack for COMPILATION
# is supplied hermetically by the Microsoft.NETFramework.ReferenceAssemblies package — so no extra install.
- name: Setup .NET (build SDK)
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: '10.0.x'
# Only these library test projects carry the net472 leg (EnableNet472Floor adds it): the tooling test
# projects (Roslyn / GenDoc / Cli) stay net10-only by design, and RequestBinder.UnitTests stays net10-only
# because its fixtures bind DateOnly, a .NET 6+ type absent from net472. RequestBinder is still floored here
# through its property tests, and JustDummies through its own contract suite (JustDummies.UnitTests), running on the
# netstandard2.0 asset .NET Framework consumers load — its net8-only tests are conditioned out (issue #215).
# JustDummies.Xunit is floored the same way: it ships netstandard2.0, so a .NET Framework consumer loads that
# asset, and its adapter suite must prove it works there and not only on net10. JustDummies.PropertyTests
# joins them so the generator INVARIANTS, not just the example-based contract, hold on the floor.
# A per-project loop (not a solution-wide -f net472, which would force the TFM onto the net10-only projects
# and fail) keeps the net472 scope exactly these six.
- name: Test the netstandard2.0 libraries on .NET Framework 4.7.2
shell: bash
run: |
set -euo pipefail
for proj in \
FirstClassErrors.UnitTests \
FirstClassErrors.PropertyTests \
FirstClassErrors.RequestBinder.PropertyTests \
JustDummies.UnitTests \
JustDummies.PropertyTests \
JustDummies.Xunit.UnitTests ; do
echo "::group::$proj (net472)"
dotnet test "$proj/$proj.csproj" -c Release -f net472 -p:EnableNet472Floor=true \
--logger "console;verbosity=normal"
echo "::endgroup::"
done
# build-test above runs the whole suite on the LATEST .NET (10). This job proves the other end of the
# supported range: that the fce tool and its worker, which ship targeting net8.0 (the floor — see
# doc/handwritten/for-maintainers/adr/0002-floor-the-tooling-runtime.md), actually run on the .NET 8 RUNTIME. The net8 TFM
# already guards the compile-time API surface on every build; what it cannot show is that the tooling
# executes on its advertised minimum runtime, which is what this job checks against the real artifacts.
floor:
name: Documentation tooling on the .NET 8 floor
runs-on: ubuntu-latest
# Build (~20s) plus one doc-generation run; cap a hung run like the build-test job.
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
# Two SDKs on purpose: 10.0.x satisfies the repo global.json (which pins the .NET 10 SDK) so the build
# runs normally, and 8.0.x brings the .NET 8 runtime — the floor the tooling ships against — so the run
# step below can execute the net8 binaries on it.
- name: Setup .NET (floor runtime + build SDK)
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: |
8.0.x
10.0.x
# The fce tool, its GenDoc worker (copied next to fce by the CLI build target) and a net8 build of the
# Usage sample as a real target to document. Built with the .NET 10 SDK — net8.0 is only a target here.
- name: Build the net8 tooling and a net8 target
run: |
dotnet build FirstClassErrors.Cli/FirstClassErrors.Cli.csproj -c Release
dotnet build FirstClassErrors.Usage/FirstClassErrors.Usage.csproj -c Release -f net8.0
# Run the net8 fce + worker on the .NET 8 RUNTIME (not rolled forward to the newer one the runner also
# carries) and document a net8 assembly end to end. GenDoc's own assembly (deployed next to fce) rides
# along as a second target: it documents its own GENDOC_-prefixed errors with the very pipeline it
# implements, so this run also proves the tool's self-catalog end to end.
#
# DOTNET_ROLL_FORWARD=LatestPatch overrides the roll-forward baked into each runtimeconfig (Major on the
# CLI, LatestMajor on the worker): the environment variable wins over runtimeconfig, and LatestPatch stays
# within the requested major, so both processes bind the highest .NET 8 patch present and can never roll
# onto .NET 10. If .NET 8 were absent the host would fail to start — so a green step means the net8 tooling
# genuinely ran on the .NET 8 runtime (the worker loads the net8 target via Assembly.LoadFrom).
- name: Generate documentation on the .NET 8 runtime
env:
DOTNET_ROLL_FORWARD: LatestPatch
run: |
set -euo pipefail
dotnet FirstClassErrors.Cli/bin/Release/net8.0/fce.dll generate \
--assemblies FirstClassErrors.Usage/bin/Release/net8.0/FirstClassErrors.Usage.dll \
--assemblies FirstClassErrors.Cli/bin/Release/net8.0/FirstClassErrors.GenDoc.dll \
--format json --verbose > floor-catalog.json
# Positive proof, not just exit 0: the worker actually loaded the target and extracted documented errors.
if ! grep -q '"code"' floor-catalog.json; then
echo "::error::no documented errors were extracted on the .NET 8 floor"
cat floor-catalog.json
exit 1
fi
# Dogfooding proof: the tool documented its own failure surface in the same catalog.
if ! grep -q '"GENDOC_' floor-catalog.json; then
echo "::error::the tool's own GENDOC_ errors are missing from the generated catalog"
cat floor-catalog.json
exit 1
fi
echo "ok: the net8 fce and worker documented a net8 target and the tool's own errors on the .NET 8 runtime"