perf: disable GitVersion MSBuild task globally#5266
Conversation
…terns Disable the GitVersion MSBuild task by default in Directory.Build.props, eliminating 153+ process spawns per build. CI already computes the version once and passes properties explicitly, so the per-project task was redundant. Also: - Skip CleanSourceGeneratedViewer in CI and when directory doesn't exist - Remove redundant -p:DisableGitVersionTask=true from CI workflow - Fix unquoted MSBuild condition expressions (AP-02) Incremental no-op build: ~30s → ~4s Full build: 5m27s → 4m20s
There was a problem hiding this comment.
Code Review
This is a well-targeted, low-risk performance PR. The changes are clearly motivated and the implementation is sound. A few observations:
✅ DisableGitVersionTask in Directory.Build.props
Good move. GenerateGitVersionInformation=false was already set, meaning no class was being generated — but the GitVersion MSBuild task was still spawning a process. Setting DisableGitVersionTask=true globally prevents that process from running entirely.
The 153+ per-TFM invocation problem is real in large solutions that multi-target (net8/net9/net10), and the fix here is correct: CI already computes the version once via gittools/actions/gitversion/execute and injects the properties explicitly via -p:, so the per-project task serves no purpose.
One thing worth documenting (even if just as a comment above the property): local developer builds will no longer have GitVersion-computed version properties unless they pass them explicitly. Since GenerateGitVersionInformation was already false, the generated GitVersionInformation class wasn't available anyway, so this mainly matters for anyone trying to do local NuGet pack testing. It's probably fine for this repo, but a comment clarifying the local-dev trade-off would help future maintainers avoid confusion.
✅ CleanSourceGeneratedViewer target conditions (TestProject.props)
The two new conditions are both correct:
'$(ContinuousIntegrationBuild)' != 'true'— CI doesn't need the SourceGeneratedViewer at all, so skipping the delete-and-recreate cycle there is the right call.Exists('$(ProjectDir)SourceGeneratedViewer')— avoids a no-opItemGroup+Deleteon first build before the directory exists.
The <Message> removal is also a good cleanup — unconditional MSBuild log noise hurts incremental-build usability.
One minor architectural note: the target still lacks Inputs/Outputs for proper MSBuild incremental tracking on local builds, meaning it runs before every local build when the directory exists. For a fast directory-clean target this is probably acceptable, but if the viewer directory ever grows large (many TFMs × many source generators), adding an Inputs/Outputs guard would be the idiomatic MSBuild solution.
✅ MSBuild condition quoting fixes
The $(MSBuildProjectName) == 'TUnit.Pipeline' → '$(MSBuildProjectName)' == 'TUnit.Pipeline' fixes are correct. Unquoted property references in MSBuild Condition expressions can silently evaluate unexpectedly (e.g., when the property is empty, the expression becomes == 'TUnit.Pipeline' which may parse differently across MSBuild versions). The quoted form is the canonical, safe syntax.
✅ CI workflow cleanup
Removing the now-redundant -p:DisableGitVersionTask=true overrides from both the Build and Publish AOT steps is correct housekeeping. The root Directory.Build.props now owns this setting globally.
Summary
The performance claims (~30s → ~4s no-op local, 5m27s → 4m20s CI) are plausible given the described root cause (153+ subprocess invocations). The changes are minimal, focused, and correct. The only suggestion I'd offer is adding a brief developer-facing comment near DisableGitVersionTask to explain the local-dev implication, which would make the intent clear to anyone who encounters a $(Version) that resolves empty in a local build.
Approved.
DisableGitVersionTask=true was added in #5266 but PackTUnitFilesModule was not updated to pass version properties explicitly. This caused dotnet pack to rebuild assemblies with default AssemblyVersion (1.0.0.0), creating strong-name version mismatches at runtime in consumers (FileNotFoundException for TUnit.Core).
DisableGitVersionTask=true was added in #5266 but PackTUnitFilesModule was not updated to pass version properties explicitly. This caused dotnet pack to rebuild assemblies with default AssemblyVersion (1.0.0.0), creating strong-name version mismatches at runtime in consumers (FileNotFoundException for TUnit.Core).
Summary
Directory.Build.props— eliminates 153+dotnet-gitversionprocess spawns per build. CI already computes the version once viagittools/actions/gitversion/executeand passes properties explicitly, making the per-project MSBuild task redundant.CleanSourceGeneratedViewerin CI — the target was running every build with noInputs/Outputs, deleting and recreating source-gen viewer files unnecessarily. Now conditioned onContinuousIntegrationBuild != trueand directory existence.-p:DisableGitVersionTask=truefrom CI workflow — no longer needed since it's the default.Directory.Build.propsandTUnit.Templates/content/Directory.Build.props.Performance Impact
Test plan
dotnet build TUnit.CI.slnx)