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

Allow duplicated resources (by name) if at most one is unconditional #15909

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/Bicep.Core.IntegrationTests/NestedResourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ public void Nested_resource_detects_invalid_child_resource_literal_names()
}

resource res3 'child' = {
name: '${res1.name}/res2'
name: '${res1.name}/res3'
}
}
");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ public void Parent_property_detects_invalid_child_resource_literal_names()

resource res3 'Microsoft.Rp1/resource1/child2@2020-06-01' = {
parent: res1
name: '${res1.name}/res2'
name: '${res1.name}/res3'
}
");

Expand Down
149 changes: 146 additions & 3 deletions src/Bicep.Core.IntegrationTests/ScenarioTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3097,11 +3097,11 @@ public void Test_Issue_3169_3()
}

resource existingStg 'Microsoft.Storage/storageAccounts@2021-04-01' existing = {
name: newStg.name
name: uniqueString(newStg.name)
}

resource newStg2 'Microsoft.Storage/storageAccounts@2021-04-01' = {
name: existingStg.name
name: uniqueString(existingStg.name)
kind: 'BlobStorage'
location: resourceGroup().location
sku: {
Expand All @@ -3110,7 +3110,7 @@ public void Test_Issue_3169_3()
}
");
result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics();
result.Template.Should().HaveValueAtPath("$.resources[?(@.kind == 'BlobStorage')].name", "test");
result.Template.Should().HaveValueAtPath("$.resources[?(@.kind == 'BlobStorage')].name", "[uniqueString(uniqueString('test'))]");
}

/// <summary>
Expand Down Expand Up @@ -6594,4 +6594,147 @@ param _aksOidcIssuerProfileURL string
result.Template.Should().HaveValueAtPath("$.resources.aksWorkloadIdentityApp1::federation.copy.name", "aksWorkloadIdentityApp1::federation");
result.Template.Should().HaveValueAtPath("$.resources.aksWorkloadIdentityApp2::federation.copy.name", "aksWorkloadIdentityApp2::federation");
}

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Mutually_exclusive_but_duplicative_resources_are_permitted()
{
var result = CompilationHelper.Compile("""
param createMode 'GeoRestore' | 'Replica' = 'GeoRestore'

resource postgres 'microsoft.dbforpostgresql/servers@2017-12-01' = if (createMode == 'GeoRestore') {
name: 'foo'
location: 'eastus'
properties: {
createMode: 'GeoRestore'
sourceServerId: '<ID>'

}
}

resource postgres2 'microsoft.dbforpostgresql/servers@2017-12-01' = if (createMode == 'Replica') {
name: 'foo'
location: 'eastus'
properties: {
createMode: 'Replica'
sourceServerId: '<ID>'
}
}
""");

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

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Resources_with_the_same_name_but_different_types_are_permitted()
{
var result = CompilationHelper.Compile("""
resource postgres 'microsoft.dbforpostgresql/servers@2017-12-01' = {
name: 'foo'
location: 'eastus'
properties: {
createMode: 'GeoRestore'
sourceServerId: '<ID>'

}
}

resource postgres2 'microsoft.dbforpostgresql/flexibleServers@2021-06-01' = {
name: 'foo'
location: 'eastus'
properties: {
createMode: 'Replica'
sourceServerResourceId: '<ID>'
}
}
""");

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

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Resources_with_the_same_name_but_different_scopes_are_permitted()
{
var result = CompilationHelper.Compile("""
resource postgres 'microsoft.dbforpostgresql/servers@2017-12-01' existing = {
name: 'foo'
scope: resourceGroup('otherRg')
}

resource postgres2 'microsoft.dbforpostgresql/servers@2017-12-01' = {
name: 'foo'
location: 'eastus'
properties: {
createMode: 'Replica'
sourceServerId: '<ID>'
}
}
""");

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

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Modules_with_the_same_name_are_not_permitted()
{
var result = CompilationHelper.Compile(
("main.bicep", """
module foo1 'empty.bicep' = {
name: 'foo'
}

module foo2 'empty.bicep' = {
name: 'foo'
}
"""),
("empty.bicep", string.Empty));

result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[]
{
("BCP122", DiagnosticLevel.Error, "Modules: \"foo1\", \"foo2\" are defined with this same name and this same scope in a file. Rename them or split into different modules."),
("BCP122", DiagnosticLevel.Error, "Modules: \"foo1\", \"foo2\" are defined with this same name and this same scope in a file. Rename them or split into different modules."),
});
}

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Mutually_exclusive_but_duplicative_modules_are_permitted()
{
var result = CompilationHelper.Compile(
("main.bicep", """
param condition bool

module foo1 'empty.bicep' = if (condition) {
name: 'foo'
}

module foo2 'empty.bicep' = if (!condition) {
name: 'foo'
}
"""),
("empty.bicep", string.Empty));
}

// https://github.com/azure/bicep/issues/1410
[TestMethod]
public void Modules_with_the_same_name_but_different_scopes_are_permitted()
{
var result = CompilationHelper.Compile(
("main.bicep", """
module foo1 'empty.bicep' = {
name: 'foo'
}

module foo2 'empty.bicep' = {
name: 'foo'
scope: resourceGroup('otherRg')
}
"""),
("empty.bicep", string.Empty));

result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void Test_Issue657_discriminators()
// parent-property child resource
resource test4 'Rp.A/parent/child@2020-10-01' = {
parent: test
name: 'notAValidVal'
name: 'notAValidVal1'
properties: {
onlyOnEnum: true
}
Expand All @@ -110,13 +110,13 @@ public void Test_Issue657_discriminators()
// 'existing' parent-property child resource
resource test5 'Rp.A/parent/child@2020-10-01' existing = {
parent: test
name: 'notAValidVal'
name: 'notAValidVal2'
}
"));

failedResult.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] {
("BCP036", DiagnosticLevel.Warning, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal'\". If this is a resource type definition inaccuracy, report it using https://aka.ms/bicep-type-issues."),
("BCP036", DiagnosticLevel.Warning, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal'\". If this is a resource type definition inaccuracy, report it using https://aka.ms/bicep-type-issues."),
("BCP036", DiagnosticLevel.Warning, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal1'\". If this is a resource type definition inaccuracy, report it using https://aka.ms/bicep-type-issues."),
("BCP036", DiagnosticLevel.Warning, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal2'\". If this is a resource type definition inaccuracy, report it using https://aka.ms/bicep-type-issues."),
});
}

Expand Down Expand Up @@ -194,7 +194,7 @@ public void Test_Issue657_enum()
// parent-property child resource
resource test4 'Rp.A/parent/child@2020-10-01' = {
parent: test
name: 'notAValidVal'
name: 'notAValidVal1'
properties: {
onlyOnEnum: true
}
Expand All @@ -203,13 +203,13 @@ public void Test_Issue657_enum()
// 'existing' parent-property child resource
resource test5 'Rp.A/parent/child@2020-10-01' existing = {
parent: test
name: 'notAValidVal'
name: 'notAValidVal2'
}
"));

failedResult.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] {
("BCP036", DiagnosticLevel.Error, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal'\"."),
("BCP036", DiagnosticLevel.Error, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal'\"."),
("BCP036", DiagnosticLevel.Error, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal1'\"."),
("BCP036", DiagnosticLevel.Error, "The property \"name\" expected a value of type \"'val1' | 'val2'\" but the provided value is of type \"'notAValidVal2'\"."),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {
}

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
name: 'resC/resD'
name: 'resC/resD_2'
properties: {
resDRef: resD.id
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
//@[14:57) [BCP081 (Warning)] Resource type "My.Rp/myResourceType/childType@2020-01-01" does not have types available. Bicep is unable to validate resource properties prior to deployment, but this will not block the resource from being deployed. (bicep https://aka.ms/bicep/core-diagnostics#BCP081) |'My.Rp/myResourceType/childType@2020-01-01'|
name: 'resC/resD'
//@[08:19) [use-parent-property (Warning)] Resource "resE" has its name formatted as a child of resource "resC". The syntax can be simplified by using the parent property. (bicep core linter https://aka.ms/bicep/linter/use-parent-property) |'resC/resD'|
name: 'resC/resD_2'
//@[08:21) [use-parent-property (Warning)] Resource "resE" has its name formatted as a child of resource "resC". The syntax can be simplified by using the parent property. (bicep core linter https://aka.ms/bicep/linter/use-parent-property) |'resC/resD_2'|
properties: {
resDRef: resD.id
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {
}

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
name: 'resC/resD'
name: 'resC/resD_2'
properties: {
resDRef: resD.id
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param deployTimeParam string = 'steve'
//@[00:1098) ProgramExpression
//@[00:1100) ProgramExpression
//@[00:0038) ├─DeclaredParameterExpression { Name = deployTimeParam }
//@[22:0028) | ├─AmbientTypeReferenceExpression { Name = string }
//@[31:0038) | └─StringLiteralExpression { Value = steve }
Expand Down Expand Up @@ -143,9 +143,9 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {
}

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
//@[00:0124) ├─DeclaredResourceExpression
//@[60:0124) | ├─ObjectExpression
name: 'resC/resD'
//@[00:0126) ├─DeclaredResourceExpression
//@[60:0126) | ├─ObjectExpression
name: 'resC/resD_2'
properties: {
//@[02:0040) | | └─ObjectPropertyExpression
//@[02:0012) | | ├─StringLiteralExpression { Value = properties }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"_generator": {
"name": "bicep",
"version": "dev",
"templateHash": "10969660194523330241"
"templateHash": "9865822508247546164"
}
},
"parameters": {
Expand Down Expand Up @@ -80,7 +80,7 @@
{
"type": "My.Rp/myResourceType/childType",
"apiVersion": "2020-01-01",
"name": "resC/resD",
"name": "resC/resD_2",
"properties": {
"resDRef": "[resourceId('My.Rp/myResourceType/childType', split(format('{0}/resD', 'resC'), '/')[0], split(format('{0}/resD', 'resC'), '/')[1])]"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@ resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
//@ {
//@ "type": "My.Rp/myResourceType/childType",
//@ "apiVersion": "2020-01-01",
//@ "name": "resC/resD",
//@ "name": "resC/resD_2",
//@ "dependsOn": [
//@ "[resourceId('My.Rp/myResourceType/childType', split(format('{0}/resD', 'resC'), '/')[0], split(format('{0}/resD', 'resC'), '/')[1])]"
//@ ]
//@ }
name: 'resC/resD'
name: 'resC/resD_2'
properties: {
//@ "properties": {
//@ },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "dev",
"templateHash": "13967933445482532999"
"templateHash": "12971250390483085890"
}
},
"parameters": {
Expand Down Expand Up @@ -81,7 +81,7 @@
"resE": {
"type": "My.Rp/myResourceType/childType",
"apiVersion": "2020-01-01",
"name": "resC/resD",
"name": "resC/resD_2",
"properties": {
"resDRef": "[resourceId('My.Rp/myResourceType/childType', split(format('{0}/resD', 'resC'), '/')[0], split(format('{0}/resD', 'resC'), '/')[1])]"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {
}

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
//@[9:13) Resource resE. Type: My.Rp/myResourceType/childType@2020-01-01. Declaration start char: 0, length: 124
name: 'resC/resD'
//@[9:13) Resource resE. Type: My.Rp/myResourceType/childType@2020-01-01. Declaration start char: 0, length: 126
name: 'resC/resD_2'
properties: {
resDRef: resD.id
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param deployTimeParam string = 'steve'
//@[00:1098) ProgramSyntax
//@[00:1100) ProgramSyntax
//@[00:0038) ├─ParameterDeclarationSyntax
//@[00:0005) | ├─Token(Identifier) |param|
//@[06:0021) | ├─IdentifierSyntax
Expand Down Expand Up @@ -392,24 +392,24 @@ resource resD 'My.Rp/myResourceType/childType@2020-01-01' = {
//@[01:0003) ├─Token(NewLine) |\n\n|

resource resE 'My.Rp/myResourceType/childType@2020-01-01' = {
//@[00:0124) ├─ResourceDeclarationSyntax
//@[00:0126) ├─ResourceDeclarationSyntax
//@[00:0008) | ├─Token(Identifier) |resource|
//@[09:0013) | ├─IdentifierSyntax
//@[09:0013) | | └─Token(Identifier) |resE|
//@[14:0057) | ├─StringSyntax
//@[14:0057) | | └─Token(StringComplete) |'My.Rp/myResourceType/childType@2020-01-01'|
//@[58:0059) | ├─Token(Assignment) |=|
//@[60:0124) | └─ObjectSyntax
//@[60:0126) | └─ObjectSyntax
//@[60:0061) | ├─Token(LeftBrace) |{|
//@[61:0062) | ├─Token(NewLine) |\n|
name: 'resC/resD'
//@[02:0019) | ├─ObjectPropertySyntax
name: 'resC/resD_2'
//@[02:0021) | ├─ObjectPropertySyntax
//@[02:0006) | | ├─IdentifierSyntax
//@[02:0006) | | | └─Token(Identifier) |name|
//@[06:0007) | | ├─Token(Colon) |:|
//@[08:0019) | | └─StringSyntax
//@[08:0019) | | └─Token(StringComplete) |'resC/resD'|
//@[19:0020) | ├─Token(NewLine) |\n|
//@[08:0021) | | └─StringSyntax
//@[08:0021) | | └─Token(StringComplete) |'resC/resD_2'|
//@[21:0022) | ├─Token(NewLine) |\n|
properties: {
//@[02:0040) | ├─ObjectPropertySyntax
//@[02:0012) | | ├─IdentifierSyntax
Expand Down
Loading
Loading