Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changewave 16.10 for restore failures #6372

Merged
merged 3 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -27,6 +27,7 @@ The opt-out comes in the form of setting the environment variable `MSBuildDisabl
- [Error when a property expansion in a condition has whitespace](https://github.com/dotnet/msbuild/pull/5672)
- [Allow Custom CopyToOutputDirectory Location With TargetPath](https://github.com/dotnet/msbuild/pull/6237)
- [Allow users that have certain special characters in their username to build successfully when using exec](https://github.com/dotnet/msbuild/pull/6223)
- [Fail restore operations when there is no `Restore` target or an SDK is unresolveable](https://github.com/dotnet/msbuild/pull/6312)
### 17.0

## Change Waves No Longer In Rotation
2 changes: 1 addition & 1 deletion src/Build/BackEnd/Shared/BuildRequestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ internal void LoadProjectIntoConfiguration(
projectLoadSettings |= ProjectLoadSettings.IgnoreMissingImports | ProjectLoadSettings.IgnoreInvalidImports | ProjectLoadSettings.IgnoreEmptyImports;
}

if (buildRequestDataFlags.HasFlag(buildRequestDataFlags & BuildRequestDataFlags.FailOnUnresolvedSdk))
if (buildRequestDataFlags.HasFlag(BuildRequestDataFlags.FailOnUnresolvedSdk))
{
projectLoadSettings |= ProjectLoadSettings.FailOnUnresolvedSdk;
}
Expand Down
46 changes: 46 additions & 0 deletions src/MSBuild.UnitTests/XMake_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Shouldly;
using System.IO.Compression;
using System.Reflection;
using Microsoft.Build.Utilities;

namespace Microsoft.Build.UnitTests
{
Expand Down Expand Up @@ -2127,6 +2128,31 @@ public void RestoreFailsOnUnresolvedSdk()
logContents.ShouldContain("error MSB4236: The SDK 'UnresolvedSdk' specified could not be found.");
}

/// <summary>
/// When specifying /t:restore under an old changewave, do not fail when an SDK can't be resolved.
/// Previous behavior was to try and continue anyway but then "restore" would succeed and build workflows continue on.
/// </summary>
[Fact]
public void RestorePassesOnUnresolvedSdkUnderChangewave()
{
string projectContents = ObjectModelHelpers.CleanupFileContents(
$@"<Project>
<Sdk Name=""UnresolvedSdk"" />
<Target Name=""Restore"">
<Message Text=""Restore target ran"" />
</Target>
</Project>");

using TestEnvironment env = Microsoft.Build.UnitTests.TestEnvironment.Create();

string logContents = ExecuteMSBuildExeExpectSuccess(projectContents,
envsToCreate: new Dictionary<string, string>() { ["MSBUILDDISABLEFEATURESFROMVERSION"]=ChangeWaves.Wave16_10.ToString() },
arguments: " /t:restore");

logContents.ShouldNotContain("MSB4236");
}


/// <summary>
/// Verifies a non-existent target doesn't fail restore as long as its not considered an entry target, in this case Restore.
/// </summary>
Expand Down Expand Up @@ -2181,6 +2207,26 @@ public void RestoreFailsWhenEntryTargetIsNonExistent()
logContents.ShouldContain("error MSB4057: The target \"Restore\" does not exist in the project.");
}

/// <summary>
/// Verifies restore will not fail if the entry target doesn't exist, when changewave applied.
/// </summary>
[Fact]
public void RestorePassesWhenEntryTargetIsNonExistentUnderChangewave()
{
string projectContents = ObjectModelHelpers.CleanupFileContents(
@"<Project DefaultTargets=""Build"">
<Target Name=""Build"">
<Message Text=""Build target ran&quot;"" />
</Target>
</Project>");

string logContents = ExecuteMSBuildExeExpectSuccess(projectContents,
envsToCreate: new Dictionary<string, string>() { ["MSBUILDDISABLEFEATURESFROMVERSION"] = ChangeWaves.Wave16_10.ToString() },
arguments: "/t:restore");

logContents.ShouldNotContain("MSB4057");
}

/// <summary>
/// Verifies restore will run InitialTargets.
/// </summary>
Expand Down
27 changes: 19 additions & 8 deletions src/MSBuild/XMake.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,20 +1421,31 @@ private static (BuildResultCode result, Exception exception) ExecuteRestore(stri
restoreGlobalProperties["MSBuildRestoreSessionId"] = Guid.NewGuid().ToString("D");

// Create a new request with a Restore target only and specify:
// - BuildRequestDataFlags.ClearCachesAfterBuild to ensure the projects will be reloaded from disk for subsequent builds
// - BuildRequestDataFlags.SkipNonexistentNonEntryTargets to ignore missing non-entry targets since Restore does not require that all targets
// exist, only top-level ones like Restore itself
// - BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports to ignore imports that don't exist, are empty, or are invalid because restore might
// make available an import that doesn't exist yet and the <Import /> might be missing a condition.
// - BuildRequestDataFlags.FailOnUnresolvedSdk to still fail in the case when an MSBuild project SDK can't be resolved since this is fatal and should
// fail the build.
BuildRequestDataFlags flags;

if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10))
{
flags = BuildRequestDataFlags.ClearCachesAfterBuild // ensure the projects will be reloaded from disk for subsequent builds
| BuildRequestDataFlags.SkipNonexistentNonEntryTargets // ignore missing non-entry targets since Restore does not require that all targets
// exist, only top-level ones like Restore itself
| BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports // ignore imports that don't exist, are empty, or are invalid because restore might
// make available an import that doesn't exist yet and the <Import /> might be missing a condition.
| BuildRequestDataFlags.FailOnUnresolvedSdk; // still fail in the case when an MSBuild project SDK can't be resolved since this is fatal and should
// fail the build.
}
else
{
// pre-16.10 flags allowed `-restore` to pass when there was no `Restore` target
flags = BuildRequestDataFlags.ClearCachesAfterBuild | BuildRequestDataFlags.SkipNonexistentTargets | BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports;
}

BuildRequestData restoreRequest = new BuildRequestData(
projectFile,
restoreGlobalProperties,
toolsVersion,
targetsToBuild: new[] { MSBuildConstants.RestoreTargetName },
hostServices: null,
flags: BuildRequestDataFlags.ClearCachesAfterBuild | BuildRequestDataFlags.SkipNonexistentNonEntryTargets | BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports | BuildRequestDataFlags.FailOnUnresolvedSdk);
flags);

return ExecuteBuild(buildManager, restoreRequest);
}
Expand Down