Skip to content

Commit

Permalink
WIP: 'existing' keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
anthony-c-martin committed Jan 26, 2021
1 parent 9e308aa commit b0dcdcc
Show file tree
Hide file tree
Showing 42 changed files with 527 additions and 309 deletions.
13 changes: 13 additions & 0 deletions docs/examples/101/resource-with-lock-existing/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
param accountName string

resource storageAcc 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {
name: accountName
}

resource lockResource 'Microsoft.Authorization/locks@2016-09-01' = {
name: 'DontDelete'
scope: storageAcc
properties: {
level: 'CanNotDelete'
}
}
22 changes: 22 additions & 0 deletions docs/examples/101/resource-with-lock-existing/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"accountName": {
"type": "string"
}
},
"functions": [],
"resources": [
{
"type": "Microsoft.Authorization/locks",
"apiVersion": "2016-09-01",
"scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('accountName'))]",
"name": "DontDelete",
"properties": {
"level": "CanNotDelete"
},
"dependsOn": []
}
]
}
4 changes: 4 additions & 0 deletions docs/examples/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@
"filePath": "101/resource-with-lock/main.bicep",
"description": "101/resource-with-lock"
},
{
"filePath": "101/resource-with-lock-existing/main.bicep",
"description": "101/resource-with-lock-existing"
},
{
"filePath": "101/sql-database/main.bicep",
"description": "101/sql-database"
Expand Down
2 changes: 1 addition & 1 deletion docs/grammar.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ parameterDefaultValue -> "=" expression
variableDecl -> "variable" IDENTIFIER(name) "=" expression NL
resourceDecl -> "resource" IDENTIFIER(name) interpString(type) "=" ifCondition? object NL
resourceDecl -> "resource" IDENTIFIER(name) interpString(type) "existing"? "=" ifCondition? object NL
moduleDecl -> "module" IDENTIFIER(name) interpString(type) "=" object NL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,27 @@ namespace Bicep.Core.UnitTests.TypeSystem.Az
[TestClass]
public class AzResourceTypeProviderTests
{
[DataTestMethod]
[DataRow(ResourceScope.Tenant)]
[DataRow(ResourceScope.ManagementGroup)]
[DataRow(ResourceScope.Subscription)]
[DataRow(ResourceScope.ResourceGroup)]
public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing(ResourceScope scopeType)
[TestMethod]
public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing()
{
var resourceTypeProvider = new AzResourceTypeProvider();
var availableTypes = resourceTypeProvider.GetAvailableTypes(scopeType);
var availableTypes = resourceTypeProvider.GetAvailableTypes();

// sanity check - we know there should be a lot of types available
var expectedTypeCount = scopeType == ResourceScope.ResourceGroup ? 2000 : 100;
var expectedTypeCount = 3000;
availableTypes.Should().HaveCountGreaterThan(expectedTypeCount);

foreach (var availableType in availableTypes)
{
resourceTypeProvider.HasType(scopeType, availableType).Should().BeTrue();
var knownResourceType = resourceTypeProvider.GetType(scopeType, availableType);
resourceTypeProvider.HasType(availableType).Should().BeTrue();
var resourceType = resourceTypeProvider.GetType(availableType, false);
var resourceTypeExisting = resourceTypeProvider.GetType(availableType, true);

try
{
var visited = new HashSet<TypeSymbol>();
VisitAllReachableTypes(knownResourceType, visited);
VisitAllReachableTypes(resourceType, visited);
VisitAllReachableTypes(resourceTypeExisting, visited);
}
catch (Exception exception)
{
Expand All @@ -53,19 +51,15 @@ public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing(Re
}
}

[DataTestMethod]
[DataRow(ResourceScope.Tenant)]
[DataRow(ResourceScope.ManagementGroup)]
[DataRow(ResourceScope.Subscription)]
[DataRow(ResourceScope.ResourceGroup)]
public void AzResourceTypeProvider_can_list_all_types_without_throwing(ResourceScope scopeType)
[TestMethod]
public void AzResourceTypeProvider_can_list_all_types_without_throwing()

{
var resourceTypeProvider = new AzResourceTypeProvider();
var availableTypes = resourceTypeProvider.GetAvailableTypes(scopeType);
var availableTypes = resourceTypeProvider.GetAvailableTypes();

// sanity check - we know there should be a lot of types available
var expectedTypeCount = scopeType == ResourceScope.ResourceGroup ? 2000 : 100;
var expectedTypeCount = 3000;
availableTypes.Should().HaveCountGreaterThan(expectedTypeCount);
}

Expand Down
6 changes: 3 additions & 3 deletions src/Bicep.Core.UnitTests/Utils/ResourceTypeProviderHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public MockResourceTypeProvider(IEnumerable<ResourceType> definedTypes)
ResourceTypeReferenceComparer.Instance);
}

public IEnumerable<ResourceTypeReference> GetAvailableTypes(ResourceScope scopeType)
public IEnumerable<ResourceTypeReference> GetAvailableTypes()
=> typeDictionary.Keys;

public ResourceType GetType(ResourceScope scopeType, ResourceTypeReference reference)
public ResourceType GetType(ResourceTypeReference reference, bool isExistingResource)
=> typeDictionary[reference];

public bool HasType(ResourceScope scopeType, ResourceTypeReference typeReference)
public bool HasType(ResourceTypeReference typeReference)
=> typeDictionary.ContainsKey(typeReference);
}

Expand Down
6 changes: 3 additions & 3 deletions src/Bicep.Core.UnitTests/Utils/TestResourceTypeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ namespace Bicep.Core.UnitTests.Utils
{
public class TestResourceTypeProvider : IResourceTypeProvider
{
public ResourceType GetType(ResourceScope scopeType, ResourceTypeReference reference)
public ResourceType GetType(ResourceTypeReference reference, bool isExistingResource)
=> new ResourceType(reference, new NamedObjectType(reference.FormatName(), TypeSymbolValidationFlags.Default, LanguageConstants.CreateResourceProperties(reference), null));

public bool HasType(ResourceScope scopeType, ResourceTypeReference typeReference)
public bool HasType(ResourceTypeReference typeReference)
=> true;

public IEnumerable<ResourceTypeReference> GetAvailableTypes(ResourceScope scopeType)
public IEnumerable<ResourceTypeReference> GetAvailableTypes()
=> Enumerable.Empty<ResourceTypeReference>();

public static IResourceTypeProvider Create()
Expand Down
41 changes: 41 additions & 0 deletions src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,34 @@ public DiagnosticBuilderInternal(TextSpan textSpan)
private static string ToQuotedString(IEnumerable<string> elements)
=> elements.Any() ? $"\"{elements.ConcatString("\", \"")}\"" : "";

private static IEnumerable<string> GetResourceScopeDescriptions(ResourceScope resourceScope)
{
if (resourceScope.HasFlag(ResourceScope.Resource))
{
yield return "resource";
}
if (resourceScope.HasFlag(ResourceScope.Module))
{
yield return "module";
}
if (resourceScope.HasFlag(ResourceScope.Tenant))
{
yield return "tenant";
}
if (resourceScope.HasFlag(ResourceScope.ManagementGroup))
{
yield return "managementGroup";
}
if (resourceScope.HasFlag(ResourceScope.Subscription))
{
yield return "subscription";
}
if (resourceScope.HasFlag(ResourceScope.ResourceGroup))
{
yield return "resourceGroup";
}
}

public ErrorDiagnostic UnrecognizedToken(string token) => new ErrorDiagnostic(
TextSpan,
"BCP001",
Expand Down Expand Up @@ -651,6 +679,7 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int mininumArgum
TextSpan,
DiagnosticLevel.Error,
"BCP113",
// ensure that this is kept up-to-date with the logic in
$"Unsupported scope for module deployment in a \"{LanguageConstants.TargetScopeTypeTenant}\" target scope. Omit this property to inherit the current scope, or specify a valid scope. " +
$"Permissible scopes include tenant: tenant(), named management group: managementGroup(<name>), named subscription: subscription(<subId>), or named resource group in a named subscription: resourceGroup(<subId>, <name>).");

Expand Down Expand Up @@ -711,6 +740,18 @@ public Diagnostic RuntimePropertyNotAllowed(string property, IEnumerable<string>
TextSpan,
"BCP122",
$"Modules: {ToQuotedString(moduleNames)} are defined with this same name and this same scope in a file. Rename them or split into different modules.");

public Diagnostic UnsupportedModuleScope(ResourceScope suppliedScope, ResourceScope supportedScopes) => new Diagnostic(
TextSpan,
DiagnosticLevel.Error,
"BCP123",
$"The supplied scope {ToQuotedString(GetResourceScopeDescriptions(suppliedScope))} is not valid for this module. Permitted scopes: {ToQuotedString(GetResourceScopeDescriptions(supportedScopes))}.");

public Diagnostic UnsupportedResourceScope(ResourceScope suppliedScope, ResourceScope supportedScopes) => new Diagnostic(
TextSpan,
DiagnosticLevel.Error,
"BCP124",
$"The supplied scope {ToQuotedString(GetResourceScopeDescriptions(suppliedScope))} is not valid for this resource type. Permitted scopes: {ToQuotedString(GetResourceScopeDescriptions(supportedScopes))}.");
}

public static DiagnosticBuilderInternal ForPosition(TextSpan span)
Expand Down
Loading

0 comments on commit b0dcdcc

Please sign in to comment.