diff --git a/src/Build/Logging/BaseConsoleLogger.cs b/src/Build/Logging/BaseConsoleLogger.cs
index 96942d03d55..7dc448e6fb5 100644
--- a/src/Build/Logging/BaseConsoleLogger.cs
+++ b/src/Build/Logging/BaseConsoleLogger.cs
@@ -12,6 +12,7 @@
using System.Threading;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
+using Microsoft.Build.Framework.Logging;
using Microsoft.Build.Internal;
using Microsoft.Build.Shared;
using ColorResetter = Microsoft.Build.Logging.ColorResetter;
@@ -75,20 +76,9 @@ internal abstract class BaseConsoleLogger : INodeLogger, IStringBuilderProvider
///
public void ParseParameters()
{
- if (Parameters == null)
+ foreach (var parameter in LoggerParametersHelper.ParseParameters(Parameters))
{
- return;
- }
-
- foreach (string parameter in Parameters.Split(parameterDelimiters))
- {
- if (string.IsNullOrWhiteSpace(parameter))
- {
- continue;
- }
-
- string[] parameterAndValue = parameter.Split(s_parameterValueSplitCharacter);
- ApplyParameter(parameterAndValue[0], parameterAndValue.Length > 1 ? parameterAndValue[1] : null);
+ ApplyParameter(parameter.Item1, parameter.Item2);
}
}
@@ -1038,33 +1028,17 @@ internal virtual bool ApplyParameter(string parameterName, string parameterValue
///
private bool ApplyVerbosityParameter(string parameterValue)
{
- switch (parameterValue.ToUpperInvariant())
+ if (LoggerParametersHelper.TryParseVerbosityParameter(parameterValue, out LoggerVerbosity? verbosity))
{
- case "Q":
- case "QUIET":
- Verbosity = LoggerVerbosity.Quiet;
- return true;
- case "M":
- case "MINIMAL":
- Verbosity = LoggerVerbosity.Minimal;
- return true;
- case "N":
- case "NORMAL":
- Verbosity = LoggerVerbosity.Normal;
- return true;
- case "D":
- case "DETAILED":
- Verbosity = LoggerVerbosity.Detailed;
- return true;
- case "DIAG":
- case "DIAGNOSTIC":
- Verbosity = LoggerVerbosity.Diagnostic;
- return true;
- default:
- string errorCode;
- string helpKeyword;
- string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(out errorCode, out helpKeyword, "InvalidVerbosity", parameterValue);
- throw new LoggerException(message, null, errorCode, helpKeyword);
+ Verbosity = (LoggerVerbosity)verbosity;
+ return true;
+ }
+ else
+ {
+ string errorCode;
+ string helpKeyword;
+ string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(out errorCode, out helpKeyword, "InvalidVerbosity", parameterValue);
+ throw new LoggerException(message, null, errorCode, helpKeyword);
}
}
@@ -1135,16 +1109,6 @@ private bool ApplyVerbosityParameter(string parameterValue)
internal const string projectSeparatorLine =
"__________________________________________________";
- ///
- /// Console logger parameters delimiters.
- ///
- internal static readonly char[] parameterDelimiters = MSBuildConstants.SemicolonChar;
-
- ///
- /// Console logger parameter value split character.
- ///
- private static readonly char[] s_parameterValueSplitCharacter = MSBuildConstants.EqualsChar;
-
///
/// When true, accumulate performance numbers.
///
diff --git a/src/Build/Logging/ConsoleLogger.cs b/src/Build/Logging/ConsoleLogger.cs
index 35886babcca..41bfaf94f50 100644
--- a/src/Build/Logging/ConsoleLogger.cs
+++ b/src/Build/Logging/ConsoleLogger.cs
@@ -4,6 +4,7 @@
using System;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Framework;
+using Microsoft.Build.Framework.Logging;
using Microsoft.Build.Framework.Telemetry;
using Microsoft.Build.Shared;
using BaseConsoleLogger = Microsoft.Build.BackEnd.Logging.BaseConsoleLogger;
@@ -113,7 +114,7 @@ private void InitializeBaseConsoleLogger()
bool preferConsoleColor = false;
if (!string.IsNullOrEmpty(_parameters))
{
- string[] parameterComponents = _parameters.Split(BaseConsoleLogger.parameterDelimiters);
+ string[] parameterComponents = _parameters.Split(LoggerParametersHelper.s_parameterDelimiters);
foreach (string param in parameterComponents)
{
if (param.Length <= 0)
diff --git a/src/Framework/Logging/LoggerParametersHelper.cs b/src/Framework/Logging/LoggerParametersHelper.cs
new file mode 100644
index 00000000000..b4f7a843d4f
--- /dev/null
+++ b/src/Framework/Logging/LoggerParametersHelper.cs
@@ -0,0 +1,69 @@
+// 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 System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Build.Shared;
+
+namespace Microsoft.Build.Framework.Logging
+{
+ internal static class LoggerParametersHelper
+ {
+ // Logger parameters delimiters.
+ public static readonly char[] s_parameterDelimiters = MSBuildConstants.SemicolonChar;
+
+ // Logger parameter value split character.
+ public static readonly char[] s_parameterValueSplitCharacter = MSBuildConstants.EqualsChar;
+
+ public static bool TryParseVerbosityParameter(string parameterValue, [NotNullWhen(true)] out LoggerVerbosity? verbosity)
+ {
+ switch (parameterValue.ToUpperInvariant())
+ {
+ case "Q":
+ case "QUIET":
+ verbosity = LoggerVerbosity.Quiet;
+ return true;
+ case "M":
+ case "MINIMAL":
+ verbosity = LoggerVerbosity.Minimal;
+ return true;
+ case "N":
+ case "NORMAL":
+ verbosity = LoggerVerbosity.Normal;
+ return true;
+ case "D":
+ case "DETAILED":
+ verbosity = LoggerVerbosity.Detailed;
+ return true;
+ case "DIAG":
+ case "DIAGNOSTIC":
+ verbosity = LoggerVerbosity.Diagnostic;
+ return true;
+ default:
+ verbosity = null;
+ return false;
+ }
+ }
+
+ public static IEnumerable> ParseParameters(string? parametersString)
+ {
+ if (parametersString is not null)
+ {
+ foreach (string parameter in parametersString.Split(s_parameterDelimiters))
+ {
+ if (string.IsNullOrWhiteSpace(parameter))
+ {
+ continue;
+ }
+
+ string[] parameterAndValue = parameter.Split(s_parameterValueSplitCharacter);
+ yield return new Tuple(parameterAndValue[0], parameterAndValue.Length > 1 ? parameterAndValue[1] : null);
+ }
+ }
+ }
+ }
+}
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..94c8f8666eb
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,8 @@
+The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDetailedVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..94c8f8666eb
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,8 @@
+The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..c0b5f816a67
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,8 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..f2c3daca5c7
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,7 @@
+The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..c0b5f816a67
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryMinimalVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,8 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..c0b5f816a67
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,8 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..f2c3daca5c7
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,7 @@
+The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..c0b5f816a67
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryNormalVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,8 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..ed7d3ade9de
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,3 @@
+]9;4;3;\directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..b52d4bf957f
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,2 @@
+directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..ed7d3ade9de
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintBuildSummaryQuietVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,3 @@
+]9;4;3;\directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Linux.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Linux.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.OSX.verified.txt
new file mode 100644
index 00000000000..94c8f8666eb
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.OSX.verified.txt
@@ -0,0 +1,8 @@
+The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Windows.verified.txt
new file mode 100644
index 00000000000..2a011fd87a4
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithOverwrittenVerbosity_FailedWithErrors.Windows.verified.txt
@@ -0,0 +1,9 @@
+]9;4;3;\The plugin credential provider could not acquire credentials.Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
+ project [31;1mfailed with 1 error(s) and 1 warning(s)[m (0.2s)
+ High importance message!
+ directory/[1mfile[m(1,2,3,4): [33;1mwarning[m [33;1mAA0000[m: Warning!
+ directory/[1mfile[m(1,2,3,4): [31;1merror[m [31;1mAA0000[m: Error!
+[?25l[1F
+[?25h
+Build [31;1mfailed with 1 error(s) and 1 warning(s)[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Linux.verified.txt
new file mode 100644
index 00000000000..ea19717537f
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Linux.verified.txt
@@ -0,0 +1,6 @@
+]9;4;3;\ project [32;1msucceeded[m (0.2s)
+ Task Command Line.
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.OSX.verified.txt
new file mode 100644
index 00000000000..809a4f0a0eb
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.OSX.verified.txt
@@ -0,0 +1,5 @@
+ project [32;1msucceeded[m (0.2s)
+ Task Command Line.
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Windows.verified.txt
new file mode 100644
index 00000000000..ea19717537f
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithTaskCommandLineEventArgs_Succeeded.Windows.verified.txt
@@ -0,0 +1,6 @@
+]9;4;3;\ project [32;1msucceeded[m (0.2s)
+ Task Command Line.
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Linux.verified.txt
new file mode 100644
index 00000000000..d5e6b72e894
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Linux.verified.txt
@@ -0,0 +1,4 @@
+]9;4;3;\[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.OSX.verified.txt
new file mode 100644
index 00000000000..4d414bf90bf
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.OSX.verified.txt
@@ -0,0 +1,3 @@
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Windows.verified.txt
new file mode 100644
index 00000000000..d5e6b72e894
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded.Windows.verified.txt
@@ -0,0 +1,4 @@
+]9;4;3;\[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Linux.verified.txt
new file mode 100644
index 00000000000..34897dfd415
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Linux.verified.txt
@@ -0,0 +1,6 @@
+]9;4;3;\ project test [32;1msucceeded[m (0.2s)
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+Test run [31;1mfailed[m. Total: 10 Failed: 1 Passed: 7 Skipped: 2, Duration: 1.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.OSX.verified.txt
new file mode 100644
index 00000000000..6615c0644e7
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.OSX.verified.txt
@@ -0,0 +1,5 @@
+ project test [32;1msucceeded[m (0.2s)
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+Test run [31;1mfailed[m. Total: 10 Failed: 1 Passed: 7 Skipped: 2, Duration: 1.0s
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Windows.verified.txt
new file mode 100644
index 00000000000..34897dfd415
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryNormalVerbosity_Succeeded.Windows.verified.txt
@@ -0,0 +1,6 @@
+]9;4;3;\ project test [32;1msucceeded[m (0.2s)
+[?25l[1F
+[?25h
+Build [32;1msucceeded[m in 5.0s
+Test run [31;1mfailed[m. Total: 10 Failed: 1 Passed: 7 Skipped: 2, Duration: 1.0s
+]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Linux.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Linux.verified.txt
new file mode 100644
index 00000000000..1631c824d25
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Linux.verified.txt
@@ -0,0 +1 @@
+]9;4;3;\]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.OSX.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.OSX.verified.txt
new file mode 100644
index 00000000000..c1b8d743e34
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.OSX.verified.txt
@@ -0,0 +1 @@
+emptyString
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Windows.verified.txt b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Windows.verified.txt
new file mode 100644
index 00000000000..1631c824d25
--- /dev/null
+++ b/src/MSBuild.UnitTests/Snapshots/TerminalLogger_Tests.PrintTestSummaryQuietVerbosity_Succeeded.Windows.verified.txt
@@ -0,0 +1 @@
+]9;4;3;\]9;4;0;\
\ No newline at end of file
diff --git a/src/MSBuild.UnitTests/TerminalLogger_Tests.cs b/src/MSBuild.UnitTests/TerminalLogger_Tests.cs
index d983a3a5596..955610abad2 100644
--- a/src/MSBuild.UnitTests/TerminalLogger_Tests.cs
+++ b/src/MSBuild.UnitTests/TerminalLogger_Tests.cs
@@ -30,6 +30,12 @@ public class TerminalLogger_Tests : IEventSource, IDisposable
{
private const int _nodeCount = 8;
private const string _eventSender = "Test";
+
+ private const string _immediateMessageString =
+ "The plugin credential provider could not acquire credentials." +
+ "Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, " +
+ "/p:NuGetInteractive=\"true\" for MSBuild or removing the -NonInteractive switch for `NuGet`";
+
private readonly string _projectFile = NativeMethods.IsUnixLike ? "/src/project.proj" : @"C:\src\project.proj";
private readonly string _projectFile2 = NativeMethods.IsUnixLike ? "/src/project2.proj" : @"C:\src\project2.proj";
@@ -39,8 +45,11 @@ public class TerminalLogger_Tests : IEventSource, IDisposable
private readonly TerminalLogger _terminallogger;
private readonly DateTime _buildStartTime = new DateTime(2023, 3, 30, 16, 30, 0);
+ private readonly DateTime _targetStartTime = new DateTime(2023, 3, 30, 16, 30, 1);
+ private readonly DateTime _messageTime = new DateTime(2023, 3, 30, 16, 30, 2);
private readonly DateTime _buildFinishTime = new DateTime(2023, 3, 30, 16, 30, 5);
+
private VerifySettings _settings = new();
private readonly CultureInfo _originalCulture = Thread.CurrentThread.CurrentCulture;
@@ -139,7 +148,7 @@ private ProjectFinishedEventArgs MakeProjectFinishedEventArgs(string projectFile
private TargetStartedEventArgs MakeTargetStartedEventArgs(string projectFile, string targetName)
{
- return new TargetStartedEventArgs("", "", targetName, projectFile, targetFile: projectFile)
+ return new TargetStartedEventArgs("", "", targetName, projectFile, targetFile: projectFile, String.Empty, TargetBuiltReason.None, _targetStartTime)
{
BuildEventContext = MakeBuildEventContext(),
};
@@ -177,14 +186,31 @@ private BuildWarningEventArgs MakeWarningEventArgs(string warning)
};
}
- private BuildMessageEventArgs MakeMessageEventArgs(string message)
+ private BuildMessageEventArgs MakeMessageEventArgs(string message, MessageImportance importance)
+ {
+ return new BuildMessageEventArgs(message, "keyword", null, importance)
+ {
+ BuildEventContext = MakeBuildEventContext(),
+ };
+ }
+
+ private BuildMessageEventArgs MakeTaskCommandLineEventArgs(string message, MessageImportance importance)
{
- return new BuildMessageEventArgs(message, "keyword", null, MessageImportance.High)
+ return new TaskCommandLineEventArgs(message, "Task", importance)
{
BuildEventContext = MakeBuildEventContext(),
};
}
+ private BuildMessageEventArgs MakeExtendedMessageEventArgs(string message, MessageImportance importance, string extendedType, Dictionary? extendedMetadata)
+ {
+ return new ExtendedBuildMessageEventArgs(extendedType, message, "keyword", null, importance, _messageTime)
+ {
+ BuildEventContext = MakeBuildEventContext(),
+ ExtendedMetadata = extendedMetadata
+ };
+ }
+
private BuildErrorEventArgs MakeErrorEventArgs(string error)
{
return new BuildErrorEventArgs("", "AA0000", "directory/file", 1, 2, 3, 4, error, null, null)
@@ -214,6 +240,24 @@ private void InvokeLoggerCallbacksForSimpleProject(bool succeeded, Action additi
BuildFinished?.Invoke(_eventSender, MakeBuildFinishedEventArgs(succeeded));
}
+ private void InvokeLoggerCallbacksForTestProject(bool succeeded, Action additionalCallbacks)
+ {
+ BuildStarted?.Invoke(_eventSender, MakeBuildStartedEventArgs());
+ ProjectStarted?.Invoke(_eventSender, MakeProjectStartedEventArgs(_projectFile));
+
+ TargetStarted?.Invoke(_eventSender, MakeTargetStartedEventArgs(_projectFile, "_TestRunStart"));
+ TaskStarted?.Invoke(_eventSender, MakeTaskStartedEventArgs(_projectFile, "Task"));
+
+ additionalCallbacks();
+
+ TaskFinished?.Invoke(_eventSender, MakeTaskFinishedEventArgs(_projectFile, "Task", succeeded));
+ TargetFinished?.Invoke(_eventSender, MakeTargetFinishedEventArgs(_projectFile, "_TestRunStart", succeeded));
+
+ ProjectFinished?.Invoke(_eventSender, MakeProjectFinishedEventArgs(_projectFile, succeeded));
+
+ BuildFinished?.Invoke(_eventSender, MakeBuildFinishedEventArgs(succeeded));
+ }
+
private void InvokeLoggerCallbacksForTwoProjects(bool succeeded, Action additionalCallbacks, Action additionalCallbacks2)
{
BuildStarted?.Invoke(_eventSender, MakeBuildStartedEventArgs());
@@ -281,10 +325,7 @@ public Task PrintImmediateMessage_Success()
{
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
{
- MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs(
- "The plugin credential provider could not acquire credentials." +
- "Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, " +
- "/p:NuGetInteractive=\"true\" for MSBuild or removing the -NonInteractive switch for `NuGet`"));
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs(_immediateMessageString, MessageImportance.High));
});
return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
@@ -295,7 +336,7 @@ public Task PrintImmediateMessage_Skipped()
{
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
{
- MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("--anycustomarg"));
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("--anycustomarg", MessageImportance.High));
});
return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
@@ -388,6 +429,142 @@ public Task PrintBuildSummary_2Projects_FailedWithErrorsAndWarnings()
#endregion
+ private void CallAllTypesOfMessagesWarningAndError()
+ {
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs(_immediateMessageString, MessageImportance.High));
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("High importance message!", MessageImportance.High));
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("Normal importance message!", MessageImportance.Normal));
+ MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("Low importance message!", MessageImportance.Low));
+ WarningRaised?.Invoke(_eventSender, MakeWarningEventArgs("Warning!"));
+ ErrorRaised?.Invoke(_eventSender, MakeErrorEventArgs("Error!"));
+ }
+
+ private void CallAllTypesOfTestMessages()
+ {
+ MessageRaised?.Invoke(_eventSender, MakeExtendedMessageEventArgs(
+ "Test passed.",
+ MessageImportance.High,
+ "TLTESTPASSED",
+ new Dictionary() { { "displayName", "testName1" }, { "localizedResult", "passed" } }));
+ MessageRaised?.Invoke(_eventSender, MakeExtendedMessageEventArgs(
+ "Test skipped.",
+ MessageImportance.High,
+ "TLTESTSKIPPED",
+ new Dictionary() { { "displayName", "testName2" }, { "localizedResult", "skipped" } }));
+ MessageRaised?.Invoke(_eventSender, MakeExtendedMessageEventArgs(
+ "Test results.",
+ MessageImportance.High,
+ "TLTESTFINISH",
+ new Dictionary() { { "total", "10" }, { "passed", "7" }, { "skipped", "2" }, { "failed", "1" } }));
+ }
+
+ [Fact]
+ public Task PrintBuildSummaryQuietVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Quiet;
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+
+ [Fact]
+ public Task PrintBuildSummaryMinimalVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Minimal;
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintBuildSummaryNormalVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Normal;
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintBuildSummaryDetailedVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Detailed;
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+
+ [Fact]
+ public Task PrintBuildSummaryDiagnosticVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Diagnostic;
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintTestSummaryNormalVerbosity_Succeeded()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Normal;
+ InvokeLoggerCallbacksForTestProject(succeeded: true, CallAllTypesOfTestMessages);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintTestSummaryQuietVerbosity_Succeeded()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Quiet;
+ InvokeLoggerCallbacksForTestProject(succeeded: true, CallAllTypesOfTestMessages);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintSummaryWithOverwrittenVerbosity_FailedWithErrors()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Minimal;
+ _terminallogger.Parameters = "v=diag";
+ _terminallogger.ParseParameters();
+
+ InvokeLoggerCallbacksForSimpleProject(succeeded: false, CallAllTypesOfMessagesWarningAndError);
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintSummaryWithTaskCommandLineEventArgs_Succeeded()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Detailed;
+ _terminallogger.Parameters = "SHOWCOMMANDLINE=on";
+ _terminallogger.ParseParameters();
+
+ InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
+ {
+ MessageRaised?.Invoke(_eventSender, MakeTaskCommandLineEventArgs("Task Command Line.", MessageImportance.High));
+ });
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
+ [Fact]
+ public Task PrintSummaryWithoutTaskCommandLineEventArgs_Succeeded()
+ {
+ _terminallogger.Verbosity = LoggerVerbosity.Detailed;
+ _terminallogger.Parameters = "SHOWCOMMANDLINE=off";
+ _terminallogger.ParseParameters();
+
+ InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
+ {
+ MessageRaised?.Invoke(_eventSender, MakeTaskCommandLineEventArgs("Task Command Line.", MessageImportance.High));
+ });
+
+ return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
+ }
+
[Fact]
public void DisplayNodesShowsCurrent()
{
diff --git a/src/MSBuild/MSBuild.csproj b/src/MSBuild/MSBuild.csproj
index 0415842c6b7..f396ca22cfe 100644
--- a/src/MSBuild/MSBuild.csproj
+++ b/src/MSBuild/MSBuild.csproj
@@ -128,6 +128,7 @@
+
diff --git a/src/MSBuild/TerminalLogger/MessageSeverity.cs b/src/MSBuild/TerminalLogger/MessageSeverity.cs
index 07aa9058be3..9f374e292dd 100644
--- a/src/MSBuild/TerminalLogger/MessageSeverity.cs
+++ b/src/MSBuild/TerminalLogger/MessageSeverity.cs
@@ -6,4 +6,4 @@ namespace Microsoft.Build.Logging.TerminalLogger;
///
/// Enumerates the supported message severities.
///
-internal enum MessageSeverity { Warning, Error }
+internal enum MessageSeverity { Message, Warning, Error }
diff --git a/src/MSBuild/TerminalLogger/TerminalLogger.cs b/src/MSBuild/TerminalLogger/TerminalLogger.cs
index 8cc93b0b588..dd13fbe28aa 100644
--- a/src/MSBuild/TerminalLogger/TerminalLogger.cs
+++ b/src/MSBuild/TerminalLogger/TerminalLogger.cs
@@ -10,10 +10,13 @@
using Microsoft.Build.Shared;
using System.Text.RegularExpressions;
using System.Diagnostics;
+using Microsoft.Build.Framework.Logging;
#if NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+
+
#endif
#if NETFRAMEWORK
using Microsoft.IO;
@@ -197,6 +200,11 @@ public ProjectContext(BuildEventContext context)
///
private DateTime? _testEndTime;
+ ///
+ /// Whether to show TaskCommandLineEventArgs high-priority messages.
+ ///
+ private bool _showCommandLine = false;
+
///
/// Default constructor, used by the MSBuild logger infra.
///
@@ -205,6 +213,12 @@ public TerminalLogger()
Terminal = new Terminal();
}
+ public TerminalLogger(LoggerVerbosity verbosity)
+ : this()
+ {
+ Verbosity = verbosity;
+ }
+
///
/// Internal constructor accepting a custom for testing.
///
@@ -217,13 +231,10 @@ internal TerminalLogger(ITerminal terminal)
#region INodeLogger implementation
///
- public LoggerVerbosity Verbosity { get => LoggerVerbosity.Minimal; set { } }
+ public LoggerVerbosity Verbosity { get; set; } = LoggerVerbosity.Minimal;
///
- public string? Parameters
- {
- get => ""; set { }
- }
+ public string? Parameters { get; set; } = null;
///
public void Initialize(IEventSource eventSource, int nodeCount)
@@ -237,6 +248,8 @@ public void Initialize(IEventSource eventSource, int nodeCount)
///
public void Initialize(IEventSource eventSource)
{
+ ParseParameters();
+
eventSource.BuildStarted += BuildStarted;
eventSource.BuildFinished += BuildFinished;
eventSource.ProjectStarted += ProjectStarted;
@@ -255,6 +268,76 @@ public void Initialize(IEventSource eventSource)
}
}
+ ///
+ /// Parses out the logger parameters from the Parameters string.
+ ///
+ public void ParseParameters()
+ {
+ foreach (var parameter in LoggerParametersHelper.ParseParameters(Parameters))
+ {
+ ApplyParameter(parameter.Item1, parameter.Item2);
+ }
+ }
+
+ ///
+ /// Apply a terminal logger parameter.
+ /// parameterValue may be null, if there is no parameter value.
+ ///
+ ///
+ /// If verbosity parameter value is not correct, throws an exception. Other incorrect parameter values are disregarded.
+ ///
+ private void ApplyParameter(string parameterName, string? parameterValue)
+ {
+ ErrorUtilities.VerifyThrowArgumentNull(parameterName, nameof(parameterName));
+
+ switch (parameterName.ToUpperInvariant())
+ {
+ case "V":
+ case "VERBOSITY":
+ ApplyVerbosityParameter(parameterValue);
+ break;
+ case "SHOWCOMMANDLINE":
+ TryApplyShowCommandLineParameter(parameterValue);
+ break;
+ }
+ }
+
+ ///
+ /// Apply the verbosity value
+ ///
+ private void ApplyVerbosityParameter(string? parameterValue)
+ {
+ if (parameterValue is not null && LoggerParametersHelper.TryParseVerbosityParameter(parameterValue, out LoggerVerbosity? verbosity))
+ {
+ Verbosity = (LoggerVerbosity)verbosity;
+ }
+ else
+ {
+ string errorCode;
+ string helpKeyword;
+ string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(out errorCode, out helpKeyword, "InvalidVerbosity", parameterValue);
+ throw new LoggerException(message, null, errorCode, helpKeyword);
+ }
+ }
+
+ ///
+ /// Apply the show command Line value
+ ///
+ private bool TryApplyShowCommandLineParameter(string? parameterValue)
+ {
+ if (String.IsNullOrEmpty(parameterValue))
+ {
+ _showCommandLine = true;
+ }
+ else
+ {
+ return ConversionUtilities.TryConvertStringToBool(parameterValue, out _showCommandLine);
+ }
+
+ return true;
+ }
+
+
///
public void Shutdown()
{
@@ -299,43 +382,46 @@ private void BuildFinished(object sender, BuildFinishedEventArgs e)
Terminal.BeginUpdate();
try
- {
- string duration = (e.Timestamp - _buildStartTime).TotalSeconds.ToString("F1");
- string buildResult = RenderBuildResult(e.Succeeded, _buildErrorsCount, _buildWarningsCount);
-
- Terminal.WriteLine("");
- if (_restoreFailed)
+ {
+ if (Verbosity > LoggerVerbosity.Quiet)
{
- Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("RestoreCompleteWithMessage",
- buildResult,
- duration));
- }
- else
- {
- Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("BuildFinished",
- buildResult,
- duration));
- }
+ string duration = (e.Timestamp - _buildStartTime).TotalSeconds.ToString("F1");
+ string buildResult = RenderBuildResult(e.Succeeded, _buildErrorsCount, _buildWarningsCount);
- if (_testRunSummaries.Any())
- {
- var total = _testRunSummaries.Sum(t => t.Total);
- var failed = _testRunSummaries.Sum(t => t.Failed);
- var passed = _testRunSummaries.Sum(t => t.Passed);
- var skipped = _testRunSummaries.Sum(t => t.Skipped);
- var testDuration = (_testStartTime != null && _testEndTime != null ? (_testEndTime - _testStartTime).Value.TotalSeconds : 0).ToString("F1");
-
- var colorizedResult = _testRunSummaries.Any(t => t.Failed > 0) || (_buildErrorsCount > 0)
- ? AnsiCodes.Colorize(ResourceUtilities.GetResourceString("BuildResult_Failed"), TerminalColor.Red)
- : AnsiCodes.Colorize(ResourceUtilities.GetResourceString("BuildResult_Succeeded"), TerminalColor.Green);
-
- Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TestSummary",
- colorizedResult,
- total,
- failed,
- passed,
- skipped,
- testDuration));
+ Terminal.WriteLine("");
+ if (_restoreFailed)
+ {
+ Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("RestoreCompleteWithMessage",
+ buildResult,
+ duration));
+ }
+ else
+ {
+ Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("BuildFinished",
+ buildResult,
+ duration));
+ }
+
+ if (_testRunSummaries.Any())
+ {
+ var total = _testRunSummaries.Sum(t => t.Total);
+ var failed = _testRunSummaries.Sum(t => t.Failed);
+ var passed = _testRunSummaries.Sum(t => t.Passed);
+ var skipped = _testRunSummaries.Sum(t => t.Skipped);
+ var testDuration = (_testStartTime != null && _testEndTime != null ? (_testEndTime - _testStartTime).Value.TotalSeconds : 0).ToString("F1");
+
+ var colorizedResult = _testRunSummaries.Any(t => t.Failed > 0) || (_buildErrorsCount > 0)
+ ? AnsiCodes.Colorize(ResourceUtilities.GetResourceString("BuildResult_Failed"), TerminalColor.Red)
+ : AnsiCodes.Colorize(ResourceUtilities.GetResourceString("BuildResult_Succeeded"), TerminalColor.Green);
+
+ Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TestSummary",
+ colorizedResult,
+ total,
+ failed,
+ passed,
+ skipped,
+ testDuration));
+ }
}
}
finally
@@ -404,6 +490,12 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e)
UpdateNodeStatus(buildEventContext, null);
}
+ // Continue execution and add project summary to the static part of the Console only if verbosity is higher than Quiet.
+ if (Verbosity <= LoggerVerbosity.Quiet)
+ {
+ return;
+ }
+
ProjectContext c = new(buildEventContext);
if (_projects.TryGetValue(c, out Project? project))
@@ -650,6 +742,7 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
if (message is not null && e.Importance == MessageImportance.High)
{
var hasProject = _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project);
+
// Detect project output path by matching high-importance messages against the "$(MSBuildProjectName) -> ..."
// pattern used by the CopyFilesToOutputDirectory target.
int index = message.IndexOf(FilePathPattern, StringComparison.Ordinal);
@@ -661,14 +754,31 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
{
ReadOnlyMemory outputPath = e.Message.AsMemory().Slice(index + 4);
project!.OutputPath = outputPath;
+ return;
}
}
- if (IsImmediateMessage(message))
+ if (Verbosity > LoggerVerbosity.Quiet)
{
- RenderImmediateMessage(message);
+ // Show immediate messages to the user.
+ if (IsImmediateMessage(message))
+ {
+ RenderImmediateMessage(message);
+ return;
+ }
+ if (e.Code == "NETSDK1057" && !_loggedPreviewMessage)
+ {
+ // The SDK will log the high-pri "not-a-warning" message NETSDK1057
+ // when it's a preview version up to MaxCPUCount times, but that's
+ // an implementation detail--the user cares about at most one.
+
+ RenderImmediateMessage(message);
+ _loggedPreviewMessage = true;
+ return;
+ }
}
- else if (hasProject && project!.IsTestProject)
+
+ if (hasProject && project!.IsTestProject)
{
var node = _nodes[NodeIndexForContext(buildEventContext)];
@@ -699,30 +809,45 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
case "TLTESTFINISH":
{
- _ = int.TryParse(extendedMessage.ExtendedMetadata!["total"]!, out int total);
- _ = int.TryParse(extendedMessage.ExtendedMetadata!["passed"]!, out int passed);
- _ = int.TryParse(extendedMessage.ExtendedMetadata!["skipped"]!, out int skipped);
- _ = int.TryParse(extendedMessage.ExtendedMetadata!["failed"]!, out int failed);
+ // Collect test run summary.
+ if (Verbosity > LoggerVerbosity.Quiet)
+ {
+ _ = int.TryParse(extendedMessage.ExtendedMetadata!["total"]!, out int total);
+ _ = int.TryParse(extendedMessage.ExtendedMetadata!["passed"]!, out int passed);
+ _ = int.TryParse(extendedMessage.ExtendedMetadata!["skipped"]!, out int skipped);
+ _ = int.TryParse(extendedMessage.ExtendedMetadata!["failed"]!, out int failed);
- _testRunSummaries.Add(new TestSummary(total, passed, skipped, failed));
+ _testRunSummaries.Add(new TestSummary(total, passed, skipped, failed));
- _testEndTime = _testEndTime == null
- ? e.Timestamp
- : e.Timestamp > _testEndTime
- ? e.Timestamp : _testEndTime;
+ _testEndTime = _testEndTime == null
+ ? e.Timestamp
+ : e.Timestamp > _testEndTime
+ ? e.Timestamp : _testEndTime;
+ }
+
break;
}
}
+ return;
}
}
- else if (e.Code == "NETSDK1057" && !_loggedPreviewMessage)
+
+ if (Verbosity > LoggerVerbosity.Normal)
{
- // The SDK will log the high-pri "not-a-warning" message NETSDK1057
- // when it's a preview version up to MaxCPUCount times, but that's
- // an implementation detail--the user cares about at most one.
+ if (e is TaskCommandLineEventArgs && !_showCommandLine)
+ {
+ return;
+ }
- RenderImmediateMessage(message);
- _loggedPreviewMessage = true;
+ if (hasProject)
+ {
+ project!.AddBuildMessage(MessageSeverity.Message, message);
+ }
+ else
+ {
+ // Display messages reported by MSBuild, even if it's not tracked in _projects collection.
+ RenderImmediateMessage(message);
+ }
}
}
}
@@ -744,7 +869,9 @@ private void WarningRaised(object sender, BuildWarningEventArgs e)
columnNumber: e.ColumnNumber,
endColumnNumber: e.EndColumnNumber);
- if (buildEventContext is not null && _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project))
+ if (buildEventContext is not null
+ && _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project)
+ && Verbosity > LoggerVerbosity.Quiet)
{
if (IsImmediateMessage(message))
{
@@ -755,7 +882,7 @@ private void WarningRaised(object sender, BuildWarningEventArgs e)
}
else
{
- // It is necessary to display warning messages reported by MSBuild, even if it's not tracked in _projects collection.
+ // It is necessary to display warning messages reported by MSBuild, even if it's not tracked in _projects collection or the verbosity is Quiet.
RenderImmediateMessage(message);
_buildWarningsCount++;
}
@@ -790,13 +917,15 @@ private void ErrorRaised(object sender, BuildErrorEventArgs e)
columnNumber: e.ColumnNumber,
endColumnNumber: e.EndColumnNumber);
- if (buildEventContext is not null && _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project))
+ if (buildEventContext is not null
+ && _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project)
+ && Verbosity > LoggerVerbosity.Quiet)
{
project.AddBuildMessage(MessageSeverity.Error, message);
}
else
{
- // It is necessary to display error messages reported by MSBuild, even if it's not tracked in _projects collection.
+ // It is necessary to display error messages reported by MSBuild, even if it's not tracked in _projects collection or the verbosity is Quiet.
RenderImmediateMessage(message);
_buildErrorsCount++;
}
diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs
index ad65e97d06c..213b842ae6a 100644
--- a/src/MSBuild/XMake.cs
+++ b/src/MSBuild/XMake.cs
@@ -3757,7 +3757,7 @@ private static ILogger[] ProcessLoggingSwitches(
}
else if (terminalloggerOptIn)
{
- ProcessTerminalLogger(noConsoleLogger, aggregatedTerminalLoggerParameters, distributedLoggerRecords, cpuCount, loggers);
+ ProcessTerminalLogger(noConsoleLogger, aggregatedTerminalLoggerParameters, distributedLoggerRecords, verbosity, cpuCount, loggers);
}
else
{
@@ -3936,13 +3936,14 @@ internal static void ProcessConsoleLoggerSwitch(
private static void ProcessTerminalLogger(bool noConsoleLogger,
string aggregatedLoggerParameters,
List distributedLoggerRecords,
+ LoggerVerbosity verbosity,
int cpuCount,
List loggers)
{
if (!noConsoleLogger)
{
// A central logger will be created for both single proc and multiproc.
- TerminalLogger logger = new TerminalLogger()
+ TerminalLogger logger = new TerminalLogger(verbosity)
{
Parameters = aggregatedLoggerParameters
};