Skip to content

Commit

Permalink
Bring back eval results (#9138)
Browse files Browse the repository at this point in the history
* Revert "Revert "Get eval results 2 - getProperty, getItem, getTargetResult (#8792)" (#9136)"

This reverts commit 4e49723.

* Fix graph case

* Always include IsGraphBuild property

* Tweak test to include graph

* PR comment + moving into if

* Avoid exception on mismatched global properties

---------

Co-authored-by: Forgind <[email protected]>
Co-authored-by: Rainer Sigwald <[email protected]>
  • Loading branch information
3 people authored Aug 30, 2023
1 parent 0974273 commit ba4f2fe
Show file tree
Hide file tree
Showing 24 changed files with 1,122 additions and 32 deletions.
6 changes: 3 additions & 3 deletions src/Build/BackEnd/BuildManager/BuildManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,13 @@ private enum BuildManagerState
Idle,

/// <summary>
/// This is the state the BuildManager is in after <see cref="BeginBuild(BuildParameters)"/> has been called but before <see cref="EndBuild"/> has been called.
/// <see cref="BuildManager.PendBuildRequest(Microsoft.Build.Execution.BuildRequestData)"/>, <see cref="BuildManager.BuildRequest(Microsoft.Build.Execution.BuildRequestData)"/>, <see cref="BuildManager.PendBuildRequest(GraphBuildRequestData)"/>, <see cref="BuildManager.BuildRequest(GraphBuildRequestData)"/>, and <see cref="BuildManager.EndBuild"/> may be called in this state.
/// This is the state the BuildManager is in after <see cref="BeginBuild(BuildParameters)"/> has been called but before <see cref="EndBuild()"/> has been called.
/// <see cref="BuildManager.PendBuildRequest(Microsoft.Build.Execution.BuildRequestData)"/>, <see cref="BuildManager.BuildRequest(Microsoft.Build.Execution.BuildRequestData)"/>, <see cref="BuildManager.PendBuildRequest(GraphBuildRequestData)"/>, <see cref="BuildManager.BuildRequest(GraphBuildRequestData)"/>, and <see cref="BuildManager.EndBuild()"/> may be called in this state.
/// </summary>
Building,

/// <summary>
/// This is the state the BuildManager is in after <see cref="BuildManager.EndBuild"/> has been called but before all existing submissions have completed.
/// This is the state the BuildManager is in after <see cref="BuildManager.EndBuild()"/> has been called but before all existing submissions have completed.
/// </summary>
WaitingForBuildToComplete
}
Expand Down
7 changes: 7 additions & 0 deletions src/Build/Definition/ProjectCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,13 @@ public bool TryUnloadProject(ProjectRootElement projectRootElement)
}
}

/// <summary>
/// Logs a BuildFinished event. This is used specifically when a ProjectCollection is created but never actually built, yet a BuildFinished event
/// is still desired. As an example, if a Project is just meant to be evaluated, but a binlog is also collected, that binlog should be able to
/// say the build succeeded or failed. This provides a mechanism to achieve that.
/// </summary>
public void LogBuildFinishedEvent(bool success) => _loggingService.LogBuildFinished(success);

/// <summary>
/// Called by a Project object to load itself into this collection.
/// If the project was already loaded under a different name, it is unloaded.
Expand Down
70 changes: 70 additions & 0 deletions src/Build/Logging/SimpleErrorLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Logging.SimpleErrorLogger
{
/// <summary>
/// This logger ignores all message-level output, writing errors and warnings to
/// standard error, colored red and yellow respectively.
///
/// It is currently used only when the user requests information about specific
/// properties, items, or target results. In that case, we write the desired output
/// to standard out, but we do not want it polluted with any other kinds of information.
/// Users still might want diagnostic information if something goes wrong, so still
/// output that as necessary.
/// </summary>
public sealed class SimpleErrorLogger : INodeLogger
{
public SimpleErrorLogger()
{
}

public bool HasLoggedErrors { get; private set; } = false;

public LoggerVerbosity Verbosity
{
get => LoggerVerbosity.Minimal;
set { }
}

public string Parameters
{
get => string.Empty;
set { }
}

public void Initialize(IEventSource eventSource, int nodeCount)
{
eventSource.ErrorRaised += HandleErrorEvent;
eventSource.WarningRaised += HandleWarningEvent;
}

private void HandleErrorEvent(object sender, BuildErrorEventArgs e)
{
HasLoggedErrors = true;
Console.Error.Write("\x1b[31;1m");
Console.Error.Write(EventArgsFormatting.FormatEventMessage(e, showProjectFile: true));
Console.Error.WriteLine("\x1b[m");
}

private void HandleWarningEvent(object sender, BuildWarningEventArgs e)
{
Console.Error.Write("\x1b[33;1m");
Console.Error.Write(EventArgsFormatting.FormatEventMessage(e, showProjectFile: true));
Console.Error.WriteLine("\x1b[m");
}

public void Initialize(IEventSource eventSource)
{
Initialize(eventSource, 1);
}

public void Shutdown()
{
}
}
}
1 change: 1 addition & 0 deletions src/Build/Microsoft.Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@
<Compile Include="Logging\ParallelLogger\ParallelConsoleLogger.cs">
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
</Compile>
<Compile Include="Logging\SimpleErrorLogger.cs" />
<Compile Include="Logging\ParallelLogger\ConsoleOutputAligner.cs" />
<Compile Include="Logging\FileLogger.cs">
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
Expand Down
58 changes: 58 additions & 0 deletions src/MSBuild.UnitTests/CommandLineSwitches_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Graph;
using Microsoft.Build.Logging;
using Microsoft.Build.Shared;
using Shouldly;
using Xunit;
Expand Down Expand Up @@ -499,6 +500,60 @@ public void PreprocessSwitchIdentificationTests(string preprocess)
unquoteParameters.ShouldBeTrue();
}

[Fact]
public void GetPropertySwitchIdentificationTest()
{
CommandLineSwitches.IsParameterizedSwitch(
"getProperty",
out CommandLineSwitches.ParameterizedSwitch parameterizedSwitch,
out string duplicateSwitchErrorMessage,
out bool multipleParametersAllowed,
out string missingParametersErrorMessage,
out _,
out _);

parameterizedSwitch.ShouldBe(CommandLineSwitches.ParameterizedSwitch.GetProperty);
duplicateSwitchErrorMessage.ShouldBeNull();
multipleParametersAllowed.ShouldBeTrue();
missingParametersErrorMessage.ShouldNotBeNullOrEmpty();
}

[Fact]
public void GetItemSwitchIdentificationTest()
{
CommandLineSwitches.IsParameterizedSwitch(
"getItem",
out CommandLineSwitches.ParameterizedSwitch parameterizedSwitch,
out string duplicateSwitchErrorMessage,
out bool multipleParametersAllowed,
out string missingParametersErrorMessage,
out _,
out _);

parameterizedSwitch.ShouldBe(CommandLineSwitches.ParameterizedSwitch.GetItem);
duplicateSwitchErrorMessage.ShouldBeNull();
multipleParametersAllowed.ShouldBeTrue();
missingParametersErrorMessage.ShouldNotBeNullOrEmpty();
}

[Fact]
public void GetTargetResultSwitchIdentificationTest()
{
CommandLineSwitches.IsParameterizedSwitch(
"getTargetResult",
out CommandLineSwitches.ParameterizedSwitch parameterizedSwitch,
out string duplicateSwitchErrorMessage,
out bool multipleParametersAllowed,
out string missingParametersErrorMessage,
out _,
out _);

parameterizedSwitch.ShouldBe(CommandLineSwitches.ParameterizedSwitch.GetTargetResult);
duplicateSwitchErrorMessage.ShouldBeNull();
multipleParametersAllowed.ShouldBeTrue();
missingParametersErrorMessage.ShouldNotBeNullOrEmpty();
}

[Theory]
[InlineData("targets")]
[InlineData("tArGeTs")]
Expand Down Expand Up @@ -1042,6 +1097,7 @@ public void InvalidToolsVersionErrors()
filename = FileUtilities.GetTemporaryFileName();
ProjectRootElement project = ProjectRootElement.Create();
project.Save(filename);
BuildResult buildResult = null;
MSBuildApp.BuildProject(
filename,
null,
Expand Down Expand Up @@ -1073,6 +1129,8 @@ public void InvalidToolsVersionErrors()
question: false,
inputResultsCaches: null,
outputResultsCache: null,
saveProjectResult: false,
ref buildResult,
#if FEATURE_REPORTFILEACCESSES
reportFileAccesses: false,
#endif
Expand Down
73 changes: 73 additions & 0 deletions src/MSBuild.UnitTests/XMake_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ public void InvalidVerbosity()
MSBuildApp.ProcessVerbositySwitch("loquacious");
});
}

[Fact]
public void ValidMaxCPUCountSwitch()
{
Expand Down Expand Up @@ -617,6 +618,78 @@ public void InvalidMaxCPUCountSwitch4()
});
}

[Theory]
[InlineData("-getProperty:Foo;Bar", true, "EvalValue", false, false, false, true)]
[InlineData("-getProperty:Foo;Bar -t:Build", true, "TargetValue", false, false, false, true)]
[InlineData("-getItem:MyItem", false, "", true, false, false, true)]
[InlineData("-getItem:MyItem -t:Build", false, "", true, true, false, true)]
[InlineData("-getItem:WrongItem -t:Build", false, "", false, false, false, true)]
[InlineData("-getProperty:Foo;Bar -getItem:MyItem -t:Build", true, "TargetValue", true, true, false, true)]
[InlineData("-getProperty:Foo;Bar -getItem:MyItem", true, "EvalValue", true, false, false, true)]
[InlineData("-getProperty:Foo;Bar -getTargetResult:MyTarget", true, "TargetValue", false, false, true, true)]
[InlineData("-getProperty:Foo;Bar", true, "EvalValue", false, false, false, false)]
[InlineData("-getProperty:Foo;Bar -t:Build", true, "TargetValue", false, false, false, false)]
[InlineData("-getItem:MyItem", false, "", true, false, false, false)]
[InlineData("-getItem:MyItem -t:Build", false, "", true, true, false, false)]
[InlineData("-getItem:WrongItem -t:Build", false, "", false, false, false, false)]
[InlineData("-getProperty:Foo;Bar -getItem:MyItem -t:Build", true, "TargetValue", true, true, false, false)]
[InlineData("-getProperty:Foo;Bar -getItem:MyItem", true, "EvalValue", true, false, false, false)]
[InlineData("-getProperty:Foo;Bar -getTargetResult:MyTarget", true, "TargetValue", false, false, true, false)]
public void ExecuteAppWithGetPropertyItemAndTargetResult(
string extraSwitch,
bool fooPresent,
string fooResult,
bool itemIncludesAlwaysThere,
bool itemIncludesTargetItem,
bool targetResultPresent,
bool isGraphBuild)
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFile project = env.CreateFile("testProject.csproj", @"
<Project>
<PropertyGroup>
<Foo>EvalValue</Foo>
<Baz>InnocuousValue</Baz>
</PropertyGroup>
<ItemGroup>
<MyItem Include=""itemAlwaysThere"" Metadatum=""metadatumValue"" />
</ItemGroup>
<Target Name=""MyTarget"" BeforeTargets=""Build"">
<PropertyGroup>
<Foo>TargetValue</Foo>
</PropertyGroup>
<ItemGroup>
<MyItem Include=""targetItem"" Metadato=""OtherMetadatum"" />
</ItemGroup>
</Target>
<Target Name=""Build"">
</Target>
</Project>
");
string graph = isGraphBuild ? "--graph" : "";
string results = RunnerUtilities.ExecMSBuild($" {project.Path} {extraSwitch} {graph}", out bool success);
success.ShouldBeTrue();
if (fooPresent)
{
results.ShouldContain($"\"Foo\": \"{fooResult}\"");
results.ShouldContain("\"Bar\": \"\"");
}

results.ShouldNotContain("InnocuousValue");

results.Contains("itemAlwaysThere").ShouldBe(itemIncludesAlwaysThere);
results.Contains("targetItem").ShouldBe(itemIncludesTargetItem);

results.Contains("MyTarget").ShouldBe(targetResultPresent);
results.Contains("\"Result\": \"Success\"").ShouldBe(targetResultPresent);
}

/// <summary>
/// Regression test for bug where the MSBuild.exe command-line app
/// would sometimes set the UI culture to just "en" which is considered a "neutral" UI
Expand Down
6 changes: 6 additions & 0 deletions src/MSBuild/CommandLineSwitches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ internal enum ParameterizedSwitch
LowPriority,
Question,
DetailedSummary,
GetProperty,
GetItem,
GetTargetResult,
NumberOfParameterizedSwitches,
}

Expand Down Expand Up @@ -274,6 +277,9 @@ internal ParameterizedSwitchInfo(
new ParameterizedSwitchInfo( new string[] { "lowpriority", "low" }, ParameterizedSwitch.LowPriority, null, false, null, true, false),
new ParameterizedSwitchInfo( new string[] { "question", "q" }, ParameterizedSwitch.Question, null, false, null, true, false),
new ParameterizedSwitchInfo( new string[] { "detailedsummary", "ds" }, ParameterizedSwitch.DetailedSummary, null, false, null, true, false),
new ParameterizedSwitchInfo( new string[] { "getProperty" }, ParameterizedSwitch.GetProperty, null, true, "MissingGetPropertyError", true, false),
new ParameterizedSwitchInfo( new string[] { "getItem" }, ParameterizedSwitch.GetItem, null, true, "MissingGetItemError", true, false),
new ParameterizedSwitchInfo( new string[] { "getTargetResult" }, ParameterizedSwitch.GetTargetResult, null, true, "MissingGetTargetResultError", true, false),
};

/// <summary>
Expand Down
Loading

0 comments on commit ba4f2fe

Please sign in to comment.