Skip to content

chore: migrate to .slnx and enable central package management - #576

Merged
jeremydmiller merged 2 commits into
mainfrom
chore/slnx-and-cpm
Jul 29, 2026
Merged

chore: migrate to .slnx and enable central package management#576
jeremydmiller merged 2 commits into
mainfrom
chore/slnx-and-cpm

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Groundwork for the xunit 3 migration, but independently useful. Two commits, both infrastructure-only.

1. jasperfx.slnjasperfx.slnx

Solution folders (src, TestHarnesses, Widgets) survive migration, so the Nuke [Solution(GenerateProjects = true)] accessors Build.cs depends on (Solution.src.*, Solution.TestHarnesses.*) keep their generated names.

Two companion changes are required, not optional:

  • .nuke/parameters.json pinned the solution by filename. Every Nuke target fails at startup without updating it.
  • global.json pinned sdk.version: 9.0.100. .slnx restore needs 9.0.200+, so the old floor can no longer build the repo. rollForward: latestMajor happened to mask this on CI (which also installs 10.0.x), but relying on roll-forward to clear a hard floor shouldn't stay implicit — now pinned to 10.0.100.

2. Central package management

All 47 package versions move into Directory.Packages.props. Three things here are load-bearing:

Per-TFM versions survive as conditional PackageVersion groups — Directory.Packages.props is evaluated per inner build, so $(TargetFramework) is available. JasperFx and JasperFx.RuntimeCompiler each had two near-identical conditional ItemGroups that collapse to one now that the version was the only difference.

Roslyn cannot collapse to one version. Three consumers want three different answers:

Consumer Version Why
JasperFx.RuntimeCompiler [4.14.0,6.0.0) net9 / 5.0.0 net10 ships runtime compilation, tracks the SDK — takes the central default
JasperFx.SourceGenerator 4.3.0 (VersionOverride) netstandard2.0; a generator built against 4.14+ won't load in an older consumer's compiler
JasperFx.Events.SourceGenerator 4.8.0 (VersionOverride) same
both generator test projects 4.8.0 (VersionOverride) host Roslyn in-process to drive the generator under test

Verified with dotnet list package after the change that all four still resolve exactly as before. The unconditional Roslyn default also has to exist so the netstandard2.0 projects resolve at all — neither TFM condition applies to them, so without it they hit NU1010.

build/ opts out via its own Directory.Packages.props. It already isolates itself from repo MSBuild via Directory.Build.props/.targets, but CPM discovery does not follow that isolation — NuGet walks up independently — so Build.csproj's inline Nuke.Common version would otherwise fail NU1008.

The one real behavior change

Five versions were drifting in EventStoreTests alone and are now unified up to match the rest of the repo:

xunit 2.9.2→2.9.3 · xunit.runner.visualstudio 2.9.2→3.0.0 · NSubstitute 5.1.0→5.3.0 · Shouldly 4.2.1→4.3.0 · Microsoft.Extensions.TimeProvider.Testing 9.0.0→9.7.0

That suite is the thing to watch in review. It passes.

Verification

Full suite green on both target frameworks:

Suite Tests
CoreTests 475
CodegenTests 419
CommandLineTests 295
EventTests 648
EventStoreTests 72
CodegenTests.FSharp 1

Plus smoke-test-aot and the CLI smoke commands.

Incidental finding, not addressed here: JasperFx.SourceGenerator.Tests (19), JasperFx.Events.SourceGenerator.Tests (26), and JasperFx.Aspire.Tests (51) are in the solution but in no Nuke target and no CI step — 96 tests that compile and never run. All three pass locally. Follow-up PR.

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits July 29, 2026 05:57
Solution folders (src, TestHarnesses, Widgets) survive the migration, so the
Nuke [Solution(GenerateProjects = true)] accessors Build.cs depends on
(Solution.src.*, Solution.TestHarnesses.*) keep their generated names.

Two companion changes are required, not optional:

  - .nuke/parameters.json pinned the solution by name; every Nuke target fails
    at startup without it.
  - global.json pinned sdk.version 9.0.100. .slnx restore needs 9.0.200+, so
    the old floor could no longer build the repo. rollForward: latestMajor
    happened to mask this on CI (which also installs 10.0.x), but relying on
    roll-forward to clear a hard floor is not a constraint you want implicit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moves all 47 package versions into Directory.Packages.props and strips the
inline Version attributes. Three things here are load-bearing and should not be
"simplified" later:

  - Per-TFM versions survive as conditional PackageVersion groups. This works
    because Directory.Packages.props is evaluated per inner build, so
    $(TargetFramework) is available. JasperFx and JasperFx.RuntimeCompiler each
    had two near-identical conditional ItemGroups that collapse to one now that
    the version is the only thing that differed.

  - Roslyn cannot collapse to one version. RuntimeCompiler tracks the SDK
    ([4.14.0,6.0.0) / 5.0.0 per TFM), but the two source generators are
    netstandard2.0 and must stay pinned low (4.3.0 / 4.8.0) or they won't load
    in an older consumer's compiler. They use VersionOverride, as do the
    generator test projects that host Roslyn to drive them. Verified post-change
    with `dotnet list package` that all four still resolve exactly as before.
    The unconditional Roslyn default also exists so the netstandard2.0 projects
    resolve at all -- neither TFM condition applies to them, so without it they
    hit NU1010.

  - build/ opts out via its own Directory.Packages.props. It already isolates
    itself from repo MSBuild, but CPM discovery does not follow that isolation
    (NuGet walks up independently), so Build.csproj's inline Nuke.Common version
    would otherwise fail NU1008.

Five versions were drifting in EventStoreTests alone and are now unified up to
match the rest of the repo: xunit 2.9.2 -> 2.9.3, xunit.runner.visualstudio
2.9.2 -> 3.0.0, NSubstitute 5.1.0 -> 5.3.0, Shouldly 4.2.1 -> 4.3.0,
Microsoft.Extensions.TimeProvider.Testing 9.0.0 -> 9.7.0. That suite is the one
real behavior change in this commit; it passes.

Full suite green, both TFMs: CoreTests 475, CodegenTests 419, CommandLineTests
295, EventTests 648, EventStoreTests 72.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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