Add flow logger to help with console output parallelism
This commit is contained in:
parent
cd11f71428
commit
d3ab458c6c
|
|
@ -29,6 +29,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- If there are duplicate properties, the properties which are defined later in the order would override the earlier ones -->
|
<!-- If there are duplicate properties, the properties which are defined later in the order would override the earlier ones -->
|
||||||
<RepositoryBuildArguments>$(RepositoryBuildArguments) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration) /p:CommitHash=$(CommitHash)</RepositoryBuildArguments>
|
<RepositoryBuildArguments>$(RepositoryBuildArguments) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration) /p:CommitHash=$(CommitHash)</RepositoryBuildArguments>
|
||||||
|
<RepositoryBuildArguments>$(RepositoryBuildArguments) /noconsolelogger '/l:RepoTasks.FlowLogger,$(MSBuildThisFileDirectory)tasks\bin\publish\RepoTasks.dll;Summary;FlowId=$(RepositoryToBuild)'</RepositoryBuildArguments>
|
||||||
|
|
||||||
<BuildArguments>$(_RepositoryBuildTargets) $(RepositoryBuildArguments)</BuildArguments>
|
<BuildArguments>$(_RepositoryBuildTargets) $(RepositoryBuildArguments)</BuildArguments>
|
||||||
<RepositoryArtifactsRoot>$(BuildRepositoryRoot)artifacts</RepositoryArtifactsRoot>
|
<RepositoryArtifactsRoot>$(BuildRepositoryRoot)artifacts</RepositoryArtifactsRoot>
|
||||||
|
|
@ -91,4 +92,4 @@
|
||||||
|
|
||||||
<Exec Command="$(PinVersionArgs)" />
|
<Exec Command="$(PinVersionArgs)" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Logging;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
internal class DefaultPrefixMessageWriter : IWriter
|
||||||
|
{
|
||||||
|
private readonly string _flowId;
|
||||||
|
|
||||||
|
public DefaultPrefixMessageWriter(WriteHandler write, string flowId)
|
||||||
|
{
|
||||||
|
_flowId = flowId;
|
||||||
|
var prefix = $"{_flowId,-22}| ";
|
||||||
|
WriteHandler = msg => write(prefix + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriteHandler WriteHandler { get; }
|
||||||
|
|
||||||
|
public void OnBuildStarted(BuildStartedEventArgs e)
|
||||||
|
{
|
||||||
|
WriteHandler(e.Message + Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBuildFinished(BuildFinishedEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Logging;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
public class FlowLogger : ConsoleLogger
|
||||||
|
{
|
||||||
|
private static readonly bool IsTeamCity = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TEAMCITY_PROJECT_NAME"));
|
||||||
|
|
||||||
|
private volatile bool _initialized;
|
||||||
|
|
||||||
|
public FlowLogger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(IEventSource eventSource, int nodeCount)
|
||||||
|
{
|
||||||
|
PreInit(eventSource);
|
||||||
|
base.Initialize(eventSource, nodeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(IEventSource eventSource)
|
||||||
|
{
|
||||||
|
PreInit(eventSource);
|
||||||
|
base.Initialize(eventSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PreInit(IEventSource eventSource)
|
||||||
|
{
|
||||||
|
if (_initialized) return;
|
||||||
|
_initialized = true;
|
||||||
|
|
||||||
|
var _flowId = GetFlowId();
|
||||||
|
|
||||||
|
var writer = IsTeamCity
|
||||||
|
? (IWriter)new TeamCityMessageWriter(WriteHandler, _flowId)
|
||||||
|
: new DefaultPrefixMessageWriter(WriteHandler, _flowId);
|
||||||
|
|
||||||
|
WriteHandler = writer.WriteHandler;
|
||||||
|
eventSource.BuildStarted += (o, e) =>
|
||||||
|
{
|
||||||
|
writer.OnBuildStarted(e);
|
||||||
|
};
|
||||||
|
eventSource.BuildFinished += (o, e) =>
|
||||||
|
{
|
||||||
|
writer.OnBuildFinished(e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFlowId()
|
||||||
|
{
|
||||||
|
var parameters = Parameters?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (parameters == null || parameters.Length == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string flowIdParamName = "FlowId=";
|
||||||
|
return parameters
|
||||||
|
.FirstOrDefault(p => p.StartsWith(flowIdParamName, StringComparison.Ordinal))
|
||||||
|
?.Substring(flowIdParamName.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Logging;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
internal interface IWriter
|
||||||
|
{
|
||||||
|
WriteHandler WriteHandler { get; }
|
||||||
|
|
||||||
|
void OnBuildFinished(BuildFinishedEventArgs e);
|
||||||
|
void OnBuildStarted(BuildStartedEventArgs e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Logging;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// See https://confluence.jetbrains.com/display/TCD10/Build+Script+Interaction+with+TeamCity
|
||||||
|
/// </summary>
|
||||||
|
internal class TeamCityMessageWriter : IWriter
|
||||||
|
{
|
||||||
|
private const string MessagePrefix = "##teamcity";
|
||||||
|
private static readonly string EOL = Environment.NewLine;
|
||||||
|
private readonly WriteHandler _write;
|
||||||
|
private readonly string _flowIdAttr;
|
||||||
|
|
||||||
|
public TeamCityMessageWriter(WriteHandler write, string flowId)
|
||||||
|
{
|
||||||
|
_write = write;
|
||||||
|
_flowIdAttr = EscapeTeamCityText(flowId);
|
||||||
|
|
||||||
|
WriteHandler = CreateMessageHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriteHandler WriteHandler { get; }
|
||||||
|
|
||||||
|
public void OnBuildFinished(BuildFinishedEventArgs e)
|
||||||
|
{
|
||||||
|
_write($"##teamcity[blockOpened name='Build {_flowIdAttr}' flowId='{_flowIdAttr}']" + EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBuildStarted(BuildStartedEventArgs e)
|
||||||
|
{
|
||||||
|
_write($"##teamcity[blockClosed name='Build {_flowIdAttr}' flowId='{_flowIdAttr}']" + EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WriteHandler CreateMessageHandler()
|
||||||
|
{
|
||||||
|
var format = "##teamcity[message text='{0}' flowId='" + _flowIdAttr + "']" + EOL;
|
||||||
|
return message =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(message))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.StartsWith(MessagePrefix, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_write(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_write(
|
||||||
|
string.Format(
|
||||||
|
System.Globalization.CultureInfo.InvariantCulture,
|
||||||
|
format,
|
||||||
|
EscapeTeamCityText(message)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EscapeTeamCityText(string txt)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(txt))
|
||||||
|
{
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder(txt.Length);
|
||||||
|
for (var i = 0; i < txt.Length; i++)
|
||||||
|
{
|
||||||
|
var ch = txt[i];
|
||||||
|
switch (ch)
|
||||||
|
{
|
||||||
|
case '\'':
|
||||||
|
case '|':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
sb.Append('|').Append(ch);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
sb.Append("|n");
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
sb.Append("|r");
|
||||||
|
break;
|
||||||
|
case '\u0085':
|
||||||
|
sb.Append("|x");
|
||||||
|
break;
|
||||||
|
case '\u2028':
|
||||||
|
sb.Append("|l");
|
||||||
|
break;
|
||||||
|
case '\u2029':
|
||||||
|
sb.Append("|p");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sb.Append(ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue