From df73a5d14f1f632bc46529bb5682f113a9f7918c Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:23:16 +0100 Subject: [PATCH 1/5] perf: optimize solution build performance - Enable ProduceReferenceAssembly to skip recompilation of dependents when only internals change - Enable RestoreUseStaticGraphEvaluation for faster NuGet restore - Enable hardlinks for CopyToOutputDirectory to avoid file copies - Move GitVersion.MsBuild from GlobalPackageReference (all 69 projects) to explicit PackageReference on the 4 projects that use it - Separate restore from build in CI workflow and enable graph build scheduling (-graphBuild:True) for better parallelism - Update workflow docs with fast inner-loop build commands --- .claude/docs/workflows.md | 11 +++++++++++ .github/workflows/dotnet.yml | 6 +++++- Directory.Build.props | 9 +++++++++ Directory.Packages.props | 5 +---- TUnit.Assertions/TUnit.Assertions.csproj | 6 ++++++ TUnit.Core/TUnit.Core.csproj | 6 ++++++ TUnit.Engine/TUnit.Engine.csproj | 4 ++++ TUnit.Mocks/TUnit.Mocks.csproj | 6 ++++++ 8 files changed, 48 insertions(+), 5 deletions(-) diff --git a/.claude/docs/workflows.md b/.claude/docs/workflows.md index 54d08d393c..773d67aad6 100644 --- a/.claude/docs/workflows.md +++ b/.claude/docs/workflows.md @@ -5,6 +5,17 @@ ## Common Commands ```bash +# Build (fast inner loop — use dev solution, separate restore, graph scheduling) +dotnet restore TUnit.Dev.slnx +dotnet build TUnit.Dev.slnx --no-restore -graphBuild:True + +# Build with centralized output layout +dotnet build TUnit.Dev.slnx --no-restore -graphBuild:True --artifacts-path artifacts + +# Build full solution (CI or pre-commit) +dotnet restore TUnit.slnx +dotnet build TUnit.slnx --no-restore -graphBuild:True + # Run all tests (excludes TUnit.TestProject) dotnet test diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 8da6269d71..ce594ffec1 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -125,10 +125,14 @@ jobs: id: gitversion uses: gittools/actions/gitversion/execute@v3 + - name: Restore + shell: bash + run: dotnet restore TUnit.CI.slnx + - name: Build shell: bash run: >- - dotnet build TUnit.CI.slnx -c Release + dotnet build TUnit.CI.slnx -c Release --no-restore -graphBuild:True "-p:Version=${{ steps.gitversion.outputs.semVer }}" "-p:AssemblyVersion=${{ steps.gitversion.outputs.assemblySemVer }}" "-p:FileVersion=${{ steps.gitversion.outputs.assemblySemFileVer }}" diff --git a/Directory.Build.props b/Directory.Build.props index 53ee2f1295..e376ada6aa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,6 +31,15 @@ enable enable preview + + + true + + true + + true + true + false NU1507;NU1903;CS9107 buildTransitive/$(TargetFramework)/ diff --git a/Directory.Packages.props b/Directory.Packages.props index adfc7a52b4..f747768636 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,10 +4,7 @@ - - all - runtime; build; native; contentfiles; analyzers - + diff --git a/TUnit.Assertions/TUnit.Assertions.csproj b/TUnit.Assertions/TUnit.Assertions.csproj index 1809c6042f..c91e9f676b 100644 --- a/TUnit.Assertions/TUnit.Assertions.csproj +++ b/TUnit.Assertions/TUnit.Assertions.csproj @@ -48,6 +48,12 @@ + + + all + runtime; build; native; contentfiles; analyzers + + diff --git a/TUnit.Core/TUnit.Core.csproj b/TUnit.Core/TUnit.Core.csproj index c0c1082638..14d727fe60 100644 --- a/TUnit.Core/TUnit.Core.csproj +++ b/TUnit.Core/TUnit.Core.csproj @@ -60,6 +60,12 @@ Include="$(MSBuildProjectDirectory)\..\TUnit.Core.SourceGenerator.Roslyn414\bin\$(Configuration)\netstandard2.0\TUnit.Core.SourceGenerator.dll" Pack="true" PackagePath="analyzers/dotnet/roslyn4.14/cs" Visible="false" /> + + + all + runtime; build; native; contentfiles; analyzers + + diff --git a/TUnit.Engine/TUnit.Engine.csproj b/TUnit.Engine/TUnit.Engine.csproj index 33b43df182..a4773857a8 100644 --- a/TUnit.Engine/TUnit.Engine.csproj +++ b/TUnit.Engine/TUnit.Engine.csproj @@ -14,6 +14,10 @@ + + all + runtime; build; native; contentfiles; analyzers + diff --git a/TUnit.Mocks/TUnit.Mocks.csproj b/TUnit.Mocks/TUnit.Mocks.csproj index 106df21a1c..af36644996 100644 --- a/TUnit.Mocks/TUnit.Mocks.csproj +++ b/TUnit.Mocks/TUnit.Mocks.csproj @@ -51,6 +51,12 @@ + + + all + runtime; build; native; contentfiles; analyzers + + From f860da1173c6d4568de133cc38799ba7749fa996 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:30:27 +0100 Subject: [PATCH 2/5] refactor: centralize GitVersion PackageReference and clean up comments - Move GitVersion.MsBuild PackageReference from 4 individual .csproj files into a single conditional block in Directory.Build.props - Move GitVersion.MsBuild PackageVersion to the alphabetized main ItemGroup in Directory.Packages.props - Remove redundant WHAT comments on build performance properties --- Directory.Build.props | 15 ++++++++++++--- Directory.Packages.props | 2 +- TUnit.Assertions/TUnit.Assertions.csproj | 6 ------ TUnit.Core/TUnit.Core.csproj | 6 ------ TUnit.Engine/TUnit.Engine.csproj | 4 ---- TUnit.Mocks/TUnit.Mocks.csproj | 6 ------ 6 files changed, 13 insertions(+), 26 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e376ada6aa..555c835416 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,11 +32,8 @@ enable preview - true - true - true true @@ -105,4 +102,16 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index f747768636..e2f8fc3aa0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,7 +4,6 @@ - @@ -19,6 +18,7 @@ + diff --git a/TUnit.Assertions/TUnit.Assertions.csproj b/TUnit.Assertions/TUnit.Assertions.csproj index c91e9f676b..1809c6042f 100644 --- a/TUnit.Assertions/TUnit.Assertions.csproj +++ b/TUnit.Assertions/TUnit.Assertions.csproj @@ -48,12 +48,6 @@ - - - all - runtime; build; native; contentfiles; analyzers - - diff --git a/TUnit.Core/TUnit.Core.csproj b/TUnit.Core/TUnit.Core.csproj index 14d727fe60..c0c1082638 100644 --- a/TUnit.Core/TUnit.Core.csproj +++ b/TUnit.Core/TUnit.Core.csproj @@ -60,12 +60,6 @@ Include="$(MSBuildProjectDirectory)\..\TUnit.Core.SourceGenerator.Roslyn414\bin\$(Configuration)\netstandard2.0\TUnit.Core.SourceGenerator.dll" Pack="true" PackagePath="analyzers/dotnet/roslyn4.14/cs" Visible="false" /> - - - all - runtime; build; native; contentfiles; analyzers - - diff --git a/TUnit.Engine/TUnit.Engine.csproj b/TUnit.Engine/TUnit.Engine.csproj index a4773857a8..33b43df182 100644 --- a/TUnit.Engine/TUnit.Engine.csproj +++ b/TUnit.Engine/TUnit.Engine.csproj @@ -14,10 +14,6 @@ - - all - runtime; build; native; contentfiles; analyzers - diff --git a/TUnit.Mocks/TUnit.Mocks.csproj b/TUnit.Mocks/TUnit.Mocks.csproj index af36644996..106df21a1c 100644 --- a/TUnit.Mocks/TUnit.Mocks.csproj +++ b/TUnit.Mocks/TUnit.Mocks.csproj @@ -51,12 +51,6 @@ - - - all - runtime; build; native; contentfiles; analyzers - - From 0f1bc8f4429a699d3d7a56e3fb52fbc572fa7fc4 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:31:35 +0100 Subject: [PATCH 3/5] chore: add TUnit.Dev.slnx for fast inner-loop builds Trimmed solution (38 projects) excluding templates, CloudShop examples, Roslyn variants, benchmarks, and pipeline. --- TUnit.Dev.slnx | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 TUnit.Dev.slnx diff --git a/TUnit.Dev.slnx b/TUnit.Dev.slnx new file mode 100644 index 0000000000..00629adc7f --- /dev/null +++ b/TUnit.Dev.slnx @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3bef9adce397ba8d06c9e8017b5289acddb2680e Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Apr 2026 01:21:28 +0100 Subject: [PATCH 4/5] fix: remove hard link publish setting causing AOT file lock conflicts Parallel Native AOT publish processes all point to the same inode when hard links are enabled, causing IOException when ILCompiler tries to access TUnit.Assertions.dll concurrently. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 555c835416..c53b236870 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,8 +34,8 @@ true true + true - true false NU1507;NU1903;CS9107 From 06d5a3191a8f87fdfebca26de161eb905677c64f Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Apr 2026 01:22:10 +0100 Subject: [PATCH 5/5] fix: remove copy hard link setting that also risks AOT file lock conflicts ILCompiler reads from build output directories during AOT publish. With hard links, all test projects point to the same inode for shared assemblies (e.g. TUnit.Assertions.dll), causing the same lock contention as the publish hard links removed in the previous commit. --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c53b236870..7064dddf7f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,8 +34,8 @@ true true - - true + false NU1507;NU1903;CS9107