diff --git a/src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs b/src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs index aa88d970109..72a7aa2bf1c 100644 --- a/src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs +++ b/src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs @@ -286,29 +286,25 @@ public async Task Build_LockedOutputFile_ShouldProduceExpectedError() } [TestMethod] - public async Task Build_WithEmptyBicepConfig_ShouldProduceOutputFile() + public async Task Build_WithEmptyBicepConfig_ShouldProduceConfigurationError() { string testOutputPath = Path.Combine(TestContext.ResultsDirectory, Guid.NewGuid().ToString()); var inputFile = FileHelper.SaveResultFile(this.TestContext, "main.bicep", DataSets.Empty.Bicep, testOutputPath); - FileHelper.SaveResultFile(this.TestContext, "bicepconfig.json", string.Empty, testOutputPath); + var configurationPath = FileHelper.SaveResultFile(this.TestContext, "bicepconfig.json", string.Empty, testOutputPath); var (output, error, result) = await Bicep("build", inputFile); - result.Should().Be(0); + result.Should().Be(1); output.Should().BeEmpty(); - error.Should().BeEmpty(); - - var expectedOutputFile = Path.Combine(testOutputPath, "main.json"); - - File.Exists(expectedOutputFile).Should().BeTrue(); + error.Should().StartWith($"Failed to parse the contents of the Bicep configuration file \"{configurationPath}\" as valid JSON: \"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. LineNumber: 0 | BytePositionInLine: 0.\"."); } [TestMethod] - public async Task Build_WithInvalidBicepConfig_ShouldProduceOutputFile() + public async Task Build_WithInvalidBicepConfig_ShouldProduceConfigurationError() { string testOutputPath = Path.Combine(TestContext.ResultsDirectory, Guid.NewGuid().ToString()); var inputFile = FileHelper.SaveResultFile(this.TestContext, "main.bicep", DataSets.Empty.Bicep, testOutputPath); - FileHelper.SaveResultFile(this.TestContext, "bicepconfig.json", @"{ + var configurationPath = FileHelper.SaveResultFile(this.TestContext, "bicepconfig.json", @"{ ""analyzers"": { ""core"": { ""verbose"": false, @@ -320,13 +316,9 @@ public async Task Build_WithInvalidBicepConfig_ShouldProduceOutputFile() var (output, error, result) = await Bicep("build", inputFile); - result.Should().Be(0); + result.Should().Be(1); output.Should().BeEmpty(); - error.Should().BeEmpty(); - - var expectedOutputFile = Path.Combine(testOutputPath, "main.json"); - - File.Exists(expectedOutputFile).Should().BeTrue(); + error.Should().StartWith($"Failed to parse the contents of the Bicep configuration file \"{configurationPath}\" as valid JSON: \"Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. LineNumber: 8 | BytePositionInLine: 0.\"."); } [TestMethod] diff --git a/src/Bicep.Cli.IntegrationTests/TestBase.cs b/src/Bicep.Cli.IntegrationTests/TestBase.cs index 893672d0988..f9d055d95be 100644 --- a/src/Bicep.Cli.IntegrationTests/TestBase.cs +++ b/src/Bicep.Cli.IntegrationTests/TestBase.cs @@ -59,7 +59,7 @@ protected static IEnumerable GetAllDiagnostics(string bicepFilePath, ICo { var dispatcher = new ModuleDispatcher(new DefaultModuleRegistryProvider(BicepTestConstants.FileResolver, clientFactory, templateSpecRepositoryFactory, BicepTestConstants.Features)); var sourceFileGrouping = SourceFileGroupingBuilder.Build(BicepTestConstants.FileResolver, dispatcher, new Workspace(), PathHelper.FilePathToFileUrl(bicepFilePath)); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, BicepTestConstants.BuiltInConfiguration); var output = new List(); foreach (var (bicepFile, diagnostics) in compilation.GetAllDiagnosticsByBicepFile()) diff --git a/src/Bicep.Cli.IntegrationTests/packages.lock.json b/src/Bicep.Cli.IntegrationTests/packages.lock.json index 35954c3b2bd..f4d520ca7d2 100644 --- a/src/Bicep.Cli.IntegrationTests/packages.lock.json +++ b/src/Bicep.Cli.IntegrationTests/packages.lock.json @@ -1380,6 +1380,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2261,7 +2277,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2296,6 +2313,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.Cli.UnitTests/packages.lock.json b/src/Bicep.Cli.UnitTests/packages.lock.json index 9a0377f29be..c2a0e3ecde4 100644 --- a/src/Bicep.Cli.UnitTests/packages.lock.json +++ b/src/Bicep.Cli.UnitTests/packages.lock.json @@ -292,8 +292,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -671,6 +671,14 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -724,6 +732,15 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.IO.FileSystem.Primitives": { "type": "Transitive", "resolved": "4.3.0", @@ -1009,6 +1026,15 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.Algorithms": { "type": "Transitive", "resolved": "4.3.0", @@ -1158,6 +1184,11 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, "System.Text.Encoding": { "type": "Transitive", "resolved": "4.3.0", @@ -1296,7 +1327,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -1752,6 +1784,15 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -1951,18 +1992,13 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.Algorithms": { @@ -2100,34 +2136,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -2622,6 +2634,15 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -2821,18 +2842,13 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.Algorithms": { @@ -2970,34 +2986,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -3492,6 +3484,15 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -3691,18 +3692,13 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.Algorithms": { @@ -3840,34 +3836,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -4344,6 +4316,15 @@ "runtime.win.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -4542,18 +4523,13 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.Algorithms": { @@ -4691,34 +4667,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", diff --git a/src/Bicep.Cli/BicepException.cs b/src/Bicep.Cli/BicepException.cs deleted file mode 100644 index 6e43db206f3..00000000000 --- a/src/Bicep.Cli/BicepException.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; - -namespace Bicep.Cli -{ - /// - /// Exception used to signal common error conditions. Message will logged to StdErr as-is. - /// - public class BicepException : Exception - { - public BicepException(string message) : base(message) - { - } - - public BicepException(string message, Exception? inner) : base(message, inner) - { - } - } -} diff --git a/src/Bicep.Cli/CommandLineException.cs b/src/Bicep.Cli/CommandLineException.cs index 03622b62404..1d474a7f8e3 100644 --- a/src/Bicep.Cli/CommandLineException.cs +++ b/src/Bicep.Cli/CommandLineException.cs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Bicep.Core.Exceptions; using System; namespace Bicep.Cli { - public class CommandLineException : Exception + public class CommandLineException : BicepException { public CommandLineException(string message, Exception? inner = null) : base(message, inner) diff --git a/src/Bicep.Cli/Commands/PublishCommand.cs b/src/Bicep.Cli/Commands/PublishCommand.cs index 38a99068a2c..3598e6550c1 100644 --- a/src/Bicep.Cli/Commands/PublishCommand.cs +++ b/src/Bicep.Cli/Commands/PublishCommand.cs @@ -5,6 +5,7 @@ using Bicep.Cli.Logging; using Bicep.Cli.Services; using Bicep.Core.Diagnostics; +using Bicep.Core.Exceptions; using Bicep.Core.FileSystem; using Bicep.Core.Modules; using Bicep.Core.Parsing; diff --git a/src/Bicep.Cli/Program.cs b/src/Bicep.Cli/Program.cs index 85db92c1caa..8c879876140 100644 --- a/src/Bicep.Cli/Program.cs +++ b/src/Bicep.Cli/Program.cs @@ -6,8 +6,9 @@ using Bicep.Cli.Helpers; using Bicep.Cli.Logging; using Bicep.Cli.Services; -using Bicep.Core.Diagnostics; +using Bicep.Core.Configuration; using Bicep.Core.Emit; +using Bicep.Core.Exceptions; using Bicep.Core.Features; using Bicep.Core.FileSystem; using Bicep.Core.Registry; @@ -19,6 +20,7 @@ using Microsoft.Extensions.Logging; using System; using System.Diagnostics; +using System.IO.Abstractions; using System.Runtime; using System.Threading.Tasks; @@ -86,21 +88,11 @@ public async Task RunAsync(string[] args) return 1; } } - catch (CommandLineException exception) - { - invocationContext.ErrorWriter.WriteLine(exception.Message); - return 1; - } catch (BicepException exception) { invocationContext.ErrorWriter.WriteLine(exception.Message); return 1; } - catch (ErrorDiagnosticException exception) - { - invocationContext.ErrorWriter.WriteLine(exception.Message); - return 1; - } } private ILoggerFactory CreateLoggerFactory() @@ -122,6 +114,8 @@ private ServiceProvider ConfigureServices() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/Bicep.Cli/Services/CompilationService.cs b/src/Bicep.Cli/Services/CompilationService.cs index 2a21c44bbc3..700777d0a13 100644 --- a/src/Bicep.Cli/Services/CompilationService.cs +++ b/src/Bicep.Cli/Services/CompilationService.cs @@ -7,12 +7,10 @@ using Bicep.Core.FileSystem; using Bicep.Core.Registry; using Bicep.Core.Semantics; -using Bicep.Core.TypeSystem.Az; using Bicep.Core.Workspaces; using Bicep.Decompiler; using System; using System.Collections.Immutable; -using System.IO; using System.Threading.Tasks; namespace Bicep.Cli.Services @@ -22,15 +20,23 @@ public class CompilationService private readonly IDiagnosticLogger diagnosticLogger; private readonly IFileResolver fileResolver; private readonly IModuleDispatcher moduleDispatcher; + private readonly IConfigurationManager configurationManager; private readonly InvocationContext invocationContext; private readonly Workspace workspace; private readonly TemplateDecompiler decompiler; - public CompilationService(IDiagnosticLogger diagnosticLogger, IFileResolver fileResolver, InvocationContext invocationContext, IModuleDispatcher moduleDispatcher, TemplateDecompiler decompiler) + public CompilationService( + IDiagnosticLogger diagnosticLogger, + IFileResolver fileResolver, + InvocationContext invocationContext, + IModuleDispatcher moduleDispatcher, + IConfigurationManager configurationManager, + TemplateDecompiler decompiler) { this.diagnosticLogger = diagnosticLogger; this.fileResolver = fileResolver; this.moduleDispatcher = moduleDispatcher; + this.configurationManager = configurationManager; this.invocationContext = invocationContext; this.workspace = new Workspace(); this.decompiler = decompiler; @@ -64,32 +70,14 @@ public async Task CompileAsync(string inputPath, bool skipRestore) } } - var configHelper = GetConfigHelper(inputUri); - var compilation = new Compilation(this.invocationContext.NamespaceProvider, sourceFileGrouping, configHelper); + var configuration = this.configurationManager.GetConfiguration(inputUri); + var compilation = new Compilation(this.invocationContext.NamespaceProvider, sourceFileGrouping, configuration); LogDiagnostics(compilation); return compilation; } - private ConfigHelper GetConfigHelper(Uri uri) - { - ConfigHelper configHelper; - - try - { - configHelper = new ConfigHelper(Path.GetDirectoryName(uri.LocalPath), fileResolver); - } - catch (Exception ex) - { - Console.Out.WriteLine(ex.Message); - - configHelper = new ConfigHelper(null, fileResolver, useDefaultConfig: true).GetDisabledLinterConfig(); - } - - return configHelper; - } - public async Task<(Uri, ImmutableDictionary)> DecompileAsync(string inputPath, string outputPath) { inputPath = PathHelper.ResolvePath(inputPath); diff --git a/src/Bicep.Cli/Services/CompilationWriter.cs b/src/Bicep.Cli/Services/CompilationWriter.cs index 25701e63bfc..4213548a8ff 100644 --- a/src/Bicep.Cli/Services/CompilationWriter.cs +++ b/src/Bicep.Cli/Services/CompilationWriter.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Bicep.Core.Emit; +using Bicep.Core.Exceptions; using Bicep.Core.Semantics; using Newtonsoft.Json; using System; diff --git a/src/Bicep.Cli/packages.lock.json b/src/Bicep.Cli/packages.lock.json index 11fb98fd77f..1d7621c5650 100644 --- a/src/Bicep.Cli/packages.lock.json +++ b/src/Bicep.Cli/packages.lock.json @@ -242,6 +242,11 @@ "System.Security.Cryptography.ProtectedData": "4.5.0" } }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -262,6 +267,23 @@ "resolved": "4.6.0", "contentHash": "mbBgoR0rRfl2uimsZ2avZY8g7Xnh1Mza0rJZLPcxqiMWlkGukjmRkuMJ/er+AhQuiRIh80CR/Hpeztr80seV5g==" }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.4", @@ -286,11 +308,25 @@ "resolved": "4.7.0", "contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, "System.Text.Encodings.Web": { "type": "Transitive", "resolved": "4.7.2", @@ -321,7 +357,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -340,31 +377,123 @@ } }, ".NETCoreApp,Version=v5.0/linux-musl-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/linux-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/osx-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/win-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } } } diff --git a/src/Bicep.Core.IntegrationTests/DecoratorTests.cs b/src/Bicep.Core.IntegrationTests/DecoratorTests.cs index 6a64e14ceb4..e879f94467f 100644 --- a/src/Bicep.Core.IntegrationTests/DecoratorTests.cs +++ b/src/Bicep.Core.IntegrationTests/DecoratorTests.cs @@ -81,7 +81,7 @@ param inputb string ", }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnosticsByFile = compilation.GetAllDiagnosticsByBicepFile().ToDictionary(kvp => kvp.Key.FileUri, kvp => kvp.Value); var success = diagnosticsByFile.Values.SelectMany(x => x).All(d => d.Level != DiagnosticLevel.Error); @@ -162,7 +162,7 @@ param inputb string ", }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnosticsByFile = compilation.GetAllDiagnosticsByBicepFile().ToDictionary(kvp => kvp.Key.FileUri, kvp => kvp.Value); var success = diagnosticsByFile.Values.SelectMany(x => x).All(d => d.Level != DiagnosticLevel.Error); diff --git a/src/Bicep.Core.IntegrationTests/Emit/TemplateEmitterTests.cs b/src/Bicep.Core.IntegrationTests/Emit/TemplateEmitterTests.cs index d2695aab3cc..ae1977047f1 100644 --- a/src/Bicep.Core.IntegrationTests/Emit/TemplateEmitterTests.cs +++ b/src/Bicep.Core.IntegrationTests/Emit/TemplateEmitterTests.cs @@ -213,7 +213,7 @@ public void TemplateEmitter_should_not_dispose_text_writer() private EmitResult EmitTemplate(SourceFileGrouping sourceFileGrouping, EmitterSettings emitterSettings, string filePath) { - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, BicepTestConstants.BuiltInConfiguration); var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings); using var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); @@ -222,7 +222,7 @@ private EmitResult EmitTemplate(SourceFileGrouping sourceFileGrouping, EmitterSe private EmitResult EmitTemplate(SourceFileGrouping sourceFileGrouping, EmitterSettings emitterSettings, MemoryStream memoryStream) { - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, BicepTestConstants.BuiltInConfiguration); var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings); TextWriter tw = new StreamWriter(memoryStream); diff --git a/src/Bicep.Core.IntegrationTests/ModuleTests.cs b/src/Bicep.Core.IntegrationTests/ModuleTests.cs index e2a4f793e98..41f6d0b99d6 100644 --- a/src/Bicep.Core.IntegrationTests/ModuleTests.cs +++ b/src/Bicep.Core.IntegrationTests/ModuleTests.cs @@ -78,7 +78,7 @@ param inputb string }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile.Values.SelectMany(x => x).Should().BeEmpty(); @@ -108,7 +108,7 @@ param inputb string }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile[mainUri].Should().HaveDiagnostics(new[] { @@ -163,7 +163,7 @@ param inputb string }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile[mainUri].Should().HaveDiagnostics(new[] { @@ -229,7 +229,7 @@ param inputb string var dispatcher = new ModuleDispatcher(new DefaultModuleRegistryProvider(mockFileResolver.Object, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingBuilder.Build(mockFileResolver.Object, dispatcher, new Workspace(), mainFileUri), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingBuilder.Build(mockFileResolver.Object, dispatcher, new Workspace(), mainFileUri), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile[mainFileUri].Should().HaveDiagnostics(new[] { @@ -302,7 +302,7 @@ param inputb int }; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile.Values.SelectMany(x => x).Should().BeEmpty(); @@ -330,7 +330,7 @@ param inputb int { [moduleAUri] = files[moduleAUri] }, - moduleAUri, BicepTestConstants.FileResolver), null), moduleATemplateHash); + moduleAUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration), moduleATemplateHash); ModuleTemplateHashValidator( new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(new Dictionary @@ -338,14 +338,14 @@ param inputb int [moduleBUri] = files[moduleBUri], [moduleCUri] = files[moduleCUri] }, - moduleBUri, BicepTestConstants.FileResolver), null), moduleBTemplateHash); + moduleBUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration), moduleBTemplateHash); ModuleTemplateHashValidator( new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(new Dictionary { [moduleCUri] = files[moduleCUri] }, - moduleCUri, BicepTestConstants.FileResolver), null), moduleCTemplateHash); + moduleCUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration), moduleCTemplateHash); } [TestMethod] @@ -373,7 +373,7 @@ param inputb string var dispatcher = new ModuleDispatcher(new DefaultModuleRegistryProvider(mockFileResolver.Object, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingBuilder.Build(mockFileResolver.Object, dispatcher, new Workspace(), mainUri), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingBuilder.Build(mockFileResolver.Object, dispatcher, new Workspace(), mainUri), BicepTestConstants.BuiltInConfiguration); var (success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile[mainUri].Should().HaveDiagnostics(new[] { diff --git a/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs b/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs index 8112dedfe1c..ca0fa5e22e9 100644 --- a/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs +++ b/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs @@ -53,7 +53,7 @@ public void NestedResources_symbols_are_bound() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); @@ -91,7 +91,7 @@ public void NestedResources_resource_can_contain_property_called_resource() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); // The property "resource" is not allowed ... @@ -149,7 +149,7 @@ public void NestedResources_valid_resource_references() output fromGrandchild string = parent::child::grandchild.properties.style "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); @@ -209,7 +209,7 @@ public void NestedResources_invalid_resource_references() output fromGrandchildInvalid string = parent::child::cousin.properties.temperature "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().HaveDiagnostics(new[]{ @@ -244,7 +244,7 @@ public void NestedResources_child_cannot_be_referenced_outside_of_scope() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); diagnostics.ExcludingMissingTypes().Should().HaveDiagnostics(new[] { ("BCP057", DiagnosticLevel.Error, "The name \"child\" does not exist in the current context."), @@ -269,7 +269,7 @@ public void NestedResources_child_cannot_specify_qualified_type() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); diagnostics.ExcludingMissingTypes().Should().HaveDiagnostics(new[] { ("BCP156", DiagnosticLevel.Error, "The resource type segment \"My.RP/parentType/childType@2020-01-01\" is invalid. Nested resources must specify a single type segment, and optionally can specify an api version using the format \"@\"."), @@ -294,7 +294,7 @@ public void NestedResources_error_in_base_type() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); diagnostics.Should().HaveDiagnostics(new[] { ("BCP029", DiagnosticLevel.Error, "The resource type is not valid. Specify a valid resource type of format \"/@\"."), @@ -326,7 +326,7 @@ public void NestedResources_error_in_parent_type() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); diagnostics.ExcludingMissingTypes().Should().HaveDiagnostics(new[] { ("BCP156", DiagnosticLevel.Error, "The resource type segment \"My.RP/parentType/childType@2020-01-01\" is invalid. Nested resources must specify a single type segment, and optionally can specify an api version using the format \"@\"."), @@ -353,7 +353,7 @@ public void NestedResources_child_cycle_is_detected_correctly() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); compilation.GetEntrypointSemanticModel().GetAllDiagnostics().ExcludingMissingTypes().Should().HaveDiagnostics(new[] { ("BCP080", DiagnosticLevel.Error, "The expression is involved in a cycle (\"child\" -> \"parent\")."), }); @@ -384,7 +384,7 @@ public void NestedResources_grandchild_cycle_results_in_binding_failure() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); compilation.GetEntrypointSemanticModel().GetAllDiagnostics().ExcludingMissingTypes().Should().HaveDiagnostics(new[] { ("BCP057", DiagnosticLevel.Error, "The name \"grandchild\" does not exist in the current context."), }); @@ -413,7 +413,7 @@ public void NestedResources_ancestors_are_detected() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); @@ -462,7 +462,7 @@ public void NestedResources_scopes_isolate_names() } "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); @@ -566,7 +566,7 @@ public void NestedResources_can_get_declared_type_for_property_completion() output hmmmm string = parent::child.properties "; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); var output = model.Root.OutputDeclarations.Single(); diff --git a/src/Bicep.Core.IntegrationTests/RegistryTests.cs b/src/Bicep.Core.IntegrationTests/RegistryTests.cs index dc5774453fb..6b12b2402dc 100644 --- a/src/Bicep.Core.IntegrationTests/RegistryTests.cs +++ b/src/Bicep.Core.IntegrationTests/RegistryTests.cs @@ -68,7 +68,7 @@ public async Task InvalidRootCachePathShouldProduceReasonableErrors() sourceFileGrouping = SourceFileGroupingBuilder.Rebuild(dispatcher, workspace, sourceFileGrouping); } - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, null); + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetAllDiagnosticsByBicepFile(); diagnostics.Should().HaveCount(1); diff --git a/src/Bicep.Core.IntegrationTests/Scenarios/FallbackTopLevelResourcePropertiesTests.cs b/src/Bicep.Core.IntegrationTests/Scenarios/FallbackTopLevelResourcePropertiesTests.cs index 926cf42a938..1694129cb49 100644 --- a/src/Bicep.Core.IntegrationTests/Scenarios/FallbackTopLevelResourcePropertiesTests.cs +++ b/src/Bicep.Core.IntegrationTests/Scenarios/FallbackTopLevelResourcePropertiesTests.cs @@ -21,8 +21,12 @@ namespace Bicep.Core.IntegrationTests.Scenarios [TestClass] public class FallbackTopLevelResourcePropertiesTests { - private static ConfigHelper configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - private static Compilation CreateCompilation(string program) => new(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), configHelper); + private static readonly RootConfiguration configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + + private static Compilation CreateCompilation(string program) => new( + BuiltInTestTypes.Create(), + SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), + configuration); public static IEnumerable FallbackProperties { @@ -175,7 +179,7 @@ param inputb string ", }; - var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), configuration); compilation.Should().HaveDiagnostics(new[] { ("BCP037", DiagnosticLevel.Error, $"The property \"{property}\" is not allowed on objects of type \"module\". Permissible properties include \"dependsOn\", \"scope\".") @@ -216,7 +220,7 @@ param inputb string ", }; - var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), configuration); compilation.Should().HaveDiagnostics(new[] { ("BCP037", DiagnosticLevel.Error, $"The property \"{property}\" is not allowed on objects of type \"params\". Permissible properties include \"inputc\".") @@ -259,7 +263,7 @@ param inputb string ", }; - var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), configuration); compilation.Should().HaveDiagnostics(new[] { ("BCP037", DiagnosticLevel.Error, $"The property \"{property}\" from source declaration \"inputs\" is not allowed on objects of type \"params\". Permissible properties include \"inputc\"."), @@ -298,7 +302,7 @@ param inputb string ", }; - var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), configHelper); + var compilation = new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), configuration); compilation.Should().HaveDiagnostics(new[] { ("BCP053", DiagnosticLevel.Error, $"The type \"module\" does not contain property \"{property}\". Available properties include \"name\", \"outputs\".") diff --git a/src/Bicep.Core.IntegrationTests/Semantics/CompilationTests.cs b/src/Bicep.Core.IntegrationTests/Semantics/CompilationTests.cs index 9f0bd7c821f..62852d0c28c 100644 --- a/src/Bicep.Core.IntegrationTests/Semantics/CompilationTests.cs +++ b/src/Bicep.Core.IntegrationTests/Semantics/CompilationTests.cs @@ -3,6 +3,7 @@ using Bicep.Core.FileSystem; using Bicep.Core.Samples; using Bicep.Core.Semantics; +using Bicep.Core.UnitTests; using Bicep.Core.UnitTests.Utils; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -17,7 +18,7 @@ public void EmptyProgram_SourceFileGrouping_should_be_persisted() { var fileResolver = new FileResolver(); var program = SourceFileGroupingFactory.CreateFromText(DataSets.Empty.Bicep, fileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), program, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), program, BicepTestConstants.BuiltInConfiguration); compilation.SourceFileGrouping.Should().BeSameAs(program); compilation.GetEntrypointSemanticModel().Should().NotBeNull(); diff --git a/src/Bicep.Core.IntegrationTests/Semantics/SemanticModelTests.cs b/src/Bicep.Core.IntegrationTests/Semantics/SemanticModelTests.cs index 47eda611b02..5009933e61a 100644 --- a/src/Bicep.Core.IntegrationTests/Semantics/SemanticModelTests.cs +++ b/src/Bicep.Core.IntegrationTests/Semantics/SemanticModelTests.cs @@ -55,7 +55,7 @@ public async Task ProgramsShouldProduceExpectedDiagnostics(DataSet dataSet) [TestMethod] public void EndOfFileFollowingSpaceAfterParameterKeyWordShouldNotThrow() { - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("parameter ", BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("parameter ", BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); compilation.GetEntrypointSemanticModel().GetParseDiagnostics(); } diff --git a/src/Bicep.Core.IntegrationTests/TypeSystem/TypeValidationTests.cs b/src/Bicep.Core.IntegrationTests/TypeSystem/TypeValidationTests.cs index e949a836ab4..b7f145d6bc1 100644 --- a/src/Bicep.Core.IntegrationTests/TypeSystem/TypeValidationTests.cs +++ b/src/Bicep.Core.IntegrationTests/TypeSystem/TypeValidationTests.cs @@ -20,9 +20,8 @@ public class TypeValidationTests private static SemanticModel GetSemanticModelForTest(string programText, IEnumerable definedTypes) { var typeProvider = TestTypeHelper.CreateProviderWithTypes(definedTypes); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - - var compilation = new Compilation(typeProvider, SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), configHelper); + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + var compilation = new Compilation(typeProvider, SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), configuration); return compilation.GetEntrypointSemanticModel(); } @@ -382,7 +381,6 @@ public void Json_function_can_obtain_types_for_string_literal_json_args() GetTypeForNamedSymbol(model, "invalidPropAccess").Name.Should().Be("error"); - var noLinterConfig = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); model.GetAllDiagnostics().Should().SatisfyRespectively( x => x.Should().HaveCodeAndSeverity("BCP083", DiagnosticLevel.Error).And.HaveMessage("The type \"object\" does not contain property \"invalidProp\". Did you mean \"validProp\"?") ); diff --git a/src/Bicep.Core.IntegrationTests/packages.lock.json b/src/Bicep.Core.IntegrationTests/packages.lock.json index 82de97fa29a..0643987cba8 100644 --- a/src/Bicep.Core.IntegrationTests/packages.lock.json +++ b/src/Bicep.Core.IntegrationTests/packages.lock.json @@ -1380,6 +1380,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2251,7 +2267,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2286,6 +2303,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.Core.Samples/DataSetsExtensions.cs b/src/Bicep.Core.Samples/DataSetsExtensions.cs index f2ea095484d..40db9713638 100644 --- a/src/Bicep.Core.Samples/DataSetsExtensions.cs +++ b/src/Bicep.Core.Samples/DataSetsExtensions.cs @@ -55,7 +55,7 @@ public static string SaveFilesToTestDirectory(this DataSet dataSet, TestContext sourceFileGrouping = SourceFileGroupingBuilder.Rebuild(dispatcher, workspace, sourceFileGrouping); } - return (new Compilation(namespaceProvider, sourceFileGrouping, null), outputDirectory, fileUri); + return (new Compilation(namespaceProvider, sourceFileGrouping, BicepTestConstants.BuiltInConfiguration), outputDirectory, fileUri); } public static IContainerRegistryClientFactory CreateMockRegistryClients(this DataSet dataSet, TestContext testContext, params (Uri registryUri, string repository)[] additionalClients) diff --git a/src/Bicep.Core.Samples/ExamplesTests.cs b/src/Bicep.Core.Samples/ExamplesTests.cs index cbde310dc82..6b7647e634b 100644 --- a/src/Bicep.Core.Samples/ExamplesTests.cs +++ b/src/Bicep.Core.Samples/ExamplesTests.cs @@ -121,14 +121,11 @@ public void ExampleIsValid(ExampleData example) var dispatcher = new ModuleDispatcher(BicepTestConstants.RegistryProvider); var sourceFileGrouping = SourceFileGroupingBuilder.Build(BicepTestConstants.FileResolver, dispatcher, new Workspace(), PathHelper.FilePathToFileUrl(bicepFileName)); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, configHelper); + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, configuration); var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), EmitterSettingsHelper.DefaultTestSettings); - // quiet the linter diagnostics - var overrideConfig = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - - foreach (var (bicepFile, diagnostics) in compilation.GetAllDiagnosticsByBicepFile(overrideConfig)) + foreach (var (bicepFile, diagnostics) in compilation.GetAllDiagnosticsByBicepFile()) { DiagnosticAssertions.DoWithDiagnosticAnnotations( bicepFile, @@ -188,14 +185,11 @@ public void ExampleIsValid_using_experimental_symbolic_names(ExampleData example var dispatcher = new ModuleDispatcher(BicepTestConstants.RegistryProvider); var sourceFileGrouping = SourceFileGroupingBuilder.Build(BicepTestConstants.FileResolver, dispatcher, new Workspace(), PathHelper.FilePathToFileUrl(bicepFileName)); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, configHelper); + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, sourceFileGrouping, configuration); var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), EmitterSettingsHelper.WithSymbolicNamesEnabled); - // quiet the linter diagnostics - var overrideConfig = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - - foreach (var (bicepFile, diagnostics) in compilation.GetAllDiagnosticsByBicepFile(overrideConfig)) + foreach (var (bicepFile, diagnostics) in compilation.GetAllDiagnosticsByBicepFile()) { DiagnosticAssertions.DoWithDiagnosticAnnotations( bicepFile, diff --git a/src/Bicep.Core.Samples/packages.lock.json b/src/Bicep.Core.Samples/packages.lock.json index 7442c02f441..f2f53681a37 100644 --- a/src/Bicep.Core.Samples/packages.lock.json +++ b/src/Bicep.Core.Samples/packages.lock.json @@ -1380,6 +1380,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2251,7 +2267,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2274,6 +2291,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.Core.UnitTests/Bicep.Core.UnitTests.csproj b/src/Bicep.Core.UnitTests/Bicep.Core.UnitTests.csproj index 8f52bf77c28..42a98227cc7 100644 --- a/src/Bicep.Core.UnitTests/Bicep.Core.UnitTests.csproj +++ b/src/Bicep.Core.UnitTests/Bicep.Core.UnitTests.csproj @@ -20,6 +20,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Bicep.Core.UnitTests/BicepTestConstants.cs b/src/Bicep.Core.UnitTests/BicepTestConstants.cs index d5ab941665e..1cd6934e2fb 100644 --- a/src/Bicep.Core.UnitTests/BicepTestConstants.cs +++ b/src/Bicep.Core.UnitTests/BicepTestConstants.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Bicep.Core.Configuration; using Bicep.Core.Features; using Bicep.Core.FileSystem; using Bicep.Core.Registry; @@ -10,6 +11,7 @@ using Bicep.Core.UnitTests.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.Core.UnitTests { @@ -33,6 +35,12 @@ public static class BicepTestConstants public static readonly IModuleRegistryProvider RegistryProvider = new DefaultModuleRegistryProvider(FileResolver, ClientFactory, TemplateSpecRepositoryFactory, Features); + public static readonly IConfigurationManager ConfigurationManager = new ConfigurationManager(new IOFileSystem()); + + public static readonly RootConfiguration BuiltInConfiguration = ConfigurationManager.GetBuiltInConfiguration(); + + public static readonly RootConfiguration BuiltInConfigurationWithAnalyzersDisabled = ConfigurationManager.GetBuiltInConfiguration(disableAnalyzers: true); + public static IFeatureProvider CreateFeaturesProvider(TestContext testContext, bool registryEnabled = false, bool symbolicNameCodegenEnabled = false, bool importsEnabled = false) { var mock = CreateMockFeaturesProvider( diff --git a/src/Bicep.Core.UnitTests/Configuration/ConfigurationManagerTests.cs b/src/Bicep.Core.UnitTests/Configuration/ConfigurationManagerTests.cs new file mode 100644 index 00000000000..5ae2cc9019c --- /dev/null +++ b/src/Bicep.Core.UnitTests/Configuration/ConfigurationManagerTests.cs @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Bicep.Core.Configuration; +using Bicep.Core.UnitTests.Mock; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; +using IOFileSystem = System.IO.Abstractions.FileSystem; + +namespace Bicep.Core.UnitTests.Configuration +{ + [TestClass] + public class ConfigurationManagerTests + { + [NotNull] + public TestContext? TestContext { get; set; } + + [TestMethod] + public void GetBuiltInConfiguration_NoParameter_ReturnsBuiltInConfigurationWithAnalyzerSettings() + { + // Arrange. + var sut = new ConfigurationManager(new IOFileSystem()); + + // Act. + var configuration = sut.GetBuiltInConfiguration(); + + // Assert. + configuration.Cloud.CurrentProfile.Should().NotBeNull(); + configuration.Cloud.CurrentProfile!.ResourceManagerEndpoint.Should().Be("https://management.azure.com"); + + configuration.ModuleAliases.TemplateSpecModuleAliases.Should().BeEmpty(); + configuration.ModuleAliases.BicepRegistryModuleAliases.Should().BeEmpty(); + + configuration.Analyzers.GetValue("core:verbose", true).Should().BeFalse(); + configuration.Analyzers.GetValue("core:enabled", false).Should().BeTrue(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:level", "").Should().Be("warning"); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:disallowedhosts", Array.Empty()).Should().NotBeEmpty(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:excludedhosts", Array.Empty()).Should().NotBeEmpty(); + } + + [TestMethod] + public void GetBuiltInConfiguration_DisableAnalyzers_ReturnsBuiltInConfigurationWithoutAnalyzerSettings() + { + // Arrange. + var sut = new ConfigurationManager(new IOFileSystem()); + + // Act. + var configuration = sut.GetBuiltInConfiguration(disableAnalyzers: true); + + // Assert. + configuration.Cloud.CurrentProfile.Should().NotBeNull(); + configuration.Cloud.CurrentProfile!.ResourceManagerEndpoint.Should().Be("https://management.azure.com"); + + configuration.ModuleAliases.TemplateSpecModuleAliases.Should().BeEmpty(); + configuration.ModuleAliases.BicepRegistryModuleAliases.Should().BeEmpty(); + + configuration.Analyzers.GetValue("core:verbose", true).Should().BeTrue(); + configuration.Analyzers.GetValue("core:enabled", false).Should().BeFalse(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:level", "").Should().BeEmpty(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:disallowedhosts", Array.Empty()).Should().BeEmpty(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:excludedhosts", Array.Empty()).Should().BeEmpty(); + } + + [TestMethod] + public void GetConfiguration_CustomConfigurationNotFound_ReturnsBuiltInConfiguration() + { + // Arrange. + var sut = new ConfigurationManager(new IOFileSystem()); + var sourceFileUri = new Uri(this.CreatePath("foo/bar/main.bicep")); + + // Act. + var configuration = sut.GetConfiguration(sourceFileUri); + + // Assert. + configuration.Should().Be(sut.GetBuiltInConfiguration()); + } + + [TestMethod] + public void GetConfiguration_InvalidCustomConfiguration_ThrowsFailedToParseConfigurationException() + { + // Arrange. + var configurataionPath = CreatePath("path/to/bicepconfig.json"); + var fileSystem = new MockFileSystem(new Dictionary + { + [configurataionPath] = "", + }); + + var sut = new ConfigurationManager(fileSystem); + var sourceFileUri = new Uri(CreatePath("path/to/main.bicep")); + + // Act & Assert. + FluentActions.Invoking(() => sut.GetConfiguration(sourceFileUri)).Should() + .Throw() + .WithMessage($"Failed to parse the contents of the Bicep configuration file \"{configurataionPath}\" as valid JSON: \"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. LineNumber: 0 | BytePositionInLine: 0.\"."); + } + + [TestMethod] + public void GetConfiguration_ConfigurationFileNotReadable_ThrowsCouldNotLoadConfigurationException() + { + // Arrange. + var configurataionPath = CreatePath("path/to/bicepconfig.json"); + var fileSystem = new MockFileSystem(new Dictionary + { + [configurataionPath] = "", + }); + + var fileSystemMock = StrictMock.Of(); + fileSystemMock.SetupGet(x => x.Path).Returns(fileSystem.Path); + fileSystemMock.SetupGet(x => x.Directory).Returns(fileSystem.Directory); + fileSystemMock.SetupGet(x => x.File).Returns(fileSystem.File); + fileSystemMock.Setup(x => x.FileStream.Create(It.IsAny(), It.IsAny(), It.IsAny())) + .Throws(new UnauthorizedAccessException("Not allowed.")); + + var sut = new ConfigurationManager(fileSystemMock.Object); + var sourceFileUri = new Uri(CreatePath("path/to/main.bicep")); + + // Act & Assert. + FluentActions.Invoking(() => sut.GetConfiguration(sourceFileUri)).Should() + .Throw() + .WithMessage($"Could not load the Bicep configuration file \"{configurataionPath}\": \"Not allowed.\"."); + } + + [TestMethod] + public void GetConfiguration_IOExceptionWhenDiscovringConfiguration_ReturnsDefaultConfiguration() + { + // Arrange. + var fileSystemMock = StrictMock.Of(); + fileSystemMock.Setup(x => x.Path.GetDirectoryName(It.IsAny())).Returns("foo"); + fileSystemMock.Setup(x => x.Path.Combine(It.IsAny(), It.IsAny())).Returns(""); + fileSystemMock.Setup(x => x.File.Exists(It.IsAny())).Returns(false); + fileSystemMock.Setup(x => x.Directory.GetParent(It.IsAny())).Throws(new IOException("Oops.")); + + var sut = new ConfigurationManager(fileSystemMock.Object); + var sourceFileUri = new Uri(CreatePath("path/to/main.bicep")); + var configuration = sut.GetConfiguration(sourceFileUri); + + // Act & Assert. + configuration.Should().Be(sut.GetBuiltInConfiguration()); + } + + [TestMethod] + public void GetConfiguration_ValidCustomConfiguration_OverridesBuiltInConfiguration() + { + // Arrange. + var fileSystem = new MockFileSystem(new Dictionary + { + [CreatePath("repo")] = new MockDirectoryData(), + [CreatePath("repo/modules")] = new MockDirectoryData(), + [CreatePath("repo/bicepconfig.json")] = @"{ + ""cloud"": { + ""currentProfile"": ""MyCloud"", + ""profiles"": { + ""MyCloud"": { + ""resourceManagerEndpoint"": ""https://bicep.example.com"" + } + } + }, + ""moduleAliases"": { + ""ts"": { + ""mySpecPath"": { + ""subscription"": ""B34C8680-F688-48C2-A44F-E1EFF5E01173"" + } + } + }, + ""analyzers"": { + ""core"": { + ""enabled"": false + } + } +}" + }); + + // Act. + var sut = new ConfigurationManager(fileSystem); + var sourceFileUri = new Uri(this.CreatePath("repo/modules/vnet.bicep")); + var configuration = sut.GetConfiguration(sourceFileUri); + + // Assert. + configuration.Cloud.CurrentProfile.Should().NotBeNull(); + configuration.Cloud.CurrentProfile!.ResourceManagerEndpoint.Should().Be("https://bicep.example.com"); + + configuration.ModuleAliases.TemplateSpecModuleAliases.Should().NotBeEmpty(); + configuration.ModuleAliases.BicepRegistryModuleAliases.Should().BeEmpty(); + + var alias = configuration.ModuleAliases.TemplateSpecModuleAliases.GetValueOrDefault("mySpecPath"); + alias.Should().NotBeNull(); + alias!.Subscription.Should().Be("B34C8680-F688-48C2-A44F-E1EFF5E01173"); + + configuration.Analyzers.GetValue("core:verbose", true).Should().BeFalse(); + configuration.Analyzers.GetValue("core:enabled", true).Should().BeFalse(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:level", "").Should().Be("warning"); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:disallowedhosts", Array.Empty()).Should().NotBeEmpty(); + configuration.Analyzers.GetValue("core:rules:no-hardcoded-env-urls:excludedhosts", Array.Empty()).Should().NotBeEmpty(); + } + + private string CreatePath(string path) => Path.Combine(this.TestContext.ResultsDirectory, path.Replace('/', Path.DirectorySeparatorChar)); + } +} diff --git a/src/Bicep.Core.UnitTests/Diagnostics/BicepConfigSchemaTests.cs b/src/Bicep.Core.UnitTests/Diagnostics/BicepConfigSchemaTests.cs index b8f185739d3..bc9aabfdd26 100644 --- a/src/Bicep.Core.UnitTests/Diagnostics/BicepConfigSchemaTests.cs +++ b/src/Bicep.Core.UnitTests/Diagnostics/BicepConfigSchemaTests.cs @@ -6,7 +6,6 @@ using System.Linq; using Bicep.Core.Analyzers.Interfaces; using Bicep.Core.Analyzers.Linter; -using Bicep.Core.Configuration; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; @@ -18,11 +17,9 @@ namespace Bicep.Core.UnitTests.Diagnostics [TestClass] public class BicepConfigSchemaTests { - private readonly ConfigHelper configHelper = new(null, BicepTestConstants.FileResolver); - private (IBicepAnalyzerRule[] rules, JObject configSchema) GetRulesAndSchema() { - var linter = new LinterAnalyzer(configHelper); + var linter = new LinterAnalyzer(BicepTestConstants.BuiltInConfiguration); var ruleSet = linter.GetRuleSet(); ruleSet.Should().NotBeEmpty(); diff --git a/src/Bicep.Core.UnitTests/Diagnostics/LinterAnalyzerTests.cs b/src/Bicep.Core.UnitTests/Diagnostics/LinterAnalyzerTests.cs index d92d9d9051e..0e73af8617b 100644 --- a/src/Bicep.Core.UnitTests/Diagnostics/LinterAnalyzerTests.cs +++ b/src/Bicep.Core.UnitTests/Diagnostics/LinterAnalyzerTests.cs @@ -19,12 +19,12 @@ namespace Bicep.Core.UnitTests.Diagnostics [TestClass] public class LinterAnalyzerTests { - private readonly ConfigHelper configHelper = new(null, BicepTestConstants.FileResolver); + private readonly RootConfiguration configuration = BicepTestConstants.BuiltInConfiguration; [TestMethod] public void HasBuiltInRules() { - var linter = new LinterAnalyzer(configHelper); + var linter = new LinterAnalyzer(configuration); linter.GetRuleSet().Should().NotBeEmpty(); } @@ -37,14 +37,14 @@ public void HasBuiltInRules() [DataRow(NoUnusedVariablesRule.Code)] public void BuiltInRulesExist(string ruleCode) { - var linter = new LinterAnalyzer(configHelper); + var linter = new LinterAnalyzer(configuration); linter.GetRuleSet().Should().Contain(r => r.Code == ruleCode); } [TestMethod] public void AllRulesHaveUniqueDetails() { - var analyzer = new LinterAnalyzer(configHelper); + var analyzer = new LinterAnalyzer(configuration); var ruleSet = analyzer.GetRuleSet(); var codeSet = ruleSet.Select(r => r.Code).ToHashSet(); @@ -57,7 +57,7 @@ public void AllRulesHaveUniqueDetails() [TestMethod] public void AllRulesEnabledByDefault() { - var analyzer = new LinterAnalyzer(configHelper); + var analyzer = new LinterAnalyzer(configuration); var ruleSet = analyzer.GetRuleSet(); ruleSet.Should().OnlyContain(r => r.IsEnabled()); } @@ -65,7 +65,7 @@ public void AllRulesEnabledByDefault() [TestMethod] public void AllRulesHaveDescription() { - var analyzer = new LinterAnalyzer(configHelper); + var analyzer = new LinterAnalyzer(configuration); var ruleSet = analyzer.GetRuleSet(); ruleSet.Should().OnlyContain(r => r.Description.Length > 0); } diff --git a/src/Bicep.Core.UnitTests/Diagnostics/LinterRuleTests/NoHardcodedEnvironmentUrlsRuleTests.cs b/src/Bicep.Core.UnitTests/Diagnostics/LinterRuleTests/NoHardcodedEnvironmentUrlsRuleTests.cs index b97fe0ec28a..990dd0c35da 100644 --- a/src/Bicep.Core.UnitTests/Diagnostics/LinterRuleTests/NoHardcodedEnvironmentUrlsRuleTests.cs +++ b/src/Bicep.Core.UnitTests/Diagnostics/LinterRuleTests/NoHardcodedEnvironmentUrlsRuleTests.cs @@ -156,8 +156,8 @@ public void InsideExpressions(int diagnosticCount, string text) public void DisallowedHostsMatchingTest(string testString, bool isMatch) { var rule = new NoHardcodedEnvironmentUrlsRule(); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver); // this ensures configuration is loaded from resources - rule.Configure(configHelper.Config); + var configuration = BicepTestConstants.BuiltInConfiguration; + rule.Configure(configuration.Analyzers); Assert.AreEqual(isMatch, actual: rule.DisallowedHosts.Any(host => NoHardcodedEnvironmentUrlsRule.FindHostnameMatches(host, testString).Any())); } @@ -185,8 +185,8 @@ public void DisallowedHostsMatchingTest(string testString, bool isMatch) public void ExcludedHostsMatchingTest(string testString, bool isMatch) { var rule = new NoHardcodedEnvironmentUrlsRule(); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver); // this ensures configuration is loaded from resources - rule.Configure(configHelper.Config); + var configuration = BicepTestConstants.BuiltInConfiguration; + rule.Configure(configuration.Analyzers); Assert.AreEqual(isMatch, rule.ExcludedHosts.Any(host => NoHardcodedEnvironmentUrlsRule.FindHostnameMatches(host, testString).Any())); } diff --git a/src/Bicep.Core.UnitTests/Emit/ExpressionConverterTests.cs b/src/Bicep.Core.UnitTests/Emit/ExpressionConverterTests.cs index 3525ba88e0f..d38fcd6dde5 100644 --- a/src/Bicep.Core.UnitTests/Emit/ExpressionConverterTests.cs +++ b/src/Bicep.Core.UnitTests/Emit/ExpressionConverterTests.cs @@ -60,7 +60,7 @@ public class ExpressionConverterTests public void ShouldConvertExpressionsCorrectly(string text, string expected) { var programText = $"var test = {text}"; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var programSyntax = compilation.SourceFileGrouping.EntryPoint.ProgramSyntax; var variableDeclarationSyntax = programSyntax.Children.OfType().First(); diff --git a/src/Bicep.Core.UnitTests/Emit/InlineDependencyVisitorTests.cs b/src/Bicep.Core.UnitTests/Emit/InlineDependencyVisitorTests.cs index bfae8a339a2..a14f6735c68 100644 --- a/src/Bicep.Core.UnitTests/Emit/InlineDependencyVisitorTests.cs +++ b/src/Bicep.Core.UnitTests/Emit/InlineDependencyVisitorTests.cs @@ -27,7 +27,7 @@ public class InlineDependencyVisitorTests [TestMethod] public void VisitorShouldCalculateInliningInBulk() { - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var inlineVariables = InlineDependencyVisitor.GetVariablesToInline(compilation.GetEntrypointSemanticModel()); @@ -44,7 +44,7 @@ public void VisitorShouldCalculateInliningInBulk() [DataTestMethod] public void VisitorShouldProduceNoChainForNonInlinedVariables(string variableName) { - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); VariableDeclarationSyntax variable = GetVariableByName(compilation, variableName); InlineDependencyVisitor.ShouldInlineVariable(compilation.GetEntrypointSemanticModel(), variable, out var chain).Should().BeFalse(); @@ -58,7 +58,7 @@ public void VisitorShouldProduceNoChainForNonInlinedVariables(string variableNam [DataTestMethod] public void VisitorShouldProduceCorrectChainForInlinedVariables(string variableName, string expectedChain) { - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); VariableDeclarationSyntax variable = GetVariableByName(compilation, variableName); InlineDependencyVisitor.ShouldInlineVariable(compilation.GetEntrypointSemanticModel(), variable, out var chain).Should().BeTrue(); diff --git a/src/Bicep.Core.UnitTests/Semantics/SymbolContextTests.cs b/src/Bicep.Core.UnitTests/Semantics/SymbolContextTests.cs index 0e50ac768b4..356c382ee40 100644 --- a/src/Bicep.Core.UnitTests/Semantics/SymbolContextTests.cs +++ b/src/Bicep.Core.UnitTests/Semantics/SymbolContextTests.cs @@ -19,7 +19,7 @@ public void LockedModeShouldBlockAccess() { const string expectedMessage = "Properties of the symbol context should not be accessed until name binding is completed."; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("", BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("", BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var bindings = new Dictionary(); var cyclesBySymbol = new Dictionary>(); var context = new SymbolContext(compilation, compilation.GetEntrypointSemanticModel()); diff --git a/src/Bicep.Core.UnitTests/TypeSystem/Az/AzResourceTypeProviderTests.cs b/src/Bicep.Core.UnitTests/TypeSystem/Az/AzResourceTypeProviderTests.cs index bee2be9d2bc..35b64fdfc7a 100644 --- a/src/Bicep.Core.UnitTests/TypeSystem/Az/AzResourceTypeProviderTests.cs +++ b/src/Bicep.Core.UnitTests/TypeSystem/Az/AzResourceTypeProviderTests.cs @@ -30,8 +30,6 @@ public class AzResourceTypeProviderTests LanguageConstants.ResourceParentPropertyName }.ToImmutableHashSet(LanguageConstants.IdentifierComparer); - private static ConfigHelper configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - [DataTestMethod] [DataRow(ResourceTypeGenerationFlags.None)] [DataRow(ResourceTypeGenerationFlags.ExistingResource)] @@ -110,8 +108,9 @@ public void AzResourceTypeProvider_can_list_all_types_without_throwing() [TestMethod] public void AzResourceTypeProvider_should_warn_for_missing_resource_types() { + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; Compilation createCompilation(string program) - => new Compilation(new DefaultNamespaceProvider(new AzResourceTypeLoader(), BicepTestConstants.Features), SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), configHelper); + => new Compilation(new DefaultNamespaceProvider(new AzResourceTypeLoader(), BicepTestConstants.Features), SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), configuration); // Missing top-level properties - should be an error var compilation = createCompilation(@" @@ -128,7 +127,7 @@ Compilation createCompilation(string program) public void AzResourceTypeProvider_should_error_for_top_level_and_warn_for_nested_properties() { Compilation createCompilation(string program) - => new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), null); + => new Compilation(BuiltInTestTypes.Create(), SourceFileGroupingFactory.CreateFromText(program, new Mock(MockBehavior.Strict).Object), BicepTestConstants.BuiltInConfiguration); // Missing top-level properties - should be an error var compilation = createCompilation(@" diff --git a/src/Bicep.Core.UnitTests/Utils/CompilationHelper.cs b/src/Bicep.Core.UnitTests/Utils/CompilationHelper.cs index 9027f0d0c6f..719ed459f80 100644 --- a/src/Bicep.Core.UnitTests/Utils/CompilationHelper.cs +++ b/src/Bicep.Core.UnitTests/Utils/CompilationHelper.cs @@ -62,7 +62,7 @@ public static CompilationResult Compile(CompilationHelperContext context, params var sourceFileGrouping = SourceFileGroupingFactory.CreateForFiles(uriDictionary, entryUri, fileResolver, context.GetFeatures()); - return Compile(context, new Compilation(context.GetNamespaceProvider(), sourceFileGrouping, null)); + return Compile(context, new Compilation(context.GetNamespaceProvider(), sourceFileGrouping, BicepTestConstants.BuiltInConfiguration)); } public static CompilationResult Compile(IAzResourceTypeLoader resourceTypeLoader, params (string fileName, string fileContents)[] files) diff --git a/src/Bicep.Core.UnitTests/packages.lock.json b/src/Bicep.Core.UnitTests/packages.lock.json index 2b5ee2803fa..ddab99e4760 100644 --- a/src/Bicep.Core.UnitTests/packages.lock.json +++ b/src/Bicep.Core.UnitTests/packages.lock.json @@ -118,6 +118,15 @@ "resolved": "13.0.1", "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Direct", + "requested": "[13.2.47, )", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.Management.Automation": { "type": "Direct", "requested": "[7.1.3, )", @@ -1407,6 +1416,14 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2247,7 +2264,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { diff --git a/src/Bicep.Core/Analyzers/AnalyzerDiagnostic.cs b/src/Bicep.Core/Analyzers/AnalyzerDiagnostic.cs index b3d859bcc5c..0a3d2cc4461 100644 --- a/src/Bicep.Core/Analyzers/AnalyzerDiagnostic.cs +++ b/src/Bicep.Core/Analyzers/AnalyzerDiagnostic.cs @@ -9,10 +9,9 @@ namespace Bicep.Core.Analyzers { public class AnalyzerDiagnostic : Diagnostic, IDiagnostic { - public AnalyzerDiagnostic(string analyzerName, TextSpan span, DiagnosticLevel level, string code, string message, Uri? documentationUri, DiagnosticLabel? label = default) - : base(span, level, code, message, documentationUri, label) + public AnalyzerDiagnostic(string analyzerName, TextSpan span, DiagnosticLevel level, string code, string message, Uri? documentationUri = null, DiagnosticLabel? label = null) + : base(span, level, code, message, documentationUri, label, $"{LanguageConstants.LanguageId} {analyzerName}") { - this.Source = $"{LanguageConstants.LanguageId} {analyzerName}"; } } } diff --git a/src/Bicep.Core/Analyzers/Interfaces/IBicepAnalyzerRule.cs b/src/Bicep.Core/Analyzers/Interfaces/IBicepAnalyzerRule.cs index 6adc58bc317..daa53431984 100644 --- a/src/Bicep.Core/Analyzers/Interfaces/IBicepAnalyzerRule.cs +++ b/src/Bicep.Core/Analyzers/Interfaces/IBicepAnalyzerRule.cs @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Bicep.Core.Configuration; using Bicep.Core.Diagnostics; using Bicep.Core.Semantics; -using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; @@ -18,12 +18,19 @@ namespace Bicep.Core.Analyzers.Interfaces public interface IBicepAnalyzerRule { string AnalyzerName { get; } + string Code { get; } + string Description { get; } + DiagnosticLevel DiagnosticLevel { get; } + DiagnosticLabel? DiagnosticLabel { get; } + Uri? Uri { get; } - void Configure(IConfigurationRoot config); + + void Configure(AnalyzersConfiguration configuration); + IEnumerable Analyze(SemanticModel model); } } diff --git a/src/Bicep.Core/Analyzers/Linter/LinterAnalyzer.cs b/src/Bicep.Core/Analyzers/Linter/LinterAnalyzer.cs index 9d8b56a3c9d..eaeaf3375f8 100644 --- a/src/Bicep.Core/Analyzers/Linter/LinterAnalyzer.cs +++ b/src/Bicep.Core/Analyzers/Linter/LinterAnalyzer.cs @@ -17,30 +17,35 @@ namespace Bicep.Core.Analyzers.Linter { public class LinterAnalyzer : IBicepAnalyzer { - public const string SettingsRoot = "analyzers"; public const string AnalyzerName = "core"; - public static string LinterEnabledSetting => $"{SettingsRoot}:{AnalyzerName}:enabled"; - public static string LinterVerboseSetting => $"{SettingsRoot}:{AnalyzerName}:verbose"; - private ConfigHelper configHelper; - private ImmutableArray RuleSet; - private ImmutableArray RuleCreationErrors; + + public static string LinterEnabledSetting => $"{AnalyzerName}:enabled"; + + public static string LinterVerboseSetting => $"{AnalyzerName}:verbose"; + + private readonly RootConfiguration configuration; + + private ImmutableArray ruleSet; + + private ImmutableArray ruleCreationErrors; // TODO: This should be controlled by a core component, not an analyzer public const string FailedRuleCode = "linter-internal-error"; - public LinterAnalyzer(ConfigHelper configHelper) + public LinterAnalyzer(RootConfiguration configuration) { - this.configHelper = configHelper; - (RuleSet, RuleCreationErrors) = CreateLinterRules(); + this.configuration = configuration; + (this.ruleSet, this.ruleCreationErrors) = CreateLinterRules(); } - private bool LinterEnabled => this.configHelper.GetValue(LinterEnabledSetting, true); - private bool LinterVerbose => this.configHelper.GetValue(LinterVerboseSetting, true); + private bool LinterEnabled => this.configuration.Analyzers.GetValue(LinterEnabledSetting, false); + + private bool LinterVerbose => this.configuration.Analyzers.GetValue(LinterVerboseSetting, false); private (ImmutableArray rules, ImmutableArray errors) CreateLinterRules() { - List errors = new List(); - List rules = new List(); + var errors = new List(); + var rules = new List(); var ruleTypes = Assembly.GetExecutingAssembly() .GetTypes() @@ -68,18 +73,18 @@ public LinterAnalyzer(ConfigHelper configHelper) return (rules.ToImmutableArray(), errors.ToImmutableArray()); } - public IEnumerable GetRuleSet() => RuleSet; + public IEnumerable GetRuleSet() => ruleSet; public IEnumerable Analyze(SemanticModel semanticModel) { var diagnostics = new List(); - this.RuleSet.ForEach(r => r.Configure(this.configHelper.Config)); + this.ruleSet.ForEach(r => r.Configure(this.configuration.Analyzers)); if (this.LinterEnabled) { // Add diaagnostics for rules that failed to load - diagnostics.AddRange(RuleCreationErrors); + diagnostics.AddRange(ruleCreationErrors); // add an info diagnostic for local configuration reporting if (this.LinterVerbose) @@ -87,49 +92,45 @@ public IEnumerable Analyze(SemanticModel semanticModel) diagnostics.Add(GetConfigurationDiagnostic()); } - diagnostics.AddRange(RuleSet.Where(rule => rule.IsEnabled()) - .SelectMany(r => r.Analyze(semanticModel))); + diagnostics.AddRange(ruleSet + .Where(rule => rule.IsEnabled()) + .SelectMany(r => r.Analyze(semanticModel))); } else { if (this.LinterVerbose) { - diagnostics.Add( - new AnalyzerDiagnostic(AnalyzerName, - new TextSpan(0, 0), - DiagnosticLevel.Info, - "Linter Disabled", - string.Format(CoreResources.LinterDisabledFormatMessage, this.configHelper.CustomSettingsFileName), - null, null)); + diagnostics.Add(new AnalyzerDiagnostic( + AnalyzerName, + new TextSpan(0, 0), + DiagnosticLevel.Info, + "Linter Disabled", + string.Format(CoreResources.LinterDisabledFormatMessage, this.configuration.ResourceName))); } } + return diagnostics; } private IDiagnostic GetConfigurationDiagnostic() { - var configMessage = this.configHelper.CustomSettingsFileName == default ? - CoreResources.BicepConfigNoCustomSettingsMessage - : string.Format(CoreResources.BicepConfigCustomSettingsFoundFormatMessage, this.configHelper.CustomSettingsFileName); - - return new AnalyzerDiagnostic(AnalyzerName, - new TextSpan(0, 0), - DiagnosticLevel.Info, - "Bicep Linter Configuration", - configMessage, - null, null); - } + var configMessage = this.configuration.IsBuiltIn + ? CoreResources.BicepConfigNoCustomSettingsMessage + : string.Format(CoreResources.BicepConfigCustomSettingsFoundFormatMessage, this.configuration.ResourceName); - internal IDiagnostic CreateInternalErrorDiagnostic(string analyzerName, string message) - { return new AnalyzerDiagnostic( - analyzerName, - new TextSpan(0, 0), - DiagnosticLevel.Warning, - LinterAnalyzer.FailedRuleCode, - message, - null, - null); + AnalyzerName, + new TextSpan(0, 0), + DiagnosticLevel.Info, + "Bicep Linter Configuration", + configMessage); } + + private static IDiagnostic CreateInternalErrorDiagnostic(string analyzerName, string message) => new AnalyzerDiagnostic( + analyzerName, + new TextSpan(0, 0), + DiagnosticLevel.Warning, + LinterAnalyzer.FailedRuleCode, + message); } } diff --git a/src/Bicep.Core/Analyzers/Linter/LinterRuleBase.cs b/src/Bicep.Core/Analyzers/Linter/LinterRuleBase.cs index 501eacc9d00..62bef9da60d 100644 --- a/src/Bicep.Core/Analyzers/Linter/LinterRuleBase.cs +++ b/src/Bicep.Core/Analyzers/Linter/LinterRuleBase.cs @@ -5,6 +5,7 @@ using Bicep.Core.CodeAction; using Bicep.Core.Configuration; using Bicep.Core.Diagnostics; +using Bicep.Core.Extensions; using Bicep.Core.Parsing; using Bicep.Core.Semantics; using Microsoft.Extensions.Configuration; @@ -17,9 +18,14 @@ namespace Bicep.Core.Analyzers.Linter { public abstract class LinterRuleBase : IBicepAnalyzerRule { - public LinterRuleBase(string code, string description, Uri? docUri = null, - DiagnosticLevel diagnosticLevel = DiagnosticLevel.Warning, - DiagnosticLabel? diagnosticLabel = null) + private AnalyzersConfiguration configuration = new(rawConfiguration: null); + + public LinterRuleBase( + string code, + string description, + Uri? docUri = null, + DiagnosticLevel diagnosticLevel = DiagnosticLevel.Warning, + DiagnosticLabel? diagnosticLabel = null) { this.AnalyzerName = LinterAnalyzer.AnalyzerName; this.Code = code; @@ -29,14 +35,18 @@ public LinterRuleBase(string code, string description, Uri? docUri = null, this.DiagnosticLabel = diagnosticLabel; } - private IConfigurationRoot? Config; public string AnalyzerName { get; } public string Code { get; } - public readonly string RuleConfigSection = $"{LinterAnalyzer.SettingsRoot}:{LinterAnalyzer.AnalyzerName}:rules"; + + public readonly string RuleConfigSection = $"{LinterAnalyzer.AnalyzerName}:rules"; + public DiagnosticLevel DiagnosticLevel { get; private set; } + public string Description { get; } + public Uri? Uri { get; } + public DiagnosticLabel? DiagnosticLabel { get; } @@ -47,13 +57,15 @@ public LinterRuleBase(string code, string description, Uri? docUri = null, /// public virtual string FormatMessage(params object[] values) => this.Description; - public virtual void Configure(IConfigurationRoot config) + public virtual void Configure(AnalyzersConfiguration configuration) { - this.Config = config; - var configDiagLevel = GetConfiguration("level", this.DiagnosticLevel.ToString()); - if (DiagnosticLevel.TryParse(configDiagLevel, true, out var lvl)) + this.configuration = configuration; + + var levelValue = this.GetConfigurationValue("level", this.DiagnosticLevel.ToString()); + + if (Enum.TryParse(levelValue, true, out var level)) { - this.DiagnosticLevel = lvl; + this.DiagnosticLevel = level; } } @@ -76,13 +88,12 @@ public IEnumerable Analyze(SemanticModel model) } catch (Exception ex) { - return new[]{ new AnalyzerDiagnostic(this.AnalyzerName, - new TextSpan(0, 0), - DiagnosticLevel.Warning, - LinterAnalyzer.FailedRuleCode, - string.Format(CoreResources.LinterRuleExceptionMessageFormat,this.AnalyzerName, ex.Message), - null, null) - }; + return new AnalyzerDiagnostic( + this.AnalyzerName, + new TextSpan(0, 0), + DiagnosticLevel.Warning, + LinterAnalyzer.FailedRuleCode, + string.Format(CoreResources.LinterRuleExceptionMessageFormat,this.AnalyzerName, ex.Message)).AsEnumerable(); } } @@ -98,23 +109,12 @@ public IEnumerable Analyze(SemanticModel model) /// Get a setting from defaults or local override /// Expectation: key names for settings are lower case /// - /// - /// - /// - /// - protected T GetConfiguration(string name, T defaultValue) - => ConfigurationBinder.GetValue(this.Config, $"{RuleConfigSection}:{Code}:{name}", defaultValue); - - /// - /// Get a section of the config file as an array of strings. - /// Expectation: all key names shoult be lower case - /// - /// - /// - /// + /// The type of the value to convert to. + /// The linter configuration key. + /// The default value to use if no value is found. /// - protected T[] GetArray(string name, T[] defaultValue) - => this.Config?.GetSection($"{RuleConfigSection}:{Code}:{name.ToLower()}").Get() ?? defaultValue; + protected T GetConfigurationValue(string key, T defaultValue) => + this.configuration.GetValue($"{RuleConfigSection}:{Code}:{key}", defaultValue); /// /// Create a simple diagnostic that displays the defined Description diff --git a/src/Bicep.Core/Analyzers/Linter/Rules/NoHardcodedEnvironmentUrlsRule.cs b/src/Bicep.Core/Analyzers/Linter/Rules/NoHardcodedEnvironmentUrlsRule.cs index 8c97b9b7ff9..001b8f87b46 100644 --- a/src/Bicep.Core/Analyzers/Linter/Rules/NoHardcodedEnvironmentUrlsRule.cs +++ b/src/Bicep.Core/Analyzers/Linter/Rules/NoHardcodedEnvironmentUrlsRule.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Bicep.Core.Configuration; using Bicep.Core.Diagnostics; using Bicep.Core.Parsing; using Bicep.Core.Semantics; using Bicep.Core.Syntax; -using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -17,13 +17,13 @@ public sealed class NoHardcodedEnvironmentUrlsRule : LinterRuleBase { public new const string Code = "no-hardcoded-env-urls"; - private ImmutableArray? disallowedHosts; - public ImmutableArray DisallowedHosts => disallowedHosts.HasValue ? disallowedHosts.Value : ImmutableArray.Empty; + private ImmutableArray disallowedHosts; + public ImmutableArray DisallowedHosts => disallowedHosts; - private ImmutableArray? excludedHosts; - public ImmutableArray ExcludedHosts => excludedHosts.HasValue ? excludedHosts.Value : ImmutableArray.Empty; + private ImmutableArray excludedHosts; + public ImmutableArray ExcludedHosts => excludedHosts; - private int MinimumHostLength; + private int minimumHostLength; private bool HasHosts; public NoHardcodedEnvironmentUrlsRule() : base( @@ -33,17 +33,15 @@ public NoHardcodedEnvironmentUrlsRule() : base( { } - public override void Configure(IConfigurationRoot config) + public override void Configure(AnalyzersConfiguration config) { base.Configure(config); - this.disallowedHosts = GetArray(nameof(DisallowedHosts), Array.Empty()) - .ToImmutableArray(); - this.MinimumHostLength = this.disallowedHosts.Value.Min(h => h.Length); - this.excludedHosts = GetArray(nameof(ExcludedHosts), Array.Empty()) - .ToImmutableArray(); + this.disallowedHosts = this.GetConfigurationValue(nameof(DisallowedHosts), Array.Empty()).ToImmutableArray(); + this.excludedHosts = this.GetConfigurationValue(nameof(ExcludedHosts), Array.Empty()).ToImmutableArray(); - this.HasHosts = this.disallowedHosts?.Any() ?? false; + this.minimumHostLength = this.disallowedHosts.Any() ? this.disallowedHosts.Min(h => h.Length) : 0; + this.HasHosts = this.disallowedHosts.Any(); } public override string FormatMessage(params object[] values) @@ -53,7 +51,7 @@ public override IEnumerable AnalyzeInternal(SemanticModel model) { if (HasHosts) { - var visitor = new Visitor(this.DisallowedHosts, this.MinimumHostLength, this.ExcludedHosts); + var visitor = new Visitor(this.DisallowedHosts, this.minimumHostLength, this.ExcludedHosts); visitor.Visit(model.SourceFile.ProgramSyntax); return visitor.DisallowedHostSpans.Select(entry => CreateDiagnosticForSpan(entry.Key, entry.Value)); diff --git a/src/Bicep.Core/Bicep.Core.csproj b/src/Bicep.Core/Bicep.Core.csproj index 0cacfe9cf7c..186fc656192 100644 --- a/src/Bicep.Core/Bicep.Core.csproj +++ b/src/Bicep.Core/Bicep.Core.csproj @@ -27,6 +27,7 @@ + @@ -45,4 +46,5 @@ CoreResources.Designer.cs + diff --git a/src/Bicep.Core/Configuration/AnalyzersConfiguration.cs b/src/Bicep.Core/Configuration/AnalyzersConfiguration.cs new file mode 100644 index 00000000000..a10e50c2d17 --- /dev/null +++ b/src/Bicep.Core/Configuration/AnalyzersConfiguration.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.Configuration; + +namespace Bicep.Core.Configuration +{ + public class AnalyzersConfiguration + { + private readonly IConfiguration? rawConfiguration; + + public AnalyzersConfiguration(IConfiguration? rawConfiguration) + { + this.rawConfiguration = rawConfiguration; + } + + public T GetValue(string key, T defaultValue) => this.rawConfiguration is not null + ? this.rawConfiguration.GetSection(key).Get() ?? defaultValue + : defaultValue; + } +} diff --git a/src/Bicep.Core/Configuration/BicepConfig.cs b/src/Bicep.Core/Configuration/BicepConfig.cs deleted file mode 100644 index 36c96bbd6f3..00000000000 --- a/src/Bicep.Core/Configuration/BicepConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Bicep.Core.Configuration -{ - public class BicepConfig - { - - } -} diff --git a/src/Bicep.Core/Configuration/CloudConfiguration.cs b/src/Bicep.Core/Configuration/CloudConfiguration.cs new file mode 100644 index 00000000000..0cf5887a368 --- /dev/null +++ b/src/Bicep.Core/Configuration/CloudConfiguration.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Bicep.Core.Configuration +{ + public record CloudProfile + { + public string ResourceManagerEndpoint { get; init; } = ""; + } + + public class CloudConfiguration + { + private CloudConfiguration(string currentProfile, IReadOnlyDictionary profiles) + { + this.CurrentProfile = profiles.GetValueOrDefault(currentProfile); + } + + public static CloudConfiguration Bind(IConfiguration rawConfiguration) + { + string currentProfile = rawConfiguration.GetValue("currentProfile", "AzureCloud"); + + var profiles = new Dictionary(); + rawConfiguration.GetSection("profiles").Bind(profiles); + + return new(currentProfile, profiles); + } + + public CloudProfile? CurrentProfile { get; } + } +} diff --git a/src/Bicep.Core/Configuration/ConfigHelper.cs b/src/Bicep.Core/Configuration/ConfigHelper.cs deleted file mode 100644 index 690b48549a1..00000000000 --- a/src/Bicep.Core/Configuration/ConfigHelper.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Bicep.Core.FileSystem; -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -namespace Bicep.Core.Configuration -{ - public class ConfigHelper - { - private readonly IFileResolver fileResolver; - private readonly bool useDefaultConfig; - - /// - /// Property exposes the configuration root - /// that is currently loaded - /// - public IConfigurationRoot Config { get; private set; } - - public ConfigHelper(string? localFolder, IFileResolver fileResolver, bool useDefaultConfig = false) - { - this.fileResolver = fileResolver; - this.useDefaultConfig = useDefaultConfig; - - if (localFolder is not null) - { - this.Config = BuildConfig(localFolder); - } - else - { - this.Config = BuildConfig(Directory.GetCurrentDirectory()); - } - } - - private IConfigurationRoot BuildConfig(Uri fileUri) - { - string? localFolder = fileUri.IsFile ? fileUri.LocalPath : null; - return BuildConfig(localFolder); - } - - private IConfigurationRoot BuildConfig(string? localFolder) - { - var configBuilder = new ConfigurationBuilder(); - - // keep this stream open until after Build() call - using (var defaultConfigStream = DefaultBicepConfigHelper.GetManifestResourceStream()) - { - Debug.Assert(defaultConfigStream != null, "Default configuration file should exist as embedded resource."); - configBuilder.AddJsonStream(defaultConfigStream); - - // last added json settings take precedent - add local settings last - if (!useDefaultConfig && DiscoverLocalConfigurationFile(localFolder) is string localConfig) - { - Trace.WriteLine($"Reloading config from file {localConfig}"); - // we must set reloadOnChange to false here - if it set to true, then ConfigurationBuilder will initialize - // a FileSystem.Watcher instance - which has severe performance impact on non-Windows OSes (https://github.com/dotnet/runtime/issues/42036) - configBuilder.AddJsonFile(localConfig, optional: true, reloadOnChange: false); - this.CustomSettingsFileName = localConfig; - } - else - { - Trace.WriteLine($"Reloading config from assembly"); - - this.CustomSettingsFileName = default; - } - - try - { - var config = configBuilder.Build(); - - foreach (var kvp in SettingOverrides) - { - config[kvp.Key] = kvp.Value.ToString(); - } - - return this.Config = config; - } - catch (Exception ex) - { - throw new Exception( - string.Format("Could not load configuration file. {0} Please fix errors in the following configuration file: {1}", ex.InnerException?.Message ?? ex.Message, this.CustomSettingsFileName)); - } - } - } - - private string? DiscoverLocalConfigurationFile(string? nextDir) - { - try - { - while (!string.IsNullOrEmpty(nextDir)) - { - while (!string.IsNullOrEmpty(nextDir)) - { - var fileName = Path.Combine(nextDir, LanguageConstants.BicepConfigSettingsFileName); - if (fileResolver.FileExists(new Uri(fileName))) - { - return fileName; - } - nextDir = Directory.GetParent(nextDir)?.FullName; - } - } - } - catch (Exception) - { - } - - return default; - } - - internal void LoadDefaultConfiguration() - { - this.Config = BuildConfig((string?)null); - } - - internal void LoadConfigurationForSourceFile(Uri fileUri) - { - this.Config = BuildConfig(fileUri); - } - - /// - /// Contains path to any custom bicepconfig.json file - /// that is currently in effect - /// - public string? CustomSettingsFileName { get; private set; } - - /// - /// Get setting value from underlying Config - /// - /// - /// - /// - public T GetValue(string settingPath, T defaultValue) - => ConfigurationBinder.GetValue(this.Config, settingPath, defaultValue); - - - #region internal config management for unit tests - - private Dictionary SettingOverrides = new Dictionary(); - - /// - /// For unit testing we want to force setting overrides - /// - /// - /// - public ConfigHelper OverrideSetting(string name, object value) - { - SettingOverrides[name] = value; - this.Config = BuildConfig(Directory.GetCurrentDirectory()); - return this; - } - - internal bool TryGetOverrideSettingValue(string name, out T? value) - { - if (SettingOverrides.TryGetValue(name, out var overrideValue) - && overrideValue is T typedValue) - { - value = typedValue; - return true; - } - value = default; - return false; - } - - #endregion - } -} diff --git a/src/Bicep.Core/Configuration/ConfigHelperExtensions.cs b/src/Bicep.Core/Configuration/ConfigHelperExtensions.cs deleted file mode 100644 index 197f5f9a7e1..00000000000 --- a/src/Bicep.Core/Configuration/ConfigHelperExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Bicep.Core.Analyzers.Linter; - -namespace Bicep.Core.Configuration -{ - public static class ConfigHelperExtensions - { - public static ConfigHelper GetDisabledLinterConfig(this ConfigHelper configHelper) => - configHelper.OverrideSetting(LinterAnalyzer.LinterEnabledSetting, false) - .OverrideSetting(LinterAnalyzer.LinterVerboseSetting, false); - } -} diff --git a/src/Bicep.Core/Configuration/ConfigurationException.cs b/src/Bicep.Core/Configuration/ConfigurationException.cs new file mode 100644 index 00000000000..9e6dd9e9bd5 --- /dev/null +++ b/src/Bicep.Core/Configuration/ConfigurationException.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Bicep.Core.Exceptions; + +namespace Bicep.Core.Configuration +{ + public class ConfigurationException : BicepException + { + public ConfigurationException(string message) + : base(message) + { + } + } +} diff --git a/src/Bicep.Core/Configuration/ConfigurationManager.cs b/src/Bicep.Core/Configuration/ConfigurationManager.cs new file mode 100644 index 00000000000..9d737d50a05 --- /dev/null +++ b/src/Bicep.Core/Configuration/ConfigurationManager.cs @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.Configuration; +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Abstractions; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Text.Json; + +namespace Bicep.Core.Configuration +{ + public class ConfigurationManager : IConfigurationManager + { + public const string BuiltInConfigurationResourceName = "Bicep.Core.Configuration.bicepconfig.json"; + + private static readonly IConfiguration builtInRawConfiguration = BuildBuiltInRawConfiguration(); + + private static readonly Lazy builtInConfigurationLazy = + new(() => RootConfiguration.Bind(builtInRawConfiguration, BuiltInConfigurationResourceName)); + + private static readonly Lazy builtInConfigurationWithAnalyzersDisabledLazy = + new(() => RootConfiguration.Bind(builtInRawConfiguration, BuiltInConfigurationResourceName, disableAnalyzers: true)); + + private readonly IFileSystem fileSystem; + + public ConfigurationManager(IFileSystem fileSystem) + { + this.fileSystem = fileSystem; + } + + public RootConfiguration GetBuiltInConfiguration(bool disableAnalyzers = false) => disableAnalyzers + ? builtInConfigurationWithAnalyzersDisabledLazy.Value + : builtInConfigurationLazy.Value; + + public RootConfiguration GetConfiguration(Uri sourceFileUri) + { + var customConfigurationPath = DiscoverConfigurationFile(fileSystem.Path.GetDirectoryName(sourceFileUri.LocalPath)); + + if (customConfigurationPath is not null) + { + IConfiguration? customConfiguration; + + try + { + using var stream = fileSystem.FileStream.Create(customConfigurationPath, FileMode.Open, FileAccess.Read); + var builder = new ConfigurationBuilder() + .AddInMemoryCollection(builtInRawConfiguration.AsEnumerable()) + .AddJsonStream(stream); + + customConfiguration = builder.Build(); + } + catch (JsonException exception) + { + throw new ConfigurationException($"Failed to parse the contents of the Bicep configuration file \"{customConfigurationPath}\" as valid JSON: \"{exception.Message}\"."); + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or SecurityException) + { + throw new ConfigurationException($"Could not load the Bicep configuration file \"{customConfigurationPath}\": \"{exception.Message}\"."); + } + + return RootConfiguration.Bind(customConfiguration, customConfigurationPath); + } + + return GetBuiltInConfiguration(); + } + + private static IConfiguration BuildBuiltInRawConfiguration() + { + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(BuiltInConfigurationResourceName); + Debug.Assert(stream is not null, "Default configuration file should exist as embedded resource."); + + var builder = new ConfigurationBuilder(); + builder.AddJsonStream(stream); + + return builder.Build(); + } + + private string? DiscoverConfigurationFile(string? currentDirectory) + { + while (!string.IsNullOrEmpty(currentDirectory)) + { + var configurationPath = this.fileSystem.Path.Combine(currentDirectory, LanguageConstants.BicepConfigurationFileName); + + if (this.fileSystem.File.Exists(configurationPath)) + { + return configurationPath; + } + + try + { + // Catching Directory.GetParent alone because it is the only one that throws IO related exceptions. + // Path.Combine only throws ArgumentNullException which indicates a bug in our code. + // File.Exists will not throw exceptions regardless the existence of path or if the user has permissions to read the file. + currentDirectory = this.fileSystem.Directory.GetParent(currentDirectory)?.FullName; + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or SecurityException) + { + // TODO: add telemetry here so that users can understand if there's an issue finding Bicep config. + // The exception could happen in senarios where users may not have read permission on the parent folder. + // We should not throw ConfigurationException in such cases since it will block compilation. + return null; + } + } + + return null; + } + } +} diff --git a/src/Bicep.Core/Configuration/IConfigurationManager.cs b/src/Bicep.Core/Configuration/IConfigurationManager.cs new file mode 100644 index 00000000000..271c3bd36d9 --- /dev/null +++ b/src/Bicep.Core/Configuration/IConfigurationManager.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; + +namespace Bicep.Core.Configuration +{ + public interface IConfigurationManager + { + /// + /// Gets the built-in configuration. + /// + /// Indicates whether the analyzer settings should be disabled. + /// The built-in configuration. + RootConfiguration GetBuiltInConfiguration(bool disableAnalyzers = false); + + /// + /// Gets the configuration for the source file with the given URI. + /// If no custom configuration is found, the built-in configuration is returned. + /// + /// The URI of the source file to get configuration for. + /// The configuration for the source file. + RootConfiguration GetConfiguration(Uri sourceFileUri); + } +} diff --git a/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs b/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs new file mode 100644 index 00000000000..9d01a09839b --- /dev/null +++ b/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Bicep.Core.Configuration +{ + public record TemplateSpecModuleAlias + { + public string? Subscription { get; init; } + + public string? ResourceGroup { get; init; } + } + + public record BicepRegistryModuleAlias + { + public string? Registry { get; init; } + + public string? ModulePath { get; init; } + } + + + public class ModuleAliasesConfiguration + { + private ModuleAliasesConfiguration( + ImmutableDictionary templateSpecModuleAliases, + ImmutableDictionary bicepRegistryModuleAliases) + { + this.TemplateSpecModuleAliases = templateSpecModuleAliases; + this.BicepRegistryModuleAliases = bicepRegistryModuleAliases; + } + + public static ModuleAliasesConfiguration Bind(IConfiguration rawConfiguration) + { + var templateSpecModuleAliases = new Dictionary(); + rawConfiguration.GetSection("ts").Bind(templateSpecModuleAliases); + + var bicepRegistryModuleAliases = new Dictionary(); + rawConfiguration.GetSection("br").Bind(bicepRegistryModuleAliases); + + return new(templateSpecModuleAliases.ToImmutableDictionary(), bicepRegistryModuleAliases.ToImmutableDictionary()); + } + + public ImmutableDictionary TemplateSpecModuleAliases { get; } + + public ImmutableDictionary BicepRegistryModuleAliases { get; } + } +} diff --git a/src/Bicep.Core/Configuration/RootConfiguration.cs b/src/Bicep.Core/Configuration/RootConfiguration.cs new file mode 100644 index 00000000000..d152fdbc2d4 --- /dev/null +++ b/src/Bicep.Core/Configuration/RootConfiguration.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.Configuration; + +namespace Bicep.Core.Configuration +{ + public class RootConfiguration + { + private RootConfiguration(CloudConfiguration cloud, ModuleAliasesConfiguration moduleAliases, AnalyzersConfiguration analyzers, string resourceName) + { + this.Cloud = cloud; + this.ModuleAliases = moduleAliases; + this.Analyzers = analyzers; + this.ResourceName = resourceName; + } + + public static RootConfiguration Bind(IConfiguration rawConfiguration, string resourceName, bool disableAnalyzers = false) + { + var cloud = CloudConfiguration.Bind(rawConfiguration.GetSection("cloud")); + var moduleAliases = ModuleAliasesConfiguration.Bind(rawConfiguration.GetSection("moduleAliases")); + var analyzers = new AnalyzersConfiguration(disableAnalyzers ? null : rawConfiguration.GetSection("analyzers")); + + return new(cloud, moduleAliases, analyzers, resourceName); + } + + public CloudConfiguration Cloud { get; } + + public ModuleAliasesConfiguration ModuleAliases { get; } + + public AnalyzersConfiguration Analyzers { get; } + + /// + /// Gets the built-in configuraiton manifest resource name if the configuration is a built-in configuraiton, + /// or a path to a bicepconfig.json file if the configuration is a custom one. + /// + public string ResourceName { get; } + + public bool IsBuiltIn => ResourceName == ConfigurationManager.BuiltInConfigurationResourceName; + } +} diff --git a/src/Bicep.Core/Configuration/bicepconfig.json b/src/Bicep.Core/Configuration/bicepconfig.json index fb68d91bc21..501a19886eb 100644 --- a/src/Bicep.Core/Configuration/bicepconfig.json +++ b/src/Bicep.Core/Configuration/bicepconfig.json @@ -1,4 +1,22 @@ { + "cloud": { + "currentProfile": "AzureCloud", + "profiles": { + "AzureCloud": { + "resourceManagerEndpoint": "https://management.azure.com" + }, + "AzureChinaCloud": { + "resourceManagerEndpoint": "https://management.chinacloudapi.cn" + }, + "AzureUSGovernment": { + "resourceManagerEndpoint": "https://management.usgovcloudapi.net" + } + } + }, + "moduleAliases": { + "ts": {}, + "br": {} + }, "analyzers": { "core": { "verbose": false, diff --git a/src/Bicep.Core/Diagnostics/Diagnostic.cs b/src/Bicep.Core/Diagnostics/Diagnostic.cs index 8828597d848..7dbf872d7be 100644 --- a/src/Bicep.Core/Diagnostics/Diagnostic.cs +++ b/src/Bicep.Core/Diagnostics/Diagnostic.cs @@ -10,8 +10,14 @@ namespace Bicep.Core.Diagnostics [DebuggerDisplay("Level = {" + nameof(Level) + "}, Code = {" + nameof(Code) + "}, Message = {" + nameof(Message) + "}")] public class Diagnostic : IDiagnostic { - public Diagnostic(TextSpan span, DiagnosticLevel level, string code, string message, - Uri? documentationUri = null, DiagnosticLabel? label = null) + public Diagnostic( + TextSpan span, + DiagnosticLevel level, + string code, + string message, + Uri? documentationUri = null, + DiagnosticLabel? label = null, + string? source = null) { Span = span; Level = level; @@ -19,7 +25,7 @@ public Diagnostic(TextSpan span, DiagnosticLevel level, string code, string mess Message = message; Label = label; Uri = documentationUri; - Source = LanguageConstants.LanguageId; + Source = source ?? LanguageConstants.LanguageId; } public string Source { get; protected set; } diff --git a/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs b/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs index a08b3e33a1a..340cff687e4 100644 --- a/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs +++ b/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs @@ -1,5 +1,6 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Bicep.Core.Exceptions; using System; namespace Bicep.Core.Diagnostics @@ -7,7 +8,7 @@ namespace Bicep.Core.Diagnostics /// /// Exception with error diagnostic information attached. /// - public class ErrorDiagnosticException : Exception + public class ErrorDiagnosticException : BicepException { public ErrorDiagnosticException(ErrorDiagnostic diagnostic, Exception? inner = null) : base(diagnostic.Message, inner) @@ -17,4 +18,4 @@ public ErrorDiagnosticException(ErrorDiagnostic diagnostic, Exception? inner = n public ErrorDiagnostic Diagnostic { get; } } -} \ No newline at end of file +} diff --git a/src/Bicep.Core/Exceptions/BicepException.cs b/src/Bicep.Core/Exceptions/BicepException.cs new file mode 100644 index 00000000000..99b775b805e --- /dev/null +++ b/src/Bicep.Core/Exceptions/BicepException.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; + +namespace Bicep.Core.Exceptions +{ + /// + /// Exception used to signal common error conditions. + /// + public class BicepException : Exception + { + public BicepException(string message, Exception? innerException = null) + : base(message, innerException) + { + } + } +} diff --git a/src/Bicep.Core/IsInternalInit.cs b/src/Bicep.Core/IsInternalInit.cs new file mode 100644 index 00000000000..da6dbc8a2c0 --- /dev/null +++ b/src/Bicep.Core/IsInternalInit.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// TODO: remove this file after switching Bicep.Core to .NET 5 (https://github.com/Azure/bicep/issues/4651). +namespace System.Runtime.CompilerServices +{ + // This is required to use record types since the project targets 'netstandard 2.1'. + // See https://developercommunity.visualstudio.com/t/error-cs0518-predefined-type-systemruntimecompiler/1244809. + internal static class IsExternalInit { } +} diff --git a/src/Bicep.Core/LanguageConstants.cs b/src/Bicep.Core/LanguageConstants.cs index 5c322a3f32d..086c69abe64 100644 --- a/src/Bicep.Core/LanguageConstants.cs +++ b/src/Bicep.Core/LanguageConstants.cs @@ -53,7 +53,7 @@ public static class LanguageConstants public const string TargetScopeTypeSubscription = "subscription"; public const string TargetScopeTypeResourceGroup = "resourceGroup"; - public const string BicepConfigSettingsFileName = "bicepconfig.json"; + public const string BicepConfigurationFileName = "bicepconfig.json"; public const string DisableLinterRuleCommandName = "bicep.DisableLinterRule"; diff --git a/src/Bicep.Core/Semantics/Compilation.cs b/src/Bicep.Core/Semantics/Compilation.cs index d6f8d484643..c73faf2b593 100644 --- a/src/Bicep.Core/Semantics/Compilation.cs +++ b/src/Bicep.Core/Semantics/Compilation.cs @@ -16,13 +16,13 @@ public class Compilation { private readonly ImmutableDictionary> lazySemanticModelLookup; - public Compilation(INamespaceProvider namespaceProvider, SourceFileGrouping sourceFileGrouping, ConfigHelper? configHelper, ImmutableDictionary? modelLookup = null) + public Compilation(INamespaceProvider namespaceProvider, SourceFileGrouping sourceFileGrouping, RootConfiguration configuration, ImmutableDictionary? modelLookup = null) { this.SourceFileGrouping = sourceFileGrouping; this.NamespaceProvider = namespaceProvider; + this.Configuration = configuration; var fileResolver = SourceFileGrouping.FileResolver; - ConfigHelper = configHelper ?? new ConfigHelper(null, fileResolver); this.lazySemanticModelLookup = sourceFileGrouping.SourceFiles.ToImmutableDictionary( sourceFile => sourceFile, @@ -30,14 +30,14 @@ public Compilation(INamespaceProvider namespaceProvider, SourceFileGrouping sour new(existingModel) : new Lazy(() => sourceFile switch { - BicepFile bicepFile => new SemanticModel(this, bicepFile, fileResolver, ConfigHelper), + BicepFile bicepFile => new SemanticModel(this, bicepFile, fileResolver, configuration), ArmTemplateFile armTemplateFile => new ArmTemplateSemanticModel(armTemplateFile), TemplateSpecFile templateSpecFile => new TemplateSpecSemanticModel(templateSpecFile), _ => throw new ArgumentOutOfRangeException(nameof(sourceFile)), })); } - public ConfigHelper ConfigHelper { get; } + public RootConfiguration Configuration { get; } public SourceFileGrouping SourceFileGrouping { get; } @@ -55,7 +55,7 @@ public ArmTemplateSemanticModel GetSemanticModel(ArmTemplateFile armTemplateFile public ISemanticModel GetSemanticModel(ISourceFile sourceFile) => this.lazySemanticModelLookup[sourceFile].Value; - public IReadOnlyDictionary> GetAllDiagnosticsByBicepFile(ConfigHelper? overrideConfig = default) + public IReadOnlyDictionary> GetAllDiagnosticsByBicepFile() => SourceFileGrouping.SourceFiles.OfType().ToDictionary( bicepFile => bicepFile, bicepFile => this.GetSemanticModel(bicepFile).GetAllDiagnostics()); diff --git a/src/Bicep.Core/Semantics/SemanticModel.cs b/src/Bicep.Core/Semantics/SemanticModel.cs index abd05807950..43455f3d462 100644 --- a/src/Bicep.Core/Semantics/SemanticModel.cs +++ b/src/Bicep.Core/Semantics/SemanticModel.cs @@ -31,14 +31,14 @@ public class SemanticModel : ISemanticModel private readonly Lazy> allResourcesLazy; private readonly Lazy> allDiagnostics; - public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolver fileResolver, ConfigHelper configHelper) + public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolver fileResolver, RootConfiguration configuration) { Trace.WriteLine($"Building semantic model for {sourceFile.FileUri}"); Compilation = compilation; SourceFile = sourceFile; FileResolver = fileResolver; - ConfigHelper = configHelper; + Configuration = configuration; // create this in locked mode by default // this blocks accidental type or binding queries until binding is done @@ -66,7 +66,7 @@ public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolve // lazy loading the linter will delay linter rule loading // and configuration loading until the linter is actually needed - this.linterAnalyzerLazy = new Lazy(() => new LinterAnalyzer(configHelper)); + this.linterAnalyzerLazy = new Lazy(() => new LinterAnalyzer(configuration)); this.allResourcesLazy = new Lazy>(() => GetAllResourceMetadata()); @@ -113,7 +113,7 @@ public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolve public Compilation Compilation { get; } - public ConfigHelper ConfigHelper { get; } + public RootConfiguration Configuration { get; } public ITypeManager TypeManager { get; } diff --git a/src/Bicep.Core/packages.lock.json b/src/Bicep.Core/packages.lock.json index 87c1aaeab22..ea627bcd83a 100644 --- a/src/Bicep.Core/packages.lock.json +++ b/src/Bicep.Core/packages.lock.json @@ -142,6 +142,15 @@ "System.Memory": "4.5.4" } }, + "System.IO.Abstractions": { + "type": "Direct", + "requested": "[13.2.47, )", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "4.7.0" + } + }, "Azure.Core": { "type": "Transitive", "resolved": "1.19.0", @@ -757,6 +766,17 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3", + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.IO.FileSystem.Primitives": { "type": "Transitive", "resolved": "4.3.0", @@ -1119,6 +1139,14 @@ "System.Runtime": "4.3.0" } }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", + "dependencies": { + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.Security.Cryptography.Algorithms": { "type": "Transitive", "resolved": "4.3.0", @@ -1271,6 +1299,11 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" + }, "System.Security.SecureString": { "type": "Transitive", "resolved": "4.3.0", @@ -1947,6 +1980,17 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3", + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -2146,18 +2190,12 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "System.Security.Principal.Windows": "4.7.0" } }, "System.Security.Cryptography.Algorithms": { @@ -2298,34 +2336,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" }, "System.Security.SecureString": { "type": "Transitive", @@ -2862,6 +2876,17 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3", + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -3061,18 +3086,12 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "System.Security.Principal.Windows": "4.7.0" } }, "System.Security.Cryptography.Algorithms": { @@ -3213,34 +3232,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" }, "System.Security.SecureString": { "type": "Transitive", @@ -3777,6 +3772,17 @@ "runtime.unix.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3", + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -3976,18 +3982,12 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "System.Security.Principal.Windows": "4.7.0" } }, "System.Security.Cryptography.Algorithms": { @@ -4128,34 +4128,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" }, "System.Security.SecureString": { "type": "Transitive", @@ -4674,6 +4650,17 @@ "runtime.win.System.IO.FileSystem": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3", + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -4863,18 +4850,12 @@ "runtime.native.System": "4.3.0" } }, - "System.Security.Claims": { + "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Security.Principal": "4.3.0" + "System.Security.Principal.Windows": "4.7.0" } }, "System.Security.Cryptography.Algorithms": { @@ -5015,34 +4996,10 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HVL1rvqYtnRCxFsYag/2le/ZfKLK4yMw79+s6FmKXbSCNN0JeAhrYxnRAHFoWRa0dEojsDcbBSpH3l22QxAVyw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Claims": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" }, "System.Security.SecureString": { "type": "Transitive", diff --git a/src/Bicep.Decompiler.IntegrationTests/DecompilationTests.cs b/src/Bicep.Decompiler.IntegrationTests/DecompilationTests.cs index e3ee641ecd0..b975037dfb4 100644 --- a/src/Bicep.Decompiler.IntegrationTests/DecompilationTests.cs +++ b/src/Bicep.Decompiler.IntegrationTests/DecompilationTests.cs @@ -18,7 +18,6 @@ using System.Text.RegularExpressions; using Bicep.Decompiler.Exceptions; using Bicep.Decompiler; -using Bicep.Core.Configuration; using Bicep.Core.Registry; using Bicep.Core.UnitTests; @@ -90,7 +89,7 @@ public void Decompiler_generates_expected_bicep_files_with_diagnostics(ExampleDa var nsProvider = BicepTestConstants.NamespaceProvider; var jsonUri = PathHelper.FilePathToFileUrl(jsonFileName); - var decompiler = new TemplateDecompiler(nsProvider, new FileResolver(), BicepTestConstants.RegistryProvider); + var decompiler = new TemplateDecompiler(nsProvider, new FileResolver(), BicepTestConstants.RegistryProvider, BicepTestConstants.ConfigurationManager); var (bicepUri, filesToSave) = decompiler.DecompileFileWithModules(jsonUri, PathHelper.ChangeToBicepExtension(jsonUri)); var bicepFiles = filesToSave.Select(kvp => SourceFileFactory.CreateBicepFile(kvp.Key, kvp.Value)); @@ -99,9 +98,9 @@ public void Decompiler_generates_expected_bicep_files_with_diagnostics(ExampleDa var dispatcher = new ModuleDispatcher(BicepTestConstants.RegistryProvider); var sourceFileGrouping = SourceFileGroupingBuilder.Build(BicepTestConstants.FileResolver, dispatcher, workspace, bicepUri); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - var compilation = new Compilation(nsProvider, sourceFileGrouping, configHelper); - var diagnosticsByBicepFile = compilation.GetAllDiagnosticsByBicepFile(configHelper); + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + var compilation = new Compilation(nsProvider, sourceFileGrouping, configuration); + var diagnosticsByBicepFile = compilation.GetAllDiagnosticsByBicepFile(); using (new AssertionScope()) { @@ -147,7 +146,7 @@ public void Decompiler_raises_errors_for_unsupported_features(string resourcePat { Action onDecompile = () => { var fileResolver = ReadResourceFile(resourcePath); - var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); + var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features), BicepTestConstants.ConfigurationManager); decompiler.DecompileFileWithModules(new Uri($"file:///{resourcePath}"), new Uri("file:///unused.bicep")); }; @@ -181,7 +180,7 @@ public void Decompiler_handles_strings_with_newlines(string newline, string esca [fileUri] = template, });; - var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); + var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features), BicepTestConstants.ConfigurationManager); var (entryPointUri, filesToSave) = decompiler.DecompileFileWithModules(fileUri, PathHelper.ChangeToBicepExtension(fileUri)); // this behavior is actually controlled by newtonsoft's deserializer, but we should assert it anyway to avoid regressions. @@ -232,7 +231,7 @@ public void Decompiler_handles_banned_function_replacement(string expression, st [fileUri] = template, }); - var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); + var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features), BicepTestConstants.ConfigurationManager); var (entryPointUri, filesToSave) = decompiler.DecompileFileWithModules(fileUri, PathHelper.ChangeToBicepExtension(fileUri)); filesToSave[entryPointUri].Should().Contain($"output calculated {type} = ({expectedValue})"); @@ -258,7 +257,7 @@ public void Decompiler_should_not_decompile_bicep_extension() Action sut = () => { - var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); + var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features), BicepTestConstants.ConfigurationManager); decompiler.DecompileFileWithModules(fileUri, PathHelper.ChangeToBicepExtension(fileUri)); }; @@ -320,7 +319,7 @@ public void Decompiler_should_partially_handle_user_defined_functions_with_place [fileUri] = template, }); - var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features)); + var decompiler = new TemplateDecompiler(TestTypeHelper.CreateEmptyProvider(), fileResolver, new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features), BicepTestConstants.ConfigurationManager); var (entryPointUri, filesToSave) = decompiler.DecompileFileWithModules(fileUri, PathHelper.ChangeToBicepExtension(fileUri)); filesToSave[entryPointUri].Should().Contain($"? /* TODO: User defined functions are not supported and have not been decompiled */"); diff --git a/src/Bicep.Decompiler.IntegrationTests/packages.lock.json b/src/Bicep.Decompiler.IntegrationTests/packages.lock.json index 7b68f2175e2..ee59998adab 100644 --- a/src/Bicep.Decompiler.IntegrationTests/packages.lock.json +++ b/src/Bicep.Decompiler.IntegrationTests/packages.lock.json @@ -1379,6 +1379,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2241,7 +2257,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2264,6 +2281,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.Decompiler.UnitTests/packages.lock.json b/src/Bicep.Decompiler.UnitTests/packages.lock.json index 7b68f2175e2..ee59998adab 100644 --- a/src/Bicep.Decompiler.UnitTests/packages.lock.json +++ b/src/Bicep.Decompiler.UnitTests/packages.lock.json @@ -1379,6 +1379,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2241,7 +2257,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2264,6 +2281,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.Decompiler/TemplateDecompiler.cs b/src/Bicep.Decompiler/TemplateDecompiler.cs index 7e4a2d4b23e..a971f8c1ff1 100644 --- a/src/Bicep.Decompiler/TemplateDecompiler.cs +++ b/src/Bicep.Decompiler/TemplateDecompiler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using Bicep.Core.Configuration; using Bicep.Core.Decompiler.Rewriters; using Bicep.Core.Extensions; using Bicep.Core.FileSystem; @@ -25,12 +26,14 @@ public class TemplateDecompiler private readonly INamespaceProvider namespaceProvider; private readonly IFileResolver fileResolver; private readonly IModuleRegistryProvider registryProvider; + private readonly IConfigurationManager configurationManager; - public TemplateDecompiler(INamespaceProvider namespaceProvider, IFileResolver fileResolver, IModuleRegistryProvider registryProvider) + public TemplateDecompiler(INamespaceProvider namespaceProvider, IFileResolver fileResolver, IModuleRegistryProvider registryProvider, IConfigurationManager configurationManager) { this.namespaceProvider = namespaceProvider; this.fileResolver = fileResolver; this.registryProvider = registryProvider; + this.configurationManager = configurationManager; } public (Uri entrypointUri, ImmutableDictionary filesToSave) DecompileFileWithModules(Uri entryJsonUri, Uri entryBicepUri) @@ -119,7 +122,7 @@ private bool RewriteSyntax(Workspace workspace, Uri entryUri, Func fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); var bicepConfigFileContents = @"{ ""analyzers"": { @@ -52,8 +48,8 @@ public async Task BicepConfigFileModification_ShouldNotRefreshCompilation() }"; var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, testOutputPath); + var bicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, testOutputPath); // open the main document and verify diagnostics { @@ -91,7 +87,7 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task BicepConfigFileDeletion_ShouldRefreshCompilation() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); var bicepConfigFileContents = @"{ ""analyzers"": { @@ -109,8 +105,8 @@ public async Task BicepConfigFileDeletion_ShouldRefreshCompilation() var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, testOutputPath); + var bicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, testOutputPath); // open the main document and verify diagnostics { @@ -151,10 +147,10 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task BicepConfigFileCreation_ShouldRefreshCompilation() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, testOutputPath); // open the main document and verify diagnostics { @@ -184,7 +180,7 @@ await VerifyDiagnosticsAsync(diagsListener, } } }"; - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); + var bicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, testOutputPath); client.Workspace.DidChangeWatchedFiles(new DidChangeWatchedFilesParams { @@ -208,10 +204,10 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task SavingBicepConfigFile_ShouldRefreshCompilation() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, testOutputPath); // open the main document and verify diagnostics { @@ -242,7 +238,7 @@ await VerifyDiagnosticsAsync(diagsListener, } }"; - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); + var bicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, testOutputPath); client.Workspace.DidChangeWatchedFiles(new DidChangeWatchedFilesParams { @@ -266,7 +262,7 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task WithBicepConfigInParentDirectory_WhenNewBicepConfigFileIsAddedToCurrentDirectory_ShouldUseNewlyAddedConfigSettings() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); var bicepConfigFileContents = @"{ ""analyzers"": { @@ -282,11 +278,11 @@ public async Task WithBicepConfigInParentDirectory_WhenNewBicepConfigFileIsAdded } }"; - SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath, fileSystemDict); + SaveFile("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath); var childDirectoryPath = Path.Combine(parentDirectoryPath, "child"); var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, childDirectoryPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, childDirectoryPath); // open the main document and verify diagnostics { @@ -317,7 +313,7 @@ await VerifyDiagnosticsAsync(diagsListener, } }"; - var newBicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, childDirectoryPath, fileSystemDict); + var newBicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, childDirectoryPath); client.Workspace.DidChangeWatchedFiles(new DidChangeWatchedFilesParams { @@ -341,11 +337,11 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task WithBicepConfigInCurrentDirectory_WhenNewBicepConfigFileIsAddedToParentDirectory_ShouldUseOldConfigSettings() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); var childDirectoryPath = Path.Combine(parentDirectoryPath, "child"); var bicepFileContents = @"param storageAccountName string = 'test'"; - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, childDirectoryPath, fileSystemDict); + var mainUri = SaveFile("main.bicep", bicepFileContents, childDirectoryPath); var bicepConfigFileContents = @"{ ""analyzers"": { @@ -360,7 +356,7 @@ public async Task WithBicepConfigInCurrentDirectory_WhenNewBicepConfigFileIsAdde } } }"; - SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, childDirectoryPath, fileSystemDict); + SaveFile("bicepconfig.json", bicepConfigFileContents, childDirectoryPath); // open the main document and verify diagnostics { @@ -390,7 +386,7 @@ await VerifyDiagnosticsAsync(diagsListener, } } }"; - var newBicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath, fileSystemDict); + var newBicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath); client.Workspace.DidChangeWatchedFiles(new DidChangeWatchedFilesParams { @@ -414,7 +410,7 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task FixingErrorsInInvalidBicepConfigFileAndSaving_ShouldRefreshCompilation() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(); var bicepConfigFileContents = @"{ ""analyzers"": { @@ -426,20 +422,20 @@ public async Task FixingErrorsInInvalidBicepConfigFileAndSaving_ShouldRefreshCom "; var bicepFileContents = @"param storageAccountName string = 'test'"; - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); + var bicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, testOutputPath); + var mainUri = SaveFile("main.bicep", bicepFileContents, testOutputPath); // open the main document and verify diagnostics { client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(mainUri, bicepFileContents, 1)); await VerifyDiagnosticsAsync(diagsListener, - @"Could not load configuration file. Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. LineNumber: 7 | BytePositionInLine: 0.", + $"Failed to parse the contents of the Bicep configuration file \"{bicepConfigUri.GetFileSystemPath()}\" as valid JSON", mainUri, DiagnosticSeverity.Error, new Position(0, 0), new Position(1, 0), - "Fatal"); + "Invalid Bicep Configuration"); } // update bicepconfig.json and verify diagnostics @@ -479,7 +475,7 @@ await VerifyDiagnosticsAsync(diagsListener, [TestMethod] public async Task WithMultipleConfigFiles_ShouldUseConfigSettingsFromRelevantDirectory() { - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); + (ILanguageClient client, MultipleMessageListener diagsListener, string parentDirectoryPath) = await StartServerWithClientConnectionAsync(); var childDirectoryPath = Path.Combine(parentDirectoryPath, "child"); @@ -496,10 +492,10 @@ public async Task WithMultipleConfigFiles_ShouldUseConfigSettingsFromRelevantDir } } }"; - SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, childDirectoryPath, fileSystemDict); + SaveFile("bicepconfig.json", bicepConfigFileContents, childDirectoryPath); string bicepFileContents = @"param storageAccountName string = 'test'"; - var documentUriOfFileInChildDirectory = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, childDirectoryPath, fileSystemDict); + var documentUriOfFileInChildDirectory = SaveFile("main.bicep", bicepFileContents, childDirectoryPath); var uriOfFileInChildDirectory = documentUriOfFileInChildDirectory.ToUri(); // open the main document and verify diagnostics @@ -517,7 +513,7 @@ await VerifyDiagnosticsAsync(diagsListener, // add bicepconfig.json to parent directory and verify diagnostics { - var documentUriOfFileInParentDirectory = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, parentDirectoryPath, fileSystemDict); + var documentUriOfFileInParentDirectory = SaveFile("main.bicep", bicepFileContents, parentDirectoryPath); var uriOfFileInParentDirectory = documentUriOfFileInParentDirectory.ToUri(); bicepConfigFileContents = @"{ @@ -533,7 +529,7 @@ await VerifyDiagnosticsAsync(diagsListener, } } }"; - var newBicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath, fileSystemDict); + var newBicepConfigUri = SaveFile("bicepconfig.json", bicepConfigFileContents, parentDirectoryPath); client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(uriOfFileInParentDirectory, bicepFileContents, 1)); @@ -556,102 +552,7 @@ await VerifyDiagnosticsAsync(diagsListener, } } - [TestMethod] - public async Task ModifyBicepConfigFileAndVerifyCallsToFileResolver() - { - var mockFileResolver = Repository.Create(); - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(mockFileResolver.Object); - - var bicepConfigFileContents = @"{ - ""analyzers"": { - ""core"": { - ""verbose"": false, - ""enabled"": true, - ""rules"": { - ""no-unused-params"": { - ""level"": ""info"" - } - } - } - } -}"; - var bicepFileContents = @"param storageAccountName string = 'test'"; - - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); - - // open main.bicep and update bicepconfig.json. Verify FileResolver.FileExists(..) was called twice - { - client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(mainUri, bicepFileContents, 1)); - - await diagsListener.WaitNext(); - - mockFileResolver.Verify(x => x.FileExists(bicepConfigUri.ToUri()), Times.Once); - - File.WriteAllText(bicepConfigUri.GetFileSystemPath(), @"{ - ""analyzers"": { - ""core"": { - ""verbose"": false, - ""enabled"": true, - ""rules"": { - ""no-unused-params"": { - ""level"": ""info"" - } - } - } - } -}"); - client.Workspace.DidChangeWatchedFiles(new DidChangeWatchedFilesParams - { - Changes = new Container(new FileEvent - { - Type = FileChangeType.Changed, - Uri = bicepConfigUri, - }) - }); - - mockFileResolver.Verify(x => x.FileExists(bicepConfigUri.ToUri()), Times.Once); - } - } - - [TestMethod] - public async Task ModifyBicepFileAndVerifyCallsToFileResolver() - { - var mockFileResolver = Repository.Create(); - (ILanguageClient client, Dictionary fileSystemDict, MultipleMessageListener diagsListener, string testOutputPath) = await StartServerWithClientConnectionAsync(mockFileResolver.Object); - - var bicepConfigFileContents = @"{ - ""analyzers"": { - ""core"": { - ""verbose"": false, - ""enabled"": true, - ""rules"": { - ""no-unused-params"": { - ""level"": ""info"" - } - } - } - } -}"; - var bicepFileContents = @"param storageAccountName string = 'test'"; - - var mainUri = SaveFileAndUpdateFileSystemDictionary("main.bicep", bicepFileContents, testOutputPath, fileSystemDict); - var bicepConfigUri = SaveFileAndUpdateFileSystemDictionary("bicepconfig.json", bicepConfigFileContents, testOutputPath, fileSystemDict); - - // open and update main.bicep. Verify FileResolver.FileExists(..) was called only once - { - client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(mainUri, bicepFileContents, 1)); - await diagsListener.WaitNext(); - - mockFileResolver.Verify(x => x.FileExists(bicepConfigUri.ToUri()), Times.Once); - - client.TextDocument.DidChangeTextDocument(TextDocumentParamHelper.CreateDidChangeTextDocumentParams(mainUri, @"param storageAccountId int = 123", 2)); - - mockFileResolver.VerifyNoOtherCalls(); - } - } - - private async Task VerifyDiagnosticsAsync(MultipleMessageListener diagsListener, + private static async Task VerifyDiagnosticsAsync(MultipleMessageListener diagsListener, string message, DocumentUri documentUri, DiagnosticSeverity diagnosticSeverity, @@ -675,13 +576,10 @@ private async Task VerifyDiagnosticsAsync(MultipleMessageListener, MultipleMessageListener, string testOutputPath)> StartServerWithClientConnectionAsync(IFileResolver? fileResolver = null) + private async Task<(ILanguageClient, MultipleMessageListener, string testOutputPath)> StartServerWithClientConnectionAsync() { var fileSystemDict = new Dictionary(); - if (fileResolver is null) - { - fileResolver = new InMemoryFileResolver(fileSystemDict); - } + var fileResolver = new InMemoryFileResolver(fileSystemDict); var diagsListener = new MultipleMessageListener(); var serverOptions = new Server.CreationOptions(FileResolver: fileResolver); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync( @@ -694,14 +592,13 @@ private async Task VerifyDiagnosticsAsync(MultipleMessageListener fileSystemDict) + private DocumentUri SaveFile(string fileName, string fileContents, string testOutputPath) { string path = FileHelper.SaveResultFile(TestContext, fileName, fileContents, testOutputPath); var documentUri = DocumentUri.FromFileSystemPath(path); - fileSystemDict[documentUri.ToUri()] = fileContents; return documentUri; } diff --git a/src/Bicep.LangServer.IntegrationTests/CodeActionTests.cs b/src/Bicep.LangServer.IntegrationTests/CodeActionTests.cs index e1883743c57..f9488b59868 100644 --- a/src/Bicep.LangServer.IntegrationTests/CodeActionTests.cs +++ b/src/Bicep.LangServer.IntegrationTests/CodeActionTests.cs @@ -33,7 +33,6 @@ namespace Bicep.LangServer.IntegrationTests { [TestClass] - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Test methods do not need to follow this convention.")] public class CodeActionTests { [NotNull] @@ -102,6 +101,24 @@ public async Task DisableLinterRuleCodeActionInvocation_WithoutBicepConfig_Shoul { var bicepFileContents = "param storageAccountName string = 'testAccount'"; var expectedBicepConfigContents = @"{ + ""cloud"": { + ""currentProfile"": ""AzureCloud"", + ""profiles"": { + ""AzureCloud"": { + ""resourceManagerEndpoint"": ""https://management.azure.com"" + }, + ""AzureChinaCloud"": { + ""resourceManagerEndpoint"": ""https://management.chinacloudapi.cn"" + }, + ""AzureUSGovernment"": { + ""resourceManagerEndpoint"": ""https://management.usgovcloudapi.net"" + } + } + }, + ""moduleAliases"": { + ""ts"": {}, + ""br"": {} + }, ""analyzers"": { ""core"": { ""verbose"": false, @@ -300,6 +317,24 @@ public async Task DisableLinterRuleCodeActionInvocation_WithOnlyCurlyBracesInBic var bicepFileContents = "param storageAccountName string = 'testAccount'"; var bicepConfigContents = @"{}"; var expectedBicepConfigContents = @"{ + ""cloud"": { + ""currentProfile"": ""AzureCloud"", + ""profiles"": { + ""AzureCloud"": { + ""resourceManagerEndpoint"": ""https://management.azure.com"" + }, + ""AzureChinaCloud"": { + ""resourceManagerEndpoint"": ""https://management.chinacloudapi.cn"" + }, + ""AzureUSGovernment"": { + ""resourceManagerEndpoint"": ""https://management.usgovcloudapi.net"" + } + } + }, + ""moduleAliases"": { + ""ts"": {}, + ""br"": {} + }, ""analyzers"": { ""core"": { ""verbose"": false, @@ -364,11 +399,11 @@ private async Task VerifyLinterRuleIsDisabledAsync(string bicepFileContents, str } else { - bicepConfigFilePath = Path.Combine(testOutputPath, LanguageConstants.BicepConfigSettingsFileName); + bicepConfigFilePath = Path.Combine(testOutputPath, LanguageConstants.BicepConfigurationFileName); } var workspace = new Workspace(); - var compilation = GetCompilation(testOutputPath, bicepFilePath, workspace); + var compilation = GetCompilation(bicepFilePath, workspace); var serverOptions = new Server.CreationOptions(FileResolver: new InMemoryFileResolver(fileSystemDict)); @@ -405,19 +440,20 @@ private async Task VerifyLinterRuleIsDisabledAsync(string bicepFileContents, str await client.Workspace.ExecuteCommand(command); // Verify diagnostics is cleared - GetCompilation(testOutputPath, bicepFilePath, workspace).GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty(); + GetCompilation(bicepFilePath, workspace).GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty(); // Verify bicepconfig.json file contents File.ReadAllText(bicepConfigFilePath).Should().BeEquivalentToIgnoringNewlines(expectedBicepConfigFileContents); } - private Compilation GetCompilation(string? folderContainingBicepConfig, string bicepFilePath, Workspace workspace) + private Compilation GetCompilation(string bicepFilePath, Workspace workspace) { var moduleRegistryProvider = new DefaultModuleRegistryProvider(BicepTestConstants.FileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features); var dispatcher = new ModuleDispatcher(moduleRegistryProvider); var sourceFileGrouping = SourceFileGroupingBuilder.Build(BicepTestConstants.FileResolver, dispatcher, workspace, PathHelper.FilePathToFileUrl(bicepFilePath)); + var configuration = BicepTestConstants.ConfigurationManager.GetConfiguration(new Uri(bicepFilePath)); - return new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, new ConfigHelper(folderContainingBicepConfig, BicepTestConstants.FileResolver)); + return new Compilation(TestTypeHelper.CreateEmptyProvider(), sourceFileGrouping, configuration); } private static IEnumerable GetOverlappingSpans(TextSpan span) diff --git a/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs b/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs index d77262bada8..d1df191f7e1 100644 --- a/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs +++ b/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs @@ -117,7 +117,7 @@ public async Task ValidateSnippetCompletionAfterPlaceholderReplacements(Completi { [combinedFileUri] = bicepContentsReplaced, }, combinedFileUri, BicepTestConstants.FileResolver); - var compilation = new Compilation(NamespaceProvider, sourceFileGrouping, null); + var compilation = new Compilation(NamespaceProvider, sourceFileGrouping, BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepContentsReplaced, "\n", diagnostics, diag => OutputHelper.GetDiagLoggingString(bicepContentsReplaced, outputDirectory, diag)); diff --git a/src/Bicep.LangServer.IntegrationTests/Helpers/IntegrationTestHelper.cs b/src/Bicep.LangServer.IntegrationTests/Helpers/IntegrationTestHelper.cs index bc7cf7e9343..2c9cca4c9ac 100644 --- a/src/Bicep.LangServer.IntegrationTests/Helpers/IntegrationTestHelper.cs +++ b/src/Bicep.LangServer.IntegrationTests/Helpers/IntegrationTestHelper.cs @@ -23,7 +23,6 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Window; using System.Linq; using Bicep.Core.UnitTests; -using Bicep.Core.Configuration; namespace Bicep.LangServer.IntegrationTests { @@ -31,7 +30,7 @@ public static class IntegrationTestHelper { private const int DefaultTimeout = 20000; - public static readonly ISnippetsProvider SnippetsProvider = new SnippetsProvider(TestTypeHelper.CreateEmptyProvider(), BicepTestConstants.FileResolver); + public static readonly ISnippetsProvider SnippetsProvider = new SnippetsProvider(TestTypeHelper.CreateEmptyProvider(), BicepTestConstants.FileResolver, BicepTestConstants.ConfigurationManager); public static async Task StartServerWithClientConnectionAsync(TestContext testContext, Action onClientOptions, Server.CreationOptions? creationOptions = null) { diff --git a/src/Bicep.LangServer.IntegrationTests/SnippetTemplatesTests.cs b/src/Bicep.LangServer.IntegrationTests/SnippetTemplatesTests.cs index 178de208ba9..ed3e3764f7c 100644 --- a/src/Bicep.LangServer.IntegrationTests/SnippetTemplatesTests.cs +++ b/src/Bicep.LangServer.IntegrationTests/SnippetTemplatesTests.cs @@ -54,7 +54,7 @@ public void VerifySnippetTemplatesAreErrorFree(CompletionData completionData) return; } - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var semanticModel = compilation.GetEntrypointSemanticModel(); if (semanticModel.HasErrors()) diff --git a/src/Bicep.LangServer.IntegrationTests/packages.lock.json b/src/Bicep.LangServer.IntegrationTests/packages.lock.json index aa2f284a8b7..1257b6d74d2 100644 --- a/src/Bicep.LangServer.IntegrationTests/packages.lock.json +++ b/src/Bicep.LangServer.IntegrationTests/packages.lock.json @@ -1393,6 +1393,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2264,7 +2280,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2299,6 +2316,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.LangServer.UnitTests/BicepCompilationManagerHelper.cs b/src/Bicep.LangServer.UnitTests/BicepCompilationManagerHelper.cs index 1fe8d64a0e2..4a6666f09ed 100644 --- a/src/Bicep.LangServer.UnitTests/BicepCompilationManagerHelper.cs +++ b/src/Bicep.LangServer.UnitTests/BicepCompilationManagerHelper.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Bicep.Core; +using Bicep.Core.Configuration; using Bicep.Core.FileSystem; using Bicep.Core.Registry; using Bicep.Core.Syntax; @@ -18,6 +19,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.LangServer.UnitTests { @@ -32,7 +34,7 @@ public static BicepCompilationManager CreateCompilationManager(DocumentUri docum var document = CreateMockDocument(p => receivedParams = p); var server = CreateMockServer(document); - BicepCompilationManager bicepCompilationManager = new BicepCompilationManager(server.Object, CreateEmptyCompilationProvider(), new Workspace(), FileResolver, BicepCompilationManagerHelper.CreateMockScheduler().Object); + BicepCompilationManager bicepCompilationManager = new(server.Object, CreateEmptyCompilationProvider(), new Workspace(), FileResolver, CreateMockScheduler().Object, new ConfigurationManager(new IOFileSystem())); if (upsertCompilation) { diff --git a/src/Bicep.LangServer.UnitTests/BicepCompilationManagerTests.cs b/src/Bicep.LangServer.UnitTests/BicepCompilationManagerTests.cs index 4443f7208b7..5c77ff86ead 100644 --- a/src/Bicep.LangServer.UnitTests/BicepCompilationManagerTests.cs +++ b/src/Bicep.LangServer.UnitTests/BicepCompilationManagerTests.cs @@ -10,13 +10,10 @@ using Bicep.Core.FileSystem; using Bicep.Core.Semantics; using Bicep.Core.Registry; -using Bicep.Core.Syntax; using Bicep.Core.UnitTests; using Bicep.Core.Workspaces; using Bicep.LanguageServer; -using Bicep.LanguageServer.CompilationManager; using Bicep.LanguageServer.Providers; -using Bicep.LanguageServer.Registry; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -25,6 +22,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Server; using Bicep.Core.UnitTests.Utils; using Bicep.Core.Configuration; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.LangServer.UnitTests { @@ -35,6 +33,8 @@ public class BicepCompilationManagerTests private static readonly MockRepository Repository = new(MockBehavior.Strict); + private static readonly ConfigurationManager configurationManager = new(new IOFileSystem()); + [NotNull] public TestContext? TestContext { get; set; } @@ -85,7 +85,7 @@ public void UpsertCompilation_InWorspaceArmTemplateFile_ShouldRefreshWorkspace(s var workspace = new Workspace(); workspace.UpsertSourceFile(originalFile); - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // first get should not return anything manager.GetCompilation(uri).Should().BeNull(); @@ -123,7 +123,7 @@ public void UpsertCompilation_BicepFile_ShouldUpsertSuccessfully(string? languag workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(uri.ToUri(), "")); } - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // first get should not return anything manager.GetCompilation(uri).Should().BeNull(); @@ -172,7 +172,7 @@ public void CloseAfterUpsert_ShouldClearDiagnostics(string? languageId) workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(uri.ToUri(), "")); } - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // first get should not return anything manager.GetCompilation(uri).Should().BeNull(); @@ -244,7 +244,7 @@ public void UpsertCompilation_ShouldUpdateDiagnostics(string? languageId) workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(uri.ToUri(), "")); } - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // first get should not return anything manager.GetCompilation(uri).Should().BeNull(); @@ -304,7 +304,7 @@ public void GetNonExistentCompilation_ShouldNotThrow() { var server = Repository.Create(); - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), new Workspace(), new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), new Workspace(), new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); var uri = DocumentUri.File(this.TestContext.TestName); @@ -319,7 +319,7 @@ public void CloseNonExistentCompilation_ShouldClearDiagnostics() var document = BicepCompilationManagerHelper.CreateMockDocument(p => receivedParams = p); var server = BicepCompilationManagerHelper.CreateMockServer(document); - var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), new Workspace(), new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), new Workspace(), new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); var uri = DocumentUri.File(this.TestContext.TestName); @@ -350,7 +350,7 @@ public void FatalException_ShouldProduceCorrectDiagnosticsAndClearThemWhenFileIs var provider = Repository.Create(); const string expectedMessage = "Internal bicep exception."; - provider.Setup(m => m.Create(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())).Throws(new InvalidOperationException(expectedMessage)); + provider.Setup(m => m.Create(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())).Throws(new InvalidOperationException(expectedMessage)); var uri = DocumentUri.File(this.TestContext.TestName); var workspace = new Workspace(); @@ -360,7 +360,7 @@ public void FatalException_ShouldProduceCorrectDiagnosticsAndClearThemWhenFileIs workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(uri.ToUri(), "")); } - var manager = new BicepCompilationManager(server.Object, provider.Object, workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, provider.Object, workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // upsert should fail because of the mock fatal exception manager.UpsertCompilation(uri, BaseVersion, "fake", languageId); @@ -414,8 +414,10 @@ public void NormalUpsertAfterFatalException_ShouldReplaceDiagnostics(string? lan // start by failing bool failUpsert = true; provider - .Setup(m => m.Create(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) - .Returns, ConfigHelper>((grouping, documentUri, modelLookup, configHelper) => failUpsert ? throw new InvalidOperationException(expectedMessage) : BicepCompilationManagerHelper.CreateEmptyCompilationProvider().Create(grouping, documentUri, modelLookup, configHelper)); + .Setup(m => m.Create(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) + .Returns, RootConfiguration>((grouping, documentUri, modelLookup, configuration) => failUpsert + ? throw new InvalidOperationException(expectedMessage) + : BicepCompilationManagerHelper.CreateEmptyCompilationProvider().Create(grouping, documentUri, modelLookup, configuration)); var workspace = new Workspace(); @@ -424,7 +426,7 @@ public void NormalUpsertAfterFatalException_ShouldReplaceDiagnostics(string? lan workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(uri.ToUri(), "")); } - var manager = new BicepCompilationManager(server.Object, provider.Object, workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var manager = new BicepCompilationManager(server.Object, provider.Object, workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); // upsert should fail because of the mock fatal exception manager.UpsertCompilation(uri, version, "fake", languageId); @@ -508,7 +510,7 @@ public void SemanticModels_should_only_be_reloaded_on_sourcefile_or_dependent_so var fileResolver = new InMemoryFileResolver(fileDict); var compilationProvider = new BicepCompilationProvider(TestTypeHelper.CreateEmptyProvider(), fileResolver, new ModuleDispatcher(new DefaultModuleRegistryProvider(fileResolver, BicepTestConstants.ClientFactory, BicepTestConstants.TemplateSpecRepositoryFactory, BicepTestConstants.Features))); - var compilationManager = new BicepCompilationManager(server.Object, compilationProvider, new Workspace(), fileResolver, BicepCompilationManagerHelper.CreateMockScheduler().Object); + var compilationManager = new BicepCompilationManager(server.Object, compilationProvider, new Workspace(), fileResolver, BicepCompilationManagerHelper.CreateMockScheduler().Object, configurationManager); diagsReceieved.Should().BeEmpty(); diff --git a/src/Bicep.LangServer.UnitTests/BicepCompilationProviderTests.cs b/src/Bicep.LangServer.UnitTests/BicepCompilationProviderTests.cs index 1e64be971e8..f9ec90f99c9 100644 --- a/src/Bicep.LangServer.UnitTests/BicepCompilationProviderTests.cs +++ b/src/Bicep.LangServer.UnitTests/BicepCompilationProviderTests.cs @@ -40,8 +40,8 @@ public void Create_ShouldReturnValidCompilation() var sourceFile = SourceFileFactory.CreateSourceFile(fileUri.ToUri(), DataSets.Parameters_LF.Bicep); var workspace = new Workspace(); workspace.UpsertSourceFile(sourceFile); - var configHelper = new ConfigHelper(null, BicepTestConstants.FileResolver).GetDisabledLinterConfig(); - var context = provider.Create(workspace, fileUri, ImmutableDictionary.Empty, configHelper); + var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; + var context = provider.Create(workspace, fileUri, ImmutableDictionary.Empty, configuration); context.Compilation.Should().NotBeNull(); // TODO: remove Where when the support of modifiers is dropped. diff --git a/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs b/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs index 4d25b465857..b782845c611 100644 --- a/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs +++ b/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs @@ -32,13 +32,13 @@ public class BicepCompletionProviderTests { private static readonly MockRepository Repository = new MockRepository(MockBehavior.Strict); private static readonly ILanguageServerFacade Server = Repository.Create().Object; - private static readonly SnippetsProvider snippetsProvider = new(TestTypeHelper.CreateEmptyProvider(), BicepTestConstants.FileResolver); + private static readonly SnippetsProvider snippetsProvider = new(TestTypeHelper.CreateEmptyProvider(), BicepTestConstants.FileResolver, BicepTestConstants.ConfigurationManager); [TestMethod] public void DeclarationContextShouldReturnKeywordCompletions() { var grouping = SourceFileGroupingFactory.CreateFromText(string.Empty, BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty(); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); @@ -119,7 +119,7 @@ param p string output o int = 42 ", BicepTestConstants.FileResolver); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Value.Span.Position; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var context = BicepCompletionContext.Create(BicepTestConstants.Features, compilation, offset); @@ -156,7 +156,7 @@ param p string public void CompletionsForOneLinerParameterDefaultValueShouldIncludeFunctionsValidInDefaultValues() { var grouping = SourceFileGroupingFactory.CreateFromText(@"param p string = ", BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var offset = ((ParameterDefaultValueSyntax) grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Modifier!).DefaultValue.Span.Position; @@ -192,7 +192,7 @@ param concat string ", BicepTestConstants.FileResolver); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Value.Span.Position; - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var context = BicepCompletionContext.Create(BicepTestConstants.Features, compilation, offset); var completions = provider.GetFilteredCompletions(compilation, context).ToList(); @@ -234,7 +234,7 @@ param concat string public void OutputTypeContextShouldReturnDeclarationTypeCompletions() { var grouping = SourceFileGroupingFactory.CreateFromText("output test ", BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Type.Span.Position; @@ -251,7 +251,7 @@ public void OutputTypeContextShouldReturnDeclarationTypeCompletions() public void ParameterTypeContextShouldReturnDeclarationTypeCompletions() { var grouping = SourceFileGroupingFactory.CreateFromText("param foo ", BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Type.Span.Position; @@ -298,7 +298,7 @@ public void ParameterTypeContextShouldReturnDeclarationTypeCompletions() public void VerifyParameterTypeCompletionWithPrecedingComment() { var grouping = SourceFileGroupingFactory.CreateFromText("/*test*/param foo ", BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Type.Span.Position; @@ -356,7 +356,7 @@ public void VerifyParameterTypeCompletionWithPrecedingComment() public void CommentShouldNotGiveAnyCompletions(string codeFragment) { var grouping = SourceFileGroupingFactory.CreateFromText(codeFragment, BicepTestConstants.FileResolver); - var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, null); + var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var offset = codeFragment.IndexOf('|'); diff --git a/src/Bicep.LangServer.UnitTests/Completions/BicepCompletionContextTests.cs b/src/Bicep.LangServer.UnitTests/Completions/BicepCompletionContextTests.cs index 3ec1dd162bb..86b6a280da8 100644 --- a/src/Bicep.LangServer.UnitTests/Completions/BicepCompletionContextTests.cs +++ b/src/Bicep.LangServer.UnitTests/Completions/BicepCompletionContextTests.cs @@ -18,7 +18,7 @@ public class BicepCompletionContextTests public void ZeroMatchingNodes_Create_ShouldThrow() { const string text = "var foo = 42"; - var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(text, BicepTestConstants.FileResolver), null); + var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); Action fail = () => BicepCompletionContext.Create(BicepTestConstants.Features, compilation, text.Length + 2); fail.Should().Throw().WithMessage("The specified offset 14 is outside the span of the specified ProgramSyntax node."); diff --git a/src/Bicep.LangServer.UnitTests/Configuration/BicepConfigChangeHandlerTests.cs b/src/Bicep.LangServer.UnitTests/Configuration/BicepConfigChangeHandlerTests.cs index fa2c11869f8..79fcce92552 100644 --- a/src/Bicep.LangServer.UnitTests/Configuration/BicepConfigChangeHandlerTests.cs +++ b/src/Bicep.LangServer.UnitTests/Configuration/BicepConfigChangeHandlerTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using Bicep.Core; +using Bicep.Core.Configuration; using Bicep.Core.FileSystem; using Bicep.Core.UnitTests.Utils; using Bicep.Core.Workspaces; @@ -18,6 +19,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.LangServer.UnitTests.Configuration { @@ -97,9 +99,9 @@ public void RefreshCompilationOfSourceFilesInWorkspace_WithInvalidBicepConfigFil diagnostics.Should().SatisfyRespectively( x => { - x.Message.Should().Contain("Could not load configuration file. Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. LineNumber: 8 | BytePositionInLine: 13."); + x.Message.Should().MatchRegex(@"Failed to parse the contents of the Bicep configuration file "".+bicepconfig.json"" as valid JSON: ""Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. LineNumber: 8 | BytePositionInLine: 13.""."); x.Severity.Should().Be(DiagnosticSeverity.Error); - x.Code?.String.Should().Be("Fatal"); + x.Code?.String.Should().Be("Invalid Bicep Configuration"); x.Range.Should().Be(new Range { Start = new Position(0, 0), @@ -216,7 +218,7 @@ private void RefreshCompilationOfSourceFilesInWorkspace(string bicepFileContents var bicepFilePath = FileHelper.SaveResultFile(TestContext, "input.bicep", bicepFileContents, testOutputPath); var workspace = new Workspace(); - var bicepCompilationManager = new BicepCompilationManager(server, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object); + var bicepCompilationManager = new BicepCompilationManager(server, BicepCompilationManagerHelper.CreateEmptyCompilationProvider(), workspace, new FileResolver(), BicepCompilationManagerHelper.CreateMockScheduler().Object, new ConfigurationManager(new IOFileSystem())); bicepCompilationManager.UpsertCompilation(DocumentUri.From(bicepFilePath), null, bicepFileContents, LanguageConstants.LanguageId); var bicepConfigDocumentUri = DocumentUri.FromFileSystemPath(bicepFilePath); diff --git a/src/Bicep.LangServer.UnitTests/Handlers/BicepBuildCommandHandlerTests.cs b/src/Bicep.LangServer.UnitTests/Handlers/BicepBuildCommandHandlerTests.cs index ae2eeeea391..0fa4cf74dd6 100644 --- a/src/Bicep.LangServer.UnitTests/Handlers/BicepBuildCommandHandlerTests.cs +++ b/src/Bicep.LangServer.UnitTests/Handlers/BicepBuildCommandHandlerTests.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Bicep.Core.Configuration; using Bicep.Core.FileSystem; using Bicep.Core.Registry; using Bicep.Core.UnitTests; @@ -20,11 +21,11 @@ using Moq; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.LanguageServer.Protocol; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.LangServer.UnitTests.Handlers { [TestClass] - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Test methods do not need to follow this convention.")] public class BicepBuildCommandHandlerTests { [NotNull] @@ -33,7 +34,8 @@ public class BicepBuildCommandHandlerTests private static readonly FileResolver FileResolver = new(); private static readonly MockRepository Repository = new(MockBehavior.Strict); private static readonly ISerializer Serializer = Repository.Create().Object; - private ModuleDispatcher ModuleDispatcher = new ModuleDispatcher(BicepTestConstants.RegistryProvider); + private static readonly IConfigurationManager configurationManager = new ConfigurationManager(new IOFileSystem()); + private readonly ModuleDispatcher ModuleDispatcher = new ModuleDispatcher(BicepTestConstants.RegistryProvider); [DataRow(null)] [DataRow("")] @@ -42,7 +44,7 @@ public class BicepBuildCommandHandlerTests public void Handle_WithInvalidPath_ShouldThrowArgumentException(string path) { ICompilationManager bicepCompilationManager = Repository.Create().Object; - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); Action sut = () => bicepBuildCommandHandler.Handle(path, CancellationToken.None); @@ -60,7 +62,7 @@ public async Task Handle_WithNullContext_ShouldCreateCompilation() DocumentUri documentUri = DocumentUri.FromFileSystemPath(bicepFilePath); // Do not upsert compilation. This will cause CompilationContext to be null BicepCompilationManager bicepCompilationManager = BicepCompilationManagerHelper.CreateCompilationManager(documentUri, bicepFileContents, upsertCompilation: false); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(bicepFilePath, CancellationToken.None); expected.Should().Be(@"Build succeeded. Created file input.json"); @@ -83,7 +85,7 @@ public async Task Handle_WithValidPath_AndOnlyWarningsAndInfoInInputFile_Returns DocumentUri documentUri = DocumentUri.From(bicepFileUri); BicepCompilationManager bicepCompilationManager = BicepCompilationManagerHelper.CreateCompilationManager(documentUri, bicepFileContents, true); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(bicepFilePath, CancellationToken.None); expected.Should().Be(@"Build succeeded. Created file input.json"); @@ -109,7 +111,7 @@ public async Task Handle_WithValidPath_AndErrorsAndWarningsInInputFile_ReturnsBu targetScope = true param accountName string = 'testAccount' ", true); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(documentUri.Path, CancellationToken.None); expected.Should().BeEquivalentToIgnoringNewlines(@"Build failed. Please fix below errors: @@ -143,7 +145,7 @@ public async Task Handle_WhenCompiledFileAlreadyExists_ReturnsBuildFailedMessage FileHelper.SaveResultFile(TestContext, "input.json", string.Empty, outputPath); DocumentUri documentUri = DocumentUri.FromFileSystemPath(bicepFilePath); BicepCompilationManager bicepCompilationManager = BicepCompilationManagerHelper.CreateCompilationManager(documentUri, string.Empty, true); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(bicepFilePath, CancellationToken.None); expected.Should().Be(@"Build failed. The file ""input.json"" already exists and was not generated by Bicep. If overwriting the file is intended, delete it manually and retry the Build command."); @@ -157,7 +159,7 @@ public async Task Handle_WhenCompiledFileAlreadyExistsAndIsMalformed_ReturnsBuil FileHelper.SaveResultFile(TestContext, "input.json", "invalid json", outputPath); DocumentUri documentUri = DocumentUri.FromFileSystemPath(bicepFilePath); BicepCompilationManager bicepCompilationManager = BicepCompilationManagerHelper.CreateCompilationManager(documentUri, string.Empty, true); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(bicepFilePath, CancellationToken.None); expected.Should().Be(@"Build failed. The file ""input.json"" already exists and was not generated by Bicep. If overwriting the file is intended, delete it manually and retry the Build command."); @@ -174,7 +176,7 @@ public async Task Handle_WithValidPath_AndNoErrorsInInputFile_ReturnsBuildSuccee "); DocumentUri documentUri = DocumentUri.FromFileSystemPath(bicepFilePath); BicepCompilationManager bicepCompilationManager = BicepCompilationManagerHelper.CreateCompilationManager(documentUri, string.Empty, true); - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Repository.Create().Object, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string expected = await bicepBuildCommandHandler.Handle(bicepFilePath, CancellationToken.None); expected.Should().Be(@"Build succeeded. Created file input.json"); @@ -187,7 +189,7 @@ public async Task Handle_WithValidPath_AndNoErrorsInInputFile_ReturnsBuildSuccee public void TemplateContainsBicepGeneratorMetadata_WithInvalidInput_ReturnsFalse(string template) { ICompilationManager bicepCompilationManager = Repository.Create().Object; - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); bool actual = bicepBuildCommandHandler.TemplateContainsBicepGeneratorMetadata(template); @@ -198,7 +200,7 @@ public void TemplateContainsBicepGeneratorMetadata_WithInvalidInput_ReturnsFalse public void TemplateContainsBicepGeneratorMetadata_WithBicepGeneratorMetadataInInput_ReturnsTrue() { ICompilationManager bicepCompilationManager = Repository.Create().Object; - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string template = @"{ ""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"", ""contentVersion"": ""1.0.0.0"", @@ -222,7 +224,7 @@ public void TemplateContainsBicepGeneratorMetadata_WithBicepGeneratorMetadataInI public void TemplateContainsBicepGeneratorMetadata_WithoutBicepGeneratorMetadataInInput_ReturnsFalse() { ICompilationManager bicepCompilationManager = Repository.Create().Object; - BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher); + BicepBuildCommandHandler bicepBuildCommandHandler = new BicepBuildCommandHandler(bicepCompilationManager, Serializer, EmitterSettingsHelper.DefaultTestSettings, BicepTestConstants.NamespaceProvider, FileResolver, ModuleDispatcher, configurationManager); string template = @"{ ""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"", ""contentVersion"": ""1.0.0.0"", diff --git a/src/Bicep.LangServer.UnitTests/Handlers/BicepDisableLinterRuleCommandHandlerTests.cs b/src/Bicep.LangServer.UnitTests/Handlers/BicepDisableLinterRuleCommandHandlerTests.cs index df0512edffc..3e9daf4112f 100644 --- a/src/Bicep.LangServer.UnitTests/Handlers/BicepDisableLinterRuleCommandHandlerTests.cs +++ b/src/Bicep.LangServer.UnitTests/Handlers/BicepDisableLinterRuleCommandHandlerTests.cs @@ -207,6 +207,24 @@ public void DisableLinterRule_WithOnlyCurlyBraces_ShouldUseDefaultConfigAndTurnO string actual = BicepDisableLinterRuleHandler.DisableLinterRule("{}", "no-unused-params"); actual.Should().BeEquivalentToIgnoringNewlines(@"{ + ""cloud"": { + ""currentProfile"": ""AzureCloud"", + ""profiles"": { + ""AzureCloud"": { + ""resourceManagerEndpoint"": ""https://management.azure.com"" + }, + ""AzureChinaCloud"": { + ""resourceManagerEndpoint"": ""https://management.chinacloudapi.cn"" + }, + ""AzureUSGovernment"": { + ""resourceManagerEndpoint"": ""https://management.usgovcloudapi.net"" + } + } + }, + ""moduleAliases"": { + ""ts"": {}, + ""br"": {} + }, ""analyzers"": { ""core"": { ""verbose"": false, @@ -254,10 +272,28 @@ public void GetBicepConfigFilePathAndContents_WithInvalidBicepConfigFilePath_Sho (string actualBicepConfigFilePath, string actualBicepConfigContents) = BicepDisableLinterRuleHandler.GetBicepConfigFilePathAndContents(documentUri, "no-unused-params", string.Empty); var directoryContainingSourceFile = Path.GetDirectoryName(documentUri.GetFileSystemPath()); - string expectedBicepConfigFilePath = Path.Combine(directoryContainingSourceFile!, LanguageConstants.BicepConfigSettingsFileName); + string expectedBicepConfigFilePath = Path.Combine(directoryContainingSourceFile!, LanguageConstants.BicepConfigurationFileName); actualBicepConfigFilePath.Should().Be(expectedBicepConfigFilePath); actualBicepConfigContents.Should().BeEquivalentToIgnoringNewlines(@"{ + ""cloud"": { + ""currentProfile"": ""AzureCloud"", + ""profiles"": { + ""AzureCloud"": { + ""resourceManagerEndpoint"": ""https://management.azure.com"" + }, + ""AzureChinaCloud"": { + ""resourceManagerEndpoint"": ""https://management.chinacloudapi.cn"" + }, + ""AzureUSGovernment"": { + ""resourceManagerEndpoint"": ""https://management.usgovcloudapi.net"" + } + } + }, + ""moduleAliases"": { + ""ts"": {}, + ""br"": {} + }, ""analyzers"": { ""core"": { ""verbose"": false, @@ -304,9 +340,27 @@ public void GetBicepConfigFilePathAndContents_WithNonExistentBicepConfigFile_Sho (string actualBicepConfigFilePath, string actualBicepConfigContents) = BicepDisableLinterRuleHandler.GetBicepConfigFilePathAndContents(documentUri, "no-unused-params", @"\nonExistent\bicepconfig.json"); var directoryContainingSourceFile = Path.GetDirectoryName(documentUri.GetFileSystemPath()); - string expectedBicepConfigFilePath = Path.Combine(directoryContainingSourceFile!, LanguageConstants.BicepConfigSettingsFileName); + string expectedBicepConfigFilePath = Path.Combine(directoryContainingSourceFile!, LanguageConstants.BicepConfigurationFileName); actualBicepConfigFilePath.Should().Be(expectedBicepConfigFilePath); actualBicepConfigContents.Should().BeEquivalentToIgnoringNewlines(@"{ + ""cloud"": { + ""currentProfile"": ""AzureCloud"", + ""profiles"": { + ""AzureCloud"": { + ""resourceManagerEndpoint"": ""https://management.azure.com"" + }, + ""AzureChinaCloud"": { + ""resourceManagerEndpoint"": ""https://management.chinacloudapi.cn"" + }, + ""AzureUSGovernment"": { + ""resourceManagerEndpoint"": ""https://management.usgovcloudapi.net"" + } + } + }, + ""moduleAliases"": { + ""ts"": {}, + ""br"": {} + }, ""analyzers"": { ""core"": { ""verbose"": false, diff --git a/src/Bicep.LangServer.UnitTests/Snippets/SnippetsProviderTests.cs b/src/Bicep.LangServer.UnitTests/Snippets/SnippetsProviderTests.cs index 44f0aa1f8a4..48c23c04636 100644 --- a/src/Bicep.LangServer.UnitTests/Snippets/SnippetsProviderTests.cs +++ b/src/Bicep.LangServer.UnitTests/Snippets/SnippetsProviderTests.cs @@ -20,7 +20,7 @@ namespace Bicep.LangServer.UnitTests.Snippets [TestClass] public class SnippetsProviderTests { - private readonly SnippetsProvider snippetsProvider = new(BicepTestConstants.NamespaceProvider, BicepTestConstants.FileResolver); + private readonly SnippetsProvider snippetsProvider = new(BicepTestConstants.NamespaceProvider, BicepTestConstants.FileResolver, BicepTestConstants.ConfigurationManager); [TestMethod] public void GetDescriptionAndText_WithEmptyInput_ReturnsEmptyDescriptionAndText() diff --git a/src/Bicep.LangServer.UnitTests/packages.lock.json b/src/Bicep.LangServer.UnitTests/packages.lock.json index aa2f284a8b7..1257b6d74d2 100644 --- a/src/Bicep.LangServer.UnitTests/packages.lock.json +++ b/src/Bicep.LangServer.UnitTests/packages.lock.json @@ -1393,6 +1393,22 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.Abstractions.TestingHelpers": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "pi6rVI4B0aB/QtpJuYXmcSQEGLOGK58mgsOWnf94syBQgNZ2KjJTduStR7RfKWY5EK9u42SJRi/mVRiyAEjqiw==", + "dependencies": { + "System.IO.Abstractions": "13.2.47" + } + }, "System.IO.Compression": { "type": "Transitive", "resolved": "4.3.0", @@ -2264,7 +2280,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -2299,6 +2316,7 @@ "Microsoft.PowerShell.SDK": "7.1.3", "Moq": "4.16.1", "Newtonsoft.Json": "13.0.1", + "System.IO.Abstractions.TestingHelpers": "13.2.47", "System.Management.Automation": "7.1.3" } }, diff --git a/src/Bicep.LangServer/BicepCompilationManager.cs b/src/Bicep.LangServer/BicepCompilationManager.cs index c39b19ce96f..3011ab65941 100644 --- a/src/Bicep.LangServer/BicepCompilationManager.cs +++ b/src/Bicep.LangServer/BicepCompilationManager.cs @@ -31,17 +31,25 @@ public class BicepCompilationManager : ICompilationManager private readonly ICompilationProvider provider; private readonly IFileResolver fileResolver; private readonly IModuleRestoreScheduler scheduler; + private readonly IConfigurationManager configurationManager; // represents compilations of open bicep files private readonly ConcurrentDictionary activeContexts = new ConcurrentDictionary(); - public BicepCompilationManager(ILanguageServerFacade server, ICompilationProvider provider, IWorkspace workspace, IFileResolver fileResolver, IModuleRestoreScheduler scheduler) + public BicepCompilationManager( + ILanguageServerFacade server, + ICompilationProvider provider, + IWorkspace workspace, + IFileResolver fileResolver, + IModuleRestoreScheduler scheduler, + IConfigurationManager configurationManager) { this.server = server; this.provider = provider; this.workspace = workspace; this.fileResolver = fileResolver; this.scheduler = scheduler; + this.configurationManager = configurationManager; } public void RefreshCompilation(DocumentUri documentUri, bool reloadBicepConfig = false) @@ -187,12 +195,13 @@ private ImmutableArray CloseCompilationInternal(DocumentUri documen private (ImmutableArray added, ImmutableArray removed) UpdateCompilationInternal(DocumentUri documentUri, int? version, IDictionary modelLookup, IEnumerable removedFiles, bool reloadBicepConfig = false) { + var configuration = this.GetConfigurationSafely(documentUri, out var configurationDiagnostic); + try { - var folderContainingSourceFile = Path.GetDirectoryName(documentUri.GetFileSystemPath()); var context = this.activeContexts.AddOrUpdate( documentUri, - (documentUri) => this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), new ConfigHelper(folderContainingSourceFile, fileResolver)), + (documentUri) => this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), configuration), (documentUri, prevContext) => { var sourceDependencies = removedFiles @@ -209,18 +218,11 @@ private ImmutableArray CloseCompilationInternal(DocumentUri documen } } - ConfigHelper configHelper; + var configuration = reloadBicepConfig + ? this.GetConfigurationSafely(documentUri.ToUri(), out configurationDiagnostic) + : prevContext.Compilation.Configuration; - if (reloadBicepConfig) - { - configHelper = new ConfigHelper(folderContainingSourceFile, fileResolver); - } - else - { - configHelper = prevContext.Compilation.ConfigHelper; - } - - return this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), configHelper); + return this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), configuration); }); foreach (var sourceFile in context.Compilation.SourceFileGrouping.SourceFiles) @@ -237,6 +239,11 @@ private ImmutableArray CloseCompilationInternal(DocumentUri documen // convert all the diagnostics to LSP diagnostics var diagnostics = GetDiagnosticsFromContext(context).ToDiagnostics(context.LineStarts); + if (configurationDiagnostic is not null) + { + diagnostics = diagnostics.Append(configurationDiagnostic); + } + // publish all the diagnostics this.PublishDocumentDiagnostics(documentUri, version, diagnostics); @@ -266,7 +273,34 @@ private ImmutableArray CloseCompilationInternal(DocumentUri documen } } - private IEnumerable GetDiagnosticsFromContext(CompilationContext context) => context.Compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); + private RootConfiguration GetConfigurationSafely(DocumentUri documentUri, out Diagnostic? diagnostic) + { + try + { + diagnostic = null; + return this.configurationManager.GetConfiguration(documentUri.ToUri()); + } + catch (ConfigurationException exception) + { + diagnostic = new Diagnostic + { + Range = new Range + { + Start = new Position(0, 0), + End = new Position(1, 0), + }, + Severity = DiagnosticSeverity.Error, + Message = exception.Message, + Code = new DiagnosticCode("Invalid Bicep Configuration"), + }; + } + + // Fallback to the default configuration with analyzers disabled. + return this.configurationManager.GetBuiltInConfiguration(disableAnalyzers: true); + } + + private static IEnumerable GetDiagnosticsFromContext(CompilationContext context) => + context.Compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); private void PublishDocumentDiagnostics(DocumentUri uri, int? version, IEnumerable diagnostics) { diff --git a/src/Bicep.LangServer/Extensions/IServiceCollectionExtensions.cs b/src/Bicep.LangServer/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 00000000000..fdf8b356509 --- /dev/null +++ b/src/Bicep.LangServer/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Extensions.DependencyInjection; + +namespace Bicep.LanguageServer.Extensions +{ + public static class IServiceCollectionExtensions + { + public static void AddSingletonOrInstance(this IServiceCollection services, TService? nullableImplementation) + where TService : class where TImplementation : class, TService + { + if (nullableImplementation is not null) + { + services.AddSingleton(nullableImplementation); + } + else + { + services.AddSingleton(); + } + } + } +} diff --git a/src/Bicep.LangServer/Handlers/BicepBuildCommandHandler.cs b/src/Bicep.LangServer/Handlers/BicepBuildCommandHandler.cs index 3dd3b1d5a7e..00d83e8f0e9 100644 --- a/src/Bicep.LangServer/Handlers/BicepBuildCommandHandler.cs +++ b/src/Bicep.LangServer/Handlers/BicepBuildCommandHandler.cs @@ -12,6 +12,7 @@ using Azure.Deployments.Core.Helpers; using Azure.Deployments.Core.Json; using Bicep.Core; +using Bicep.Core.Configuration; using Bicep.Core.Diagnostics; using Bicep.Core.Emit; using Bicep.Core.FileSystem; @@ -38,8 +39,9 @@ public class BicepBuildCommandHandler : ExecuteTypedResponseCommandHandlerBase Handle(string bicepFilePath, CancellationToken cancellationToken) @@ -74,13 +77,26 @@ private string GenerateCompiledFileAndReturnBuildOutputMessage(string bicepFileP return "Build failed. The file \"" + compiledFile + "\" already exists and was not generated by Bicep. If overwriting the file is intended, delete it manually and retry the Build command."; } - CompilationContext? context = compilationManager.GetCompilation(documentUri); + var fileUri = documentUri.ToUri(); + RootConfiguration? configuration = null; + + try + { + configuration = this.configurationManager.GetConfiguration(fileUri); + } + catch (ConfigurationException exception) + { + // Fail the build if there's configuration errors. + return exception.Message; + } + + CompilationContext? context = compilationManager.GetCompilation(fileUri); Compilation compilation; if (context is null) { - SourceFileGrouping sourceFileGrouping = SourceFileGroupingBuilder.Build(this.fileResolver, this.moduleDispatcher, new Workspace(), documentUri.ToUri()); - compilation = new Compilation(namespaceProvider, sourceFileGrouping, null); + SourceFileGrouping sourceFileGrouping = SourceFileGroupingBuilder.Build(this.fileResolver, this.moduleDispatcher, new Workspace(), fileUri); + compilation = new Compilation(namespaceProvider, sourceFileGrouping, configuration); } else { @@ -88,23 +104,21 @@ private string GenerateCompiledFileAndReturnBuildOutputMessage(string bicepFileP } KeyValuePair> diagnosticsByFile = compilation.GetAllDiagnosticsByBicepFile() - .FirstOrDefault(x => x.Key.FileUri == documentUri.ToUri()); + .FirstOrDefault(x => x.Key.FileUri == fileUri); if (diagnosticsByFile.Value.Any(x => x.Level == DiagnosticLevel.Error)) { return GetDiagnosticsMessage(diagnosticsByFile); } - using (FileStream fileStream = new FileStream(compiledFilePath, FileMode.Create, FileAccess.ReadWrite)) - { - TemplateEmitter emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings); - EmitResult result = emitter.Emit(fileStream); + using var fileStream = new FileStream(compiledFilePath, FileMode.Create, FileAccess.ReadWrite); + var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings); + EmitResult result = emitter.Emit(fileStream); - return "Build succeeded. Created file " + compiledFile; - } + return "Build succeeded. Created file " + compiledFile; } - private string GetDiagnosticsMessage(KeyValuePair> diagnosticsByFile) + private static string GetDiagnosticsMessage(KeyValuePair> diagnosticsByFile) { StringBuilder sb = new StringBuilder(); sb.AppendLine("Build failed. Please fix below errors:"); diff --git a/src/Bicep.LangServer/Handlers/BicepCodeActionHandler.cs b/src/Bicep.LangServer/Handlers/BicepCodeActionHandler.cs index e9df9c5a020..2924f2d3ac0 100644 --- a/src/Bicep.LangServer/Handlers/BicepCodeActionHandler.cs +++ b/src/Bicep.LangServer/Handlers/BicepCodeActionHandler.cs @@ -63,7 +63,7 @@ public override Task Handle(CodeActionParams reque analyzerDiagnostic.Span.ContainsInclusive(requestEndOffset) || (requestStartOffset <= analyzerDiagnostic.Span.Position && analyzerDiagnostic.GetEndPosition() <= requestEndOffset)) .OfType() - .Select(analyzerDiagnostic => DisableLinterRule(documentUri, analyzerDiagnostic.Code, compilation.ConfigHelper.CustomSettingsFileName)); + .Select(analyzerDiagnostic => DisableLinterRule(documentUri, analyzerDiagnostic.Code, compilation.Configuration.ResourceName)); commandOrCodeActions.AddRange(analyzerDiagnostics); diff --git a/src/Bicep.LangServer/Handlers/BicepDidChangeWatchedFilesHandler.cs b/src/Bicep.LangServer/Handlers/BicepDidChangeWatchedFilesHandler.cs index 29930216158..e6220f85c24 100644 --- a/src/Bicep.LangServer/Handlers/BicepDidChangeWatchedFilesHandler.cs +++ b/src/Bicep.LangServer/Handlers/BicepDidChangeWatchedFilesHandler.cs @@ -33,7 +33,7 @@ public override Task Handle(DidChangeWatchedFilesParams request, Cancellat { Container fileEvents = request.Changes; IEnumerable bicepConfigFileChangeEvents = fileEvents.Where(x => string.Equals(Path.GetFileName(x.Uri.Path), - LanguageConstants.BicepConfigSettingsFileName, + LanguageConstants.BicepConfigurationFileName, StringComparison.OrdinalIgnoreCase)); // Refresh compilation of source files in workspace when local bicepconfig.json file is created, deleted or changed diff --git a/src/Bicep.LangServer/Handlers/BicepDisableLinterRuleCommandHandler.cs b/src/Bicep.LangServer/Handlers/BicepDisableLinterRuleCommandHandler.cs index f0b5df1d0b5..27291f90b61 100644 --- a/src/Bicep.LangServer/Handlers/BicepDisableLinterRuleCommandHandler.cs +++ b/src/Bicep.LangServer/Handlers/BicepDisableLinterRuleCommandHandler.cs @@ -45,7 +45,7 @@ public override async Task Handle(DocumentUri documentUri, string code, st var directoryContainingSourceFile = Path.GetDirectoryName(documentUri.GetFileSystemPath()) ?? throw new ArgumentException("Unable to find directory information"); - bicepConfigFilePath = Path.Combine(directoryContainingSourceFile, LanguageConstants.BicepConfigSettingsFileName); + bicepConfigFilePath = Path.Combine(directoryContainingSourceFile, LanguageConstants.BicepConfigurationFileName); return (bicepConfigFilePath, DisableLinterRule(string.Empty, code)); } } diff --git a/src/Bicep.LangServer/Providers/BicepCompilationProvider.cs b/src/Bicep.LangServer/Providers/BicepCompilationProvider.cs index 45b992d0f39..c2624595dd3 100644 --- a/src/Bicep.LangServer/Providers/BicepCompilationProvider.cs +++ b/src/Bicep.LangServer/Providers/BicepCompilationProvider.cs @@ -30,21 +30,21 @@ public BicepCompilationProvider(INamespaceProvider namespaceProvider, IFileResol this.moduleDispatcher = moduleDispatcher; } - public CompilationContext Create(IReadOnlyWorkspace workspace, DocumentUri documentUri, ImmutableDictionary modelLookup, ConfigHelper? configHelper) + public CompilationContext Create(IReadOnlyWorkspace workspace, DocumentUri documentUri, ImmutableDictionary modelLookup, RootConfiguration configuration) { var syntaxTreeGrouping = SourceFileGroupingBuilder.Build(fileResolver, moduleDispatcher, workspace, documentUri.ToUri()); - return this.CreateContext(syntaxTreeGrouping, modelLookup, configHelper); + return this.CreateContext(syntaxTreeGrouping, modelLookup, configuration); } - public CompilationContext Update(IReadOnlyWorkspace workspace, CompilationContext current, ImmutableDictionary modelLookup) + public CompilationContext Update(IReadOnlyWorkspace workspace, CompilationContext current, ImmutableDictionary modelLookup, RootConfiguration configuration) { var syntaxTreeGrouping = SourceFileGroupingBuilder.Rebuild(moduleDispatcher, workspace, current.Compilation.SourceFileGrouping); - return this.CreateContext(syntaxTreeGrouping, modelLookup, null); + return this.CreateContext(syntaxTreeGrouping, modelLookup, configuration); } - private CompilationContext CreateContext(SourceFileGrouping syntaxTreeGrouping, ImmutableDictionary modelLookup, ConfigHelper? configHelper) + private CompilationContext CreateContext(SourceFileGrouping syntaxTreeGrouping, ImmutableDictionary modelLookup, RootConfiguration configuration) { - var compilation = new Compilation(namespaceProvider, syntaxTreeGrouping, configHelper, modelLookup); + var compilation = new Compilation(namespaceProvider, syntaxTreeGrouping, configuration, modelLookup); return new CompilationContext(compilation); } } diff --git a/src/Bicep.LangServer/Providers/ICompilationProvider.cs b/src/Bicep.LangServer/Providers/ICompilationProvider.cs index 35bfe391866..3d8e66492cb 100644 --- a/src/Bicep.LangServer/Providers/ICompilationProvider.cs +++ b/src/Bicep.LangServer/Providers/ICompilationProvider.cs @@ -11,8 +11,8 @@ namespace Bicep.LanguageServer.Providers { public interface ICompilationProvider { - CompilationContext Create(IReadOnlyWorkspace workspace, DocumentUri documentUri, ImmutableDictionary modelLookup, ConfigHelper? configHelper); + CompilationContext Create(IReadOnlyWorkspace workspace, DocumentUri documentUri, ImmutableDictionary modelLookup, RootConfiguration configuration); - CompilationContext Update(IReadOnlyWorkspace workspace, CompilationContext current, ImmutableDictionary modelLookup); + CompilationContext Update(IReadOnlyWorkspace workspace, CompilationContext current, ImmutableDictionary modelLookup, RootConfiguration configuration); } } diff --git a/src/Bicep.LangServer/Server.cs b/src/Bicep.LangServer/Server.cs index 72b379251e3..f245888bb78 100644 --- a/src/Bicep.LangServer/Server.cs +++ b/src/Bicep.LangServer/Server.cs @@ -1,32 +1,34 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; -using System.IO; -using System.IO.Pipelines; -using System.Threading; -using System.Threading.Tasks; -using System.Diagnostics; + +using Bicep.Core.Configuration; using Bicep.Core.Emit; +using Bicep.Core.Features; using Bicep.Core.FileSystem; using Bicep.Core.Registry; -using Bicep.Core.TypeSystem; +using Bicep.Core.Semantics.Namespaces; using Bicep.Core.TypeSystem.Az; using Bicep.Core.Workspaces; using Bicep.LanguageServer.CompilationManager; using Bicep.LanguageServer.Completions; +using Bicep.LanguageServer.Extensions; using Bicep.LanguageServer.Handlers; using Bicep.LanguageServer.Providers; using Bicep.LanguageServer.Registry; using Bicep.LanguageServer.Snippets; using Bicep.LanguageServer.Telemetry; +using Bicep.LanguageServer.Utils; using Microsoft.Extensions.DependencyInjection; using OmniSharp.Extensions.LanguageServer.Protocol.Window; using OmniSharp.Extensions.LanguageServer.Server; +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Abstractions; +using System.IO.Pipelines; +using System.Threading; +using System.Threading.Tasks; using OmnisharpLanguageServer = OmniSharp.Extensions.LanguageServer.Server.LanguageServer; -using Bicep.LanguageServer.Utils; -using Bicep.Core.Features; -using Bicep.Core.Configuration; -using Bicep.Core.Semantics.Namespaces; namespace Bicep.LanguageServer { @@ -100,21 +102,19 @@ public async Task RunAsync(CancellationToken cancellationToken) private static void RegisterServices(CreationOptions creationOptions, IServiceCollection services) { - var fileResolver = creationOptions.FileResolver ?? new FileResolver(); - var featureProvider = creationOptions.Features ?? new FeatureProvider(); // using type based registration so dependencies can be injected automatically // without manually constructing up the graph services.AddSingleton(); - AddSingletonOrInstance(services, creationOptions.NamespaceProvider); - services.AddSingleton(services => new EmitterSettings(creationOptions.AssemblyFileVersion ?? ThisAssembly.AssemblyFileVersion, enableSymbolicNames: featureProvider.SymbolicNameCodegenEnabled)); - services.AddSingleton(services => new ConfigHelper(null, fileResolver, useDefaultConfig: false)); - AddSingletonOrInstance(services, creationOptions.SnippetsProvider); - services.AddSingleton(services => fileResolver); - services.AddSingleton(services => creationOptions.Features ?? new FeatureProvider()); + services.AddSingletonOrInstance(creationOptions.NamespaceProvider); + services.AddSingletonOrInstance(creationOptions.SnippetsProvider); + services.AddSingletonOrInstance(creationOptions.FileResolver); + services.AddSingletonOrInstance(creationOptions.Features); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -122,19 +122,9 @@ private static void RegisterServices(CreationOptions creationOptions, IServiceCo services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - } - - private static void AddSingletonOrInstance(IServiceCollection services, TService? nullableImplementation) - where TService : class where TImplementation : class, TService - { - if (nullableImplementation is not null) - { - services.AddSingleton(nullableImplementation); - } - else - { - services.AddSingleton(); - } + services.AddSingleton(services => new EmitterSettings( + creationOptions.AssemblyFileVersion ?? ThisAssembly.AssemblyFileVersion, + enableSymbolicNames: services.GetRequiredService().SymbolicNameCodegenEnabled)); } } } diff --git a/src/Bicep.LangServer/Snippets/SnippetsProvider.cs b/src/Bicep.LangServer/Snippets/SnippetsProvider.cs index 85b5d32bf85..ebe612e9cb4 100644 --- a/src/Bicep.LangServer/Snippets/SnippetsProvider.cs +++ b/src/Bicep.LangServer/Snippets/SnippetsProvider.cs @@ -21,7 +21,6 @@ using Bicep.Core.Semantics.Namespaces; using Bicep.Core.Syntax; using Bicep.Core.TypeSystem; -using Bicep.Core.TypeSystem.Az; using Bicep.Core.Workspaces; using Bicep.LanguageServer.Completions; @@ -69,11 +68,13 @@ public class SnippetsProvider : ISnippetsProvider }; private readonly INamespaceProvider namespaceProvider; private readonly IFileResolver fileResolver; + private readonly IConfigurationManager configurationManager; - public SnippetsProvider(INamespaceProvider namespaceProvider, IFileResolver fileResolver) + public SnippetsProvider(INamespaceProvider namespaceProvider, IFileResolver fileResolver, IConfigurationManager configurationManager) { this.namespaceProvider = namespaceProvider; this.fileResolver = fileResolver; + this.configurationManager = configurationManager; Initialize(); } @@ -223,8 +224,7 @@ private ImmutableDictionary // We'll use default bicepconfig.json settings during SnippetsProvider creation to avoid errors during language service initialization. // We don't do any validation in SnippetsProvider. So using default settings shouldn't be a problem. - var configHelper = new ConfigHelper(null, fileResolver, useDefaultConfig: true); - Compilation compilation = new Compilation(namespaceProvider, sourceFileGrouping, configHelper); + Compilation compilation = new Compilation(namespaceProvider, sourceFileGrouping, configurationManager.GetBuiltInConfiguration(disableAnalyzers: true)); SemanticModel semanticModel = compilation.GetEntrypointSemanticModel(); diff --git a/src/Bicep.LangServer/packages.lock.json b/src/Bicep.LangServer/packages.lock.json index ab18f8cedb0..d40afa37116 100644 --- a/src/Bicep.LangServer/packages.lock.json +++ b/src/Bicep.LangServer/packages.lock.json @@ -269,8 +269,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "3.0.0", - "contentHash": "TsETIgVJb/AKoYfSP+iCxkuly5d3inZjTdx/ItZLk2CxY85v8083OBS3uai84kK3/baLnS5/b5XGs6zR7SuuHQ==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -415,6 +415,23 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.IO.Pipelines": { "type": "Transitive", "resolved": "4.7.3", @@ -510,11 +527,11 @@ }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "gmlk6khICtVhiUnVBBtlsH0H/5QFDqhTZgtpp3AX14wWE6OIE+BX95NLD+X4AolXnIy/oXpNNmXYnsNfW1KuDQ==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "System.Security.Principal.Windows": "4.6.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.ProtectedData": { @@ -524,8 +541,8 @@ }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Mdukseovp0YIGaz16FMH6nbfgZkrCFOJbtXQptv0aeBO9h775Ilb9+TDwLVTKikoW7y7CY7lpoXl9zmZ5G3ndA==" + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -582,7 +599,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -717,6 +735,15 @@ "runtime.any.System.IO": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Private.Uri": { "type": "Transitive", "resolved": "4.3.0", @@ -801,11 +828,11 @@ }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "gmlk6khICtVhiUnVBBtlsH0H/5QFDqhTZgtpp3AX14wWE6OIE+BX95NLD+X4AolXnIy/oXpNNmXYnsNfW1KuDQ==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "System.Security.Principal.Windows": "4.6.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.ProtectedData": { @@ -815,8 +842,8 @@ }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Mdukseovp0YIGaz16FMH6nbfgZkrCFOJbtXQptv0aeBO9h775Ilb9+TDwLVTKikoW7y7CY7lpoXl9zmZ5G3ndA==" + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -966,6 +993,15 @@ "runtime.any.System.IO": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Private.Uri": { "type": "Transitive", "resolved": "4.3.0", @@ -1050,11 +1086,11 @@ }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "gmlk6khICtVhiUnVBBtlsH0H/5QFDqhTZgtpp3AX14wWE6OIE+BX95NLD+X4AolXnIy/oXpNNmXYnsNfW1KuDQ==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "System.Security.Principal.Windows": "4.6.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.ProtectedData": { @@ -1064,8 +1100,8 @@ }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Mdukseovp0YIGaz16FMH6nbfgZkrCFOJbtXQptv0aeBO9h775Ilb9+TDwLVTKikoW7y7CY7lpoXl9zmZ5G3ndA==" + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -1215,6 +1251,15 @@ "runtime.any.System.IO": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Private.Uri": { "type": "Transitive", "resolved": "4.3.0", @@ -1299,11 +1344,11 @@ }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "gmlk6khICtVhiUnVBBtlsH0H/5QFDqhTZgtpp3AX14wWE6OIE+BX95NLD+X4AolXnIy/oXpNNmXYnsNfW1KuDQ==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "System.Security.Principal.Windows": "4.6.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.ProtectedData": { @@ -1313,8 +1358,8 @@ }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Mdukseovp0YIGaz16FMH6nbfgZkrCFOJbtXQptv0aeBO9h775Ilb9+TDwLVTKikoW7y7CY7lpoXl9zmZ5G3ndA==" + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", @@ -1446,6 +1491,15 @@ "runtime.any.System.IO": "4.3.0" } }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Private.Uri": { "type": "Transitive", "resolved": "4.3.0", @@ -1529,11 +1583,11 @@ }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "gmlk6khICtVhiUnVBBtlsH0H/5QFDqhTZgtpp3AX14wWE6OIE+BX95NLD+X4AolXnIy/oXpNNmXYnsNfW1KuDQ==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "System.Security.Principal.Windows": "4.6.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Cryptography.ProtectedData": { @@ -1543,8 +1597,8 @@ }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Mdukseovp0YIGaz16FMH6nbfgZkrCFOJbtXQptv0aeBO9h775Ilb9+TDwLVTKikoW7y7CY7lpoXl9zmZ5G3ndA==" + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding": { "type": "Transitive", diff --git a/src/Bicep.Wasm/Interop.cs b/src/Bicep.Wasm/Interop.cs index 682b307e066..fbba962ed62 100644 --- a/src/Bicep.Wasm/Interop.cs +++ b/src/Bicep.Wasm/Interop.cs @@ -19,6 +19,8 @@ using Bicep.Core.Registry; using Bicep.Core.Semantics.Namespaces; using Bicep.Core.Features; +using Bicep.Core.Configuration; +using IOFileSystem = System.IO.Abstractions.FileSystem; namespace Bicep.Wasm { @@ -59,7 +61,7 @@ public DecompileResult Decompile(string jsonContent) try { var bicepUri = PathHelper.ChangeToBicepExtension(jsonUri); - var decompiler = new TemplateDecompiler(namespaceProvider, fileResolver, new EmptyModuleRegistryProvider()); + var decompiler = new TemplateDecompiler(namespaceProvider, fileResolver, new EmptyModuleRegistryProvider(), new ConfigurationManager(new IOFileSystem())); var (entrypointUri, filesToSave) = decompiler.DecompileFileWithModules(jsonUri, bicepUri); return new DecompileResult(filesToSave[entrypointUri], null); @@ -154,9 +156,10 @@ private static Compilation GetCompilation(string fileContents) var fileResolver = new FileResolver(); var dispatcher = new ModuleDispatcher(new EmptyModuleRegistryProvider()); + var configurationManager = new ConfigurationManager(new IOFileSystem()); var sourceFileGrouping = SourceFileGroupingBuilder.Build(fileResolver, dispatcher, workspace, fileUri); - return new Compilation(namespaceProvider, sourceFileGrouping, null); + return new Compilation(namespaceProvider, sourceFileGrouping, configurationManager.GetBuiltInConfiguration()); } private static string ReadStreamToEnd(Stream stream) diff --git a/src/Bicep.Wasm/packages.lock.json b/src/Bicep.Wasm/packages.lock.json index 5f624017a6f..acd3f20ffcf 100644 --- a/src/Bicep.Wasm/packages.lock.json +++ b/src/Bicep.Wasm/packages.lock.json @@ -321,6 +321,11 @@ "Microsoft.JSInterop": "5.0.9" } }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -341,6 +346,23 @@ "resolved": "4.6.0", "contentHash": "mbBgoR0rRfl2uimsZ2avZY8g7Xnh1Mza0rJZLPcxqiMWlkGukjmRkuMJ/er+AhQuiRIh80CR/Hpeztr80seV5g==" }, + "System.IO.Abstractions": { + "type": "Transitive", + "resolved": "13.2.47", + "contentHash": "t1hPTax+QnZscqwCY2Xuszm+qGm9qPDFvDPOjB31nR1XBtKDbt/RE5s0gBTOvQ9EP//jfrg2HEQUQyN5asFocg==", + "dependencies": { + "System.IO.FileSystem.AccessControl": "5.0.0" + } + }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.IO.Pipelines": { "type": "Transitive", "resolved": "5.0.1", @@ -370,11 +392,25 @@ "resolved": "4.7.0", "contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, "System.Text.Encodings.Web": { "type": "Transitive", "resolved": "4.7.2", @@ -405,7 +441,8 @@ "Microsoft.Extensions.Configuration.Binder": "5.0.0", "Microsoft.Extensions.Configuration.Json": "5.0.0", "Newtonsoft.Json": "13.0.1", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.IO.Abstractions": "13.2.47" } }, "bicep.core.registryclient": { @@ -424,38 +461,153 @@ } }, ".NETCoreApp,Version=v5.0/browser-wasm": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/linux-musl-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/linux-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/osx-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } }, ".NETCoreApp,Version=v5.0/win-x64": { + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" } } }