Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Implements design in Azure/bicep-reps/pull/5 #13537

Merged
merged 2 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public async Task Build_Valid_SingleFile_WithTemplateSpecReference_ShouldSucceed
{
// 7. assert the provider files were restored to the cache directory
Directory.Exists(settings.FeatureOverrides!.CacheRootDirectory).Should().BeTrue();
var providerDir = Path.Combine(settings.FeatureOverrides.CacheRootDirectory!, ModuleReferenceSchemes.Oci, containingFolder, "bicep$providers$az", "2.0.0$");
var providerDir = Path.Combine(settings.FeatureOverrides.CacheRootDirectory!, ArtifactReferenceSchemes.Oci, containingFolder, "bicep$providers$az", "2.0.0$");
Directory.EnumerateFiles(providerDir).ToList().Select(Path.GetFileName).Should().BeEquivalentTo(new List<string> { "types.tgz", "lock", "manifest", "metadata" });
}
}
Expand Down
14 changes: 3 additions & 11 deletions src/Bicep.Core.IntegrationTests/DynamicAzTypesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,7 @@ public async Task External_Az_namespace_can_be_loaded_from_configuration()
// }
services = services.WithConfigurationPatch(c => c.WithProvidersConfiguration($$"""
{
"az": {
"source": "{{LanguageConstants.BicepPublicMcrRegistry}}/bicep/providers/az",
"version": "{{BicepTestConstants.BuiltinAzProviderVersion}}"
}
"az": "br:{{LanguageConstants.BicepPublicMcrRegistry}}/bicep/providers/az:{{BicepTestConstants.BuiltinAzProviderVersion}}"
}
"""));
var result = await CompilationHelper.RestoreAndCompile(services, ("main.bicep", @$"
Expand All @@ -358,9 +355,7 @@ public async Task BuiltIn_Az_namespace_can_be_loaded_from_configuration()
// Built-In Config contains the following entries:
// {
// "providers": {
// "az": {
// "builtIn": true
// }
// "az": "builtin:"
// },
// "implicitProviders": ["az"]
// }
Expand All @@ -384,10 +379,7 @@ public async Task Az_namespace_can_be_loaded_dynamically_using_provider_configur
ThirdPartyTypeHelper.GetTypesTgzBytesFromFiles(("index.json", """{"resources": {}, "resourceFunctions": {}}""")));
services = services.WithConfigurationPatch(c => c.WithProvidersConfiguration($$"""
{
"az": {
"source": "{{artifactRegistryAddress.RegistryAddress}}/{{artifactRegistryAddress.RepositoryPath}}",
"version": "{{artifactRegistryAddress.ProviderVersion}}"
}
"az": "{{artifactRegistryAddress.ToSpecificationString(':')}}"
}
"""));
//ACT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ private static ServiceBuilder GetServiceBuilder(IFileSystem fileSystem, string r
var clientFactory = RegistryHelper.CreateMockRegistryClient(registryHost, repositoryPath);

return new ServiceBuilder()
.WithFeatureOverrides(new(ExtensibilityEnabled: true, ProviderRegistry: true))
.WithFeatureOverrides(new(ExtensibilityEnabled: true, ProviderRegistry: true, DynamicTypeLoadingEnabled: true))
.WithFileSystem(fileSystem)
.WithContainerRegistryClientFactory(clientFactory);
}
Expand Down
26 changes: 1 addition & 25 deletions src/Bicep.Core.UnitTests/Configuration/BicepConfigSchemaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,7 @@ public void UserConfig_SysProviderIsProhibited()
var bicepConfigJson = JObject.Parse("""
{
"providers": {
"sys": {
"source": "example.azurecr.io/some/fake/path",
"version": "1.0.0"
}
"sys": "example.azurecr.io/some/fake/path:1.0.0"
}
}
""");
Expand All @@ -366,26 +363,5 @@ public void UserConfig_SysProviderIsProhibited()
errors.Single().Path.Should().Be("providers.sys");
isValid.Should().BeFalse();
}

[TestMethod]
public void UserConfig_BuiltIn_property_is_mutually_exclusive_with_source_and_version()
{
var bicepConfigJson = JObject.Parse("""
{
"providers": {
"az": {
"source": "example.azurecr.io/some/fake/path",
"version": "1.0.0",
"builtIn": true
}
}
}
""");
var schema = GetConfigSchema();
bool isValid = bicepConfigJson.IsValid(schema, out IList<ValidationError> errors);
errors.Should().HaveCount(1);
errors.Single().Path.Should().Be("providers.az");
isValid.Should().BeFalse();
}
}
}
48 changes: 12 additions & 36 deletions src/Bicep.Core.UnitTests/Configuration/ConfigurationManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,9 @@ public void GetBuiltInConfiguration_NoParameter_ReturnsBuiltInConfigurationWithA
}
},
"providers": {
"az": {
"builtIn": true
},
"kubernetes": {
"builtIn": true
},
"microsoftGraph": {
"builtIn": true
}
"az": "builtin:",
"kubernetes": "builtin:",
"microsoftGraph": "builtin:"
},
"implicitProviders": ["az"],
"analyzers": {
Expand Down Expand Up @@ -193,15 +187,9 @@ public void GetBuiltInConfiguration_DisableAllAnalyzers_ReturnsBuiltInConfigurat
}
},
"providers": {
"az": {
"builtIn": true
},
"kubernetes": {
"builtIn": true
},
"microsoftGraph": {
"builtIn": true
}
"az": "builtin:",
"kubernetes": "builtin:",
"microsoftGraph": "builtin:"
},
"implicitProviders": [
"az"
Expand Down Expand Up @@ -281,15 +269,9 @@ public void GetBuiltInConfiguration_DisableAnalyzers_ReturnsBuiltInConfiguration
}
},
"providers": {
"az": {
"builtIn": true
},
"kubernetes": {
"builtIn": true
},
"microsoftGraph": {
"builtIn": true
}
"az": "builtin:",
"kubernetes": "builtin:",
"microsoftGraph": "builtin:"
},
"implicitProviders": [
"az"
Expand Down Expand Up @@ -739,15 +721,9 @@ public void GetConfiguration_ValidCustomConfiguration_OverridesBuiltInConfigurat
}
},
"providers": {
"az": {
"builtIn": true
},
"kubernetes": {
"builtIn": true
},
"microsoftGraph": {
"builtIn": true
}
"az": "builtin:",
"kubernetes": "builtin:",
"microsoftGraph": "builtin:"
},
"implicitProviders": [
"az"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ public void ProviderConfiguration_deserialization()
var data = JsonElementFactory.CreateElement("""
{
"providers": {
"az": {
"source": "mcr.microsoft.com/bicep/providers/az",
"version": "0.2.3"
},
"kubernetes": {
"builtIn": true
}
"az": "br:mcr.microsoft.com/bicep/providers/az:0.2.3",
"kubernetes": "builtin:"
}
}
""");
Expand All @@ -35,15 +30,13 @@ public void ProviderConfiguration_deserialization()
providers.Should().NotBeNull();

providers.TryGetProviderSource("az").IsSuccess(out var azProvider).Should().BeTrue();
azProvider!.Source.Should().Be("mcr.microsoft.com/bicep/providers/az");
azProvider.Version.Should().Be("0.2.3");
azProvider!.Path.Should().Be("mcr.microsoft.com/bicep/providers/az:0.2.3");
azProvider.BuiltIn.Should().BeFalse();

providers.TryGetProviderSource("kubernetes").IsSuccess(out var k8sProvider).Should().BeTrue();
k8sProvider.Should().NotBeNull();
k8sProvider!.BuiltIn.Should().BeTrue();
k8sProvider.Source.Should().BeNull();
k8sProvider.Version.Should().BeNull();
k8sProvider.Path.Should().BeEmpty();

providers.TryGetProviderSource("unspecified").IsSuccess(out var provider, out var errorBuilder).Should().BeFalse();
provider.Should().BeNull();
Expand All @@ -52,29 +45,6 @@ public void ProviderConfiguration_deserialization()
errorBuilder!.Should().HaveMessage($"Provider namespace \"unspecified\" is not recognized.");
}

[TestMethod]
public void ProviderConfiguration_deserialization_enforces_mutually_exclusive_properties()
{
var data = JsonElementFactory.CreateElement("""
{
"providers": {
"az": {
"source": "mcr.microsoft.com/bicep/providers/az",
"version": "0.2.3",
"builtIn": true
}
}
}
""");

var providers = ProvidersConfiguration.Bind(data.GetProperty(RootConfiguration.ProvidersConfigurationKey));
providers.TryGetProviderSource("az").IsSuccess(out var azProvider).Should().BeTrue();
azProvider!.BuiltIn.Should().BeFalse(); // because we must coerce the value for example of a result of a merge
azProvider.Source.Should().Be("mcr.microsoft.com/bicep/providers/az");
azProvider.Version.Should().Be("0.2.3");

}

[TestMethod]
public void ProviderConfiguration_default_configuration_returns_known_list_of_built_in_providers_with_expected_default_values()
{
Expand All @@ -87,8 +57,7 @@ public void ProviderConfiguration_default_configuration_returns_known_list_of_bu
{
config.ProvidersConfig!.TryGetProviderSource(providerName).IsSuccess(out var provider).Should().BeTrue();
provider!.BuiltIn.Should().BeTrue();
provider.Source.Should().BeNull();
provider.Version.Should().BeNull();
provider.Path.Should().BeEmpty();
}

// assert that 'sys' is not present in the default configuration
Expand All @@ -104,14 +73,8 @@ public void ProviderConfiguration_user_provided_configuration_overrides_default_
[bicepConfigFileName] = new("""
{
"providers": {
"foo": {
"source": "example.azurecr.io/some/fake/path",
"version": "1.0.0"
},
"az": {
"source": "mcr.microsoft.com/bicep/providers/az",
"version": "0.2.3"
}
"foo": "br:example.azurecr.io/some/fake/path:1.0.0",
"az": "br:mcr.microsoft.com/bicep/providers/az:0.2.3"
}
}
""")
Expand All @@ -127,13 +90,11 @@ public void ProviderConfiguration_user_provided_configuration_overrides_default_
var providers = config.ProvidersConfig!;
// assert 'source' and 'version' are valid properties for 'foo'
providers.TryGetProviderSource("foo").IsSuccess(out var fooProvider).Should().BeTrue();
fooProvider!.Source.Should().Be("example.azurecr.io/some/fake/path");
fooProvider.Version.Should().Be("1.0.0");
fooProvider!.Path.Should().Be("example.azurecr.io/some/fake/path:1.0.0");

// assert 'az' provider properties are overridden by the user provided configuration
providers.TryGetProviderSource("az").IsSuccess(out var azProvider).Should().BeTrue();
azProvider!.Source.Should().Be("mcr.microsoft.com/bicep/providers/az");
azProvider.Version.Should().Be("0.2.3");
azProvider!.Path.Should().Be("mcr.microsoft.com/bicep/providers/az:0.2.3");

// assert that 'sys' is not present in the merged configuration
providers.TryGetProviderSource("sys").IsSuccess(out var provider, out var errorBuilder).Should().BeFalse();
Expand Down
45 changes: 33 additions & 12 deletions src/Bicep.Core/Configuration/ProvidersConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.Json;
using Bicep.Core.Diagnostics;
using Bicep.Core.Extensions;
Expand All @@ -10,19 +11,24 @@ namespace Bicep.Core.Configuration;

public record ProviderConfigEntry
{
public bool BuiltIn { get; }
public string? Source { get; }
public string? Version { get; }
public bool BuiltIn => this.Scheme == "builtin";

public ProviderConfigEntry(bool builtIn, string? source, string? version)
public string Path { get; }

public string Scheme {get;}

public ProviderConfigEntry(string providerConfigEntry)
{
BuiltIn = builtIn;
Source = source;
Version = version;
if (source is not null && version is not null && builtIn)
{
BuiltIn = false;
}
var parts = providerConfigEntry.Split(':', StringSplitOptions.None);
Debug.Assert(parts.Length is >= 1 and <= 3, "The provider configuration entry must have 1-3 parts separated by colons.");

this.Scheme = parts[0]; // Is ensured to exist since there is a pattern match in the bicepconfig json schema
this.Path = parts.Length > 1 ? string.Join(':', parts[1..]) : string.Empty;
}

public override string ToString()
{
return $"{this.Scheme}:{this.Path}";
}
}

Expand All @@ -31,7 +37,11 @@ public partial class ProvidersConfiguration : ConfigurationSection<ImmutableDict
private ProvidersConfiguration(ImmutableDictionary<string, ProviderConfigEntry> data) : base(data) { }

public static ProvidersConfiguration Bind(JsonElement element)
=> new(element.ToNonNullObject<ImmutableDictionary<string, ProviderConfigEntry>>());
=> new(element.ToNonNullObject<ImmutableDictionary<string, string>>()
.ToImmutableDictionary(
pair => pair.Key,
pair => new ProviderConfigEntry(pair.Value))
);

public ResultWithDiagnostic<ProviderConfigEntry> TryGetProviderSource(string providerName)
{
Expand All @@ -41,6 +51,17 @@ public ResultWithDiagnostic<ProviderConfigEntry> TryGetProviderSource(string pro
}
return new(providerConfigEntry);
}

public override void WriteTo(Utf8JsonWriter writer)
{
writer.WriteStartObject();
foreach (var (key, value) in this.Data)
{
writer.WritePropertyName(key);
writer.WriteStringValue(value.ToString());
}
writer.WriteEndObject();
}
}


21 changes: 5 additions & 16 deletions src/Bicep.Core/Configuration/bicepconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
"activeDirectoryAuthority": "https://login.microsoftonline.us"
}
},
"credentialPrecedence": [
"AzureCLI",
"AzurePowerShell"
]
"credentialPrecedence": ["AzureCLI", "AzurePowerShell"]
},
"moduleAliases": {
"ts": {},
Expand All @@ -41,15 +38,9 @@
}
},
"providers": {
"az": {
"builtIn": true
},
"kubernetes": {
"builtIn": true
},
"microsoftGraph": {
"builtIn": true
}
"az": "builtin:",
"kubernetes": "builtin:",
"microsoftGraph": "builtin:"
},
"implicitProviders": ["az"],
"analyzers": {
Expand All @@ -76,9 +67,7 @@
"trafficmanager.net",
"vault.azure.net"
],
"excludedhosts": [
"schema.management.azure.com"
]
"excludedhosts": ["schema.management.azure.com"]
}
}
}
Expand Down