From 3fb562c6ab226ecbb245d1a81116838c77691455 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 18 Apr 2024 13:55:15 +0200 Subject: [PATCH 01/11] add tests infra --- src/BuildCheck.UnitTests/EndToEndTests.cs | 43 ++++++++++++++++--- ...icrosoft.Build.BuildCheck.UnitTests.csproj | 3 ++ .../AnalysisCandidate.csproj | 18 ++++++++ .../AnalysisCandidate/nugetTemplate.config | 9 ++++ .../TestAssets/CustomAnalyzer/Analyzer1.cs | 38 ++++++++++++++++ .../CustomAnalyzer/CustomAnalyzer.csproj | 42 ++++++++++++++++++ .../CustomAnalyzer/CustomAnalyzer.props | 6 +++ .../TestAssets/CustomAnalyzer/nuget.config | 9 ++++ .../TestAssets/CustomAnalyzers/Analyzer1.cs | 38 ++++++++++++++++ .../TestAssets/CustomAnalyzers/Analyzer2.cs | 38 ++++++++++++++++ .../CustomAnalyzers/CustomAnalyzers.csproj | 41 ++++++++++++++++++ .../CustomAnalyzers/CustomAnalyzers.props | 6 +++ .../TestAssets/CustomAnalyzers/nuget.config | 9 ++++ 13 files changed, 294 insertions(+), 6 deletions(-) create mode 100644 src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer1.cs create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index a0007d2c103..edc3793c509 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; +using Microsoft.Build.Evaluation; using Microsoft.Build.UnitTests; using Microsoft.Build.UnitTests.Shared; using Shouldly; @@ -19,6 +16,7 @@ namespace Microsoft.Build.BuildCheck.UnitTests; public class EndToEndTests : IDisposable { private readonly TestEnvironment _env; + public EndToEndTests(ITestOutputHelper output) { _env = TestEnvironment.Create(output); @@ -27,6 +25,8 @@ public EndToEndTests(ITestOutputHelper output) _env.WithEnvironmentInvariant(); } + private static string TestAssetsRootPath { get; } = Path.Combine(AppContext.BaseDirectory, "TestAssets"); + public void Dispose() => _env.Dispose(); [Theory] @@ -91,7 +91,6 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana // var cache = new SimpleProjectRootElementCache(); // ProjectRootElement xml = ProjectRootElement.OpenProjectOrSolution(projectFile.Path, /*unused*/null, /*unused*/null, cache, false /*Not explicitly loaded - unused*/); - TransientTestFile config = _env.CreateFile(workFolder, "editorconfig.json", /*lang=json,strict*/ """ @@ -134,4 +133,36 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana output.ShouldNotContain("BC0101"); } } + + [Theory] + [InlineData("CustomAnalyzer", "AnalysisCandidate", new[] { "CustomRule1" })] + public void CustomAnalyzerTest(string caName, string acName, string[] expectedRegistedRulesNames) + { + using (var env = TestEnvironment.Create()) + { + var caProjectPath = Path.Combine(TestAssetsRootPath, caName, $"{caName}.csproj"); + string caBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + $"{caProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + + if (success) + { + var caNugetPackageFullPath = Regex.Match(caBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + var analysisCandidateSolutionPath = Path.Combine(TestAssetsRootPath, acName); + AddCutomDataSourceToNugetConfig(analysisCandidateSolutionPath, Path.GetDirectoryName(caNugetPackageFullPath)); + + string acBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + $"{Path.Combine(analysisCandidateSolutionPath, $"{acName}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -verbosity:d", out _); + + } + } + } + + private void AddCutomDataSourceToNugetConfig(string filePath, string pathToCustomDataSource) + { + var nugetTemplatePath = Path.Combine(filePath, "nugetTemplate.config"); + string existingContent = File.ReadAllText(nugetTemplatePath); + + string modifiedContent = existingContent.Replace("LocalPackageSourcePlaceholder", pathToCustomDataSource); + File.WriteAllText(Path.Combine(filePath, "nuget.config"), modifiedContent); + } } diff --git a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj index 3aa9eaff7d1..a507bf76f65 100644 --- a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj +++ b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj @@ -33,5 +33,8 @@ PreserveNewest + + PreserveNewest + diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj new file mode 100644 index 00000000000..52f65afffee --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + + + + + + + + + PreserveNewest + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config new file mode 100644 index 00000000000..4b939f6afc2 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer1.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer1.cs new file mode 100644 index 00000000000..5cd1d3317c0 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer1.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Build.Construction; +using Microsoft.Build.Experimental.BuildCheck; + +namespace CustomAnalyzer +{ + public sealed class Analyzer1 : BuildAnalyzer + { + public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( + "X01234", + "Title", + "Description", + "Message format: {0}", + new BuildAnalyzerConfiguration()); + + public override string FriendlyName => "CustomRule1"; + + public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; + + public override void Initialize(ConfigurationContext configurationContext) + { + // configurationContext to be used only if analyzer needs external configuration data. + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); + } + + private void EvaluatedPropertiesAction(BuildCheckDataContext context) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + ElementLocation.EmptyLocation, + "Argument for the message format")); + } + } +} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj new file mode 100644 index 00000000000..557fdd2cbfc --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.0 + True + false + + NU5101;NU5128 + + + + + + + + + + + + + + + + + + + <_PackagesToPack Remove="@(_PackagesToPack)" /> + + + + + + + + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props new file mode 100644 index 00000000000..4ad56ac84e3 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props @@ -0,0 +1,6 @@ + + + + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzer.dll)) + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config new file mode 100644 index 00000000000..27a07cc2040 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs new file mode 100644 index 00000000000..a77318023b1 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Build.Construction; +using Microsoft.Build.Experimental.BuildCheck; + +namespace CustomRule +{ + public sealed class Analyzer1 : BuildAnalyzer + { + public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( + "X01234", + "Title", + "Description", + "Message format: {0}", + new BuildAnalyzerConfiguration()); + + public override string FriendlyName => "CustomRule1"; + + public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; + + public override void Initialize(ConfigurationContext configurationContext) + { + // configurationContext to be used only if analyzer needs external configuration data. + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); + } + + private void EvaluatedPropertiesAction(BuildCheckDataContext context) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + ElementLocation.EmptyLocation, + "Argument for the message format")); + } + } +} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs new file mode 100644 index 00000000000..76de267fe4c --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Build.Construction; +using Microsoft.Build.Experimental.BuildCheck; + +namespace CustomRule +{ + public sealed class Analyzer2 : BuildAnalyzer + { + public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( + "X01234", + "Title", + "Description", + "Message format: {0}", + new BuildAnalyzerConfiguration()); + + public override string FriendlyName => "CustomRule2"; + + public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; + + public override void Initialize(ConfigurationContext configurationContext) + { + // configurationContext to be used only if analyzer needs external configuration data. + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); + } + + private void EvaluatedPropertiesAction(BuildCheckDataContext context) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + ElementLocation.EmptyLocation, + "Argument for the message format")); + } + } +} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj new file mode 100644 index 00000000000..2b348b402d0 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj @@ -0,0 +1,41 @@ + + + + netstandard2.0 + True + + NU5101;NU5128 + + + + + + + + + + + + + + + + + + + <_PackagesToPack Remove="@(_PackagesToPack)" /> + + + + + + + + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props new file mode 100644 index 00000000000..0ce5884ec9f --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props @@ -0,0 +1,6 @@ + + + + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzers.dll)) + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config new file mode 100644 index 00000000000..27a07cc2040 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config @@ -0,0 +1,9 @@ + + + + + + + + + From efa1ae8cfbc8e7865a966504ef410e5f73160662 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 25 Apr 2024 12:13:52 +0200 Subject: [PATCH 02/11] add e2e test for custom analyzer --- .../BuildCheckConnectorLogger.cs | 18 ++++---- src/BuildCheck.UnitTests/EndToEndTests.cs | 32 ++++++++------- ...icrosoft.Build.BuildCheck.UnitTests.csproj | 2 +- .../AnalysisCandidate.csproj | 2 +- .../AnalysisCandidate/nugetTemplate.config | 1 - .../TestAssets/CustomAnalyzers/Analyzer1.cs | 38 ----------------- .../TestAssets/CustomAnalyzers/Analyzer2.cs | 38 ----------------- .../CustomAnalyzers/CustomAnalyzers.csproj | 41 ------------------- .../CustomAnalyzers/CustomAnalyzers.props | 6 --- .../TestAssets/CustomAnalyzers/nuget.config | 9 ---- 10 files changed, 28 insertions(+), 159 deletions(-) delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index 361c30c4200..8327d66695e 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -83,14 +83,7 @@ private void EventSource_BuildFinished(object sender, BuildFinishedEventArgs e) _stats.Merge(_buildCheckManager.CreateTracingStats(), (span1, span2) => span1 + span2); string msg = string.Join(Environment.NewLine, _stats.Select(a => a.Key + ": " + a.Value)); - BuildEventContext buildEventContext = e.BuildEventContext - ?? new BuildEventContext( - BuildEventContext.InvalidNodeId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTaskId); - - LoggingContext loggingContext = _loggingContextFactory.CreateLoggingContext(buildEventContext); + LoggingContext loggingContext = _loggingContextFactory.CreateLoggingContext(GetBuildEventContext(e)); // Tracing: https://github.com/dotnet/msbuild/issues/9629 loggingContext.LogCommentFromText(MessageImportance.High, msg); @@ -103,6 +96,13 @@ private void EventSource_BuildFinished(object sender, BuildFinishedEventArgs e) { typeof(ProjectStartedEventArgs), (BuildEventArgs e) => _buildCheckManager.StartProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, { typeof(ProjectFinishedEventArgs), (BuildEventArgs e) => _buildCheckManager.EndProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => _stats.Merge(((BuildCheckTracingEventArgs)e).TracingData, (span1, span2) => span1 + span2) }, - { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => _buildCheckManager.ProcessAnalyzerAcquisition(((BuildCheckAcquisitionEventArgs)e).ToAnalyzerAcquisitionData(), e.BuildEventContext!) }, + { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => _buildCheckManager.ProcessAnalyzerAcquisition(((BuildCheckAcquisitionEventArgs)e).ToAnalyzerAcquisitionData(), GetBuildEventContext(e)) }, }; + + private BuildEventContext GetBuildEventContext(BuildEventArgs e) => e.BuildEventContext + ?? new BuildEventContext( + BuildEventContext.InvalidNodeId, + BuildEventContext.InvalidTargetId, + BuildEventContext.InvalidProjectContextId, + BuildEventContext.InvalidTaskId); } diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index a4d10515418..e9e0a4ed4d2 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Text.RegularExpressions; -using Microsoft.Build.Evaluation; using Microsoft.Build.UnitTests; using Microsoft.Build.UnitTests.Shared; using Shouldly; @@ -135,34 +134,37 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana } [Theory] - [InlineData("CustomAnalyzer", "AnalysisCandidate", new[] { "CustomRule1" })] - public void CustomAnalyzerTest(string caName, string acName, string[] expectedRegistedRulesNames) + [InlineData("CustomAnalyzer", "AnalysisCandidate", "CustomRule1")] + public void CustomAnalyzerTest(string customAnalyzerName, string analysisCandidate, string expectedRegistredRule) { using (var env = TestEnvironment.Create()) { - var caProjectPath = Path.Combine(TestAssetsRootPath, caName, $"{caName}.csproj"); - string caBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( - $"{caProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + var candidateAnalysisProjectPath = Path.Combine(TestAssetsRootPath, customAnalyzerName, $"{customAnalyzerName}.csproj"); + string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); if (success) { - var caNugetPackageFullPath = Regex.Match(caBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; - var analysisCandidateSolutionPath = Path.Combine(TestAssetsRootPath, acName); - AddCutomDataSourceToNugetConfig(analysisCandidateSolutionPath, Path.GetDirectoryName(caNugetPackageFullPath)); + var analysisCandidatePath = Path.Combine(TestAssetsRootPath, analysisCandidate); + AddCustomDataSourceToNugetConfig(analysisCandidatePath, candidateAnalysisBuildLog); string acBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( - $"{Path.Combine(analysisCandidateSolutionPath, $"{acName}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -verbosity:d", out _); + $"{Path.Combine(analysisCandidatePath, $"{analysisCandidate}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -analyze -verbosity:d", + out bool _); + acBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegistredRule} has been registered successfully."); } } } - private void AddCutomDataSourceToNugetConfig(string filePath, string pathToCustomDataSource) + private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, string candidateAnalysisBuildLog) { - var nugetTemplatePath = Path.Combine(filePath, "nugetTemplate.config"); - string existingContent = File.ReadAllText(nugetTemplatePath); + var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + string pathToCustomDataSource = Path.GetDirectoryName(candidatesNugetPackageFullPath) ?? string.Empty; + var nugetTemplatePath = Path.Combine(analysisCandidatePath, "nugetTemplate.config"); - string modifiedContent = existingContent.Replace("LocalPackageSourcePlaceholder", pathToCustomDataSource); - File.WriteAllText(Path.Combine(filePath, "nuget.config"), modifiedContent); + File.WriteAllText( + Path.Combine(analysisCandidatePath, "nuget.config"), + File.ReadAllText(nugetTemplatePath).Replace("LocalPackageSourcePlaceholder", pathToCustomDataSource)); } } diff --git a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj index a507bf76f65..7bdf6513dbf 100644 --- a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj +++ b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj @@ -33,7 +33,7 @@ PreserveNewest - + PreserveNewest diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj index 52f65afffee..86c0710e572 100644 --- a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config index 4b939f6afc2..d72fd466a47 100644 --- a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config @@ -1,7 +1,6 @@ - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs deleted file mode 100644 index a77318023b1..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer1.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using Microsoft.Build.Construction; -using Microsoft.Build.Experimental.BuildCheck; - -namespace CustomRule -{ - public sealed class Analyzer1 : BuildAnalyzer - { - public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( - "X01234", - "Title", - "Description", - "Message format: {0}", - new BuildAnalyzerConfiguration()); - - public override string FriendlyName => "CustomRule1"; - - public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; - - public override void Initialize(ConfigurationContext configurationContext) - { - // configurationContext to be used only if analyzer needs external configuration data. - } - - public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) - { - registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); - } - - private void EvaluatedPropertiesAction(BuildCheckDataContext context) - { - context.ReportResult(BuildCheckResult.Create( - SupportedRule, - ElementLocation.EmptyLocation, - "Argument for the message format")); - } - } -} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs deleted file mode 100644 index 76de267fe4c..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/Analyzer2.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using Microsoft.Build.Construction; -using Microsoft.Build.Experimental.BuildCheck; - -namespace CustomRule -{ - public sealed class Analyzer2 : BuildAnalyzer - { - public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( - "X01234", - "Title", - "Description", - "Message format: {0}", - new BuildAnalyzerConfiguration()); - - public override string FriendlyName => "CustomRule2"; - - public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; - - public override void Initialize(ConfigurationContext configurationContext) - { - // configurationContext to be used only if analyzer needs external configuration data. - } - - public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) - { - registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); - } - - private void EvaluatedPropertiesAction(BuildCheckDataContext context) - { - context.ReportResult(BuildCheckResult.Create( - SupportedRule, - ElementLocation.EmptyLocation, - "Argument for the message format")); - } - } -} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj deleted file mode 100644 index 2b348b402d0..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.csproj +++ /dev/null @@ -1,41 +0,0 @@ - - - - netstandard2.0 - True - - NU5101;NU5128 - - - - - - - - - - - - - - - - - - - <_PackagesToPack Remove="@(_PackagesToPack)" /> - - - - - - - - - - - - - - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props deleted file mode 100644 index 0ce5884ec9f..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/CustomAnalyzers.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzers.dll)) - - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config deleted file mode 100644 index 27a07cc2040..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzers/nuget.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - From a8caff46dfc3e89f585354a3a8a389cd26e98294 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 25 Apr 2024 14:56:12 +0200 Subject: [PATCH 03/11] fix test --- src/BuildCheck.UnitTests/EndToEndTests.cs | 9 +++-- ...icrosoft.Build.BuildCheck.UnitTests.csproj | 1 + .../AnalysisCandidate.csproj | 2 +- .../TestAssets/CustomAnalyzer/Analyzer2.cs | 38 +++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer2.cs diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index e9e0a4ed4d2..5c0b0909b85 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -134,8 +134,8 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana } [Theory] - [InlineData("CustomAnalyzer", "AnalysisCandidate", "CustomRule1")] - public void CustomAnalyzerTest(string customAnalyzerName, string analysisCandidate, string expectedRegistredRule) + [InlineData("CustomAnalyzer", "AnalysisCandidate", new[] { "CustomRule1", "CustomRule2" })] + public void CustomAnalyzerTest(string customAnalyzerName, string analysisCandidate, string[] expectedRegisteredRules) { using (var env = TestEnvironment.Create()) { @@ -152,7 +152,10 @@ public void CustomAnalyzerTest(string customAnalyzerName, string analysisCandida $"{Path.Combine(analysisCandidatePath, $"{analysisCandidate}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -analyze -verbosity:d", out bool _); - acBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegistredRule} has been registered successfully."); + foreach (var expectedRegisteredRule in expectedRegisteredRules) + { + acBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegisteredRule} has been registered successfully."); + } } } } diff --git a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj index 7bdf6513dbf..ada169a4b49 100644 --- a/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj +++ b/src/BuildCheck.UnitTests/Microsoft.Build.BuildCheck.UnitTests.csproj @@ -37,4 +37,5 @@ PreserveNewest + diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj index 86c0710e572..52f65afffee 100644 --- a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/AnalysisCandidate.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer2.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer2.cs new file mode 100644 index 00000000000..714a82ae95a --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/Analyzer2.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Build.Construction; +using Microsoft.Build.Experimental.BuildCheck; + +namespace CustomAnalyzer +{ + public sealed class Analyzer2 : BuildAnalyzer + { + public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( + "X01235", + "Title", + "Description", + "Message format: {0}", + new BuildAnalyzerConfiguration()); + + public override string FriendlyName => "CustomRule2"; + + public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; + + public override void Initialize(ConfigurationContext configurationContext) + { + // configurationContext to be used only if analyzer needs external configuration data. + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); + } + + private void EvaluatedPropertiesAction(BuildCheckDataContext context) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + ElementLocation.EmptyLocation, + "Argument for the message format")); + } + } +} From dc29085b8ea8d44be2dae031e853ed4c5b9b5ec5 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 25 Apr 2024 15:53:13 +0200 Subject: [PATCH 04/11] extend test with multiple packages case --- src/BuildCheck.UnitTests/EndToEndTests.cs | 71 ++++++++++++++----- .../AnalysisCandidate/nugetTemplate.config | 2 - ...sCandidateWithMultipleRulesInjected.csproj | 19 +++++ .../nugetTemplate.config | 6 ++ .../TestAssets/CustomAnalyzer2/Analyzer3.cs | 38 ++++++++++ .../CustomAnalyzer2/CustomAnalyzer2.csproj | 42 +++++++++++ .../CustomAnalyzer2/CustomAnalyzer2.props | 6 ++ .../TestAssets/CustomAnalyzer2/nuget.config | 9 +++ 8 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/Analyzer3.cs create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props create mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 5c0b0909b85..a9323871f2f 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -2,8 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.RegularExpressions; +using System.Xml; using Microsoft.Build.UnitTests; using Microsoft.Build.UnitTests.Shared; using Shouldly; @@ -134,40 +137,76 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana } [Theory] - [InlineData("CustomAnalyzer", "AnalysisCandidate", new[] { "CustomRule1", "CustomRule2" })] - public void CustomAnalyzerTest(string customAnalyzerName, string analysisCandidate, string[] expectedRegisteredRules) + [InlineData(new[] { "CustomAnalyzer" }, "AnalysisCandidate", new[] { "CustomRule1", "CustomRule2" })] + [InlineData(new[] { "CustomAnalyzer", "CustomAnalyzer2" }, "AnalysisCandidateWithMultipleRulesInjected", new[] { "CustomRule1", "CustomRule2", "CustomRule3" })] + public void CustomAnalyzerTest(string[] customAnalyzerNames, string analysisCandidate, string[] expectedRegisteredRules) { using (var env = TestEnvironment.Create()) { - var candidateAnalysisProjectPath = Path.Combine(TestAssetsRootPath, customAnalyzerName, $"{customAnalyzerName}.csproj"); - string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( - $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + var candidatesNugetFullPaths = BuildAnalyzerRules(env, customAnalyzerNames); - if (success) + if (candidatesNugetFullPaths.Any()) { var analysisCandidatePath = Path.Combine(TestAssetsRootPath, analysisCandidate); - AddCustomDataSourceToNugetConfig(analysisCandidatePath, candidateAnalysisBuildLog); + AddCustomDataSourceToNugetConfig(analysisCandidatePath, candidatesNugetFullPaths); - string acBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + string projectAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( $"{Path.Combine(analysisCandidatePath, $"{analysisCandidate}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -analyze -verbosity:d", out bool _); - foreach (var expectedRegisteredRule in expectedRegisteredRules) + foreach (string expectedRegisteredRule in expectedRegisteredRules) { - acBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegisteredRule} has been registered successfully."); + projectAnalysisBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegisteredRule} has been registered successfully."); } } } } - private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, string candidateAnalysisBuildLog) + private IList BuildAnalyzerRules(TestEnvironment env, string[] customAnalyzerNames) + { + var candidatesNugetFullPaths = new List(); + + foreach (var customAnalyzerName in customAnalyzerNames) + { + var candidateAnalysisProjectPath = Path.Combine(TestAssetsRootPath, customAnalyzerName, $"{customAnalyzerName}.csproj"); + string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + + var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); + } + + return candidatesNugetFullPaths; + } + + private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, IList candidatesNugetPackageFullPaths) { - var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; - string pathToCustomDataSource = Path.GetDirectoryName(candidatesNugetPackageFullPath) ?? string.Empty; var nugetTemplatePath = Path.Combine(analysisCandidatePath, "nugetTemplate.config"); - File.WriteAllText( - Path.Combine(analysisCandidatePath, "nuget.config"), - File.ReadAllText(nugetTemplatePath).Replace("LocalPackageSourcePlaceholder", pathToCustomDataSource)); + var doc = new XmlDocument(); + doc.Load(nugetTemplatePath); + + XmlNode packageSourcesNode = doc.SelectSingleNode("//packageSources"); + for (var i = 0; i < candidatesNugetPackageFullPaths.Count; i++) + { + AddPackageSource(doc, packageSourcesNode, $"Key{i}", Path.GetDirectoryName(candidatesNugetPackageFullPaths[i])); + } + + doc.Save(Path.Combine(analysisCandidatePath, "nuget.config")); + } + + private static void AddPackageSource(XmlDocument doc, XmlNode packageSourcesNode, string key, string value) + { + var addNode = doc.CreateElement("add"); + + var keyAttribute = doc.CreateAttribute("key"); + keyAttribute.Value = key; + addNode.Attributes.Append(keyAttribute); + + var valueAttribute = doc.CreateAttribute("value"); + valueAttribute.Value = value; + addNode.Attributes.Append(valueAttribute); + + packageSourcesNode.AppendChild(addNode); } } diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config index d72fd466a47..1097d29bafd 100644 --- a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidate/nugetTemplate.config @@ -2,7 +2,5 @@ - - diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj new file mode 100644 index 00000000000..9e71d7ff38f --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + + + + + + + + + + PreserveNewest + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config new file mode 100644 index 00000000000..1097d29bafd --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/Analyzer3.cs b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/Analyzer3.cs new file mode 100644 index 00000000000..c0272937c87 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/Analyzer3.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Build.Construction; +using Microsoft.Build.Experimental.BuildCheck; + +namespace CustomAnalyzer2 +{ + public sealed class Analyzer3 : BuildAnalyzer + { + public static BuildAnalyzerRule SupportedRule = new BuildAnalyzerRule( + "X01235", + "Title", + "Description", + "Message format: {0}", + new BuildAnalyzerConfiguration()); + + public override string FriendlyName => "CustomRule3"; + + public override IReadOnlyList SupportedRules { get; } = new List() { SupportedRule }; + + public override void Initialize(ConfigurationContext configurationContext) + { + // configurationContext to be used only if analyzer needs external configuration data. + } + + public override void RegisterActions(IBuildCheckRegistrationContext registrationContext) + { + registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction); + } + + private void EvaluatedPropertiesAction(BuildCheckDataContext context) + { + context.ReportResult(BuildCheckResult.Create( + SupportedRule, + ElementLocation.EmptyLocation, + "Argument for the message format")); + } + } +} diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj new file mode 100644 index 00000000000..603880ac6f5 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.0 + True + false + + NU5101;NU5128 + + + + + + + + + + + + + + + + + + + <_PackagesToPack Remove="@(_PackagesToPack)" /> + + + + + + + + + + + + + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props new file mode 100644 index 00000000000..f3ecf06f130 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props @@ -0,0 +1,6 @@ + + + + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzer2.dll)) + + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config new file mode 100644 index 00000000000..27a07cc2040 --- /dev/null +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config @@ -0,0 +1,9 @@ + + + + + + + + + From fe527b283d97fcbda816cf5a0600f35cf20274d1 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 25 Apr 2024 15:58:52 +0200 Subject: [PATCH 05/11] cleanup --- src/BuildCheck.UnitTests/EndToEndTests.cs | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index a9323871f2f..4166c2e6cd1 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -172,8 +172,11 @@ private IList BuildAnalyzerRules(TestEnvironment env, string[] customAna string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); - var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; - candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); + if (success) + { + var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); + } } return candidatesNugetFullPaths; @@ -185,9 +188,8 @@ private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, ILis var doc = new XmlDocument(); doc.Load(nugetTemplatePath); - XmlNode packageSourcesNode = doc.SelectSingleNode("//packageSources"); - for (var i = 0; i < candidatesNugetPackageFullPaths.Count; i++) + for (int i = 0; i < candidatesNugetPackageFullPaths.Count; i++) { AddPackageSource(doc, packageSourcesNode, $"Key{i}", Path.GetDirectoryName(candidatesNugetPackageFullPaths[i])); } @@ -195,18 +197,20 @@ private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, ILis doc.Save(Path.Combine(analysisCandidatePath, "nuget.config")); } - private static void AddPackageSource(XmlDocument doc, XmlNode packageSourcesNode, string key, string value) + private void AddPackageSource(XmlDocument doc, XmlNode packageSourcesNode, string key, string value) { - var addNode = doc.CreateElement("add"); + XmlElement addNode = doc.CreateElement("add"); - var keyAttribute = doc.CreateAttribute("key"); - keyAttribute.Value = key; - addNode.Attributes.Append(keyAttribute); + PopulateXmlAttribute(doc, addNode, "key", key); + PopulateXmlAttribute(doc, addNode, "value", value); - var valueAttribute = doc.CreateAttribute("value"); - valueAttribute.Value = value; - addNode.Attributes.Append(valueAttribute); + _ = packageSourcesNode.AppendChild(addNode); + } - packageSourcesNode.AppendChild(addNode); + private void PopulateXmlAttribute(XmlDocument doc, XmlNode node, string attributeName, string attributeValue) + { + var attribute = doc.CreateAttribute(attributeName); + attribute.Value = attributeValue; + node.Attributes.Append(attribute); } } From 2d62e425d42b69f272dd597d368c75156d5317ee Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 25 Apr 2024 16:37:09 +0200 Subject: [PATCH 06/11] fix warnings --- src/BuildCheck.UnitTests/EndToEndTests.cs | 37 ++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 4166c2e6cd1..d645c62fa6a 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -187,30 +187,39 @@ private void AddCustomDataSourceToNugetConfig(string analysisCandidatePath, ILis var nugetTemplatePath = Path.Combine(analysisCandidatePath, "nugetTemplate.config"); var doc = new XmlDocument(); - doc.Load(nugetTemplatePath); - XmlNode packageSourcesNode = doc.SelectSingleNode("//packageSources"); - for (int i = 0; i < candidatesNugetPackageFullPaths.Count; i++) + doc.LoadXml(File.ReadAllText(nugetTemplatePath)); + if (doc.DocumentElement != null) { - AddPackageSource(doc, packageSourcesNode, $"Key{i}", Path.GetDirectoryName(candidatesNugetPackageFullPaths[i])); - } + XmlNode? packageSourcesNode = doc.SelectSingleNode("//packageSources"); + for (int i = 0; i < candidatesNugetPackageFullPaths.Count; i++) + { + AddPackageSource(doc, packageSourcesNode, $"Key{i}", Path.GetDirectoryName(candidatesNugetPackageFullPaths[i]) ?? string.Empty); + } - doc.Save(Path.Combine(analysisCandidatePath, "nuget.config")); + doc.Save(Path.Combine(analysisCandidatePath, "nuget.config")); + } } - private void AddPackageSource(XmlDocument doc, XmlNode packageSourcesNode, string key, string value) + private void AddPackageSource(XmlDocument doc, XmlNode? packageSourcesNode, string key, string value) { - XmlElement addNode = doc.CreateElement("add"); + if (packageSourcesNode != null) + { + XmlElement addNode = doc.CreateElement("add"); - PopulateXmlAttribute(doc, addNode, "key", key); - PopulateXmlAttribute(doc, addNode, "value", value); + PopulateXmlAttribute(doc, addNode, "key", key); + PopulateXmlAttribute(doc, addNode, "value", value); - _ = packageSourcesNode.AppendChild(addNode); + packageSourcesNode.AppendChild(addNode); + } } private void PopulateXmlAttribute(XmlDocument doc, XmlNode node, string attributeName, string attributeValue) { - var attribute = doc.CreateAttribute(attributeName); - attribute.Value = attributeValue; - node.Attributes.Append(attribute); + if (node != null) + { + var attribute = doc.CreateAttribute(attributeName); + attribute.Value = attributeValue; + node.Attributes!.Append(attribute); + } } } From c5de6c8391f863f9b5346d951f08544775a7aa8f Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 3 May 2024 12:50:24 +0200 Subject: [PATCH 07/11] fix review comments --- src/BuildCheck.UnitTests/EndToEndTests.cs | 45 +++++++++---------- ...idateWithMultipleAnalyzersInjected.csproj} | 0 .../nugetTemplate.config | 0 .../CustomAnalyzer/CustomAnalyzer.csproj | 21 ++------- .../TestAssets/CustomAnalyzer/nuget.config | 9 ---- .../CustomAnalyzer2/CustomAnalyzer2.csproj | 22 ++------- .../TestAssets/CustomAnalyzer2/nuget.config | 9 ---- 7 files changed, 28 insertions(+), 78 deletions(-) rename src/BuildCheck.UnitTests/TestAssets/{AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj => AnalysisCandidateWithMultipleAnalyzersInjected/AnalysisCandidateWithMultipleAnalyzersInjected.csproj} (100%) rename src/BuildCheck.UnitTests/TestAssets/{AnalysisCandidateWithMultipleRulesInjected => AnalysisCandidateWithMultipleAnalyzersInjected}/nugetTemplate.config (100%) delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config delete mode 100644 src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index d645c62fa6a..eabf4affe54 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text.RegularExpressions; using System.Xml; using Microsoft.Build.UnitTests; @@ -27,7 +26,7 @@ public EndToEndTests(ITestOutputHelper output) _env.WithEnvironmentInvariant(); } - private static string TestAssetsRootPath { get; } = Path.Combine(AppContext.BaseDirectory, "TestAssets"); + private static string TestAssetsRootPath { get; } = Path.Combine(Path.GetDirectoryName(typeof(EndToEndTests).Assembly.Location) ?? AppContext.BaseDirectory, "TestAssets"); public void Dispose() => _env.Dispose(); @@ -138,26 +137,26 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana [Theory] [InlineData(new[] { "CustomAnalyzer" }, "AnalysisCandidate", new[] { "CustomRule1", "CustomRule2" })] - [InlineData(new[] { "CustomAnalyzer", "CustomAnalyzer2" }, "AnalysisCandidateWithMultipleRulesInjected", new[] { "CustomRule1", "CustomRule2", "CustomRule3" })] + [InlineData(new[] { "CustomAnalyzer", "CustomAnalyzer2" }, "AnalysisCandidateWithMultipleAnalyzersInjected", new[] { "CustomRule1", "CustomRule2", "CustomRule3" })] public void CustomAnalyzerTest(string[] customAnalyzerNames, string analysisCandidate, string[] expectedRegisteredRules) { using (var env = TestEnvironment.Create()) { var candidatesNugetFullPaths = BuildAnalyzerRules(env, customAnalyzerNames); - if (candidatesNugetFullPaths.Any()) - { - var analysisCandidatePath = Path.Combine(TestAssetsRootPath, analysisCandidate); - AddCustomDataSourceToNugetConfig(analysisCandidatePath, candidatesNugetFullPaths); + candidatesNugetFullPaths.ShouldNotBeEmpty("Nuget package with custom analyzer was not generated or detected."); - string projectAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( - $"{Path.Combine(analysisCandidatePath, $"{analysisCandidate}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -analyze -verbosity:d", - out bool _); + var analysisCandidatePath = Path.Combine(TestAssetsRootPath, analysisCandidate); + AddCustomDataSourceToNugetConfig(analysisCandidatePath, candidatesNugetFullPaths); - foreach (string expectedRegisteredRule in expectedRegisteredRules) - { - projectAnalysisBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegisteredRule} has been registered successfully."); - } + string projectAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( + $"{Path.Combine(analysisCandidatePath, $"{analysisCandidate}.csproj")} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -analyze -verbosity:d", + out bool successBuild); + successBuild.ShouldBeTrue(); + + foreach (string expectedRegisteredRule in expectedRegisteredRules) + { + projectAnalysisBuildLog.ShouldContain($"Custom analyzer rule: {expectedRegisteredRule} has been registered successfully."); } } } @@ -171,12 +170,10 @@ private IList BuildAnalyzerRules(TestEnvironment env, string[] customAna var candidateAnalysisProjectPath = Path.Combine(TestAssetsRootPath, customAnalyzerName, $"{customAnalyzerName}.csproj"); string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + success.ShouldBeTrue(); - if (success) - { - var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; - candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); - } + var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); } return candidatesNugetFullPaths; @@ -215,11 +212,9 @@ private void AddPackageSource(XmlDocument doc, XmlNode? packageSourcesNode, stri private void PopulateXmlAttribute(XmlDocument doc, XmlNode node, string attributeName, string attributeValue) { - if (node != null) - { - var attribute = doc.CreateAttribute(attributeName); - attribute.Value = attributeValue; - node.Attributes!.Append(attribute); - } + node.ShouldNotBeNull($"The attribute {attributeName} can not be populated with {attributeValue}. Xml node is null."); + var attribute = doc.CreateAttribute(attributeName); + attribute.Value = attributeValue; + node.Attributes!.Append(attribute); } } diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleAnalyzersInjected/AnalysisCandidateWithMultipleAnalyzersInjected.csproj similarity index 100% rename from src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/AnalysisCandidateWithMultipleRulesInjected.csproj rename to src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleAnalyzersInjected/AnalysisCandidateWithMultipleAnalyzersInjected.csproj diff --git a/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config b/src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleAnalyzersInjected/nugetTemplate.config similarity index 100% rename from src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleRulesInjected/nugetTemplate.config rename to src/BuildCheck.UnitTests/TestAssets/AnalysisCandidateWithMultipleAnalyzersInjected/nugetTemplate.config diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj index 557fdd2cbfc..35b1af25347 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj @@ -13,27 +13,14 @@ - + + + $(MSBuildProjectDirectory)\..\..\Microsoft.Build.dll + - - - - - - - - <_PackagesToPack Remove="@(_PackagesToPack)" /> - - - - - - - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config deleted file mode 100644 index 27a07cc2040..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/nuget.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj index 603880ac6f5..5e6271f531a 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj @@ -3,7 +3,6 @@ netstandard2.0 True - false NU5101;NU5128 @@ -13,27 +12,14 @@ - + + + $(MSBuildProjectDirectory)\..\..\Microsoft.Build.dll + - - - - - - - - <_PackagesToPack Remove="@(_PackagesToPack)" /> - - - - - - - diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config deleted file mode 100644 index 27a07cc2040..00000000000 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/nuget.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - From 38e94360d6dcc6077ee96ccd9e93ad9b53b3d9ec Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 3 May 2024 13:30:44 +0200 Subject: [PATCH 08/11] return missed code --- .../BuildCheckConnectorLogger.cs | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index e4e7d3dfde5..867a50b5b04 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -9,7 +9,6 @@ using Microsoft.Build.BuildCheck.Utilities; using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; -using static Microsoft.Build.BuildCheck.Infrastructure.BuildCheckManagerProvider; namespace Microsoft.Build.BuildCheck.Infrastructure; @@ -67,6 +66,14 @@ private void HandleProjectEvaluationStartedEvent(ProjectEvaluationStartedEventAr } } + private void HandleBuildCheckTracingEvent(BuildCheckTracingEventArgs eventArgs) + { + if (!eventArgs.IsAggregatedGlobalReport) + { + _stats.Merge(eventArgs.TracingData, (span1, span2) => span1 + span2); + } + } + private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); private void EventSource_AnyEventRaised(object sender, BuildEventArgs e) @@ -81,19 +88,12 @@ private void EventSource_AnyEventRaised(object sender, BuildEventArgs e) private void EventSource_BuildFinished(object sender, BuildFinishedEventArgs e) { - BuildEventContext buildEventContext = e.BuildEventContext - ?? new BuildEventContext( - BuildEventContext.InvalidNodeId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTaskId); - - LoggingContext loggingContext = _loggingContextFactory.CreateLoggingContext(buildEventContext); + LoggingContext loggingContext = _loggingContextFactory.CreateLoggingContext(GetBuildEventContext(e)); _stats.Merge(_buildCheckManager.CreateAnalyzerTracingStats(), (span1, span2) => span1 + span2); LogAnalyzerStats(loggingContext); } - + private void LogAnalyzerStats(LoggingContext loggingContext) { Dictionary infraStats = new Dictionary(); @@ -131,19 +131,12 @@ private string BuildCsvString(string title, Dictionary rowData private Dictionary> GetBuildEventHandlers() => new() { - { typeof(ProjectEvaluationFinishedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationFinishedEvent((ProjectEvaluationFinishedEventArgs) e) }, - { typeof(ProjectEvaluationStartedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationStartedEvent((ProjectEvaluationStartedEventArgs) e) }, + { typeof(ProjectEvaluationFinishedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationFinishedEvent((ProjectEvaluationFinishedEventArgs)e) }, + { typeof(ProjectEvaluationStartedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationStartedEvent((ProjectEvaluationStartedEventArgs)e) }, { typeof(ProjectStartedEventArgs), (BuildEventArgs e) => _buildCheckManager.StartProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, { typeof(ProjectFinishedEventArgs), (BuildEventArgs e) => _buildCheckManager.EndProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, - { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => - { - if(!((BuildCheckTracingEventArgs)e).IsAggregatedGlobalReport) - { - _stats.Merge(((BuildCheckTracingEventArgs)e).TracingData, (span1, span2) => span1 + span2); - } - } - }, - { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => _buildCheckManager.ProcessAnalyzerAcquisition(((BuildCheckAcquisitionEventArgs)e).ToAnalyzerAcquisitionData(), e.BuildEventContext!) }, + { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => HandleBuildCheckTracingEvent((BuildCheckTracingEventArgs)e) }, + { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => _buildCheckManager.ProcessAnalyzerAcquisition(((BuildCheckAcquisitionEventArgs)e).ToAnalyzerAcquisitionData(), GetBuildEventContext(e)) }, }; private BuildEventContext GetBuildEventContext(BuildEventArgs e) => e.BuildEventContext From 1b2ff326ed17906a5669d23b78177c54dadd50ec Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 3 May 2024 16:23:15 +0200 Subject: [PATCH 09/11] fix review comment --- .../TestAssets/CustomAnalyzer/CustomAnalyzer.csproj | 2 +- .../TestAssets/CustomAnalyzer/CustomAnalyzer.props | 2 +- .../TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj | 2 +- .../TestAssets/CustomAnalyzer2/CustomAnalyzer2.props | 2 +- .../Company.AnalyzerTemplate.csproj | 4 ++-- .../Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj index 35b1af25347..5fd360fd9d8 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props index 4ad56ac84e3..54d94d857fb 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props @@ -1,6 +1,6 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzer.dll)) + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)CustomAnalyzer.dll)) diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj index 5e6271f531a..aff8c27bbd6 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props index f3ecf06f130..69e846d8463 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props @@ -1,6 +1,6 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\CustomAnalyzer2.dll)) + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)CustomAnalyzer2.dll)) diff --git a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.csproj b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.csproj index 0a1b8f974fc..33d8c992326 100644 --- a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.csproj +++ b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.csproj @@ -36,10 +36,10 @@ - + - + diff --git a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props index 3b752b831cc..aa4d4c70abf 100644 --- a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props +++ b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props @@ -1,7 +1,7 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)..\lib\Company.AnalyzerTemplate.dll)) + $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)Company.AnalyzerTemplate.dll)) From 5749d63b2ef2f0789f30e704994c324a115bea45 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 7 May 2024 13:55:53 +0200 Subject: [PATCH 10/11] rename RegisterAnalyzer -> RegisterBuildCheck --- .../Evaluation/Expander_Tests.cs | 4 ++-- src/Build/Evaluation/Expander.cs | 22 +++++++++---------- src/Build/Evaluation/IntrinsicFunctions.cs | 2 +- .../CustomAnalyzer/CustomAnalyzer.props | 2 +- .../CustomAnalyzer2/CustomAnalyzer2.props | 2 +- .../Company.AnalyzerTemplate.props | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 90f06cf86c7..f47f94fd217 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -5071,7 +5071,7 @@ private static bool ICUModeAvailable() } [Fact] - public void PropertyFunctionRegisterAnalyzer() + public void PropertyFunctionRegisterBuildCheck() { using (var env = TestEnvironment.Create()) { @@ -5084,7 +5084,7 @@ public void PropertyFunctionRegisterAnalyzer() var dummyAssemblyFile = env.CreateFile(env.CreateFolder(), "test.dll"); var result = new Expander(new PropertyDictionary(), FileSystems.Default) - .ExpandIntoStringLeaveEscaped($"$([MSBuild]::RegisterAnalyzer({dummyAssemblyFile.Path}))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance, loggingContext); + .ExpandIntoStringLeaveEscaped($"$([MSBuild]::RegisterBuildCheck({dummyAssemblyFile.Path}))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance, loggingContext); result.ShouldBe(Boolean.TrueString); _ = logger.AllBuildEvents.Select(be => be.ShouldBeOfType()); diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index 84d485b7c59..b095e57a043 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -3917,12 +3917,12 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst } else if (_receiverType == typeof(IntrinsicFunctions)) { - if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RegisterAnalyzer), StringComparison.OrdinalIgnoreCase)) + if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RegisterBuildCheck), StringComparison.OrdinalIgnoreCase)) { - ErrorUtilities.VerifyThrow(_loggingContext != null, $"The logging context is missed. {nameof(IntrinsicFunctions.RegisterAnalyzer)} can not be invoked."); + ErrorUtilities.VerifyThrow(_loggingContext != null, $"The logging context is missed. {nameof(IntrinsicFunctions.RegisterBuildCheck)} can not be invoked."); if (TryGetArg(args, out string arg0)) { - returnVal = IntrinsicFunctions.RegisterAnalyzer(arg0, _loggingContext); + returnVal = IntrinsicFunctions.RegisterBuildCheck(arg0, _loggingContext); return true; } } @@ -4229,14 +4229,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } - else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.SubstringByAsciiChars), StringComparison.OrdinalIgnoreCase)) - { - if (TryGetArgs(args, out string arg0, out int arg1, out int arg2)) - { - returnVal = IntrinsicFunctions.SubstringByAsciiChars(arg0, arg1, arg2); - return true; - } - } + //else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.SubstringByAsciiChars), StringComparison.OrdinalIgnoreCase)) + //{ + // if (TryGetArgs(args, out string arg0, out int arg1, out int arg2)) + // { + // returnVal = IntrinsicFunctions.SubstringByAsciiChars(arg0, arg1, arg2); + // return true; + // } + //} else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.CheckFeatureAvailability), StringComparison.OrdinalIgnoreCase)) { if (TryGetArg(args, out string arg0)) diff --git a/src/Build/Evaluation/IntrinsicFunctions.cs b/src/Build/Evaluation/IntrinsicFunctions.cs index 944478d4be6..17e67ce123a 100644 --- a/src/Build/Evaluation/IntrinsicFunctions.cs +++ b/src/Build/Evaluation/IntrinsicFunctions.cs @@ -697,7 +697,7 @@ public static string GetMSBuildExtensionsPath() public static bool IsRunningFromVisualStudio() => BuildEnvironmentHelper.Instance.Mode == BuildEnvironmentMode.VisualStudio; - public static bool RegisterAnalyzer(string pathToAssembly, LoggingContext loggingContext) + public static bool RegisterBuildCheck(string pathToAssembly, LoggingContext loggingContext) { pathToAssembly = FileUtilities.GetFullPathNoThrow(pathToAssembly); if (File.Exists(pathToAssembly)) diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props index 54d94d857fb..31a9526dd62 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.props @@ -1,6 +1,6 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)CustomAnalyzer.dll)) + $([MSBuild]::RegisterBuildCheck($(MSBuildThisFileDirectory)CustomAnalyzer.dll)) diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props index 69e846d8463..869000fa12f 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.props @@ -1,6 +1,6 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)CustomAnalyzer2.dll)) + $([MSBuild]::RegisterBuildCheck($(MSBuildThisFileDirectory)CustomAnalyzer2.dll)) diff --git a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props index aa4d4c70abf..5a606b3cac6 100644 --- a/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props +++ b/template_feed/Microsoft.AnalyzerTemplate/Company.AnalyzerTemplate.props @@ -1,7 +1,7 @@ - $([MSBuild]::RegisterAnalyzer($(MSBuildThisFileDirectory)Company.AnalyzerTemplate.dll)) + $([MSBuild]::RegisterBuildCheck($(MSBuildThisFileDirectory)Company.AnalyzerTemplate.dll)) From 0fe2ba3b42fc90df75a25db5e81afc1a5949d9ee Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 7 May 2024 18:11:13 +0200 Subject: [PATCH 11/11] fix review comment --- src/Build/Evaluation/Expander.cs | 16 +++++------ src/BuildCheck.UnitTests/EndToEndTests.cs | 11 +++++--- .../CustomAnalyzer/CustomAnalyzer.csproj | 2 +- .../CustomAnalyzer2/CustomAnalyzer2.csproj | 2 +- src/UnitTests.Shared/RunnerUtilities.cs | 28 ++++++++++++++----- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index b095e57a043..e67785390a4 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -4229,14 +4229,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } - //else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.SubstringByAsciiChars), StringComparison.OrdinalIgnoreCase)) - //{ - // if (TryGetArgs(args, out string arg0, out int arg1, out int arg2)) - // { - // returnVal = IntrinsicFunctions.SubstringByAsciiChars(arg0, arg1, arg2); - // return true; - // } - //} + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.SubstringByAsciiChars), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out string arg0, out int arg1, out int arg2)) + { + returnVal = IntrinsicFunctions.SubstringByAsciiChars(arg0, arg1, arg2); + return true; + } + } else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.CheckFeatureAvailability), StringComparison.OrdinalIgnoreCase)) { if (TryGetArg(args, out string arg0)) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index eabf4affe54..cc2aa1ae612 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text.RegularExpressions; using System.Xml; using Microsoft.Build.UnitTests; using Microsoft.Build.UnitTests.Shared; +using Newtonsoft.Json.Linq; using Shouldly; using Xunit; using Xunit.Abstractions; @@ -168,11 +168,14 @@ private IList BuildAnalyzerRules(TestEnvironment env, string[] customAna foreach (var customAnalyzerName in customAnalyzerNames) { var candidateAnalysisProjectPath = Path.Combine(TestAssetsRootPath, customAnalyzerName, $"{customAnalyzerName}.csproj"); - string candidateAnalysisBuildLog = RunnerUtilities.ExecBootstrapedMSBuild( - $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path}", out bool success); + var nugetPackResults = RunnerUtilities.ExecBootstrapedMSBuild( + $"{candidateAnalysisProjectPath} /m:1 -nr:False -restore /p:OutputPath={env.CreateFolder().Path} -getTargetResult:Build", out bool success, attachProcessId: false); + success.ShouldBeTrue(); - var candidatesNugetPackageFullPath = Regex.Match(candidateAnalysisBuildLog, @"Successfully created package '(.*?)'").Groups[1].Value; + string? candidatesNugetPackageFullPath = (string?)(JObject.Parse(nugetPackResults)?["TargetResults"]?["Build"]?["Items"]?[0]?["RelativeDir"] ?? string.Empty); + + candidatesNugetPackageFullPath.ShouldNotBeNull(); candidatesNugetFullPaths.Add(candidatesNugetPackageFullPath); } diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj index 5fd360fd9d8..f780e9eb213 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer/CustomAnalyzer.csproj @@ -5,7 +5,7 @@ True false - NU5101;NU5128 + NU5101;NU5128;MSB3277 diff --git a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj index aff8c27bbd6..17007b03785 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CustomAnalyzer2/CustomAnalyzer2.csproj @@ -4,7 +4,7 @@ netstandard2.0 True - NU5101;NU5128 + NU5101;NU5128;MSB3277 diff --git a/src/UnitTests.Shared/RunnerUtilities.cs b/src/UnitTests.Shared/RunnerUtilities.cs index a61f1a9fb4c..6b8354dc0da 100644 --- a/src/UnitTests.Shared/RunnerUtilities.cs +++ b/src/UnitTests.Shared/RunnerUtilities.cs @@ -52,7 +52,12 @@ public static string ExecMSBuild(string pathToMsBuildExe, string msbuildParamete return RunProcessAndGetOutput(pathToExecutable, msbuildParameters, out successfulExit, shellExecute, outputHelper); } - public static string ExecBootstrapedMSBuild(string msbuildParameters, out bool successfulExit, bool shellExecute = false, ITestOutputHelper outputHelper = null) + public static string ExecBootstrapedMSBuild( + string msbuildParameters, + out bool successfulExit, + bool shellExecute = false, + ITestOutputHelper outputHelper = null, + bool attachProcessId = true) { BootstrapLocationAttribute attribute = Assembly.GetExecutingAssembly().GetCustomAttribute() ?? throw new InvalidOperationException("This test assembly does not have the BootstrapLocationAttribute"); @@ -64,7 +69,7 @@ public static string ExecBootstrapedMSBuild(string msbuildParameters, out bool s #else string pathToExecutable = Path.Combine(binaryFolder, "MSBuild.exe"); #endif - return RunProcessAndGetOutput(pathToExecutable, msbuildParameters, out successfulExit, shellExecute, outputHelper); + return RunProcessAndGetOutput(pathToExecutable, msbuildParameters, out successfulExit, shellExecute, outputHelper, attachProcessId); } private static void AdjustForShellExecution(ref string pathToExecutable, ref string arguments) @@ -84,9 +89,15 @@ private static void AdjustForShellExecution(ref string pathToExecutable, ref str } /// - /// Run the process and get stdout and stderr + /// Run the process and get stdout and stderr. /// - public static string RunProcessAndGetOutput(string process, string parameters, out bool successfulExit, bool shellExecute = false, ITestOutputHelper outputHelper = null) + public static string RunProcessAndGetOutput( + string process, + string parameters, + out bool successfulExit, + bool shellExecute = false, + ITestOutputHelper outputHelper = null, + bool attachProcessId = true) { if (shellExecute) { @@ -148,10 +159,13 @@ public static string RunProcessAndGetOutput(string process, string parameters, o successfulExit = p.ExitCode == 0; } - WriteOutput("Process ID is " + pid + "\r\n"); - WriteOutput("=============="); + if (attachProcessId) + { + output += "Process ID is " + pid + "\r\n"; + WriteOutput("Process ID is " + pid + "\r\n"); + WriteOutput("=============="); + } - output += "Process ID is " + pid + "\r\n"; return output; void WriteOutput(string data)