From 3dbb207c71adb2ae5c9db1250d4c93874bf9bee6 Mon Sep 17 00:00:00 2001 From: Johnathon Mohr Date: Mon, 17 Mar 2025 17:59:21 -0700 Subject: [PATCH 1/4] Update Bicep Core libraries, conform to breaking changes. --- .../Analyzer.BicepProcessor.csproj | 1 - .../BicepTemplateProcessor.cs | 60 ++++++++++--------- .../SourceMapFeatureProvider.cs | 23 +++---- .../Analyzer.TemplateProcessor.csproj | 1 - .../ArmTemplateProcessor.cs | 2 +- src/Directory.Packages.props | 23 ++++--- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj b/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj index 721cfe71..c20728fd 100644 --- a/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj +++ b/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj @@ -10,6 +10,5 @@ - \ No newline at end of file diff --git a/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs b/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs index 18021637..6c60aeb4 100644 --- a/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs +++ b/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.Linq; @@ -15,14 +16,18 @@ using Bicep.Core.Extensions; using Bicep.Core.Features; using Bicep.Core.FileSystem; +using Bicep.Core.Navigation; using Bicep.Core.Registry; using Bicep.Core.Registry.Auth; +using Bicep.Core.Registry.PublicRegistry; using Bicep.Core.Semantics.Namespaces; using Bicep.Core.Syntax; using Bicep.Core.Text; using Bicep.Core.TypeSystem.Providers; using Bicep.Core.Utils; using Bicep.Core.Workspaces; +using Bicep.IO.Abstraction; +using Bicep.IO.FileSystem; using Microsoft.Extensions.DependencyInjection; using BicepEnvironment = Bicep.Core.Utils.Environment; using IOFileSystem = System.IO.Abstractions.FileSystem; @@ -41,14 +46,16 @@ public static class BicepTemplateProcessor /// /// public static IServiceCollection AddBicepCore(this IServiceCollection services) => services - .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() @@ -91,47 +98,42 @@ public static (string, BicepMetadata) ConvertBicepToJson(string bicepPath) throw new Exception($"Bicep issues found:{SysEnvironment.NewLine}{string.Join(SysEnvironment.NewLine, bicepIssues)}"); } - string GetPathRelativeToEntryPoint(string absolutePath) => Path.GetRelativePath( - Path.GetDirectoryName(compilation.SourceFileGrouping.EntryPoint.FileUri.AbsolutePath), absolutePath); + string entryPointDirectory = Path.GetDirectoryName(compilation.SourceFileGrouping.EntryPoint.Uri.AbsolutePath); + + bool IsLocalModuleReference(KeyValuePair artifact) => + artifact.Key is ModuleDeclarationSyntax moduleDeclaration && + moduleDeclaration.Path is StringSyntax moduleDeclarationPath && + !moduleDeclarationPath.SegmentValues.Any(IsModuleRegistryPathRegex.IsMatch) && + artifact.Value.Result.IsSuccess(); // Collect all needed module info from SourceFileGrouping metadata - var moduleInfo = compilation.SourceFileGrouping.FileUriResultByArtifactReference.Select(sourceFileAndMetadata => - { - var bicepSourceFile = sourceFileAndMetadata.Key as BicepSourceFile; - var pathRelativeToEntryPoint = GetPathRelativeToEntryPoint(bicepSourceFile.FileUri.AbsolutePath); - var modules = sourceFileAndMetadata.Value - .Select(artifactRefAndUriResult => + var moduleInfo = compilation.SourceFileGrouping.ArtifactLookup + .Where(IsLocalModuleReference) + .GroupBy(artifact => artifact.Value.Origin) + .Select(grouping => + { + var bicepSourceFile = grouping.Key; + var pathRelativeToEntryPoint = Path.GetRelativePath( + Path.GetDirectoryName(compilation.SourceFileGrouping.EntryPoint.Uri.AbsolutePath), bicepSourceFile.Uri.AbsolutePath); + + var modules = grouping.Select(artifactRefAndUriResult => { - // Do not include modules imported from public/private registries, as it is more useful for user to see line number - // of the module declaration itself instead of line number in the module as the user does not control template in registry directly - if (artifactRefAndUriResult.Key is not ModuleDeclarationSyntax moduleDeclaration - || moduleDeclaration.Path is not StringSyntax moduleDeclarationPath - || moduleDeclarationPath.SegmentValues.Any(v => IsModuleRegistryPathRegex.IsMatch(v))) - { - return null; - } - - if (!artifactRefAndUriResult.Value.IsSuccess()) - { - return null; - } - - var moduleLine = TextCoordinateConverter.GetPosition(bicepSourceFile.LineStarts, moduleDeclaration.Span.Position).line; - var modulePath = new FileInfo(artifactRefAndUriResult.Value.Unwrap().AbsolutePath).FullName; // converts path to current platform + var module = artifactRefAndUriResult.Key as ModuleDeclarationSyntax; + var moduleLine = TextCoordinateConverter.GetPosition(bicepSourceFile.LineStarts, module.Span.Position).line; + var modulePath = new FileInfo(artifactRefAndUriResult.Value.Result.Unwrap().AbsolutePath).FullName; // converts path to current platform // Use relative paths for bicep to match file paths used in bicep modules and source map if (modulePath.EndsWith(".bicep")) { - modulePath = GetPathRelativeToEntryPoint(modulePath); + modulePath = Path.GetRelativePath(entryPointDirectory, modulePath); } return new { moduleLine, modulePath }; }) - .WhereNotNull() .ToDictionary(c => c.moduleLine, c => c.modulePath); - return new SourceFileModuleInfo(pathRelativeToEntryPoint, modules); - }); + return new SourceFileModuleInfo(pathRelativeToEntryPoint, modules); + }); var bicepMetadata = new BicepMetadata() { diff --git a/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs b/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs index 677f9192..74bd8a73 100644 --- a/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs +++ b/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs @@ -1,6 +1,7 @@ using System; using Azure.ResourceManager.Resources; using Bicep.Core.Features; +using Bicep.IO.Abstraction; namespace Microsoft.Azure.Templates.Analyzer.BicepProcessor { @@ -39,7 +40,7 @@ public SourceMapFeatureProvider(IFeatureProvider features) public string AssemblyVersion => features.AssemblyVersion; /// - public string CacheRootDirectory => features.CacheRootDirectory; + public IDirectoryHandle CacheRootDirectory => features.CacheRootDirectory; /// public bool SymbolicNameCodegenEnabled => features.SymbolicNameCodegenEnabled; @@ -54,33 +55,33 @@ public SourceMapFeatureProvider(IFeatureProvider features) public bool SourceMappingEnabled => true; /// - public bool UserDefinedFunctionsEnabled => features.UserDefinedFunctionsEnabled; + public bool TestFrameworkEnabled => features.TestFrameworkEnabled; /// - public bool DynamicTypeLoadingEnabled => features.DynamicTypeLoadingEnabled; + public bool AssertsEnabled => features.AssertsEnabled; /// - public bool PrettyPrintingEnabled => features.PrettyPrintingEnabled; + public bool OptionalModuleNamesEnabled => features.OptionalModuleNamesEnabled; /// - public bool TestFrameworkEnabled => features.TestFrameworkEnabled; + public bool ResourceDerivedTypesEnabled => features.ResourceDerivedTypesEnabled; /// - public bool AssertsEnabled => features.AssertsEnabled; + public bool LegacyFormatterEnabled => features.LegacyFormatterEnabled; /// - public bool MicrosoftGraphPreviewEnabled => features.MicrosoftGraphPreviewEnabled; + public bool LocalDeployEnabled => features.LocalDeployEnabled; /// - public bool PublishSourceEnabled => features.PublishSourceEnabled; + public bool ExtendableParamFilesEnabled => features.ExtendableParamFilesEnabled; /// - public bool ProviderRegistryEnabled => features.ProviderRegistryEnabled; + public bool SecureOutputsEnabled => features.SecureOutputsEnabled; /// - public bool OptionalModuleNamesEnabled => features.OptionalModuleNamesEnabled; + public bool ResourceInfoCodegenEnabled => features.ResourceInfoCodegenEnabled; /// - public bool ResourceDerivedTypesEnabled => features.ResourceDerivedTypesEnabled; + public bool ExtensibilityV2EmittingEnabled => features.ExtensibilityV2EmittingEnabled; } } diff --git a/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj b/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj index ec55f9b3..afb1ae24 100644 --- a/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj +++ b/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj @@ -9,7 +9,6 @@ - diff --git a/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs b/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs index b6f0d218..b3a36247 100644 --- a/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs +++ b/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs @@ -438,7 +438,7 @@ private TemplateExpressionEvaluationHelper GetTemplateFunctionEvaluationHelper(T parametersLookup: parametersLookup, variablesLookup: variablesLookup, validationContext: null, - diagnostics: null); + metricsRecorder: null); // Set reference lookup helper.OnGetTemplateReference = (TemplateReference templateReference) => diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 6121cd4e..a7408859 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -5,20 +5,19 @@ $(NoWarn);NU1507 - - - - - + + + + - - - + + + - + - + @@ -29,10 +28,10 @@ - + - + \ No newline at end of file From d2da3eeaf9dd7520983c378fce4b4c7414a7eaee Mon Sep 17 00:00:00 2001 From: Johnathon Mohr Date: Mon, 17 Mar 2025 18:33:26 -0700 Subject: [PATCH 2/4] Update other packages, revert PSRule update. --- .../Analyzer.BicepProcessor.UnitTests.csproj | 5 ++++- .../Analyzer.Core.BuiltInRuleTests.csproj | 5 ++++- .../Analyzer.Core.UnitTests.csproj | 5 ++++- .../Analyzer.JsonRuleEngine.FunctionalTests.csproj | 5 ++++- .../Analyzer.JsonRuleEngine.UnitTests.csproj | 5 ++++- .../ExistsOperatorTests.cs | 2 +- .../ExpressionConverterTests.cs | 12 ++++++------ .../HasValueOperatorTests.cs | 2 +- .../Analyzer.PowerShellRuleEngine.UnitTests.csproj | 5 ++++- .../PowerShellRuleEngineTests.cs | 4 ++-- .../Analyzer.Reports.UnitTests.csproj | 5 ++++- .../SarifReportWriterE2ETests.cs | 10 +++++----- .../Analyzer.TemplateProcessor.UnitTests.csproj | 5 ++++- .../Analyzer.Utilities.UnitTests.csproj | 5 ++++- src/Directory.Packages.props | 14 +++++++------- 15 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj b/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj index 9b55fde8..67718005 100644 --- a/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj +++ b/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj @@ -8,7 +8,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj b/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj index 92ef0c8e..9292ad4a 100644 --- a/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj +++ b/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj @@ -7,7 +7,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj b/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj index 867abb80..0c0ecf2e 100644 --- a/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj +++ b/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj @@ -8,7 +8,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj b/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj index 6a3c7f06..24e710cd 100644 --- a/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj +++ b/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj @@ -9,7 +9,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj b/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj index c3d6d2f1..8a30dabc 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj +++ b/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj @@ -10,7 +10,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/ExistsOperatorTests.cs b/src/Analyzer.JsonRuleEngine.UnitTests/ExistsOperatorTests.cs index 63694654..27e188a8 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/ExistsOperatorTests.cs +++ b/src/Analyzer.JsonRuleEngine.UnitTests/ExistsOperatorTests.cs @@ -15,7 +15,7 @@ public class ExistsOperatorTests [DataRow(true, DisplayName = "Property value is a boolean")] [DataRow(1, DisplayName = "Property value is an integer")] [DataRow(0.1, DisplayName = "Property value is a float")] - [DataRow(new object[] { }, DisplayName = "Property value is an array")] + [DataRow((object)(new object[] { }), DisplayName = "Property value is an array")] [DataRow(null, DisplayName = "Property value is null")] public void EvaluateExpression_PropertyExists_ExistsExpressionIsTrue(object jTokenValue) { diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs b/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs index 231e3635..f1ffba19 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs +++ b/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs @@ -214,9 +214,9 @@ void ValidateExpression(ExpressionDefinition expression, Type expectedSpecificTy } [DataTestMethod] - [DataRow(DisplayName = "Not Expression")] - [DataRow("not", typeof(NotExpressionDefinition), DisplayName = "Not Expression with Where condition")] - public void ReadJson_ValidNotExpression_ReturnsCorrectTypeAndValues(params object[] whereCondition) + [DataRow(new object[] { }, DisplayName = "Not Expression")] + [DataRow(new object[] { "not", typeof(NotExpressionDefinition) }, DisplayName = "Not Expression with Where condition")] + public void ReadJson_ValidNotExpression_ReturnsCorrectTypeAndValues(object[] whereCondition) { var expressionTemplate = $@" {{ @@ -313,10 +313,10 @@ public void ReadJson_StructuredExpressionWithInvalidExpression_ThrowsParsingExce } [TestMethod] - [DataRow(DisplayName = "No operators")] - [DataRow("hasValue", true, "exists", true, DisplayName = "HasValue and Exists")] + [DataRow(null, DisplayName = "No operators")] + [DataRow(["hasValue", true, "exists", true], DisplayName = "HasValue and Exists")] [ExpectedException(typeof(JsonSerializationException))] - public void ReadJson_LeafWithInvalidOperatorCount_ThrowsParsingException(params object[] operators) + public void ReadJson_LeafWithInvalidOperatorCount_ThrowsParsingException(object[] operators) { var leafDefinition = "{\"resourceType\": \"resource\", \"path\": \"path\""; diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/HasValueOperatorTests.cs b/src/Analyzer.JsonRuleEngine.UnitTests/HasValueOperatorTests.cs index 424ced4f..6afe9231 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/HasValueOperatorTests.cs +++ b/src/Analyzer.JsonRuleEngine.UnitTests/HasValueOperatorTests.cs @@ -14,7 +14,7 @@ public class HasValueOperatorTests [DataRow(true, DisplayName = "Property value is a boolean")] [DataRow(1, DisplayName = "Property value is an integer")] [DataRow(0.1, DisplayName = "Property value is a float")] - [DataRow(new object[] { }, DisplayName = "Property value is an array")] + [DataRow((object)(new object[] { }), DisplayName = "Property value is an array")] public void EvaluateExpression_PropertyHasValue_HasValueIsTrue(object jTokenValue) { var jToken = TestUtilities.ToJToken(jTokenValue); diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj b/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj index b7fb7c2f..1bebd849 100644 --- a/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj @@ -7,7 +7,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs b/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs index 33b9311c..2d29dd5d 100644 --- a/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs @@ -49,7 +49,7 @@ public static void AssemblyInitialize(TestContext context) [DataRow("template_and_resource_level_results.json", true, 14, new int[] { 1, 1, 1, 1, 8, 11, 14, 17, 1, 17, 17, 1, 17, 1 }, DisplayName = "Running all the rules against a template with errors reported in both analysis stages")] [DataRow("template_and_resource_level_results.json", false, 5, new int[] { 11, 17, 17, 17, 17 }, DisplayName = "Running only the security rules against a template with errors reported in both analysis stages")] // TODO add test case for error, warning (rule with severity level of warning?) and informational (also rule with that severity level?) - public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string templateFileName, bool runsAllRules, int expectedErrorCount, dynamic expectedLineNumbers) + public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string templateFileName, bool runsAllRules, int expectedErrorCount, int[] expectedLineNumbers) { Assert.AreEqual(expectedErrorCount, expectedLineNumbers.Length); @@ -97,7 +97,7 @@ public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string temp Assert.AreEqual(expectedErrorCount, failedEvaluations.Count); // PSRule evaluations can change order depending on the OS: - foreach (var expectedLineNumber in expectedLineNumbers) + foreach (int expectedLineNumber in expectedLineNumbers) { var matchingEvaluation = failedEvaluations.Find(evaluation => evaluation.Result.SourceLocation.LineNumber == expectedLineNumber); failedEvaluations.Remove(matchingEvaluation); diff --git a/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj b/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj index 0ab51ac3..524bae23 100644 --- a/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj +++ b/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj @@ -16,7 +16,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.Reports.UnitTests/SarifReportWriterE2ETests.cs b/src/Analyzer.Reports.UnitTests/SarifReportWriterE2ETests.cs index 73c2d986..875f76ad 100644 --- a/src/Analyzer.Reports.UnitTests/SarifReportWriterE2ETests.cs +++ b/src/Analyzer.Reports.UnitTests/SarifReportWriterE2ETests.cs @@ -142,11 +142,11 @@ public void AnalyzeTemplateTests(string template, string referencedTemplate = nu } [DataTestMethod] - [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, DisplayName = "Templates in root directory")] - [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, "subPath", DisplayName = "Template in subdirectory")] - [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, "..", "anotherRepo", "subfolder", DisplayName = "Templates under root directory and outside of root")] - [DataRow("RedisCache.bicep", "RedisAndSQL.bicep", "SQLServerAuditingSettings.bicep", DisplayName = "RedisCache template results have multiple references, file results should be deduped")] - public void AnalyzeDirectoryTests(string firstTemplate, string secondTemplate, string nestedTemplate, params string[] secondTemplatePathPieces) + [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, new string[] { }, DisplayName = "Templates in root directory")] + [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, new string[] { "subPath" }, DisplayName = "Template in subdirectory")] + [DataRow("RedisCache.json", "SQLServerAuditingSettings.json", null, new string[] { "..", "anotherRepo", "subfolder" }, DisplayName = "Templates under root directory and outside of root")] + [DataRow("RedisCache.bicep", "RedisAndSQL.bicep", "SQLServerAuditingSettings.bicep", new string[] { }, DisplayName = "RedisCache template results have multiple references, file results should be deduped")] + public void AnalyzeDirectoryTests(string firstTemplate, string secondTemplate, string nestedTemplate, string[] secondTemplatePathPieces) { var secondTemplateUsesRelativePath = !secondTemplatePathPieces.Contains(".."); diff --git a/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj b/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj index 6c164262..358b8c7b 100644 --- a/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj +++ b/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj @@ -8,7 +8,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj b/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj index a3ce5096..543800fc 100644 --- a/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj +++ b/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj @@ -9,7 +9,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index a7408859..56f8f467 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -9,19 +9,19 @@ - + - - + + - + - - - + + + From 2e76d519de8a1083b8cee3afa19543b28e93a8cb Mon Sep 17 00:00:00 2001 From: Johnathon Mohr Date: Tue, 18 Mar 2025 11:13:56 -0700 Subject: [PATCH 3/4] Missed test update --- .../ExpressionConverterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs b/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs index f1ffba19..87c870f2 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs +++ b/src/Analyzer.JsonRuleEngine.UnitTests/ExpressionConverterTests.cs @@ -313,7 +313,7 @@ public void ReadJson_StructuredExpressionWithInvalidExpression_ThrowsParsingExce } [TestMethod] - [DataRow(null, DisplayName = "No operators")] + [DataRow(new object[] { }, DisplayName = "No operators")] [DataRow(["hasValue", true, "exists", true], DisplayName = "HasValue and Exists")] [ExpectedException(typeof(JsonSerializationException))] public void ReadJson_LeafWithInvalidOperatorCount_ThrowsParsingException(object[] operators) From 6ffbfad9663dbebe488fdb6a8b9ba2eb490ec21a Mon Sep 17 00:00:00 2001 From: Johnathon Mohr Date: Wed, 19 Mar 2025 14:58:51 -0700 Subject: [PATCH 4/4] Additional comments for Bicep processing --- .../BicepTemplateProcessor.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs b/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs index 6c60aeb4..5ba5e290 100644 --- a/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs +++ b/src/Analyzer.BicepProcessor/BicepTemplateProcessor.cs @@ -100,15 +100,19 @@ public static (string, BicepMetadata) ConvertBicepToJson(string bicepPath) string entryPointDirectory = Path.GetDirectoryName(compilation.SourceFileGrouping.EntryPoint.Uri.AbsolutePath); - bool IsLocalModuleReference(KeyValuePair artifact) => + bool IsResolvedLocalModuleReference(KeyValuePair artifact) => + // Only include local module references (not modules imported from public/private registries, i.e. those that match IsModuleRegistryPathRegex), + // as it is more useful for user to see line number of the module declaration itself, + // rather than the line number in the module (as the user does not control the template in the registry directly). artifact.Key is ModuleDeclarationSyntax moduleDeclaration && moduleDeclaration.Path is StringSyntax moduleDeclarationPath && !moduleDeclarationPath.SegmentValues.Any(IsModuleRegistryPathRegex.IsMatch) && artifact.Value.Result.IsSuccess(); - // Collect all needed module info from SourceFileGrouping metadata + // Create SourceFileModuleInfo collection by gathering all needed module info from SourceFileGrouping metadata. + // Group by the source file path to allow for easy construction of SourceFileModuleInfo. var moduleInfo = compilation.SourceFileGrouping.ArtifactLookup - .Where(IsLocalModuleReference) + .Where(IsResolvedLocalModuleReference) .GroupBy(artifact => artifact.Value.Origin) .Select(grouping => { @@ -116,6 +120,9 @@ moduleDeclaration.Path is StringSyntax moduleDeclarationPath && var pathRelativeToEntryPoint = Path.GetRelativePath( Path.GetDirectoryName(compilation.SourceFileGrouping.EntryPoint.Uri.AbsolutePath), bicepSourceFile.Uri.AbsolutePath); + // Use the grouping value (KeyValuePair) to create + // a dictionary of module line numbers to file paths. + // This represents the modules in the source file, and where (what lines) they are referenced. var modules = grouping.Select(artifactRefAndUriResult => { var module = artifactRefAndUriResult.Key as ModuleDeclarationSyntax;