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

TL: Fix logs appearance from nuget client/credential provider #9407

Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
]9;4;3;\[?25l
[?25h
Build succeeded in 0.0s
]9;4;0;\
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[?25l
[?25h
Build succeeded in 0.0s
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
]9;4;3;\[?25l
[?25h
Build succeeded in 0.0s
]9;4;0;\
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
]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`
[?25l
[?25h
Build succeeded in 0.0s
]9;4;0;\
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
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`
[?25l
[?25h
Build succeeded in 0.0s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
]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`
[?25l
[?25h
Build succeeded in 0.0s
]9;4;0;\
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
]9;4;3;\directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
project succeeded with warnings (0.0s)
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
[?25l
[?25h
Build succeeded with warnings in 0.0s
]9;4;0;\
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
project succeeded with warnings (0.0s)
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
[?25l
[?25h
Build succeeded with warnings in 0.0s
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
]9;4;3;\directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
project succeeded with warnings (0.0s)
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]DeviceFlow: https://testfeed/index.json
directory/file(1,2,3,4): warning AA0000: [CredentialProvider]ATTENTION: User interaction required.**********************************************************************To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate.**********************************************************************
[?25l
[?25h
Build succeeded with warnings in 0.0s
]9;4;0;\
49 changes: 49 additions & 0 deletions src/MSBuild.UnitTests/TerminalLogger_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ private BuildWarningEventArgs MakeWarningEventArgs(string warning)
};
}

private BuildMessageEventArgs MakeMessageEventArgs(string message)
{
return new BuildMessageEventArgs(message, "keyword", null, MessageImportance.High)
{
BuildEventContext = MakeBuildEventContext(),
};
}

private BuildErrorEventArgs MakeErrorEventArgs(string error)
{
return new BuildErrorEventArgs("", "AA0000", "directory/file", 1, 2, 3, 4, error, null, null)
Expand Down Expand Up @@ -229,6 +237,47 @@ public Task PrintBuildSummary_SucceededWithWarnings()
return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
}

[Fact]
public Task PrintImmediateWarningMessage_Succeeded()
{
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
{
WarningRaised?.Invoke(_eventSender, MakeWarningEventArgs("[CredentialProvider]DeviceFlow: https://testfeed/index.json"));
WarningRaised?.Invoke(_eventSender, MakeWarningEventArgs(
"[CredentialProvider]ATTENTION: User interaction required." +
"**********************************************************************" +
"To sign in, use a web browser to open the page https://devicelogin and enter the code XXXXXX to authenticate." +
"**********************************************************************"));
});

return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
}

[Fact]
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`"));
});

return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
}

[Fact]
public Task PrintImmediateMessage_Skipped()
{
InvokeLoggerCallbacksForSimpleProject(succeeded: true, () =>
{
MessageRaised?.Invoke(_eventSender, MakeMessageEventArgs("--anycustomarg"));
});

return Verify(_outputWriter.ToString(), _settings).UniqueForOSPlatform();
}

[Fact]
public Task PrintBuildSummary_Failed()
{
Expand Down
59 changes: 56 additions & 3 deletions src/MSBuild/TerminalLogger/TerminalLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using System.Text.RegularExpressions;
#if NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif
#if NETFRAMEWORK
using Microsoft.IO;
#else
Expand All @@ -23,8 +27,26 @@ namespace Microsoft.Build.Logging.TerminalLogger;
/// <remarks>
/// Uses ANSI/VT100 control codes to erase and overwrite lines as the build is progressing.
/// </remarks>
internal sealed class TerminalLogger : INodeLogger
internal sealed partial class TerminalLogger : INodeLogger
{
private const string FilePathPattern = " -> ";

#if NET7_0_OR_GREATER
[StringSyntax(StringSyntaxAttribute.Regex)]
#endif
private const string ImmediateMessagePattern = @"\[CredentialProvider\]|--interactive";

private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture;

#if NET7_0_OR_GREATER
[GeneratedRegex(ImmediateMessagePattern, Options)]
private static partial Regex ImmediateMessageRegex();
#else
private static Regex ImmediateMessageRegex() => immediateMessageRegex;

private static readonly Regex immediateMessageRegex = new(ImmediateMessagePattern, RegexOptions.Compiled | Options);
YuliiaKovalova marked this conversation as resolved.
Show resolved Hide resolved
#endif

/// <summary>
/// A wrapper over the project context ID passed to us in <see cref="IEventSource"/> logger events.
/// </summary>
Expand Down Expand Up @@ -549,7 +571,7 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
{
// Detect project output path by matching high-importance messages against the "$(MSBuildProjectName) -> ..."
// pattern used by the CopyFilesToOutputDirectory target.
int index = message.IndexOf(" -> ", StringComparison.Ordinal);
int index = message.IndexOf(FilePathPattern, StringComparison.Ordinal);
if (index > 0)
{
var projectFileName = Path.GetFileName(e.ProjectFile.AsSpan());
Expand All @@ -561,6 +583,11 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
project.OutputPath = outputPath;
}
}

if (IsImmediateMessage(message))
{
RenderImmediateMessage(message);
}
}
}

Expand All @@ -586,10 +613,21 @@ private void WarningRaised(object sender, BuildWarningEventArgs e)
threadId: e.ThreadId,
logOutputProperties: null);

if (IsImmediateMessage(message))
{
RenderImmediateMessage(message);
}
project.AddBuildMessage(MessageSeverity.Warning, message);
YuliiaKovalova marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// <summary>
/// Detect markers that require special attention from a customer.
/// </summary>
/// <param name="message">Raised event.</param>
/// <returns>true if marker is detected.</returns>
private bool IsImmediateMessage(string message) => ImmediateMessageRegex().IsMatch(message);

/// <summary>
/// The <see cref="IEventSource.ErrorRaised"/> callback.
/// </summary>
Expand Down Expand Up @@ -848,6 +886,21 @@ private string RenderBuildResult(bool succeeded, bool hasError, bool hasWarning)
}
}

/// <summary>
/// Print a build messages to the output that require special customer's attention.
/// </summary>
/// <param name="message">Build message needed to be shown immediately.</param>
private void RenderImmediateMessage(string message)
{
lock (_lock)
{
// Calling erase helps to clear the screen before printing the message
// The immediate output will not overlap with node status reporting
EraseNodes();
Terminal.WriteLine(message);
}
}

/// <summary>
/// Returns the <see cref="_nodes"/> index corresponding to the given <see cref="BuildEventContext"/>.
/// </summary>
Expand Down