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

BuildCheck Replay Mode #10224

Merged
merged 44 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
31af242
use AnalyzerLoggingContext instead of LoggingService in BuildCheckAcq…
surayya-MS Jun 11, 2024
bc63e18
include buildCheck unit tests in sln
surayya-MS Jun 11, 2024
e47a8ff
use AnalyzerLoggingContext instead of LoggingService in BuildCheckMan…
surayya-MS Jun 11, 2024
0743775
create IAnalysisContext in order to handle BuildEventContext
surayya-MS Jun 11, 2024
fc86743
add e2e test for analyze on build replay
surayya-MS Jun 11, 2024
6961d57
implement analyze on binary log replay
surayya-MS Jun 11, 2024
b9f4165
remove old AnalyzerLoggingContext
surayya-MS Jun 11, 2024
6ed4a79
remove Microsoft.Build.Experimental.BuildCheck.Logging
surayya-MS Jun 13, 2024
b732de8
create EventCreatorHelper
surayya-MS Jun 13, 2024
4c08a5e
renamed BuildEventArgsDispatcher file to EventArgsDispatcher accordin…
surayya-MS Jun 13, 2024
0b2e5b5
1. decoupled event handling from BuildCheckConnectorLogger in order t…
surayya-MS Jun 13, 2024
1e2f0bc
use Action<BuildEventArgs> dispatch instead of EventArgsDispatcher in…
surayya-MS Jun 13, 2024
0cf40b1
rename variable
surayya-MS Jun 13, 2024
6feca72
small fix
surayya-MS Jun 13, 2024
ea30fc4
changed the implementation - introduce BuildCheckBinaryLogReplaySourc…
surayya-MS Jun 14, 2024
bce1a44
make BuildCheckBinaryLogReplaySourcerWrapper internal
surayya-MS Jun 17, 2024
6506888
remove BuildCheckBinaryLogReplaySourcerWrapper
surayya-MS Jun 17, 2024
30873a4
use the event source that merges events from the binlog replay and nt…
surayya-MS Jun 18, 2024
24418b3
Revert "use the event source that merges events from the binlog repla…
surayya-MS Jun 18, 2024
50ed0b7
Reapply "use the event source that merges events from the binlog repl…
surayya-MS Jun 18, 2024
624ff6e
simplify the design: pass the EventArgsDispatcher to the AnalysisDisp…
surayya-MS Jun 18, 2024
6e81c3b
implement BuildCheckReplayModeConnector
surayya-MS Jun 19, 2024
40d0e3b
add xml comments
surayya-MS Jun 19, 2024
1e6694e
rename method
surayya-MS Jun 19, 2024
f9fbfab
make BuildManager.EnableBuildCheck internal
surayya-MS Jun 19, 2024
393f8b0
Merge branch 'main' into buildCheck-replay-mode-dispatcher
surayya-MS Jun 20, 2024
6b98451
add check for BC0102 in the test; set same timeout
surayya-MS Jun 20, 2024
878fc88
merge from main
surayya-MS Jun 20, 2024
b8c1714
remove skip from the test
surayya-MS Jun 20, 2024
fd5e4f5
Update src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDi…
surayya-MS Jun 20, 2024
00f9681
Update src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDi…
surayya-MS Jun 20, 2024
eee06cc
Merge branch 'main' into buildCheck-replay-mode-dispatcher
surayya-MS Jun 20, 2024
a5057bc
Update src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandle…
surayya-MS Jun 20, 2024
c3a4786
Update src/Build/BackEnd/Shared/EventsCreatorHelper.cs
surayya-MS Jun 20, 2024
a2cdd88
Update src/Build/BackEnd/Shared/EventsCreatorHelper.cs
surayya-MS Jun 20, 2024
4a7fc21
small fix
surayya-MS Jun 21, 2024
965ad71
add summary for IAnalysisContext
surayya-MS Jun 21, 2024
50c1f78
use VerifyThrowInternalNull instead of VerifyThrowArgumentNull
surayya-MS Jun 21, 2024
0ed4347
compile all BuildCheck\**\*.cs files instead of manually specifying e…
surayya-MS Jun 24, 2024
d1815bd
add doc comment for BuildManager.EnableBuildCheck method
surayya-MS Jun 25, 2024
0f7d161
add skips for e2e flak tests
surayya-MS Jun 26, 2024
5a4e6b0
fix typo in doc comment
surayya-MS Jun 26, 2024
31a4ac3
fix typos + improve doc comment
surayya-MS Jun 26, 2024
8311b11
improve doc comment
surayya-MS Jun 26, 2024
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
12 changes: 9 additions & 3 deletions src/Build/BackEnd/BuildManager/BuildManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
using Microsoft.Build.BackEnd;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.BackEnd.SdkResolution;
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Experimental.BuildCheck.Logging;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Eventing;
using Microsoft.Build.Exceptions;
using Microsoft.Build.Experimental;
using Microsoft.Build.Experimental.BuildCheck;
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Experimental.ProjectCache;
using Microsoft.Build.FileAccesses;
using Microsoft.Build.Framework;
Expand Down Expand Up @@ -2951,6 +2950,13 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e)
});
}

internal void EnableBuildCheck()
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
{
_buildParameters ??= new BuildParameters();

_buildParameters.IsBuildCheckEnabled = true;
}

/// <summary>
/// Creates a logging service around the specified set of loggers.
/// </summary>
Expand Down Expand Up @@ -2999,7 +3005,7 @@ private ILoggingService CreateLoggingService(
verbosity: LoggerVerbosity.Quiet);

ILogger buildCheckLogger =
new BuildCheckConnectorLogger(new AnalyzerLoggingContextFactory(loggingService),
new BuildCheckConnectorLogger(new AnalysisLoggingContextFactory(loggingService),
buildCheckManagerProvider.Instance);

ForwardingLoggerRecord[] forwardingLogger = { new ForwardingLoggerRecord(buildCheckLogger, forwardingLoggerDescription) };
Expand Down
37 changes: 3 additions & 34 deletions src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Build.BackEnd.Shared;
using Microsoft.Build.Framework;
using Microsoft.Build.Framework.Profiler;
using Microsoft.Build.Shared;
Expand Down Expand Up @@ -69,17 +70,8 @@ public void LogCommentFromText(BuildEventContext buildEventContext, MessageImpor
{
if (!OnlyLogCriticalEvents)
{
ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null");
ErrorUtilities.VerifyThrow(message != null, "message was null");
BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs);

BuildMessageEventArgs buildEvent = new BuildMessageEventArgs(
message,
helpKeyword: null,
senderName: "MSBuild",
importance,
DateTime.UtcNow,
messageArgs);
buildEvent.BuildEventContext = buildEventContext;
ProcessLoggingEvent(buildEvent);
}
}
Expand Down Expand Up @@ -136,31 +128,8 @@ public void LogError(BuildEventContext buildEventContext, string subcategoryReso
/// <exception cref="InternalErrorException">Message is null</exception>
public void LogErrorFromText(BuildEventContext buildEventContext, string subcategoryResourceName, string errorCode, string helpKeyword, BuildEventFileInfo file, string message)
{
ErrorUtilities.VerifyThrow(buildEventContext != null, "Must specify the buildEventContext");
ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file.");
ErrorUtilities.VerifyThrow(message != null, "Need error message.");
BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(buildEventContext, subcategoryResourceName, errorCode, helpKeyword, file, message);

string subcategory = null;

if (subcategoryResourceName != null)
{
subcategory = AssemblyResources.GetString(subcategoryResourceName);
}

BuildErrorEventArgs buildEvent =
new BuildErrorEventArgs(
subcategory,
errorCode,
file.File,
file.Line,
file.Column,
file.EndLine,
file.EndColumn,
message,
helpKeyword,
"MSBuild");

buildEvent.BuildEventContext = buildEventContext;
if (buildEvent.ProjectFile == null && buildEventContext.ProjectContextId != BuildEventContext.InvalidProjectContextId)
{
_projectFileMap.TryGetValue(buildEventContext.ProjectContextId, out string projectFile);
Expand Down
4 changes: 2 additions & 2 deletions src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Collections;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Eventing;
using Microsoft.Build.Exceptions;
using Microsoft.Build.Execution;
using Microsoft.Build.Experimental.BuildCheck;
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Framework;
using Microsoft.Build.Internal;
using Microsoft.Build.Shared;
Expand Down Expand Up @@ -1123,7 +1123,7 @@ private async Task<BuildResult> BuildProject()
{
buildCheckManager.StartProjectEvaluation(
BuildCheckDataSource.BuildExecution,
_requestEntry.Request.ParentBuildEventContext,
new AnalysisLoggingContext(_nodeLoggingContext.LoggingService, _requestEntry.Request.ParentBuildEventContext),
_requestEntry.RequestConfiguration.ProjectFullPath);

_requestEntry.RequestConfiguration.LoadProjectIntoConfiguration(
Expand Down
63 changes: 63 additions & 0 deletions src/Build/BackEnd/Shared/EventsCreatorHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

namespace Microsoft.Build.BackEnd.Shared;

internal static class EventsCreatorHelper
{
public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs)
{
ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null");
ErrorUtilities.VerifyThrow(message != null, "message was null");
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

BuildMessageEventArgs buildEvent = new BuildMessageEventArgs(
message,
helpKeyword: null,
senderName: "MSBuild",
importance,
DateTime.UtcNow,
messageArgs);
buildEvent.BuildEventContext = buildEventContext;

return buildEvent;
}

public static BuildErrorEventArgs CreateErrorEventFromText(BuildEventContext buildEventContext, string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message)
{
ErrorUtilities.VerifyThrow(buildEventContext != null, "Must specify the buildEventContext");
ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file.");
ErrorUtilities.VerifyThrow(message != null, "Need error message.");
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

string? subcategory = null;

if (subcategoryResourceName != null)
{
subcategory = AssemblyResources.GetString(subcategoryResourceName);
}

BuildErrorEventArgs buildEvent =
new BuildErrorEventArgs(
subcategory,
errorCode,
file!.File,
file.Line,
file.Column,
file.EndLine,
file.EndColumn,
message,
helpKeyword,
"MSBuild");

buildEvent.BuildEventContext = buildEventContext;

return buildEvent;
}
}
14 changes: 6 additions & 8 deletions src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ namespace Microsoft.Build.Experimental.BuildCheck.Acquisition;

internal class BuildCheckAcquisitionModule : IBuildCheckAcquisitionModule
{
private readonly ILoggingService _loggingService;

internal BuildCheckAcquisitionModule(ILoggingService loggingService) => _loggingService = loggingService;

#if FEATURE_ASSEMBLYLOADCONTEXT
/// <summary>
/// AssemblyContextLoader used to load DLLs outside of msbuild.exe directory.
Expand All @@ -29,7 +25,9 @@ internal class BuildCheckAcquisitionModule : IBuildCheckAcquisitionModule
/// <summary>
/// Creates a list of factory delegates for building analyzer rules instances from a given assembly path.
/// </summary>
public List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, BuildEventContext buildEventContext)
public List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(
AnalyzerAcquisitionData analyzerAcquisitionData,
IAnalysisContext analysisContext)
{
var analyzersFactories = new List<BuildAnalyzerFactory>();

Expand All @@ -52,7 +50,7 @@ public List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(AnalyzerAcquisiti

if (availableTypes.Count != analyzerTypes.Count)
{
availableTypes.Except(analyzerTypes).ToList().ForEach(t => _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly));
availableTypes.Except(analyzerTypes).ToList().ForEach(t => analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly));
}
}
catch (ReflectionTypeLoadException ex)
Expand All @@ -61,13 +59,13 @@ public List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(AnalyzerAcquisiti
{
foreach (Exception? loaderException in ex.LoaderExceptions)
{
_loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message);
analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message);
}
}
}
catch (Exception ex)
{
_loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message);
analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message);
}

return analyzersFactories;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ internal interface IBuildCheckAcquisitionModule
/// <summary>
/// Creates a list of factory delegates for building analyzer rules instances from a given assembly path.
/// </summary>
List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, BuildEventContext buildEventContext);
List<BuildAnalyzerFactory> CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, IAnalysisContext analysisContext);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.BackEnd.Shared;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Experimental.BuildCheck;

/// <summary>
/// <see cref="IAnalysisContext"/> that uses <see cref="EventArgsDispatcher"/> to dispatch.
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
internal class AnalysisDispatchingContext : IAnalysisContext
{
private readonly EventArgsDispatcher _eventDispatcher;
private readonly BuildEventContext _eventContext;

public AnalysisDispatchingContext(
EventArgsDispatcher dispatch,
BuildEventContext eventContext)
{
_eventDispatcher = dispatch;
_eventContext = eventContext;
}

public BuildEventContext BuildEventContext => _eventContext;

public void DispatchBuildEvent(BuildEventArgs buildEvent)
{
ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null");
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

_eventDispatcher.Dispatch(buildEvent);
}

public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs)
{
ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(messageResourceName), "Need resource string for comment message.");
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

DispatchAsCommentFromText(_eventContext, importance, ResourceUtilities.GetResourceString(messageResourceName), messageArgs);
}

public void DispatchAsCommentFromText(MessageImportance importance, string message)
=> DispatchAsCommentFromText(_eventContext, importance, message, messageArgs: null);

private void DispatchAsCommentFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs)
{
BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs);

_eventDispatcher.Dispatch(buildEvent);
}

public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message)
{
BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message);

_eventDispatcher.Dispatch(buildEvent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Framework;
using Microsoft.Build.Logging;

namespace Microsoft.Build.Experimental.BuildCheck;

internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory
{
private readonly EventArgsDispatcher _eventDispatcher;

public event AnyEventHandler? AnyEventRaised;

public AnalysisDispatchingContextFactory(EventArgsDispatcher eventDispatcher)
{
_eventDispatcher = eventDispatcher;

_eventDispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e);
}

public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext)
=> new AnalysisDispatchingContext(_eventDispatcher, eventContext);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Experimental.BuildCheck;

/// <summary>
/// <see cref="IAnalysisContext"/> that uses <see cref="LoggingService"/> to dispatch.
/// </summary>
internal class AnalysisLoggingContext : IAnalysisContext
rainersigwald marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly ILoggingService _loggingService;
private readonly BuildEventContext _eventContext;

public AnalysisLoggingContext(ILoggingService loggingService, BuildEventContext eventContext)
{
_loggingService = loggingService;
_eventContext = eventContext;
}

public BuildEventContext BuildEventContext => _eventContext;

public void DispatchBuildEvent(BuildEventArgs buildEvent)
=> _loggingService
.LogBuildEvent(buildEvent);

public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs)
=> _loggingService
.LogComment(_eventContext, importance, messageResourceName, messageArgs);

public void DispatchAsCommentFromText(MessageImportance importance, string message)
=> _loggingService
.LogCommentFromText(_eventContext, importance, message);

public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message)
=> _loggingService
.LogErrorFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message);
}
Loading
Loading