Skip to content

Every project builds, tests and packs for both .NET 9 and .NET 10 - #130

Open
MelbourneDeveloper wants to merge 4 commits into
mainfrom
feat/multi-target-net9-net10
Open

MelbourneDeveloper wants to merge 4 commits into
mainfrom
feat/multi-target-net9-net10

Conversation

@MelbourneDeveloper

@MelbourneDeveloper MelbourneDeveloper commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

TLDR

Every project now builds, tests and packs for both .NET 9 and .NET 10.

What Was Added?

  • [BUILD-MULTI-TARGET] in docs/specs/ci-spec.md.
  • Per-framework Microsoft.AspNetCore.Mvc.Testing references (9.0.3 for net9.0, 10.0.0 for net10.0) in Sync.Http.Tests, Sync.Integration.Tests and Reporting.Integration.Tests. The package ships one framework per major version.

What Was Changed or Deleted?

  • Shared targets: Directory.Build.props replaces <TargetFramework>net9.0</TargetFramework> with <TargetFrameworks>net9.0;net10.0</TargetFrameworks>. Projects that pinned a single framework now inherit it. That covers the DataProvider tool (was net10.0 only), Reporting.Integration.Tests (was net10.0 only), the F# projects, Lql.Browser and the type-provider test data project.
  • Opt-outs: two projects stay single-target with an empty TargetFrameworks:
    • The Blazor WebAssembly Lql.Website (net9.0, deployed once).
    • The h5 Reporting.React (netstandard2.1, the only framework h5 transpiles from).
  • Native AOT DataProviderMigrate: a multi-targeted publish needs -f. make aot, the CI smoke-test path and release-dotnet-aot-multiplatform.yml publish -f net10.0. The binary is self-contained, so it ships one runtime, .NET 10 (LTS), instead of .NET 9.
  • Coverage gate: make test reads every per-framework coverage.cobertura.xml and gates on the lowest line rate. Before, it read only the first report it found.
  • Sync.Integration.Tests: references Microsoft.Extensions.Logging.Abstractions 10.0.0 (which also supports net9.0). Mvc.Testing 10 needs it, and 9.0.3 was a NU1605 downgrade on net10.0.
  • Reporting.Integration.Tests: this project only ever built for net10.0, where these analyzer rules never ran on it. Its new net9.0 build raised 45 analyzer errors, which I fixed in the code (no suppressions):
    • CA2234: absolute URLs passed as Uri.
    • CA2000: request StringContent disposed with using.
    • CA2007: ConfigureAwait(false) in the fixture.
    • CA2000: the static file host serves through UseWebRoot, so the host owns and disposes its file provider.
    • CA1711: collection definitions renamed to ReportingE2ECollectionDefinition and ReportingPlatformCollectionDefinition.
  • Codegen tool paths: Example, Lql.TypeProvider.FSharp.Tests and Lql.TypeProvider.FSharp.Tests.Data run the DataProvider, DataProviderMigrate and Lql tools from bin/$(Configuration)/$(TargetFramework)/. Before, they used hard-coded net9.0/net10.0 paths. Their build targets build each tool through the MSBuild task, which inherits the caller's TargetFramework. So a clean dotnet build DataProvider.sln -c Debug (the CI build job) built the DataProvider tool for net9.0 only, then ran the net10.0 path, which didn't exist yet. Codegen produced nothing, and the build failed with 'Generated' could not be found.

How Do The Automated Tests Prove It Works?

  • make ci passes. All 12 .NET test projects ran twice, once on .NETCoreApp v9.0 and once on v10.0, with identical test counts (for example Migration.Tests 614/614 and DataProvider.Tests 393/393 on each). Each project produced two coverage reports with the same line rate, and every gate passed.
  • make aot RID=linux-x64 publishes the net10.0 native binary and its smoke migrate passes. NativeAotMigrateSmokeTests pass against it on both test frameworks.
  • dotnet pack output:
    • Nimblesite.Sql.Model carries lib/net9.0 and lib/net10.0.
    • The DataProvider, DataProviderMigrate and Lql tools carry tools/net9.0/any and tools/net10.0/any.
  • dotnet build DataProvider.sln -c Release: 0 warnings, 0 errors for both frameworks.
  • I reproduced the CI build failure locally with a clean tree and CI's exact command, dotnet build DataProvider.sln -c Debug. It fails before the tool-path fix and passes after it (0 errors). DataProvider.Example.Tests (194) and Lql.TypeProvider.FSharp.Tests (70) then pass on both net9.0 and net10.0.

Spec / Doc Changes

  • docs/specs/ci-spec.md: new [BUILD-MULTI-TARGET] section. It covers the shared targets, opt-outs, per-framework packages, the net10.0 AOT binary, the coverage gate, and why netstandard2.1 is not a target. Migration and Sync depend on SqlParserCS, Npgsql and SqlClient, which ship no netstandard build. The other libraries use .NET 6+ APIs that would need polyfills plus a separate test harness.
  • docs/specs/codegen-cli-tool.md: the tool targets net9.0 and net10.0.
  • Website installation.md and getting-started.md: .NET 9 or .NET 10 SDK, and net9.0 works.
  • ci.yml comment: projects target both net9.0 and net10.0.

Breaking Changes

  • None
  • Consumers on .NET 9 keep working: every package still carries lib/net9.0. The native DataProviderMigrate binary now runs on the .NET 10 runtime, but it is self-contained, so users need no runtime installed.

- Directory.Build.props targets net9.0;net10.0. The Blazor WASM site and the
  h5 netstandard2.1 project opt out.
- Mvc.Testing is referenced per framework; Reporting integration tests fixed for
  the analyzer findings the new net9.0 build surfaced.
- Native AOT DataProviderMigrate publishes from net10.0 (LTS).
- make test gates coverage on the lowest per-framework report.
The codegen targets build each tool through the MSBuild task, which inherits the
caller's TargetFramework. Hard-coded net9.0/net10.0 tool paths therefore pointed at
outputs a clean build had not produced yet, so `dotnet build -c Debug` from clean
failed with missing Generated types. Tool paths now use $(TargetFramework).

Also restores the LqlExtension threshold to 54%: CI measures 54.48%.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant