chore: migrate from .sln to .slnx solution format#4984
Conversation
There was a problem hiding this comment.
Code Review: chore: migrate from .sln to .slnx solution format
Overall, this is a clean, well-executed migration. The new format is significantly more readable (125 lines vs 1,333 lines) and eliminates the GUID-heavy noise of the legacy format. The folder hierarchy is preserved, and the tooling references are consistently updated.
Observations
Positive:
- The XML format is far easier to review in diffs and resolve merge conflicts on — this is a genuine improvement to the developer experience.
- All IDE/tooling references (, docs) are updated consistently.
- The PR correctly notes that no GitHub Actions workflows referenced the directly.
- Platform configurations (, , ) carry over correctly.
Concerns
1. Unorganized root-level Mocks projects
The following projects are listed at the root of the solution in rather than in any folder:
<Project Path="TUnit.Mocks.Analyzers.Tests/TUnit.Mocks.Analyzers.Tests.csproj" />
<Project Path="TUnit.Mocks.Analyzers/TUnit.Mocks.Analyzers.csproj" />
<Project Path="TUnit.Mocks.Assertions/TUnit.Mocks.Assertions.csproj" />
<!-- ... and many more TUnit.Mocks.* -->
<Project Path="TUnit.Logging.Microsoft/TUnit.Logging.Microsoft.csproj" />
<Project Path="TUnit.SourceGenerator.Benchmarks/TUnit.SourceGenerator.Benchmarks.csproj" />This is inconsistent with the other projects which are organized into folders (, , etc.). If these were added to the solution after the last reorganization, they should be placed in appropriate folders (e.g., into and ). This isn't a blocking issue, but it's worth tidying up.
2. IDE/tooling compatibility — worth documenting
The format requires:
- Visual Studio: 2022 17.12+
- JetBrains Rider: 2024.2+
- **
Usage: dotnet [path-to-application]
Usage: dotnet [commands]
path-to-application:
The path to an application .dll file to execute.
commands:
-h|--help Display help.
--info Display .NET information.
--list-runtimes [--arch ] Display the installed runtimes matching the host or specified architecture. Example architectures: arm64, x64, x86.
--list-sdks [--arch ] Display the installed SDKs matching the host or specified architecture. Example architectures: arm64, x64, x86. CLI**: .NET SDK 9+
Since TUnit targets , contributors using only .NET 8 SDK tooling may not be able to open the solution. The project already requires .NET SDK 10 via , so in practice this is fine — but it's worth a note in or the README for visibility.
3. Dockerfile documentation pattern
The change in :
-COPY *.sln .
+COPY *.slnx .This is correct for TUnit's own CI example. However, users copying this Dockerfile template for their own projects will still have files. A brief inline comment (e.g., ) would make the example more transferable. Minor, but worth considering given this is public-facing documentation.
Summary
The migration itself is correct and the code is good. The main suggestion worth acting on is organizing the root-level Mocks/Logging/Benchmarks projects into appropriate solution folders to maintain the consistency established by the folder structure. The tooling compatibility and docs comment are minor nice-to-haves.
There was a problem hiding this comment.
Code Review: chore: migrate from .sln to .slnx solution format
Overall, this is a clean, well-executed migration. The new .slnx format is significantly more readable (125 lines vs 1,333 lines) and eliminates the GUID-heavy noise of the legacy format. The folder hierarchy is preserved, and the tooling references are consistently updated.
Observations
Positive:
- The XML format is far easier to review in diffs and resolve merge conflicts on — this is a genuine improvement to the developer experience.
- All IDE/tooling references (
.vscode/tasks.json, docs) are updated consistently. - The PR correctly notes that no GitHub Actions workflows referenced the
.slndirectly. - Platform configurations (
Any CPU,x64,x86) carry over correctly.
Concerns
1. Unorganized root-level Mocks projects
Several projects appear at the root of TUnit.slnx rather than in any solution folder:
- All
TUnit.Mocks.*projects (analyzers, tests, source generators, etc.) TUnit.Logging.MicrosoftTUnit.SourceGenerator.BenchmarksTUnit.Aspire,TUnit.Assertions.FSharp,TUnit.Assertions.SourceGenerator, etc.
This is inconsistent with the rest of the solution where projects are organized into named folders (/Libraries/, /Test/, /Analyzers/, etc.). These projects were likely added to the solution after the original folder structure was set up and missed being categorized. Since the .slnx format makes this trivially easy to fix, it would be worth grouping them into appropriate folders (e.g., TUnit.Mocks.* into /Libraries/ and /Test/).
2. IDE/tooling compatibility
The .slnx format requires Visual Studio 2022 17.12+, JetBrains Rider 2024.2+, and .NET SDK 9+. The project's global.json already enforces .NET SDK 10+, so this is fine in practice. However, a brief note in CONTRIBUTING.md or the README callling out that .slnx requires modern tooling would help contributors who hit IDE issues.
3. Dockerfile docs pattern
The update to docs/docs/examples/tunit-ci-pipeline.md correctly reflects the new format for TUnit's own pipeline. Since this is public-facing example documentation that users copy for their own projects, consider adding a comment like # Use *.sln for projects still on the legacy format so the intent is clear to users who haven't migrated.
Summary
The migration is correct and well done. The main actionable suggestion is organizing the root-level projects (especially all the TUnit.Mocks.* entries) into appropriate solution folders to match the folder structure already established for the rest of the solution. The other two points are minor.
Replace TUnit.sln with the new TUnit.slnx XML format via `dotnet sln migrate`, then reorganize all 86 projects into logical folders for a better IDE experience: - /Core/ — TUnit, TUnit.Core, TUnit.Engine, TUnit.Assertions - /Libraries/ — Aspire, AspNetCore, FsCheck, Playwright, Logging, Mocks - /Analyzers/ — all Roslyn analyzers and code fixers - /SourceGenerators/ — all source generators and Roslyn variants - /Tests/ — all test projects - /Benchmarks/ — source generator benchmarks - /Build/ — TUnit.Pipeline - /Examples/ — playground and example projects - /Templates/ — project templates (unchanged) No projects were at the solution root previously without a folder; now zero remain orphaned. Update .vscode/tasks.json and docs Dockerfile example references.
198d588 to
e35e99d
Compare
There was a problem hiding this comment.
Code Review: chore: migrate from .sln to .slnx solution format
Follow-up on Previous Review Comments
The two previous reviews raised a concern about root-level Mocks projects lacking folder organization. Checking the current PR HEAD (e35e99d): this has been addressed. All TUnit.Mocks.* projects are now correctly organized into appropriate folders (/Libraries/, /Analyzers/, /SourceGenerators/, /Tests/). The concern is resolved.
Current State Assessment
This is a clean, well-structured migration. The .slnx format cuts the solution file from 1,333 lines to ~125, eliminates GUID noise, and makes folder organization human-readable and diff-friendly. All tooling references (.vscode/tasks.json, docs Dockerfile example) are consistently updated.
All previous review concerns are now addressed.
Remaining Minor Observations
1. TUnit.Profile placement
TUnit.Profile is placed in the /Tests/ folder alongside test projects, but a /Benchmarks/ folder already exists (containing TUnit.SourceGenerator.Benchmarks). TUnit.Profile is a profiling project, not a test project. It would be more consistent to move it to /Benchmarks/:
<Folder Name="/Benchmarks/">
<Project Path="TUnit.Profile/TUnit.Profile.csproj" />
<Project Path="TUnit.SourceGenerator.Benchmarks/TUnit.SourceGenerator.Benchmarks.csproj" />
</Folder>This keeps the categorization semantically accurate. Very minor, not blocking.
2. Dockerfile docs snippet
The change from COPY *.sln . to COPY *.slnx . is correct for TUnit's own pipeline. Since this is public-facing example docs that contributors copy for their own projects, a small inline comment would improve clarity for users who haven't migrated yet:
# Use *.sln if your project hasn't migrated to .slnx format yet
COPY *.slnx .Not blocking, but this is a commonly copied snippet.
Summary
The migration is correct and the folder structure is well organized. The only actionable suggestion worth considering is moving TUnit.Profile from /Tests/ to /Benchmarks/ for consistency. Both remaining points are non-blocking. This is ready to merge.
There was a problem hiding this comment.
Code Review: chore: migrate from .sln to .slnx solution format
Follow-up on Previous Review Comments
The two previous reviews raised a concern about root-level Mocks projects lacking folder organization. Checking the current PR HEAD (e35e99d): this has been addressed. All TUnit.Mocks.* projects are now correctly organized into appropriate folders (/Libraries/, /Analyzers/, /SourceGenerators/, /Tests/). The concern is resolved.
Current State Assessment
This is a clean, well-structured migration. The .slnx format cuts the solution file from 1,333 lines to ~125, eliminates GUID noise, and makes folder organization human-readable and diff-friendly. All tooling references (.vscode/tasks.json, docs Dockerfile example) are consistently updated.
All previous review concerns are now addressed.
Remaining Minor Observations
1. TUnit.Profile placement
TUnit.Profile sits in /Tests/ alongside test projects, but a /Benchmarks/ folder already exists (containing TUnit.SourceGenerator.Benchmarks). TUnit.Profile is a profiling project, not a test project. Moving it to /Benchmarks/ would keep the categorization semantically accurate:
<Folder Name="/Benchmarks/">
<Project Path="TUnit.Profile/TUnit.Profile.csproj" />
<Project Path="TUnit.SourceGenerator.Benchmarks/TUnit.SourceGenerator.Benchmarks.csproj" />
</Folder>Very minor — the .slnx format makes this trivial to change.
2. Dockerfile docs snippet
The change from COPY *.sln . to COPY *.slnx . is correct for TUnit's own pipeline. Since this is public-facing example docs that users copy for their own projects, a small inline comment would improve clarity for those who haven't migrated yet:
# Use *.sln if your project hasn't migrated to .slnx format yet
COPY *.slnx .Not blocking.
Summary
The migration is correct and all previous concerns are resolved. The only actionable suggestion is moving TUnit.Profile from /Tests/ to /Benchmarks/ for consistency. Both points above are non-blocking. This is ready to merge.
Summary
TUnit.slnwith the newTUnit.slnxXML format viadotnet sln migrate.vscode/tasks.jsonreferences (build, publish, watch tasks)COPY *.slnx ..slndirectlyTest plan
dotnet build TUnit.slnxsucceeds