From 154e57d8f2bb686c18944b3cefb5ee1e1297fde8 Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Tue, 21 Sep 2021 14:00:49 -0400 Subject: [PATCH] Support symbolic management group references to be used as scopes (#4476) --- .../ScenarioTests.cs | 33 +++++++++++++++++++ src/Bicep.Core/Emit/ScopeHelper.cs | 18 ++++++++++ .../TypeSystem/Az/AzResourceTypeProvider.cs | 1 + 3 files changed, 52 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index c05ae3ae32c..10bfc506b78 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -2403,6 +2403,39 @@ param tags object }); } + /// + /// https://github.com/Azure/bicep/issues/1833 + /// + [TestMethod] + public void Test_Issue1833() + { + var result = CompilationHelper.Compile( + ("managementGroup.bicep", @" +targetScope = 'managementGroup' +"), + ("main.bicep", @" +targetScope = 'tenant' + +param mainMgName string +param managementGroups array + +resource mainMg 'Microsoft.Management/managementGroups@2020-05-01' = { + name: mainMgName +} + +resource mgs 'Microsoft.Management/managementGroups@2020-05-01' = [for (mg, i) in managementGroups: { + name: mg +}] + +module singleMgModule 'managementGroup.bicep' = { + name: 'single-mg' + scope: mainMg +} +")); + + result.Should().NotHaveAnyDiagnostics(); + } + [TestMethod] // https://github.com/Azure/bicep/issues/3617 public void Test_Issue3617() diff --git a/src/Bicep.Core/Emit/ScopeHelper.cs b/src/Bicep.Core/Emit/ScopeHelper.cs index f6a49502403..6225aa0f654 100644 --- a/src/Bicep.Core/Emit/ScopeHelper.cs +++ b/src/Bicep.Core/Emit/ScopeHelper.cs @@ -158,6 +158,24 @@ public class ScopeData } } + if (StringComparer.OrdinalIgnoreCase.Equals(targetResource.TypeReference.FullyQualifiedType, AzResourceTypeProvider.ResourceTypeManagementGroup)) + { + // special-case 'Microsoft.Management/managementGroups' in order to allow it to create a managementGroup-scope resource + // ignore diagnostics - these will be collected separately in the pass over resources + var hasErrors = false; + var mgScopeData = ScopeHelper.ValidateScope(semanticModel, (_, _, _) => { hasErrors = true; }, targetResource.Type.ValidParentScopes, targetResource.Symbol.DeclaringResource.Value, targetResource.ScopeSyntax); + if (!hasErrors) + { + if (!supportedScopes.HasFlag(ResourceScope.ManagementGroup)) + { + logInvalidScopeFunc(scopeValue, ResourceScope.ManagementGroup, supportedScopes); + return null; + } + + return new ScopeData { RequestedScope = ResourceScope.ManagementGroup, ManagementGroupNameProperty = targetResource.NameSyntax, IndexExpression = indexExpression }; + } + } + if (!supportedScopes.HasFlag(ResourceScope.Resource)) { logInvalidScopeFunc(scopeValue, ResourceScope.Resource, supportedScopes); diff --git a/src/Bicep.Core/TypeSystem/Az/AzResourceTypeProvider.cs b/src/Bicep.Core/TypeSystem/Az/AzResourceTypeProvider.cs index 40ff0f1e045..f536639fd80 100644 --- a/src/Bicep.Core/TypeSystem/Az/AzResourceTypeProvider.cs +++ b/src/Bicep.Core/TypeSystem/Az/AzResourceTypeProvider.cs @@ -54,6 +54,7 @@ public ResourceType GetOrAdd(ResourceTypeGenerationFlags flags, ResourceTypeRefe public const string ResourceTypeDeployments = "Microsoft.Resources/deployments"; public const string ResourceTypeResourceGroup = "Microsoft.Resources/resourceGroups"; + public const string ResourceTypeManagementGroup = "Microsoft.Management/managementGroups"; private readonly IResourceTypeLoader resourceTypeLoader; private readonly ImmutableHashSet availableResourceTypes;