Repository navigation
334 lines (291 loc) · 17.5 KB
/
Copy pathpr.yml
File metadata and controls
334 lines (291 loc) · 17.5 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
name: PR
on:
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build and test
uses: purview-dev/build/.github/workflows/purview-build.yml@main
with:
# The shared workflow defaults to the 10.0.x SDK, but this repository targets net11.0 and pins
# the .NET 11 SDK in global.json. Without the matching SDK the runner cannot resolve global.json
# ("A compatible .NET SDK was not found") and every step fails, starting with `dotnet tool
# install`. Before global.json pinned a version the same gap failed later instead, with
# NETSDK1045 on the net11.0 target, because the 10.0.x SDK cannot build it.
# Keep in sync with `sdk.version` in global.json.
dotnet-version: "11.0.100-rc.3.26522.148"
run-pack: true
validate-pack: true
secrets: inherit
# The shared pipeline runs the C# suite only, so the TypeScript/Zod side of the cross-platform
# parity guarantee (docs/wiki/quality/Guarantees-and-Limitations.md) would otherwise never run in CI.
# The vitest suite validates the JSON the C# cross-platform tests write, so the C# tests must run
# first, in this same workspace — hence running them here rather than relying on the `build` job.
cross-platform:
name: Cross-platform (C# to Zod)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Installs exactly the SDK global.json pins, which is the only thing the first dotnet command
# in the job can resolve against. Naming a floating version and a feed quality instead does
# not work: `11.0.x` with quality `preview` resolves the latest *preview*-channel build, and a
# preview sorts below the pinned rc, so global.json is left unsatisfiable.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
- uses: oven-sh/setup-bun@v2
with:
bun-version-file: package.json
- run: bun install --frozen-lockfile
# There are FOUR producers of the fixtures vitest reads, in different assemblies, namespaces and
# classes, so they cannot be selected by one treenode filter:
#
# tests/ts/cross-platform.test.ts <- src/tests/cross-platform/output/
# ZodSharp.Json/*CrossPlatformTests (SystemTextJson and
# NewtonsoftJson unit tests)
# tests/ts/guid-uuid-parity.test.ts <- src/tests/cross-platform/guid-parity/
# ZodSharp.SourceGenerators/ZodSchemaGeneratorTests
# tests/ts/temporal-parity.test.ts <- src/tests/cross-platform/temporal-parity/
# ZodSharp.SourceGenerators/ZodSchemaGeneratorTests
# tests/ts/client-validators.test.ts <- src/tests/cross-platform/client-rules/
# ZodSharp.Blazor.Ssr/ClientRuleParityFixtureTests
#
# They run as separate steps rather than one OR-ed filter: `a|b` is not honoured as a top-level
# alternation by the treenode filter — it silently selects a different, broader set and skips a
# parity producer, which is how the parity artifacts came to be missing in CI while this job stayed
# green. Keep a step per producer, and keep each filter anchored to its class.
- name: Run the C# cross-platform tests (writes cross-platform/output)
run: >-
dotnet test --solution src/ZodSharp.slnx --configuration Debug
--treenode-filter '/*/ZodSharp.Json/*CrossPlatformTests/*'
- name: Run the C# Guid/UUID parity test (writes cross-platform/guid-parity)
run: >-
dotnet test --solution src/ZodSharp.slnx --configuration Debug
--treenode-filter
'/*/ZodSharp.SourceGenerators/ZodSchemaGeneratorTests/JsonSchema_GivenGeneratedGuidSchemas_WritesZodParityArtifacts'
- name: Run the C# temporal parity test (writes cross-platform/temporal-parity)
run: >-
dotnet test --solution src/ZodSharp.slnx --configuration Debug
--treenode-filter
'/*/ZodSharp.SourceGenerators/ZodSchemaGeneratorTests/JsonSchema_GivenGeneratedTemporalSchemas_WritesZodParityArtifacts'
- name: Run the C# client-validator parity test (writes cross-platform/client-rules)
run: >-
dotnet test --solution src/ZodSharp.slnx --configuration Debug
--treenode-filter
'/*/ZodSharp.Blazor.Ssr/ClientRuleParityFixtureTests/ClientRules_GivenEveryMappedRule_WritesParityFixtures'
- name: Run the TypeScript/Zod cross-platform tests
run: bun run test
# The only reliable proof that the minimal-API integration is trim- and Native AOT-safe end to end
# (generated registration, the Microsoft.Extensions.Validation bridge, ProblemDetails and the OpenAPI
# transformers): publish the sample with PublishAot=true, fail on any IL2xxx/IL3xxx warning, then run the
# native binary and check one failing request still returns the ProblemDetails contract. The analyzers that
# run during the normal build only see each assembly on its own; ILC sees the whole application.
aot-sample:
name: Native AOT sample (publish and smoke)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Same reason as the cross-platform job: the SDK comes from global.json, not a floating
# version plus a feed quality.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
# Native AOT links with clang and needs the zlib headers; the hosted image may not carry both.
- name: Install the Native AOT prerequisites
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends clang zlib1g-dev
# -warnaserror turns every warning ILC reports (IL2xxx trim, IL3xxx AOT) into an error, so the publish
# itself fails. The grep is a second gate in case a warning is ever logged without failing the step.
- name: Publish Examples.MinimalApi with Native AOT (fails on any trim or AOT warning)
shell: bash
run: |
dotnet publish src/src/Examples.MinimalApi/Examples.MinimalApi.csproj \
--configuration Release --runtime linux-x64 --output artifacts/aot-sample \
-warnaserror 2>&1 | tee publish.log
if grep -E 'warning IL[23][0-9]{3}' publish.log; then
echo "::error::The Native AOT publish reported trim or AOT warnings."
exit 1
fi
test -x artifacts/aot-sample/ZodSharp.Examples.MinimalApi
# Compiler-host assemblies (the generator, the code fixes, Purview.SourceGeneratorFramework, Roslyn) must never
# reach build or publish output: Purview.SourceGeneratorFramework.dll once did, through analyzer-only references,
# and broke Blazor WebAssembly AOT. Scans file names and every deps/runtimeconfig/boot manifest.
- name: Scan the build and publish output for compiler-host assemblies
shell: pwsh
run: >-
./scripts/assert-no-compiler-host-assemblies.ps1
-Path artifacts/aot-sample, src/src/Examples.MinimalApi/bin/Release
- name: Run the native binary and check a failing request returns ProblemDetails
shell: bash
working-directory: artifacts/aot-sample
run: |
ASPNETCORE_URLS=http://127.0.0.1:5080 ./ZodSharp.Examples.MinimalApi > app.log 2>&1 &
app_pid=$!
trap 'kill "$app_pid" 2>/dev/null || true' EXIT
for _ in $(seq 1 30); do
curl --silent --fail --output /dev/null http://127.0.0.1:5080/openapi/v1.json && break
sleep 1
done
result=$(curl --silent --show-error --output body.json \
--write-out '%{http_code} %{content_type}' \
--request POST http://127.0.0.1:5080/orders \
--header 'Content-Type: application/json' \
--data '{"customerEmail":"not-an-email","lines":[{"sku":"abc","quantity":0}]}')
echo "$result"
cat body.json; echo
if [[ "$result" != "400 application/problem+json"* ]] || ! grep -q '"issues"' body.json; then
echo "::error::Expected a 400 application/problem+json response with ZodSharp issues."
cat app.log
exit 1
fi
# The only reliable proof that the Blazor integration is trim-safe in the browser: publish the WebAssembly half of
# the Blazor sample (Examples.Blazor.Client - ZodValidator, ZodValidationMessage, AddZodProblemDetails, the generated
# registration and the service-aware async rule) trimmed, and fail on any IL2xxx/IL3xxx warning. Then hold the
# Brotli-compressed size of every Purview.ZodSharp assembly in the output to .config/wasm-size-baseline.json (+10%).
# The RunAOTCompilation publish and the browser test are slower and run nightly (wasm-nightly.yml). `just wasm-size`
# runs the same publish and check locally.
wasm-trimmed:
name: Blazor WebAssembly trimmed publish and size budget
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Same reason as the cross-platform job: the SDK comes from global.json, not a floating
# version plus a feed quality.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
# -warnaserror fails the publish on any trim warning ILLink reports. The grep is a second gate in case a warning
# is ever logged without failing the step.
- name: Publish Examples.Blazor.Client trimmed (fails on any trim or AOT warning)
shell: bash
run: |
dotnet publish src/src/Examples.Blazor.Client/Examples.Blazor.Client.csproj \
--configuration Release --output artifacts/wasm-trimmed \
-warnaserror 2>&1 | tee publish.log
if grep -E 'warning IL[23][0-9]{3}' publish.log; then
echo "::error::The trimmed WebAssembly publish reported trim or AOT warnings."
exit 1
fi
- name: Check the Purview.ZodSharp size budget
shell: pwsh
run: ./scripts/check-wasm-size.ps1 -PublishDirectory artifacts/wasm-trimmed
# Compiler-host assemblies (the generator, the code fixes, Purview.SourceGeneratorFramework, Roslyn) must never
# reach build or publish output: Purview.SourceGeneratorFramework.dll once did, through analyzer-only references,
# and broke Blazor WebAssembly AOT. Scans file names and every deps/runtimeconfig/boot manifest.
- name: Scan the build and publish output for compiler-host assemblies
shell: pwsh
run: >-
./scripts/assert-no-compiler-host-assemblies.ps1
-Path artifacts/wasm-trimmed, src/src/Examples.Blazor.Client/bin/Release
# Proves the whole trim-safe surface, not just what one sample calls. The harness publishes with PublishAot=true twice:
# once with every Purview.ZodSharp assembly except NewtonsoftJson rooted whole, so ILC analyses all of their code, and
# once as a plain consumer. Any IL2xxx/IL3xxx warning fails the publish, and each native binary exercises runtime
# schemas, generated validators, System.Text.Json, JSON Schema, the validation bridge, ProblemDetails and options
# validation, exiting non-zero on any mismatch. See src/tests/TrimSafety.Verification.
verify-trim:
name: Trim and Native AOT verification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Same reason as the cross-platform job: the SDK comes from global.json, not a floating
# version plus a feed quality.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
# Native AOT links with clang and needs the zlib headers; the hosted image may not carry both.
- name: Install the Native AOT prerequisites
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends clang zlib1g-dev
# -warnaserror and the project's TreatWarningsAsErrors fail the publish on any trim or AOT warning. The grep is a
# second gate in case a warning is ever logged without failing the step.
- name: Publish and run the harness (every ZodSharp assembly rooted)
shell: bash
run: |
dotnet publish src/tests/TrimSafety.Verification/TrimSafety.Verification.csproj \
--configuration Release --runtime linux-x64 --output artifacts/trim-verification/rooted \
-p:TrimVerificationMode=Rooted -warnaserror 2>&1 | tee publish-rooted.log
if grep -E 'warning IL[23][0-9]{3}' publish-rooted.log; then
echo "::error::The rooted Native AOT publish reported trim or AOT warnings."
exit 1
fi
./artifacts/trim-verification/rooted/ZodSharp.TrimSafety.Verification
- name: Publish and run the harness (as a consumer)
shell: bash
run: |
dotnet publish src/tests/TrimSafety.Verification/TrimSafety.Verification.csproj \
--configuration Release --runtime linux-x64 --output artifacts/trim-verification/consumer \
-p:TrimVerificationMode=Consumer -warnaserror 2>&1 | tee publish-consumer.log
if grep -E 'warning IL[23][0-9]{3}' publish-consumer.log; then
echo "::error::The consumer Native AOT publish reported trim or AOT warnings."
exit 1
fi
./artifacts/trim-verification/consumer/ZodSharp.TrimSafety.Verification
# Compiler-host assemblies (the generator, the code fixes, Purview.SourceGeneratorFramework, Roslyn) must never
# reach build or publish output: Purview.SourceGeneratorFramework.dll once did, through analyzer-only references,
# and broke Blazor WebAssembly AOT. Scans file names and every deps/runtimeconfig/boot manifest.
- name: Scan the build and publish output for compiler-host assemblies
shell: pwsh
run: >-
./scripts/assert-no-compiler-host-assemblies.ps1
-Path artifacts/trim-verification/rooted, artifacts/trim-verification/consumer,
src/tests/TrimSafety.Verification/bin/Release
# Pack validation checks the IL-merged generator is present in the .nupkg; it cannot check that the
# assembly loads and generates. That merge has regressed twice (#36, #38), both times breaking consumers
# while the in-repo tests stayed green, because those run against the unmerged generator.
packed-generator:
name: Packed generator smoke test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Same reason as the cross-platform job: the SDK comes from global.json, not a floating
# version plus a feed quality.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
- name: Build and run a consumer against the packed generator
shell: pwsh
run: ./scripts/test-packed-generator.ps1 -Configuration Release
# Every other publish job builds against ProjectReferences; this one builds what ships. It packs every shipping
# package to an isolated feed and package cache, then publishes and runs throwaway consumers that reference the
# packages only - a Native AOT console, a Blazor WebAssembly app (trimmed and RunAOTCompilation) and a Native AOT
# minimal API - and leak-scans every bin and publish folder for compiler-host assemblies. It then proves every
# PackValidation ForbiddenContent rule rejects a package, against the packages the consumers used.
# `just smoke-packed-consumers` and `just verify-pack-rules` run the same locally. See docs/wiki/development/Release-Flow.md.
packed-consumers:
name: Packed consumers (Native AOT, Blazor WebAssembly, minimal API)
runs-on: ubuntu-latest
env:
# An extra feed for Purview.SourceGeneratorFramework only, for a version that is not on nuget.org yet. Unset, the
# gate restores it from nuget.org alone.
ZODSHARP_SGF_FEED: ${{ vars.ZODSHARP_SGF_FEED }}
steps:
- uses: actions/checkout@v7
# Same reason as the cross-platform job: the SDK comes from global.json, not a floating
# version plus a feed quality.
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
# First, before any toolchain is installed: the generator is built against the Purview.SourceGeneratorFramework
# version Directory.Packages.props pins, so nothing can be packed until that version restores. This fails with
# what to do (publish it to nuget.org, or set the ZODSHARP_SGF_FEED repository variable) rather than skipping.
- name: Check Purview.SourceGeneratorFramework restores
shell: pwsh
run: ./scripts/test-packed-consumers.ps1 -PreflightOnly
# Native AOT links with clang and needs the zlib headers; the hosted image may not carry both.
- name: Install the Native AOT prerequisites
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends clang zlib1g-dev
# RunAOTCompilation needs the Emscripten toolchain and the Mono AOT cross compiler. -WasmAot Require below makes a
# missing workload an error instead of a skipped step.
- name: Install the wasm-tools workload
run: dotnet workload install wasm-tools
- name: Pack, then publish, run and leak-scan consumers of the packages
shell: pwsh
run: >-
./scripts/test-packed-consumers.ps1 -RuntimeIdentifier linux-x64 -WasmAot Require
-PackOutput artifacts/packed
- name: Prove every pack-validation forbidden-content rule rejects a package
shell: pwsh
run: |
dotnet tool restore
./scripts/test-pack-validation-rules.ps1 -PackagesFolder artifacts/packed