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

Tidy up some experimental features #14944

Merged
merged 3 commits into from
Aug 30, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions docs/experimental-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,12 @@ The following features can be optionally enabled through your `bicepconfig.json`
### `assertions`
Should be enabled in tandem with `testFramework` experimental feature flag for expected functionality. Allows you to author boolean assertions using the `assert` keyword comparing the actual value of a parameter, variable, or resource name to an expected value. Assert statements can only be written directly within the Bicep file whose resources they reference. For more information, see [Bicep Experimental Test Framework](https://github.com/Azure/bicep/issues/11967).

### `dynamicTypeLoading`
Requires `extensibility` to be enabled. If enabled, users are able to fetch the azure resource type definitions from an OCI Registry as a runtime dependency. To fetch the type definitions the following syntax can be used. For example `extension 'br:mcr.microsoft.com/bicep/extensions/[email protected]' as az`.
The extension definitions also support aliasing via `bicepconfig.json` similar to [`moduleAliases`](https://learn.microsoft.com/azure/azure-resource-manager/bicep/bicep-config-modules#aliases-for-modules). For example `extension 'br/public:[email protected]' as az`.

### `extendableParamFiles`
Enables the ability to extend bicepparam files from other bicepparam files. For more information, see [Extendable Bicep Params Files](./experimental/extendable-param-files.md).

### `extensibility`
Allows Bicep to use an extensibility model to deploy non-ARM resources. Currently, we support Kubernetes extension ([Bicep Kubernetes extension](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-extensibility-kubernetes-provider)) and Microsoft Graph extension ([Bicep templates for Microsoft Graph](https://aka.ms/graphbicep)).

### `extensionRegistry`
Requires `dynamicTypeLoading` and `extensibility` to be enabled. If enabled, users are able to fetch the third party resource type definitions from an OCI Registry as a runtime dependency. To fetch the type definitions the following syntax can be used. For example `extension 'br:thirdpartyregistry.azurecr.io/bicep/extension/[email protected]' as thirdparty`.
The extension definitions also support aliasing via `bicepconfig.json` similar to [`moduleAliases`](https://learn.microsoft.com/azure/azure-resource-manager/bicep/bicep-config-modules#aliases-for-modules). For example `extension 'br/public:[email protected]' as thirdparty`.

### `legacyFormatter`
Enables code formatting with the legacy formatter. This feature flag is introduced to ensure a safer transition to the v2 formatter that implements a pretty-printing algorithm. It is intended for temporary use and will be phased out soon.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
]
},
"experimentalFeaturesEnabled": {
"extensibility": true,
"dynamicTypeLoading": true,
"extensionRegistry": true
"extensibility": true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
"credentialPrecedence": ["AzureCLI"]
},
"experimentalFeaturesEnabled": {
"extensibility": true,
"dynamicTypeLoading": true,
"extensionRegistry": true
"extensibility": true
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"experimentalFeaturesEnabled": {
"extensibility": true,
"extensionRegistry": true,
"localDeploy": true
},
"extensions": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"experimentalFeaturesEnabled": {
"extensibility": true,
"extensionRegistry": true,
"localDeploy": true
},
"extensions": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"experimentalFeaturesEnabled": {
"extensibility": true,
"extensionRegistry": true,
"localDeploy": true
},
"extensions": {
Expand Down
104 changes: 0 additions & 104 deletions src/Bicep.Cli.IntegrationTests/BuildCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,110 +101,6 @@ public async Task Build_Valid_SingleFile_WithTemplateSpecReference_ShouldSucceed
actualLocation: compiledFilePath);
}

[DataTestMethod]
//[DataRow("br:mcr.microsoft.com/bicep/extension/az", true, LanguageConstants.BicepPublicMcrRegistry)]
//[DataRow("br/public:az", true, LanguageConstants.BicepPublicMcrRegistry)]
[DataRow("br/contoso:az", true, "contoso.azurecr.io")]
//[DataRow("br/mcr:az", true, LanguageConstants.BicepPublicMcrRegistry)]
//[DataRow("br:contoso.azurecr.io/bicep/extensions/az", true, "contoso.azurecr.io")]
// Negative
// [DataRow("az", false)] - commented out while we graciously deprecate the legacy provider declaration syntax.
//[DataRow("br:invalid.azureacr.io/bicep/extensions/az", false)]
//[DataRow("br/unknown:az", false)]
public async Task Build_Valid_SingleFile_WithExtensionDeclarationStatement(
string extensionDeclarationSyntax,
bool shouldSucceed,
string containingFolder = "")
{
// SETUP
// 1. create a mock registry client
var hosts = new[] {
LanguageConstants.BicepPublicMcrRegistry,
"contoso.azurecr.io",
"invalid.azureacr.io"
};
(var clientFactory, var blobClients) = RegistryUtils.CreateMockRegistryClients(hosts.Select(host => (host, "bicep/extensions/az")).ToArray());


// 2. upload a manifest and its blob layer
foreach (var ((uri, _), client) in blobClients)
{
if (uri.Host.Contains("invalid")) { continue; }
var layer = await client.UploadBlobAsync(BinaryData.FromString(""));
var config = await client.UploadBlobAsync(BinaryData.FromString("{}"));
await client.SetManifestAsync(BicepTestConstants.GetBicepExtensionManifest(layer, config), "2.0.0");
}

// 3. create a main.bicep and save it to a output directory
var bicepFile = $"""
extension '{extensionDeclarationSyntax}:2.0.0'
""";
var tempDirectory = FileHelper.GetUniqueTestOutputPath(TestContext);
Directory.CreateDirectory(tempDirectory);
var bicepFilePath = Path.Combine(tempDirectory, "main.bicep");
File.WriteAllText(bicepFilePath, bicepFile);

var bicepConfigFile = """
{
"extensionAliases" : {
"br": {
"contoso": {
"registry": "contoso.azurecr.io",
"extensionPath": "bicep/extensions"
},
"mcr": {
"registry": "mcr.microsoft.com",
"extensionPath": "bicep/extensions"
}
}
}
}
""";
var bicepConfigPath = Path.Combine(tempDirectory, "bicepconfig.json");
File.WriteAllText(bicepConfigPath, bicepConfigFile);

// 4. create a settings object with the mock registry client and relevant features enabled
var settings = new InvocationSettings(new(TestContext, RegistryEnabled: true, ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true), clientFactory, Repository.Create<ITemplateSpecRepositoryFactory>().Object);

// TEST
// 5. run bicep build
var (output, error, result) = await TextWriterHelper.InvokeWriterAction((@out, err)
=> new Program(new(Output: @out, Error: err), services
=>
{
if (settings.FeatureOverrides is { })
{
services.WithFeatureOverrides(settings.FeatureOverrides);
}

services
.WithEmptyAzResources()
.AddSingleton(settings.Environment ?? BicepTestConstants.EmptyEnvironment)
.AddSingleton(settings.ClientFactory)
.AddSingleton(settings.TemplateSpecRepositoryFactory);
})
.RunAsync(["build", bicepFilePath], CancellationToken.None));

// ASSERT
// 6. assert 'bicep build' completed successfully
using (new AssertionScope())
{
result.Should().Be(shouldSucceed ? 0 : 1);
output.Should().BeEmpty();
if (shouldSucceed)
{
AssertNoErrors(error);
}
}
if (shouldSucceed)
{
// 7. assert the extension files were restored to the cache directory
Directory.Exists(settings.FeatureOverrides!.CacheRootDirectory).Should().BeTrue();
var extensionDir = Path.Combine(settings.FeatureOverrides.CacheRootDirectory!, ArtifactReferenceSchemes.Oci, containingFolder, "bicep$extensions$az", "2.0.0$");
Directory.EnumerateFiles(extensionDir).ToList().Select(Path.GetFileName).Should().BeEquivalentTo(new List<string> { "types.tgz", "lock", "manifest", "metadata" });
}
}

[DataTestMethod]
[DynamicData(nameof(GetValidDataSets), DynamicDataSourceType.Method, DynamicDataDisplayNameDeclaringType = typeof(DataSet), DynamicDataDisplayName = nameof(DataSet.GetDisplayName))]
public async Task Build_Valid_SingleFile_WithTemplateSpecReference_ToStdOut_ShouldSucceed(DataSet dataSet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public async Task Publish_extension_should_succeed_to_filesystem()
var publishResult = await Bicep(services => services.WithFileSystem(fs), ["publish-extension", indexPath, "--target", targetPath]);
publishResult.Should().Succeed().And.NotHaveStdout();

var services = new ServiceBuilder().WithFileSystem(fs).WithFeatureOverrides(new(ExtensibilityEnabled: true, ExtensionRegistry: true));
var services = new ServiceBuilder().WithFileSystem(fs).WithFeatureOverrides(new(ExtensibilityEnabled: true));
var compileResult = await CompilationHelper.RestoreAndCompile(services, """
extension '../../target/extension.tgz'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Bicep.Core.Configuration;
using Bicep.Core.Diagnostics;
using Bicep.Core.Semantics.Namespaces;
using Bicep.Core.TypeSystem.Providers;
using Bicep.Core.UnitTests;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Mock;
Expand All @@ -20,17 +21,30 @@ namespace Bicep.Core.IntegrationTests
{

[TestClass]
public class DynamicAzTypesTests : TestBase
public class AzTypesViaRegistryTests : TestBase
{
private static readonly string EmptyIndexJson = """
{
"resources": {},
"resourceFunctions": {},
"settings": {
"name": "AzureResourceManager",
"version": "1.2.3",
"isSingleton": true
}
}
""";


private async Task<ServiceBuilder> GetServices()
{
var indexJson = FileHelper.SaveResultFile(TestContext, "types/index.json", """{"resources": {}, "resourceFunctions": {}}""");
var indexJson = FileHelper.SaveResultFile(TestContext, "types/index.json", EmptyIndexJson);

var cacheRoot = FileHelper.GetUniqueTestOutputPath(TestContext);
Directory.CreateDirectory(cacheRoot);

var services = new ServiceBuilder()
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true, CacheRootDirectory: cacheRoot))
.WithFeatureOverrides(new(ExtensibilityEnabled: true, CacheRootDirectory: cacheRoot))
.WithContainerRegistryClientFactory(RegistryHelper.CreateOciClientForAzExtension());

await RegistryHelper.PublishAzExtension(services.Build(), indexJson);
Expand All @@ -52,89 +66,8 @@ private async Task<ServiceBuilder> ServicesWithTestExtensionArtifact(ArtifactReg
Directory.CreateDirectory(cacheRoot);

return new ServiceBuilder()
.WithFeatureOverrides(new(
ExtensibilityEnabled: true,
DynamicTypeLoadingEnabled: true,
CacheRootDirectory: cacheRoot))
.WithContainerRegistryClientFactory(clientFactory);
}

[TestMethod]
public async Task Az_namespace_can_be_used_without_configuration()
{
var services = await GetServices();
var result = await CompilationHelper.RestoreAndCompile(services, ("main.bicep", @$"
extension 'br/public:az:{BicepTestConstants.BuiltinAzExtensionVersion}'
"));

result.Should().GenerateATemplate();
result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics();
}

[TestMethod]
public async Task Az_namespace_errors_with_configuration()
{
var services = await GetServices();
var result = await CompilationHelper.RestoreAndCompile(services, @$"
extension 'br/public:az:{BicepTestConstants.BuiltinAzExtensionVersion}' with {{}}
");

result.Should().NotGenerateATemplate();
result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] {
("BCP205", DiagnosticLevel.Error, "Extension \"az\" does not support configuration."),
});
}

[TestMethod]
public async Task Az_namespace_can_be_used_with_alias()
{
var services = await GetServices();
var result = await CompilationHelper.RestoreAndCompile(services, @$"
extension 'br/public:az:{BicepTestConstants.BuiltinAzExtensionVersion}' as testAlias
");

result.Should().GenerateATemplate();
result.Compilation.GetEntrypointSemanticModel().Root.ExtensionDeclarations.Should().Contain(x => x.Name.Equals("testAlias"));
}

[TestMethod]
public async Task Az_namespace_can_be_used_with_bicepconfig_extension_alias()
{
var services = await GetServices();

services = services.WithConfigurationPatch(c => c.WithExtensionAliases("""
{
"br": {
"customAlias": {
"registry": "mcr.microsoft.com",
"extensionPath": "bicep/extensions"
}
}
}
"""));

var result = await CompilationHelper.RestoreAndCompile(services, @$"
extension 'br/customAlias:az:{BicepTestConstants.BuiltinAzExtensionVersion}'
");

result.Should().GenerateATemplate();
result.Compilation.GetEntrypointSemanticModel().Root.ExtensionDeclarations.Should().Contain(x => x.Name.Equals("az"));
}

[TestMethod]
public async Task Inlined_Az_namespace_alias_is_not_specified_in_config_yields_diagnostic()
{
var services = new ServiceBuilder()
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true));

var result = await CompilationHelper.RestoreAndCompile(services, @"
extension 'br/notFound:az:0.2.661'
");

result.Should().NotGenerateATemplate();
result.Should().HaveDiagnostics([
("BCP379", DiagnosticLevel.Error, "The OCI artifact extension alias name \"notFound\" does not exist in the built-in Bicep configuration."),
]);
.WithFeatureOverrides(new(ExtensibilityEnabled: true, CacheRootDirectory: cacheRoot))
.WithContainerRegistryClientFactory(clientFactory);
}

[TestMethod]
Expand All @@ -146,7 +79,7 @@ public async Task Bicep_module_artifact_specified_in_extension_declaration_synta
var clientFactory = RegistryHelper.CreateMockRegistryClients((testArtifact.RegistryAddress, testArtifact.RepositoryPath)).factoryMock;
var services = new ServiceBuilder()
.WithFileSystem(fsMock)
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true))
.WithFeatureOverrides(new(ExtensibilityEnabled: true))
.WithContainerRegistryClientFactory(clientFactory);

await RegistryHelper.PublishModuleToRegistryAsync(
Expand Down Expand Up @@ -221,7 +154,7 @@ public async Task Repository_not_found_in_registry(
mockBlobClient.Object);

var services = new ServiceBuilder()
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true))
.WithFeatureOverrides(new(ExtensibilityEnabled: true))
.WithContainerRegistryClientFactory(containerRegistryFactoryBuilder.Build().clientFactory);

// ACT
Expand Down Expand Up @@ -349,7 +282,7 @@ public async Task Az_namespace_can_be_loaded_dynamically_using_extension_configu
"1.0.0-fake");
var services = await ServicesWithTestExtensionArtifact(
artifactRegistryAddress,
ThirdPartyTypeHelper.GetTypesTgzBytesFromFiles(("index.json", """{"resources": {}, "resourceFunctions": {}}""")));
ThirdPartyTypeHelper.GetTypesTgzBytesFromFiles(("index.json", EmptyIndexJson)));
services = services.WithConfigurationPatch(c => c.WithExtensions($$"""
{
"az": "{{artifactRegistryAddress.ToSpecificationString(':')}}"
Expand All @@ -362,7 +295,7 @@ extension az
//ASSERT
result.Should().GenerateATemplate();
result.Template.Should().NotBeNull();
result.Template.Should().HaveValueAtPath("$.imports.az.version", AzNamespaceType.EmbeddedAzExtensionVersion);
result.Template.Should().HaveValueAtPath("$.imports.az.version", AzNamespaceType.Settings.TemplateExtensionVersion);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ namespace Bicep.Core.IntegrationTests
[TestClass]
public class CentralizedExtensionVersionManagementTests : TestBase
{
private ServiceBuilder Services => new ServiceBuilder()
.WithFeatureOverrides(new(
ExtensibilityEnabled: true,
DynamicTypeLoadingEnabled: true));
private ServiceBuilder Services => new ServiceBuilder().WithFeatureOverrides(new(ExtensibilityEnabled: true));

[TestMethod]
[DynamicData(nameof(ExtensionsConfig_SupportForConfigManagedExtensionDeclarationSyntax_When_ExtensionIsBuiltIn_TestCases))]
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, ExtensionRegistry: true, DynamicTypeLoadingEnabled: true))
.WithFeatureOverrides(new(ExtensibilityEnabled: true))
.WithFileSystem(fileSystem)
.WithContainerRegistryClientFactory(clientFactory);
}
Expand Down
Loading
Loading