Update packages and add net10.0 target; drop net6.0 by mscottford · Pull Request #330 · Buildalyzer/Buildalyzer · GitHub
Skip to content

Update packages and add net10.0 target; drop net6.0 - #330

Open
mscottford wants to merge 3 commits into
Buildalyzer:mainfrom
mscottford:update/net10-and-package-updates
Open

mscottford wants to merge 3 commits into
Buildalyzer:mainfrom
mscottford:update/net10-and-package-updates

Conversation

@mscottford

Copy link
Copy Markdown

Summary

  • Drop net6.0 target, add net10.0 to Buildalyzer and Buildalyzer.Workspaces
  • Update MSBuild packages to 18.4.0 (aligns with the .NET 10 SDK)
  • Update MSBuild.StructuredLogger to 2.3.154 (required to parse binlog format 25 produced by MSBuild 18.x)
  • Update Roslyn, NuGet, logging, and test packages to current releases
  • Bump version to 8.1.0
  • Suppress NU1701 for net8+/net10 consumers of MSBuild 18.x (which only ships net472 assets but works fine via compatibility fallback)
  • Pin System.Security.Cryptography.Xml 10.0.6 to clear NU1903 vulnerability warnings

Dependencies

Test plan

  • All existing integration tests pass on net8.0 and net10.0
  • No NU1701 or NU1903 warnings in build output

🤖 Generated with Claude Code

mscottford and others added 3 commits April 17, 2026 16:49
…r path

Three related fixes for reading binlogs produced by the .NET 10 SDK:

1. AnalyzerManager.Analyze: replace StructuredLogger.BinLogReader with
   Microsoft.Build.Logging.BinaryLogReplayEventSource. The official MSBuild
   reader handles all 18.x event types (AssemblyLoadBuildEventArgs etc.),
   whereas BinLogReader from MSBuild.StructuredLogger may stop replaying
   mid-stream when it encounters event types it does not recognise, leaving
   _evalulationResults empty so ProjectStarted falls back to null
   propertiesAndItems and produces no results.

2. EventProcessor.ProjectStarted: treat an empty e.Properties collection
   the same as null. BinLogReader creates ProjectStartedEventArgs with
   Properties set to a non-null but empty collection for binlog format 14+
   events, so the existing `e.Properties is null` check always fell through
   to the old-format path, using the empty collection instead of the
   populated evaluation-phase results.

3. AnalyzerManager obsolete string constructor: wrap the path in
   Path.GetFullPath() before passing it to IOPath.Parse(), restoring the
   behaviour of the previous NormalizePath implementation that was removed
   when IOPath was introduced.

Regression tests added for fixes 1 and 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix binlog replay with MSBuild 18.x and normalize obsolete constructor path.
See Buildalyzer#329.
- Buildalyzer, Buildalyzer.Workspaces: drop net6.0, add net10.0 target
- Microsoft.Build / Microsoft.Build.Tasks.Core: 17.14.28 → 18.4.0
- Microsoft.Build.Utilities.Core (Logger): 14.3.0 → 18.4.0
- MSBuild.StructuredLogger: 2.2.158 → 2.3.154
- Microsoft.Extensions.Logging: 6.0.0 → 10.0.6
- NuGet.Frameworks: 6.9.1 → 7.3.1
- Microsoft.CodeAnalysis.CSharp/VisualBasic.Workspaces: 4.10.0 → 5.3.0
- AwesomeAssertions: 9.3.0 → 9.4.0
- NUnit: 4.4.0 → 4.5.1
- Microsoft.SourceLink.GitHub: 8.0.0 → 10.0.202
- Microsoft.Sbom.Targets: 4.1.4 → 4.1.5
- Version bump: 1.0.0 → 8.1.0
- Suppress NU1701 for net8+/net10 consumers of MSBuild 18.x assets
- Pin System.Security.Cryptography.Xml 10.0.6 to suppress NU1903 warnings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mscottford added a commit to mscottford/Buildalyzer that referenced this pull request Apr 17, 2026
Update packages and add net10.0 target; drop net6.0.
See Buildalyzer#330.
@Corniel

Corniel commented Apr 18, 2026

Copy link
Copy Markdown
Collaborator

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.3.0" />

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've think we should only go for [5.0.0,), I guess we facilitate people who are stuck to older Roslyn versions.

/// The fix is to treat an empty <c>e.Properties</c> the same as null.
/// </summary>
[Test]
public void SdkProjectWithProjectReferenceGetsReferencesFromBinaryLog(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use Buildalyzer.TestTools.Context.ForProject instead? Is should lead to a cleaner test.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates Buildalyzer to align with the .NET 10 / MSBuild 18 toolchain by adjusting target frameworks, refreshing key dependencies, and improving binlog replay behavior (plus adding regression coverage around project references when replaying binlogs).

Changes:

  • Drop net6.0 and add/standardize net10.0 targeting (plus version bump to 8.1.0).
  • Upgrade MSBuild-related packages and adjust binlog replay to handle newer MSBuild 18.x event types reliably.
  • Add binlog replay regression tests to ensure ProjectReferences survive a build → binlog → replay round-trip.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/Buildalyzer.Workspaces.Tests/Buildalyzer.Workspaces.Tests.csproj Updates test dependency versions (AwesomeAssertions, NUnit).
tests/Buildalyzer.Tests/Buildalyzer.Tests.csproj Updates test dependency versions (AwesomeAssertions, NUnit).
tests/Buildalyzer.Tests/Integration/SimpleProjectsFixture.cs Adds regression tests for ProjectReferences when replaying binlogs.
src/Buildalyzer/Logging/EventProcessor.cs Treats empty ProjectStartedEventArgs.Properties as equivalent to null for evaluation fallback.
src/Buildalyzer/AnalyzerManager.cs Switches binlog replay to BinaryLogReplayEventSource and normalizes obsolete ctor input paths.
src/Buildalyzer/Buildalyzer.csproj Drops net6.0, adds net10.0, upgrades core packages, and suppresses NU1701.
src/Buildalyzer.Workspaces/Buildalyzer.Workspaces.csproj Drops net6.0, keeps net8.0 + net10.0, upgrades Roslyn Workspaces packages, suppresses NU1701.
src/Buildalyzer.Logger/Buildalyzer.Logger.csproj Updates MSBuild Utilities dependency to align with MSBuild 18.x.
package.props Minor build-time package bump (SBOM targets).
Directory.Build.props Bumps version to 8.1.0, upgrades SourceLink, pins System.Security.Cryptography.Xml to address audit warnings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// stops replaying mid-stream when it encounters unknown event types in newer binlogs,
// causing ProjectEvaluationFinishedEventArgs to never fire and leaving _evalulationResults
// empty, so ProjectStarted falls back to null propertiesAndItems and no results are produced.
var reader = new Microsoft.Build.Logging.BinaryLogReplayEventSource();

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BinaryLogReplayEventSource holds unmanaged resources/streams and should be disposed after replay. Wrap reader in a using (or try/finally) so the binlog file handle is reliably released even if Replay throws, and to satisfy IDisposable analyzers.

Suggested change
var reader = new Microsoft.Build.Logging.BinaryLogReplayEventSource();
using var reader = new Microsoft.Build.Logging.BinaryLogReplayEventSource();

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +89
// Treat an empty e.Properties the same as null: BinLogReader (MSBuild.StructuredLogger)
// creates ProjectStartedEventArgs with Properties set to a non-null but empty collection
// rather than null for binlog format 14+ events. The empty collection carries no useful

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment (and the related tests) still refers to BinLogReader from MSBuild.StructuredLogger, but Analyze now replays binlogs via BinaryLogReplayEventSource. Update the comment to describe the current replay mechanism (or generalize it to “binlog replay event sources”) so the rationale stays accurate over time.

Suggested change
// Treat an empty e.Properties the same as null: BinLogReader (MSBuild.StructuredLogger)
// creates ProjectStartedEventArgs with Properties set to a non-null but empty collection
// rather than null for binlog format 14+ events. The empty collection carries no useful
// Treat an empty e.Properties the same as null: some binlog replay event sources
// create ProjectStartedEventArgs with Properties set to a non-null but empty collection
// rather than null for binlog format 14+ events. The empty collection carries no useful

Copilot uses AI. Check for mistakes.
StringWriter log = new StringWriter();
IProjectAnalyzer analyzer = GetProjectAnalyzer(@"SdkNetCore2ProjectWithReference\SdkNetCore2ProjectWithReference.csproj", log);
EnvironmentOptions options = new EnvironmentOptions { Preference = preference };
string binLogPath = Path.ChangeExtension(Path.GetTempFileName(), ".binlog");

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path.GetTempFileName() creates a real temp file; changing the extension leaves the original .tmp file behind, so these tests will leak temp files over time. Use Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".binlog") (or delete the original temp file returned by GetTempFileName) instead.

Suggested change
string binLogPath = Path.ChangeExtension(Path.GetTempFileName(), ".binlog");
string binLogPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".binlog");

Copilot uses AI. Check for mistakes.
Preference = preference
};
// Child-side binary logging: the build process itself writes the binlog
options.Arguments.Add($"/bl:{binLogPath}");

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/bl: is being passed without quoting the path. Since BuildEnvironment.Arguments are concatenated into a single command-line string, a temp path containing spaces can break MSBuild argument parsing and make the test flaky on machines with spaced user profiles. Quote the path (e.g., /bl:"...") or ensure the argument builder quotes paths automatically.

Suggested change
options.Arguments.Add($"/bl:{binLogPath}");
options.Arguments.Add($"/bl:\"{binLogPath}\"");

Copilot uses AI. Check for mistakes.
// Given
StringWriter log = new StringWriter();
IProjectAnalyzer analyzer = GetProjectAnalyzer(@"SdkNetCore2ProjectWithReference\SdkNetCore2ProjectWithReference.csproj", log);
string binLogPath = Path.ChangeExtension(Path.GetTempFileName(), ".binlog");

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same temp-file leak as above: Path.GetTempFileName() creates a .tmp file that is never deleted when you only delete the .binlog path. Prefer a non-creating temp filename (random name under GetTempPath) or delete the original temp file too.

Suggested change
string binLogPath = Path.ChangeExtension(Path.GetTempFileName(), ".binlog");
string binLogPath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), ".binlog"));

Copilot uses AI. Check for mistakes.
Comment on lines +381 to +388
/// Root cause: <see cref="Buildalyzer.Logging.EventProcessor"/> checks
/// <c>e.Properties is null</c> to detect the "new-format" binlog (format 14+) and fall
/// back to evaluation-phase items. However, <c>BinLogReader</c> from
/// MSBuild.StructuredLogger creates <c>ProjectStartedEventArgs</c> with
/// <c>Properties</c> set to an empty non-null collection rather than <c>null</c>,
/// so the check always resolves to the old-format path — using the empty
/// <c>e.Properties</c>/<c>e.Items</c> instead of the populated evaluation results.
/// The fix is to treat an empty <c>e.Properties</c> the same as null.

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML doc comment still describes the replay path as going through BinLogReader and EventProcessor’s e.Properties is null logic, but the implementation now uses BinaryLogReplayEventSource in AnalyzerManager.Analyze. Update the comment to reflect the current code path so future debugging doesn’t chase the wrong component.

Suggested change
/// Root cause: <see cref="Buildalyzer.Logging.EventProcessor"/> checks
/// <c>e.Properties is null</c> to detect the "new-format" binlog (format 14+) and fall
/// back to evaluation-phase items. However, <c>BinLogReader</c> from
/// MSBuild.StructuredLogger creates <c>ProjectStartedEventArgs</c> with
/// <c>Properties</c> set to an empty non-null collection rather than <c>null</c>,
/// so the check always resolves to the old-format path — using the empty
/// <c>e.Properties</c>/<c>e.Items</c> instead of the populated evaluation results.
/// The fix is to treat an empty <c>e.Properties</c> the same as null.
/// This test exercises the current replay path used by <see cref="IAnalyzerManager.Analyze"/>,
/// which replays the binlog through <c>BinaryLogReplayEventSource</c>. Keep this comment in
/// sync with that code path so future debugging does not chase older implementations such as
/// <c>BinLogReader</c> or the previous <c>EventProcessor</c> <c>e.Properties</c> handling.

Copilot uses AI. Check for mistakes.
Comment on lines +426 to +431
/// it from the build process itself. Replaying that log via
/// <see cref="IAnalyzerManager.Analyze"/> triggers the
/// <c>BinLogReader</c> path in <c>EventProcessor</c> where
/// <c>ProjectStartedEventArgs.Properties</c> is a non-null but empty collection.
/// Because <see cref="Logging.EventProcessor"/> checks <c>e.Properties is null</c>
/// it never falls back to the evaluation-phase items, leaving

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the previous doc block: this comment explains the failure in terms of a BinLogReader code path, but Analyze now replays binlogs using BinaryLogReplayEventSource. Please update the comment to match the current implementation so it remains a useful regression note.

Suggested change
/// it from the build process itself. Replaying that log via
/// <see cref="IAnalyzerManager.Analyze"/> triggers the
/// <c>BinLogReader</c> path in <c>EventProcessor</c> where
/// <c>ProjectStartedEventArgs.Properties</c> is a non-null but empty collection.
/// Because <see cref="Logging.EventProcessor"/> checks <c>e.Properties is null</c>
/// it never falls back to the evaluation-phase items, leaving
/// it from the build process itself. Replaying that log via
/// <see cref="IAnalyzerManager.Analyze"/> uses <c>BinaryLogReplayEventSource</c>, and in
/// this scenario <c>ProjectStartedEventArgs.Properties</c> can be a non-null but empty
/// collection. Because <see cref="Logging.EventProcessor"/> checks
/// <c>e.Properties is null</c>, it never falls back to the evaluation-phase items, leaving

Copilot uses AI. Check for mistakes.
@Corniel

Corniel commented Apr 18, 2026

Copy link
Copy Markdown
Collaborator

@mscottford Lets merge #332 first. That should make continuing with this easier (at least, I hope so).

@Frulfump

Frulfump commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

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.

4 participants