Skip to content

Commit

Permalink
Feat: Implements design in Azure/bicep-reps/pull/5 (Azure#13537)
Browse files Browse the repository at this point in the history
  • Loading branch information
asilverman and asilverman committed Mar 5, 2024
1 parent 27a4913 commit 3a300e5
Show file tree
Hide file tree
Showing 18 changed files with 87 additions and 194 deletions.
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
Loading

0 comments on commit 3a300e5

Please sign in to comment.