build: Fix parallel build race on Analyzers.Common deps file#37
build: Fix parallel build race on Analyzers.Common deps file#37DrBarnabus merged 1 commit intomainfrom
Conversation
Add GlobalPropertiesToRemove="TargetFramework" to ProjectReference items for CompositeKey.Analyzers.Common in multi-targeted projects. Without this, each parent TFM passes its own TargetFramework as a global property, causing MSBuild to treat them as separate build requests that can run concurrently—all writing to the same netstandard2.0 output directory and racing on the .deps.json file.
WalkthroughFour C# project files are modified to add a Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~4 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #37 +/- ##
=======================================
Coverage 87.66% 87.66%
=======================================
Files 35 35
Lines 2099 2099
Branches 344 344
=======================================
Hits 1840 1840
Misses 157 157
Partials 102 102 ☔ View full report in Codecov by Sentry. |
The previous fix (#37) added GlobalPropertiesToRemove="TargetFramework" to all direct references to Analyzers.Common, but transient CI failures persisted. Investigation revealed two root causes: 1. Missing fix on Analyzers.UnitTests -> Analyzers reference: The 3-TFM test project (net10.0/net9.0/net8.0) passed its own TargetFramework to the multi-targeted Analyzers project without SetTargetFramework, creating 3 parallel build configurations that all converged on Analyzers.Common simultaneously. 2. Inconsistent ProjectReference strategies across consuming projects: FunctionalTests used SetTargetFramework="TargetFramework=netstandard2.0" on its Analyzers.Common reference while all other projects used GlobalPropertiesToRemove="TargetFramework". These produce different MSBuild global property sets ({TargetFramework=netstandard2.0} vs {}) for the same single-targeted project, creating two distinct build configurations both writing to the same output directory — the actual source of the race condition. The correct strategy depends on whether the referenced project is single-targeted or multi-targeted: - Single-targeted (Analyzers.Common): Use GlobalPropertiesToRemove to strip TargetFramework. This produces a config matching the solution's natural build, so MSBuild deduplicates correctly. - Multi-targeted (Analyzers, SourceGeneration): Use SetTargetFramework to pin to netstandard2.0. This matches one of the inner builds dispatched by the solution's outer multi-target build. Additionally, --graph is added to the CI build command as defense-in-depth. Graph builds evaluate the full project dependency graph upfront and ensure each project+config is built exactly once in topological order.
The previous fix (#37) added GlobalPropertiesToRemove="TargetFramework" to all direct references to Analyzers.Common, but transient CI failures persisted. Investigation revealed two root causes: 1. Missing fix on Analyzers.UnitTests -> Analyzers reference: The 3-TFM test project (net10.0/net9.0/net8.0) passed its own TargetFramework to the multi-targeted Analyzers project without SetTargetFramework, creating 3 parallel build configurations that all converged on Analyzers.Common simultaneously. 2. Inconsistent ProjectReference strategies across consuming projects: FunctionalTests used SetTargetFramework="TargetFramework=netstandard2.0" on its Analyzers.Common reference while all other projects used GlobalPropertiesToRemove="TargetFramework". These produce different MSBuild global property sets ({TargetFramework=netstandard2.0} vs {}) for the same single-targeted project, creating two distinct build configurations both writing to the same output directory — the actual source of the race condition. The correct strategy depends on whether the referenced project is single-targeted or multi-targeted: - Single-targeted (Analyzers.Common): Use GlobalPropertiesToRemove to strip TargetFramework. This produces a config matching the solution's natural build, so MSBuild deduplicates correctly. - Multi-targeted (Analyzers, SourceGeneration): Use SetTargetFramework to pin to netstandard2.0. This matches one of the inner builds dispatched by the solution's outer multi-target build. Additionally, --graph is added to the CI build command as defense-in-depth. Graph builds evaluate the full project dependency graph upfront and ensure each project+config is built exactly once in topological order.
Add GlobalPropertiesToRemove="TargetFramework" to ProjectReference items for CompositeKey.Analyzers.Common in multi-targeted projects.
Without this, each parent TFM passes its own TargetFramework as a global property, causing MSBuild to treat them as separate build requests that can run concurrently—all writing to the same netstandard2.0 output directory and racing on the .deps.json file.
Summary by CodeRabbit
Release Notes