Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
02bcc36
Fix unresolved P2P references losing Configuration in solution build…
Mar 27, 2026
5fa4dca
Merge branch 'dotnet:main' into main
jimpark Mar 27, 2026
8576ac1
Update src/Tasks/AssignProjectConfiguration.cs
jimpark Mar 27, 2026
ba4fdfb
Add PR requested tests
Mar 27, 2026
5c2f7b9
Trigger CI rerun
Mar 28, 2026
678fef8
Retry CI
Mar 29, 2026
14c5e33
Add stronger tests
Mar 31, 2026
af1e727
Merge branch 'main' into main
jimpark Apr 9, 2026
1970dd1
Update MicrosoftBuildVersion to 18.7.0
invalid-email-address Apr 9, 2026
055366e
Merge pull request #1 from jimpark/main-update-msbuild-version-for-an…
jimpark Apr 13, 2026
6c5d5b7
Merge branch 'dotnet:main' into main
jimpark Apr 13, 2026
7accd44
Merge branch 'dotnet:main' into main
jimpark Apr 27, 2026
3d5b40e
Merge branch 'dotnet:main' into main
jimpark Apr 29, 2026
23ef479
Fix build errors by removing unused Xunit.Abstractions reference
Apr 29, 2026
338af44
Merge branch 'main' into main
jimpark Apr 30, 2026
0983f2b
Merge branch 'main' into main
jimpark May 1, 2026
e696e0d
Merge branch 'dotnet:main' into main
jimpark May 1, 2026
14bf2b0
Merge branch 'dotnet:main' into main
jimpark May 5, 2026
e940634
Merge branch 'dotnet:main' into main
jimpark May 5, 2026
676f2dd
Merge branch 'dotnet:main' into main
jimpark May 11, 2026
5276142
Update MicrosoftBuildVersion to 18.8.0
invalid-email-address May 11, 2026
a8ba934
Merge pull request #2 from jimpark/main-update-msbuild-version-for-an…
jimpark May 15, 2026
29a04c7
Merge branch 'dotnet:main' into main
jimpark May 16, 2026
730ce3b
Merge branch 'dotnet:main' into main
jimpark May 19, 2026
dd3e56a
Merge branch 'dotnet:main' into main
jimpark May 25, 2026
2fba265
Merge branch 'dotnet:main' into main
jimpark May 26, 2026
5bb788e
Merge branch 'dotnet:main' into main
jimpark May 29, 2026
8758c78
Update MicrosoftBuildVersion to 18.9.0
invalid-email-address May 29, 2026
c0a1517
Merge branch 'dotnet:main' into main
jimpark May 29, 2026
e4f4449
Merge pull request #3 from jimpark/main-update-msbuild-version-for-an…
jimpark May 29, 2026
2a494a7
Merge branch 'dotnet:main' into main
jimpark May 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions documentation/wiki/ChangeWaves.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Change wave checks around features will be removed in the release that accompani
- [TaskHostTask forwards request-level global properties (e.g. MSBuildRestoreSessionId) to out-of-proc TaskHost in -mt mode](https://github.com/dotnet/msbuild/pull/13443)
- [Fix ShouldTreatWarningAsError in OOP TaskHost checking wrong collection (WarningsAsMessages instead of WarningsAsErrors)](https://github.com/dotnet/msbuild/issues/11952)
- [Fix ToolTask hang when tool spawns grandchild processes that inherit stdout/stderr pipe handles](https://github.com/dotnet/msbuild/issues/2981)
- [Unresolved project references in solution builds inherit parent Configuration and Platform instead of stripping them via GlobalPropertiesToRemove](https://github.com/dotnet/msbuild/issues/13453)

### 18.5
- [FindUnderPath and AssignTargetPath tasks no longer throw on invalid path characters when using TaskEnvironment.GetAbsolutePath](https://github.com/dotnet/msbuild/pull/13069)
Expand Down
207 changes: 207 additions & 0 deletions src/Tasks.UnitTests/AssignProjectConfigurationChangeWave_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Shouldly;
using Xunit;
using Xunit.Abstractions;

#nullable disable

namespace Microsoft.Build.UnitTests
{
/// <summary>
/// Tests for the ChangeWave 18.6 behavior change in AssignProjectConfiguration:
/// When project references are not found in the solution configuration blob,
/// they should inherit the parent's Configuration and Platform rather than
/// having them stripped via GlobalPropertiesToRemove.
/// </summary>
public sealed class AssignProjectConfigurationChangeWave_Tests
{
private readonly ITestOutputHelper _output;

public AssignProjectConfigurationChangeWave_Tests(ITestOutputHelper output)
{
_output = output;
}

/// <summary>
/// Verifies that when ShouldUnsetParentConfigurationAndPlatform is true,
/// unresolved project references do NOT get GlobalPropertiesToRemove=Configuration;Platform
/// set on them. This ensures child projects inherit the parent's Configuration and Platform
/// rather than falling back to their defaults (which breaks non-standard configuration names
/// like "Debug Unicode").
/// </summary>
[Fact]
public void UnresolvedReferencesDoNotStripConfigurationUnderChangeWave()
{
using TestEnvironment env = TestEnvironment.Create(_output);

var projectRefs = new ArrayList();
// This reference is NOT in the solution config → will be unresolved
var unresolvedRef = ResolveNonMSBuildProjectOutput_Tests.CreateReferenceItem(
"Utility.vcxproj",
"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}",
"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}",
"Utility");
projectRefs.Add(unresolvedRef);

// Solution config only contains a DIFFERENT project
var projectConfigurations = new Hashtable();
projectConfigurations.Add("{BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB}", @"Debug Unicode|x64");

string xmlString = ResolveNonMSBuildProjectOutput_Tests.CreatePregeneratedPathDoc(projectConfigurations);

MockEngine engine = new MockEngine(_output);
AssignProjectConfiguration task = new AssignProjectConfiguration();
task.BuildEngine = engine;
task.SolutionConfigurationContents = xmlString;
task.ProjectReferences = (ITaskItem[])projectRefs.ToArray(typeof(ITaskItem));
task.ShouldUnsetParentConfigurationAndPlatform = true;

bool result = task.Execute();
result.ShouldBeTrue();

// The reference should be unresolved (not in solution config)
task.UnassignedProjects.Length.ShouldBe(1);
task.AssignedProjects.Length.ShouldBe(0);

// Under ChangeWave 18.6, GlobalPropertiesToRemove should NOT include Configuration;Platform
ITaskItem unresolved = task.UnassignedProjects[0];
string globalPropertiesToRemove = unresolved.GetMetadata("GlobalPropertiesToRemove");
globalPropertiesToRemove.ShouldNotContain("Configuration");
globalPropertiesToRemove.ShouldNotContain("Platform");
}

Comment thread
jimpark marked this conversation as resolved.
/// <summary>
/// Verifies that when ShouldUnsetParentConfigurationAndPlatform is false,
/// unresolved references never had GlobalPropertiesToRemove set (this behavior
/// is unchanged by the ChangeWave).
/// </summary>
[Fact]
public void UnresolvedReferencesWithoutShouldUnsetDoNotStripConfiguration()
{
using TestEnvironment env = TestEnvironment.Create(_output);

var projectRefs = new ArrayList();
var unresolvedRef = ResolveNonMSBuildProjectOutput_Tests.CreateReferenceItem(
"Utility.vcxproj",
"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}",
"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}",
"Utility");
projectRefs.Add(unresolvedRef);

var projectConfigurations = new Hashtable();
projectConfigurations.Add("{BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB}", @"Debug Unicode|x64");

string xmlString = ResolveNonMSBuildProjectOutput_Tests.CreatePregeneratedPathDoc(projectConfigurations);

MockEngine engine = new MockEngine(_output);
AssignProjectConfiguration task = new AssignProjectConfiguration();
task.BuildEngine = engine;
task.SolutionConfigurationContents = xmlString;
task.ProjectReferences = (ITaskItem[])projectRefs.ToArray(typeof(ITaskItem));
task.ShouldUnsetParentConfigurationAndPlatform = false; // default for non-solution builds

bool result = task.Execute();
result.ShouldBeTrue();

task.UnassignedProjects.Length.ShouldBe(1);
ITaskItem unresolved = task.UnassignedProjects[0];
string globalPropertiesToRemove = unresolved.GetMetadata("GlobalPropertiesToRemove");
globalPropertiesToRemove.ShouldBeEmpty();
}

/// <summary>
/// Verifies that resolved references still get correct SetConfiguration and SetPlatform
/// metadata with configurations containing spaces.
/// </summary>
[Fact]
public void ResolvedReferencesPreserveSpacesInConfigurationName()
{
using TestEnvironment env = TestEnvironment.Create(_output);

var projectRefs = new ArrayList();
var resolvedRef = ResolveNonMSBuildProjectOutput_Tests.CreateReferenceItem(
"Main.vcxproj",
"{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC}",
"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}",
"Main");
projectRefs.Add(resolvedRef);

// Solution config contains this project with a space in config name
var projectConfigurations = new Hashtable();
projectConfigurations.Add("{CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC}", @"Debug Unicode|x64");

string xmlString = ResolveNonMSBuildProjectOutput_Tests.CreatePregeneratedPathDoc(projectConfigurations);

MockEngine engine = new MockEngine(_output);
AssignProjectConfiguration task = new AssignProjectConfiguration();
task.BuildEngine = engine;
task.SolutionConfigurationContents = xmlString;
task.ProjectReferences = (ITaskItem[])projectRefs.ToArray(typeof(ITaskItem));
task.ShouldUnsetParentConfigurationAndPlatform = true;

bool result = task.Execute();
result.ShouldBeTrue();

task.AssignedProjects.Length.ShouldBe(1);
task.UnassignedProjects.Length.ShouldBe(0);

ITaskItem resolved = task.AssignedProjects[0];
resolved.GetMetadata("SetConfiguration").ShouldBe("Configuration=Debug Unicode");
resolved.GetMetadata("SetPlatform").ShouldBe("Platform=x64");
resolved.GetMetadata("Configuration").ShouldBe("Debug Unicode");
resolved.GetMetadata("Platform").ShouldBe("x64");
}

/// <summary>
/// Verifies that existing GlobalPropertiesToRemove metadata on an unresolved reference
/// is preserved (not appended to) under ChangeWave 18.6.
/// </summary>
[Fact]
public void ExistingGlobalPropertiesToRemovePreservedForUnresolvedReferences()
{
using TestEnvironment env = TestEnvironment.Create(_output);

var projectRefs = new ArrayList();
var unresolvedRef = ResolveNonMSBuildProjectOutput_Tests.CreateReferenceItem(
"Utility.vcxproj",
"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}",
"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}",
"Utility");
// Set some pre-existing GlobalPropertiesToRemove
unresolvedRef.SetMetadata("GlobalPropertiesToRemove", "TargetFramework");
projectRefs.Add(unresolvedRef);

var projectConfigurations = new Hashtable();
projectConfigurations.Add("{BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB}", @"Debug|x64");

string xmlString = ResolveNonMSBuildProjectOutput_Tests.CreatePregeneratedPathDoc(projectConfigurations);

MockEngine engine = new MockEngine(_output);
AssignProjectConfiguration task = new AssignProjectConfiguration();
task.BuildEngine = engine;
task.SolutionConfigurationContents = xmlString;
task.ProjectReferences = (ITaskItem[])projectRefs.ToArray(typeof(ITaskItem));
task.ShouldUnsetParentConfigurationAndPlatform = true;

bool result = task.Execute();
result.ShouldBeTrue();

task.UnassignedProjects.Length.ShouldBe(1);
ITaskItem unresolved = task.UnassignedProjects[0];
string globalPropertiesToRemove = unresolved.GetMetadata("GlobalPropertiesToRemove");

// The pre-existing TargetFramework should still be there
globalPropertiesToRemove.ShouldContain("TargetFramework");
// But Configuration;Platform should NOT be appended
globalPropertiesToRemove.ShouldNotContain("Configuration");
globalPropertiesToRemove.ShouldNotContain("Platform");
}
}
}
3 changes: 2 additions & 1 deletion src/Tasks/AssignProjectConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ public override bool Execute()
// If the reference was unresolved, we want to undefine the Configuration and Platform
// global properties, so that the project will build using its default Configuration and
// Platform rather than that of its parent.
Comment thread
jimpark marked this conversation as resolved.
Outdated
if (ShouldUnsetParentConfigurationAndPlatform)
if (ShouldUnsetParentConfigurationAndPlatform
&& !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_6))
{
string globalPropertiesToRemove = projectRef.GetMetadata("GlobalPropertiesToRemove");

Expand Down
Loading