From 20ac8b7116cf7781600646dc0d5d85dcdae0df45 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 7 Nov 2023 22:23:26 +0100 Subject: [PATCH 01/37] Added skeleton --- .../compliance/module.tests.ps1 | 272 ++++++++++++------ 1 file changed, 185 insertions(+), 87 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 700771fe11..c1a0174819 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -3,7 +3,7 @@ param ( [Parameter(Mandatory = $false)] [array] $moduleFolderPaths = ((Get-ChildItem $repoRootPath -Recurse -Directory -Force).FullName | Where-Object { - (Get-ChildItem $_ -File -Depth 0 -Include @('main.json', 'main.bicep') -Force).Count -gt 0 + (Get-ChildItem $_ -File -Depth 0 -Include @('main.bicep') -Force).Count -gt 0 }), [Parameter(Mandatory = $false)] @@ -27,7 +27,6 @@ $script:convertedTemplates = @{} # Shared exception messages $script:bicepTemplateCompilationFailedException = "Unable to compile the main.bicep template's content. This can happen if there is an error in the template. Please check if you can run the command ``bicep build {0} --stdout | ConvertFrom-Json -AsHashtable``." # -f $templateFilePath -$script:jsonTemplateLoadFailedException = "Unable to load the main.json template's content. This can happen if there is an error in the template. Please check if you can run the command `Get-Content {0} -Raw | ConvertFrom-Json -AsHashtable`." # -f $templateFilePath $script:templateNotFoundException = 'No template file found in folder [{0}]' # -f $moduleFolderPath # Import any helper function used in this test script @@ -203,24 +202,14 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -342,24 +331,14 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -423,17 +402,13 @@ Describe 'Module tests' -Tag 'Module' { $SchemaArray = @() if ($Schemaverion -eq $RgDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $SubscriptionDeploymentSchema) { + } elseIf ($Schemaverion -eq $SubscriptionDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $MgDeploymentSchema) { + } elseIf ($Schemaverion -eq $MgDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $TenantDeploymentSchema) { + } elseIf ($Schemaverion -eq $TenantDeploymentSchema) { $SchemaOutput = $true - } - else { + } else { $SchemaOutput = $false } $SchemaArray += $SchemaOutput @@ -496,8 +471,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Param in $Parameter) { if ($Param.substring(0, 1) -cnotmatch '[a-z]' -or $Param -match '-' -or $Param -match '_') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -522,8 +496,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Variab in $Variable) { if ($Variab.substring(0, 1) -cnotmatch '[a-z]' -or $Variab -match '-') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -542,8 +515,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Output in $Outputs) { if ($Output.substring(0, 1) -cnotmatch '[a-z]' -or $Output -match '-' -or $Output -match '_') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -560,8 +532,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -579,8 +550,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -604,8 +574,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -634,8 +603,7 @@ Describe 'Module tests' -Tag 'Module' { if ($Locationparamoutput -contains 'Location') { if ($Locationparamoutputvalue -eq '[resourceGroup().Location]' -or $Locationparamoutputvalue -eq 'global') { $LocationFlag = $true - } - else { + } else { $LocationFlag = $false } @@ -696,8 +664,7 @@ Describe 'Module tests' -Tag 'Module' { $readMeFileContentHeader = (Get-Content -Path $readMeFilePath)[0] if ($readMeFileContentHeader -match '^.*`\[(.+)\]`.*') { $primaryResourceType = $matches[1] - } - else { + } else { Write-Error "Cannot identity primary resource type in readme header [$readMeFileContentHeader] and cannot execute the test." return } @@ -705,8 +672,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -732,8 +698,7 @@ Describe 'Module tests' -Tag 'Module' { $readMeFileContentHeader = (Get-Content -Path $readMeFilePath)[0] if ($readMeFileContentHeader -match '^.*`\[(.+)\]`.*') { $primaryResourceType = $matches[1] - } - else { + } else { Write-Error "Cannot identity primary resource type in readme header [$readMeFileContentHeader] and cannot execute the test." return } @@ -741,8 +706,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -856,7 +820,6 @@ Describe 'Module tests' -Tag 'Module' { $incorrectOutputs | Should -BeNullOrEmpty } - # Update to work with nullable parameters It '[] All non-required parameters in template file should not have description that start with "Required.".' -TestCases $deploymentFolderTestCases { param ( [hashtable[]] $testFileTestCases, @@ -895,23 +858,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } @@ -954,6 +907,96 @@ Describe 'Module tests' -Tag 'Module' { $templateFileContent.metadata.owner | Should -Not -BeNullOrEmpty } } + + Context 'User-defined-types tests' -Tag 'UDT' { + + $udtTestCases = [System.Collections.ArrayList] @() + foreach ($moduleFolderPath in $moduleFolderPaths) { + + $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// + + # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key + $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') + if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { + if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($bicepTemplateCompilationFailedException -f $templateFilePath) + } + } else { + throw ($templateNotFoundException -f $moduleFolderPath) + } + $convertedTemplates[$moduleFolderPathKey] = @{ + templateContent = $templateContent + } + } else { + $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent + } + + $udtTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + } + } + + + It "[] If template has [roleAssignments] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [privateEndpoints] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [lock] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [customerManagedKey] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + } } Describe 'Test file tests' -Tag 'TestTemplate' { @@ -978,6 +1021,74 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } + It "[] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'default' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'max' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'waf' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + } + It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( @@ -1021,8 +1132,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { try { $apiSpecs = Invoke-WebRequest -Uri $ApiSpecsFileUri $ApiVersions = ConvertFrom-Json $apiSpecs.Content -AsHashtable - } - catch { + } catch { Write-Warning "Failed to download API specs file from [$ApiSpecsFileUri]. Skipping API tests" Set-ItResult -Skipped -Because "Failed to download API specs file from [$ApiSpecsFileUri]. Skipping API tests." return @@ -1042,24 +1152,14 @@ Describe 'API version tests' -Tag 'ApiCheck' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -1165,8 +1265,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { # We allow the latest 5 including previews (in case somebody wants to use preview), or the latest 3 non-preview $approvedApiVersions += $resourceTypeApiVersions | Select-Object -Last 5 $approvedApiVersions += $resourceTypeApiVersions | Where-Object { $_ -notlike '*-preview' } | Select-Object -Last 5 - } - else { + } else { # We allow the latest 5 non-preview preview $approvedApiVersions += $resourceTypeApiVersions | Where-Object { $_ -notlike '*-preview' } | Select-Object -Last 5 } @@ -1179,8 +1278,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { # The original failed test was # $approvedApiVersions | Should -Contain $TargetApi - } - else { + } else { # Provide a warning if an API version is second to next to expire. $indexOfVersion = $approvedApiVersions.IndexOf($TargetApi) From 4939b4d2e85ac2db8d8b2a67cb17fac7363196c7 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 00:38:44 +0100 Subject: [PATCH 02/37] Implemented first new tests --- avm/res/key-vault/vault/main.bicep | 3 - avm/res/key-vault/vault/main.json | 26 +-- .../compliance/module.tests.ps1 | 148 +++++++++++------- 3 files changed, 103 insertions(+), 74 deletions(-) diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index ae038cf1f5..4e62950d9c 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -353,9 +353,6 @@ type roleAssignmentType = { @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container"') condition: string? - @description('Optional. Version of the condition.') - conditionVersion: '2.0'? - @description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? }[]? diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index f10c40c0fb..bfcfb41b93 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9188769706526490100" + "version": "0.23.1.45101", + "templateHash": "8353941507512521049" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -164,16 +164,6 @@ "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, @@ -682,8 +672,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9999250509448584761" + "version": "0.23.1.45101", + "templateHash": "4111939022872407830" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -815,8 +805,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "11139788551431901948" + "version": "0.23.1.45101", + "templateHash": "9180551172362989336" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1104,8 +1094,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "15591839680984542683" + "version": "0.23.1.45101", + "templateHash": "2691621623448325959" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index c1a0174819..f3ab52891e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -935,67 +935,109 @@ Describe 'Module tests' -Tag 'Module' { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } - $udtTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - } - } - - - It "[] If template has [roleAssignments] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - - param( - [object[]] $templateFileContent + # Setting expected URL only for those that doen't have multiple different variants + $avmInterfaceSpecsBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $udtCases = @( + @{ + parameterName = 'diagnosticSettings' + udtName = 'diagnosticSettingType' + } + @{ + parameterName = 'roleAssignments' + udtName = 'roleAssignmentType' + udtExpectedUrl = "$avmInterfaceSpecsBase/int.rbac.udt.schema.bicep" + } + @{ + parameterName = 'lock' + udtName = 'lockType' + udtExpectedUrl = "$avmInterfaceSpecsBase/int.locks.udt.schema.bicep" + } + @{ + parameterName = 'managedIdentities' + udtName = 'managedIdentitiesType' + } + @{ + parameterName = 'privateEndpoints' + udtName = 'privateEndpointType' + } + @{ + parameterName = 'customerManagedKey' + udtName = 'customerManagedKeyType' + } ) - throw 'Not implemented' + foreach ($udtCase in $udtCases) { + $udtTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + templateFileContentBicep = Get-Content $templateFilePath + parameterName = $udtCase.parameterName + udtName = $udtCase.udtName + expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' + } + } } - It "[] If template has [privateEndpoints] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } - - It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + It "[] If template has [] parameter, it should implement the expected user-defined type []" -TestCases $udtTestCases { param( - [object[]] $templateFileContent + [hashtable] $templateFileContent, + [string[]] $templateFileContentBicep, + [string] $parameterName, + [string] $udtName, + [string] $expectedUdtUrl ) - throw 'Not implemented' - - } - It "[] If template has [lock] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + if ($templateFileContent.parameters.Keys -contains $parameterName) { + $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type." + $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]." - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } - - It "[] If template has [customerManagedKey] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { + $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") + $implementedSchemaEndIndex = $implementedSchemaStartIndex + 1 + while ($templateFileContentBicep[$implementedSchemaEndIndex] -notmatch '^\}.*' -and $implementedSchemaEndIndex -lt $templateFileContentBicep.Length) { + $implementedSchemaEndIndex++ + } + if ($implementedSchemaEndIndex -eq $templateFileContentBicep.Length) { + throw "Failed to identify [$udtName] user-defined type in template." + } + $implementedSchema = $templateFileContentBicep[$implementedSchemaStartIndex..$implementedSchemaEndIndex] - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' + $expectedSchemaFull = (Invoke-WebRequest -Uri $expectedUdtUrl).Content -split "\n" + $expectedSchemaStartIndex = $expectedSchemaFull.IndexOf("type $udtName = {") + $expectedSchemaEndIndex = $expectedSchemaStartIndex + 1 + while ($expectedSchemaFull[$expectedSchemaEndIndex] -notmatch '^\}.*' -and $expectedSchemaEndIndex -lt $expectedSchemaFull.Length) { + $expectedSchemaEndIndex++ + } + if ($expectedSchemaEndIndex -eq $expectedSchemaFull.Length) { + throw "Failed to identify [$udtName] user-defined type in expected schema at URL [$expectedUdtUrl]." + } + $expectedSchema = $expectedSchemaFull[$expectedSchemaStartIndex..$expectedSchemaEndIndex] + + $formattedDiff = @() + foreach ($finding in (Compare-Object $implementedSchema $expectedSchema)) { + if ($finding.SideIndicator -eq '=>') { + $formattedDiff += ('+ {0}' -f $finding.InputObject) + } elseif ($finding.SideIndicator -eq '<=') { + $formattedDiff += ('- {0}' -f $finding.InputObject) + } + } + if ($formattedDiff.Count -gt 0) { + Write-Warning ($formattedDiff | Out-String) -Verbose + $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + } + ($implementedSchema | Out-String) | Should -Be ($expectedSchema | Out-String) -Because ('The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff
{1}
.' -f $expectedUdtUrl, $mdFormattedDiff) + } + } else { + Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." + } } - It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } + # TODO Add test for tags + # TODO add tests for msi principal id output } } @@ -1026,7 +1068,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1037,7 +1079,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'default' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1048,7 +1090,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'max' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1059,7 +1101,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'waf' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1068,7 +1110,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1077,7 +1119,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1086,7 +1128,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 4e1d86f3848f9aa4e858f834bb373af04d64c179 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 09:19:19 +0100 Subject: [PATCH 03/37] Changed to warning --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index f3ab52891e..dd9c9fb5e1 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1023,12 +1023,10 @@ Describe 'Module tests' -Tag 'Module' { $formattedDiff += ('- {0}' -f $finding.InputObject) } } + if ($formattedDiff.Count -gt 0) { - Write-Warning ($formattedDiff | Out-String) -Verbose - $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + Write-Warning ("The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff`n{1}" -f $expectedUdtUrl, ($formattedDiff | Out-String)) } - - ($implementedSchema | Out-String) | Should -Be ($expectedSchema | Out-String) -Because ('The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff
{1}
.' -f $expectedUdtUrl, $mdFormattedDiff) } } else { Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." From 94fff0ba27001ed731cd18daee02d1b06b7cef21 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 14:19:32 +0100 Subject: [PATCH 04/37] Expanded test verbosity & added additional tets --- .../compliance/module.tests.ps1 | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index dd9c9fb5e1..cc36fb716e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -910,7 +910,8 @@ Describe 'Module tests' -Tag 'Module' { Context 'User-defined-types tests' -Tag 'UDT' { - $udtTestCases = [System.Collections.ArrayList] @() + $udtTestCases = [System.Collections.ArrayList] @() # General UDT tests (e.g. param should exist) + $udtSpecificTestCases = [System.Collections.ArrayList] @() # Specific UDT test cases for singular UDTs (e.g. tags) foreach ($moduleFolderPath in $moduleFolderPaths) { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// @@ -935,34 +936,47 @@ Describe 'Module tests' -Tag 'Module' { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } + $udtSpecificTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + templateFileContentBicep = Get-Content $templateFilePath + } + # Setting expected URL only for those that doen't have multiple different variants - $avmInterfaceSpecsBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $avmInterfaceSpecsTemplateBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $avmInterfaceSpecsBase = 'https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces' $udtCases = @( @{ parameterName = 'diagnosticSettings' udtName = 'diagnosticSettingType' + link = "$avmInterfaceSpecsBase#diagnostic-settings" } @{ parameterName = 'roleAssignments' udtName = 'roleAssignmentType' - udtExpectedUrl = "$avmInterfaceSpecsBase/int.rbac.udt.schema.bicep" + udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.rbac.udt.schema.bicep" + link = "$avmInterfaceSpecsBase#role-assignments" } @{ parameterName = 'lock' udtName = 'lockType' - udtExpectedUrl = "$avmInterfaceSpecsBase/int.locks.udt.schema.bicep" + udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.locks.udt.schema.bicep" + link = "$avmInterfaceSpecsBase#resource-locks" } @{ parameterName = 'managedIdentities' udtName = 'managedIdentitiesType' + link = "$avmInterfaceSpecsBase#managed-identities" } @{ parameterName = 'privateEndpoints' udtName = 'privateEndpointType' + link = "$avmInterfaceSpecsBase#private-endpoints" } @{ parameterName = 'customerManagedKey' udtName = 'customerManagedKeyType' + link = "$avmInterfaceSpecsBase#customer-managed-keys" } ) @@ -979,19 +993,20 @@ Describe 'Module tests' -Tag 'Module' { } - It "[] If template has [] parameter, it should implement the expected user-defined type []" -TestCases $udtTestCases { + It "[] If template has [] parameter, it should implement the user-defined type []" -TestCases $udtTestCases { param( [hashtable] $templateFileContent, [string[]] $templateFileContentBicep, [string] $parameterName, [string] $udtName, - [string] $expectedUdtUrl + [string] $expectedUdtUrl, + [string] $link ) if ($templateFileContent.parameters.Keys -contains $parameterName) { - $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type." - $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]." + $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For for information please review the [AVM Specs]($link)." + $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]. For for information please review the [AVM Specs]($link)." if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") @@ -1025,7 +1040,7 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - Write-Warning ("The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff`n{1}" -f $expectedUdtUrl, ($formattedDiff | Out-String)) + Write-Warning ("The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String)) } } } else { @@ -1033,9 +1048,31 @@ Describe 'Module tests' -Tag 'Module' { } } + It "[] If a [managedIdentitiesType] UDT definition exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { + + param( + [hashtable] $templateFileContent + ) + + if ($templateFileContent.definitions.Keys -contains 'managedIdentitiesType' -and $templateFileContent.definitions.managedIdentitiesType.properties.keys -contains 'systemAssigned') { + $templateFileContent.outputs.Keys | Should -Contain 'systemAssignedMIPrincipalId' -Because 'The AVM specs require a this output. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#managed-identities).' + } else { + Set-ItResult -Skipped -Because "the module template has no [managedIdentitiesType] UDT definition or does not support system-assigned-identities." + } + } + + It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtTestCases { - # TODO Add test for tags - # TODO add tests for msi principal id output + param( + [hashtable] $templateFileContent + ) + + if ($templateFileContent.parameters.Keys -contains 'tags') { + $templateFileContent.parameters.tags.nullable | Should -Be $true -Because 'The AVM specs require a specific format. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#tags).' + } else { + Set-ItResult -Skipped -Because "the module template has no [tags] parameter." + } + } } } From c18ce6baea39a873b231c956c2439b3913935dc1 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 15:45:41 +0100 Subject: [PATCH 05/37] Finalized further tests --- .../compliance/module.tests.ps1 | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index cc36fb716e..24dbbc5c5f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1061,7 +1061,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtTestCases { + It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1103,41 +1103,49 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' } - It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'default' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*min" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' + } } - It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'max' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*max" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' + } } - It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'waf' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*waf" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' + } } It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { From a3436942147ce7690ab14a9c12ce11f1bc5c628b Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:18:05 +0100 Subject: [PATCH 06/37] Update to latest --- .../staticValidation/compliance/module.tests.ps1 | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 24dbbc5c5f..98caa78e5d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1113,8 +1113,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*min" + $Matches[1] | Should -BeLike "*min" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' } @@ -1127,8 +1126,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*max" + $Matches[1] | Should -BeLike "*max" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' } @@ -1141,8 +1139,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*waf" + $Matches[1] | Should -BeLike "*waf" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' } @@ -1153,8 +1150,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + (($testFileContent | Out-String) -match "metadata name = ") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { @@ -1162,8 +1158,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + (($testFileContent | Out-String) -match "metadata description = ") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { From 3a6f0a2b56d426ce7e54bfc5145f45cf28dbd440 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:27:54 +0100 Subject: [PATCH 07/37] Update to latest --- .../staticValidation/compliance/module.tests.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 98caa78e5d..013972eabb 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1150,7 +1150,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = ") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { @@ -1158,7 +1158,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = ") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { @@ -1166,7 +1166,9 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' + + (($testFileContent | Out-String) -match "@description('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.')") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' + (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' } It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 4ab6a5bb23b592796960daf61cb831fcf91cd3ac Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:38:29 +0100 Subject: [PATCH 08/37] Added module name + small fix --- .../compliance/module.tests.ps1 | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 013972eabb..d5dd1215c6 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1090,6 +1090,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// $deploymentTestFileTestCases += @{ + testName = Split-Path (Split-Path $testFilePath) -Leaf testFilePath = $testFilePath testFileContent = $testFileContent moduleFolderName = $resourceTypeIdentifier @@ -1098,7 +1099,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1106,7 +1107,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' } - It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1119,7 +1120,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1132,7 +1133,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1145,7 +1146,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1153,7 +1154,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1161,17 +1162,17 @@ Describe 'Test file tests' -Tag 'TestTemplate' { (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.')") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' + (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' } - It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1182,7 +1183,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $testIndex -ne -1 | Should -Be $true -Because 'the module test invocation should be in the expected format to allow identification.' } - It '[] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { + It '[] [] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1193,7 +1194,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $expectedNameFormat | Should -Be $true -Because 'the handle ''-test-'' should be part of the module test invocation''s resource name to allow identification.' } - It '[] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { + It '[] [] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent From 9bb64bde34d8b5de3d1b2bda2a0fe2687855b35f Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 17:31:08 +0100 Subject: [PATCH 09/37] Fixed kvlt --- avm/res/key-vault/vault/access-policy/main.json | 4 ++-- avm/res/key-vault/vault/key/main.json | 4 ++-- avm/res/key-vault/vault/main.bicep | 3 +++ avm/res/key-vault/vault/main.json | 12 +++++++++++- avm/res/key-vault/vault/secret/main.json | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 9b6725ecc4..8aa7ea483d 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9999250509448584761" + "version": "0.23.1.45101", + "templateHash": "4111939022872407830" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 6ecce215ac..6e85c7d6ad 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "15591839680984542683" + "version": "0.23.1.45101", + "templateHash": "2691621623448325959" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 4e62950d9c..ae038cf1f5 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -353,6 +353,9 @@ type roleAssignmentType = { @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container"') condition: string? + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + @description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? }[]? diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index bfcfb41b93..8478ccde4e 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "8353941507512521049" + "templateHash": "1913015049301539374" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -164,6 +164,16 @@ "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" } }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index 62c5c52a19..f778252db1 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "11139788551431901948" + "version": "0.23.1.45101", + "templateHash": "9180551172362989336" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", From 68e2bd2fbc6301b199fd0258411da31781ba4380 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 17:56:38 +0100 Subject: [PATCH 10/37] Small caching fix --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index d5dd1215c6..8dc880fdb9 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -930,10 +930,12 @@ Describe 'Module tests' -Tag 'Module' { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent + templateContent = $templateContent + templateFilePath = $templateFilePath } } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent + $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } $udtSpecificTestCases += @{ From 1a013c2a4115610d4260515205158ed831860de8 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 19:25:21 +0100 Subject: [PATCH 11/37] Small fix and enabled passthru of warnings to GH --- .../compliance/Set-PesterGitHubOutput.ps1 | 72 ++++++++++++++++--- .../compliance/module.tests.ps1 | 9 ++- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index 4c84e61eaf..ada2dc98e9 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -81,10 +81,12 @@ function Set-PesterGitHubOutput { $passedTests = $PesterTestResults.Passed $failedTests = $PesterTestResults.Failed $skippedTests = $PesterTestResults.Skipped + $testsWithWarnings = ($passedTests + $failedTests + $skippedTests) | Where-Object { $_.StandardOutput.Keys -eq 'Warning' } Write-Verbose ('Formatting [{0}] passed tests' -f $passedTests.Count) Write-Verbose ('Formatting [{0}] failed tests' -f $failedTests.Count) Write-Verbose ('Formatting [{0}] skipped tests' -f $skippedTests.Count) + Write-Verbose ('Formatting [{0}] tests with explicit warnings' -f $warnings.Count) ###################### # Set output content # @@ -98,9 +100,9 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( - '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: |', - '| :-- | :-- | :-- | :-- |' - ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count), + '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', + '| :-- | :-- | :-- | :-- |', + ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), '' ) @@ -140,8 +142,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} | {2} |' -f $testName, $errorMessage, $testReference } - } - else { + } else { $fileContent += ('No tests failed.') } @@ -164,6 +165,8 @@ function Set-PesterGitHubOutput { if (($passedTests.Count -gt 0)) { + # TODO: Add support for outputs + $fileContent += [System.Collections.ArrayList]@( '| Name | Source |', '| :-- | :-- |' @@ -185,8 +188,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} |' -f $testName, $testReference } - } - else { + } else { $fileContent += ('No tests passed.') } @@ -222,8 +224,8 @@ function Set-PesterGitHubOutput { $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() - $testLine = $passedTest.ScriptBlock.StartPosition.StartLine - $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + $testLine = $skippedTest.ScriptBlock.StartPosition.StartLine + $testFile = (($skippedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { @@ -233,8 +235,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} | {2} |' -f $testName, $reason, $testReference } - } - else { + } else { $fileContent += ('No tests were skipped.') } @@ -244,6 +245,55 @@ function Set-PesterGitHubOutput { '' ) + ################## + ## Warnings ## + ################## + + Write-Verbose 'Adding warnings' + $fileContent += [System.Collections.ArrayList]@( + '', + '
', + 'List of explicit warnings', + '' + ) + + if ($testsWithWarnings.Count -gt 0) { + + $fileContent += [System.Collections.ArrayList]@( + '| Name | Warning | Source |', + '| :-- | :-- | :-- |' + ) + foreach ($test in ($testsWithWarnings | Sort-Object -Property { $PSItem.ExpandedName }) ) { + foreach ($warning in $test.StandardOutput.Warning) { + $intermediateNameElements = $test.Path + $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + + $testLine = $test.ScriptBlock.StartPosition.StartLine + $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + + $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine + if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { + # Creating URL to test file to enable users to 'click' on it + $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" + } + + $fileContent += '| {0} | {1} | {2} |' -f $testName, ($warning -replace '\|', '\|'), $testReference + } + } + } else { + $fileContent += ('No tests with warnings.') + } + + $fileContent += [System.Collections.ArrayList]@( + '', + '
', + '' + ) + + + + if ($PSCmdlet.ShouldProcess("Test results file in path [$OutputFilePath]", 'Create')) { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 8dc880fdb9..8ba6483758 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -990,6 +990,7 @@ Describe 'Module tests' -Tag 'Module' { parameterName = $udtCase.parameterName udtName = $udtCase.udtName expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' + link = $udtCase.link } } } @@ -1042,7 +1043,13 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - Write-Warning ("The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String)) + $warningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) + Write-Warning $warningMessage + + # Adding also to output to show in GitHub CI + Write-Output @{ + Warning = $warningMessage + } } } } else { From 1c2fc8ab54eafaef98ab28b8feaa3073d9469436 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 19:31:09 +0100 Subject: [PATCH 12/37] More updates --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index ada2dc98e9..e716f14f5b 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -101,8 +101,8 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', - '| :-- | :-- | :-- | :-- |', - ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), + '| :-- | :-- | :-- | :-- | :-- |', + ('| {0} | {1} | {2} | {3} | {4} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), '' ) @@ -278,7 +278,7 @@ function Set-PesterGitHubOutput { $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" } - $fileContent += '| {0} | {1} | {2} |' -f $testName, ($warning -replace '\|', '\|'), $testReference + $fileContent += '| {0} | {1} | {2} |' -f $testName, (($warning -join '
') -replace '\|', '\|'), $testReference } } } else { From d9c6dd5deffd8fd307107e5ce8be98961163996a Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 20:16:57 +0100 Subject: [PATCH 13/37] Update to latest --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 4 +--- .../pipelines/staticValidation/compliance/module.tests.ps1 | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index e716f14f5b..e1c207936d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -165,8 +165,6 @@ function Set-PesterGitHubOutput { if (($passedTests.Count -gt 0)) { - # TODO: Add support for outputs - $fileContent += [System.Collections.ArrayList]@( '| Name | Source |', '| :-- | :-- |' @@ -278,7 +276,7 @@ function Set-PesterGitHubOutput { $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" } - $fileContent += '| {0} | {1} | {2} |' -f $testName, (($warning -join '
') -replace '\|', '\|'), $testReference + $fileContent += ('| {0} | {1} | {2} |' -f $testName, $warning, $testReference) } } } else { diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 8ba6483758..997ac427a6 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1043,12 +1043,14 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - $warningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) + $warningMessage = "The implemented user-defined type is not the same as the expected user-defined type ({0}) defined in the AVM specs ({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) Write-Warning $warningMessage # Adding also to output to show in GitHub CI + $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + $mdFormattedWarningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff
{2}
" -f $expectedUdtUrl, $link, $mdFormattedDiff Write-Output @{ - Warning = $warningMessage + Warning = $mdFormattedWarningMessage } } } From dd0c343fb884869740436c238b367d13029fc549 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 21:00:06 +0100 Subject: [PATCH 14/37] Updated test names --- .../compliance/module.tests.ps1 | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 997ac427a6..e46c6fc17d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -996,7 +996,7 @@ Describe 'Module tests' -Tag 'Module' { } - It "[] If template has [] parameter, it should implement the user-defined type []" -TestCases $udtTestCases { + It "[] If template has a parameter [], it should implement the user-defined type []" -TestCases $udtTestCases { param( [hashtable] $templateFileContent, @@ -1059,7 +1059,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [managedIdentitiesType] UDT definition exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { + It "[] If a UDT definition [managedIdentitiesType] exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1072,7 +1072,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtSpecificTestCases { + It "[] If a parameter [tags] exists it should be nullable." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1110,15 +1110,15 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a parameter [serviceShort]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' + ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' } - It "[] [] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1127,11 +1127,11 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*min" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*min''] but it doesn''t.' } } - It "[] [] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1140,11 +1140,11 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*max" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*max''] but it doesn''t.' } } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1153,34 +1153,34 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*waf" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' } } - It "[] [] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a metadata string [name]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] [] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] [] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' - (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' + (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter [namePrefix] should have the expected description.' + (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 2ebd45891d75ce145710733437cb82c5814128c4 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:32:08 +0100 Subject: [PATCH 15/37] JSON rollback --- avm/res/key-vault/vault/access-policy/main.json | 4 ++-- avm/res/key-vault/vault/key/main.json | 4 ++-- avm/res/key-vault/vault/main.json | 16 ++++++++-------- avm/res/key-vault/vault/secret/main.json | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 8aa7ea483d..9b6725ecc4 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "4111939022872407830" + "version": "0.22.6.54827", + "templateHash": "9999250509448584761" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 6e85c7d6ad..6ecce215ac 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2691621623448325959" + "version": "0.22.6.54827", + "templateHash": "15591839680984542683" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 8478ccde4e..f10c40c0fb 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "1913015049301539374" + "version": "0.22.6.54827", + "templateHash": "9188769706526490100" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -682,8 +682,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "4111939022872407830" + "version": "0.22.6.54827", + "templateHash": "9999250509448584761" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -815,8 +815,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9180551172362989336" + "version": "0.22.6.54827", + "templateHash": "11139788551431901948" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1104,8 +1104,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2691621623448325959" + "version": "0.22.6.54827", + "templateHash": "15591839680984542683" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index f778252db1..62c5c52a19 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9180551172362989336" + "version": "0.22.6.54827", + "templateHash": "11139788551431901948" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", From f6caf7e44eadf5ed72103aa3bcada9c3cf1c8fce Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:49:57 +0100 Subject: [PATCH 16/37] Updated regex --- .../compliance/Set-PesterGitHubOutput.ps1 | 2 +- .../staticValidation/compliance/module.tests.ps1 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index e1c207936d..a8a773640e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -131,7 +131,7 @@ function Set-PesterGitHubOutput { $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - $errorMessage = $failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown + $errorMessage = ($failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '_', '\_') -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown $testReference = '{0}:{1}' -f (Split-Path $errorTestFile -Leaf), $errorTestLine diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index e46c6fc17d..6b7c50807b 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1162,7 +1162,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + ($testFileContent | Out-String) | Should -Match "metadata name = .+" -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { @@ -1170,7 +1170,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + ($testFileContent | Out-String) | Should -Match "metadata description = .+" -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { @@ -1179,8 +1179,8 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter [namePrefix] should have the expected description.' - (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' + ($testFileContent | Out-String) | Should -Match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)" -Because 'The parameter [namePrefix] should have the expected description.' + ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From f56f66af2a884495d5eeafb4f580d76960ee93f3 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:52:45 +0100 Subject: [PATCH 17/37] Removed assertion --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 6b7c50807b..b7c9ab905f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1179,7 +1179,6 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) - ($testFileContent | Out-String) | Should -Match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)" -Because 'The parameter [namePrefix] should have the expected description.' ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } From 282b640a884885ba59db841457ddfdc5ea1ec59e Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:58:17 +0100 Subject: [PATCH 18/37] Update to latest --- .../compliance/Set-PesterGitHubOutput.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index a8a773640e..d23f8d4f8f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -127,7 +127,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $failedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -173,7 +173,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $passedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $testLine = $passedTest.ScriptBlock.StartPosition.StartLine $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -218,7 +218,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $skippedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() @@ -265,7 +265,7 @@ function Set-PesterGitHubOutput { foreach ($warning in $test.StandardOutput.Warning) { $intermediateNameElements = $test.Path $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $testLine = $test.ScriptBlock.StartPosition.StartLine $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] From c025f526216b35a93c6ffee5dfe4beb3dc29cada Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 Nov 2023 07:32:30 +0100 Subject: [PATCH 19/37] Update avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index b7c9ab905f..cdd40eb5ed 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1131,7 +1131,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [max] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent From 405901aff9656cb669db03eb90cfb96f2fa13908 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 Nov 2023 07:33:08 +0100 Subject: [PATCH 20/37] Update avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index cdd40eb5ed..a2ac22d565 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1118,7 +1118,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [defaults] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent From ef24d1f1e65cad599a9f8eaf311a4aa41f1452db Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 9 Nov 2023 19:29:56 +0100 Subject: [PATCH 21/37] Rollback of unrelated changes --- .../compliance/Set-PesterGitHubOutput.ps1 | 71 +---- .../compliance/module.tests.ps1 | 291 +++--------------- 2 files changed, 45 insertions(+), 317 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index d23f8d4f8f..66561b92fe 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -81,12 +81,10 @@ function Set-PesterGitHubOutput { $passedTests = $PesterTestResults.Passed $failedTests = $PesterTestResults.Failed $skippedTests = $PesterTestResults.Skipped - $testsWithWarnings = ($passedTests + $failedTests + $skippedTests) | Where-Object { $_.StandardOutput.Keys -eq 'Warning' } Write-Verbose ('Formatting [{0}] passed tests' -f $passedTests.Count) Write-Verbose ('Formatting [{0}] failed tests' -f $failedTests.Count) Write-Verbose ('Formatting [{0}] skipped tests' -f $skippedTests.Count) - Write-Verbose ('Formatting [{0}] tests with explicit warnings' -f $warnings.Count) ###################### # Set output content # @@ -100,9 +98,9 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( - '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', - '| :-- | :-- | :-- | :-- | :-- |', - ('| {0} | {1} | {2} | {3} | {4} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), + '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: |', + '| :-- | :-- | :-- | :-- |' + ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count), '' ) @@ -127,11 +125,11 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $failedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - $errorMessage = ($failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '_', '\_') -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown + $errorMessage = $failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown $testReference = '{0}:{1}' -f (Split-Path $errorTestFile -Leaf), $errorTestLine @@ -173,7 +171,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $passedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $testLine = $passedTest.ScriptBlock.StartPosition.StartLine $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -218,12 +216,12 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $skippedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() - $testLine = $skippedTest.ScriptBlock.StartPosition.StartLine - $testFile = (($skippedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + $testLine = $passedTest.ScriptBlock.StartPosition.StartLine + $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { @@ -243,57 +241,8 @@ function Set-PesterGitHubOutput { '' ) - ################## - ## Warnings ## - ################## - - Write-Verbose 'Adding warnings' - $fileContent += [System.Collections.ArrayList]@( - '', - '
', - 'List of explicit warnings', - '' - ) - - if ($testsWithWarnings.Count -gt 0) { - - $fileContent += [System.Collections.ArrayList]@( - '| Name | Warning | Source |', - '| :-- | :-- | :-- |' - ) - foreach ($test in ($testsWithWarnings | Sort-Object -Property { $PSItem.ExpandedName }) ) { - foreach ($warning in $test.StandardOutput.Warning) { - $intermediateNameElements = $test.Path - $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() - - $testLine = $test.ScriptBlock.StartPosition.StartLine - $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - - $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine - if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { - # Creating URL to test file to enable users to 'click' on it - $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" - } - - $fileContent += ('| {0} | {1} | {2} |' -f $testName, $warning, $testReference) - } - } - } else { - $fileContent += ('No tests with warnings.') - } - - $fileContent += [System.Collections.ArrayList]@( - '', - '
', - '' - ) - - - - if ($PSCmdlet.ShouldProcess("Test results file in path [$OutputFilePath]", 'Create')) { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } Write-Verbose "Create results file [$outputFilePath]" -} +} \ No newline at end of file diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index a2ac22d565..d975dea940 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -3,7 +3,7 @@ param ( [Parameter(Mandatory = $false)] [array] $moduleFolderPaths = ((Get-ChildItem $repoRootPath -Recurse -Directory -Force).FullName | Where-Object { - (Get-ChildItem $_ -File -Depth 0 -Include @('main.bicep') -Force).Count -gt 0 + (Get-ChildItem $_ -File -Depth 0 -Include @('main.json', 'main.bicep') -Force).Count -gt 0 }), [Parameter(Mandatory = $false)] @@ -27,6 +27,7 @@ $script:convertedTemplates = @{} # Shared exception messages $script:bicepTemplateCompilationFailedException = "Unable to compile the main.bicep template's content. This can happen if there is an error in the template. Please check if you can run the command ``bicep build {0} --stdout | ConvertFrom-Json -AsHashtable``." # -f $templateFilePath +$script:jsonTemplateLoadFailedException = "Unable to load the main.json template's content. This can happen if there is an error in the template. Please check if you can run the command `Get-Content {0} -Raw | ConvertFrom-Json -AsHashtable`." # -f $templateFilePath $script:templateNotFoundException = 'No template file found in folder [{0}]' # -f $moduleFolderPath # Import any helper function used in this test script @@ -202,6 +203,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -331,6 +339,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -820,6 +835,7 @@ Describe 'Module tests' -Tag 'Module' { $incorrectOutputs | Should -BeNullOrEmpty } + # Update to work with nullable parameters It '[] All non-required parameters in template file should not have description that start with "Required.".' -TestCases $deploymentFolderTestCases { param ( [hashtable[]] $testFileTestCases, @@ -858,6 +874,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -907,184 +930,6 @@ Describe 'Module tests' -Tag 'Module' { $templateFileContent.metadata.owner | Should -Not -BeNullOrEmpty } } - - Context 'User-defined-types tests' -Tag 'UDT' { - - $udtTestCases = [System.Collections.ArrayList] @() # General UDT tests (e.g. param should exist) - $udtSpecificTestCases = [System.Collections.ArrayList] @() # Specific UDT test cases for singular UDTs (e.g. tags) - foreach ($moduleFolderPath in $moduleFolderPaths) { - - $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// - - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent - templateFilePath = $templateFilePath - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } - - $udtSpecificTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - templateFileContentBicep = Get-Content $templateFilePath - } - - # Setting expected URL only for those that doen't have multiple different variants - $avmInterfaceSpecsTemplateBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' - $avmInterfaceSpecsBase = 'https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces' - $udtCases = @( - @{ - parameterName = 'diagnosticSettings' - udtName = 'diagnosticSettingType' - link = "$avmInterfaceSpecsBase#diagnostic-settings" - } - @{ - parameterName = 'roleAssignments' - udtName = 'roleAssignmentType' - udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.rbac.udt.schema.bicep" - link = "$avmInterfaceSpecsBase#role-assignments" - } - @{ - parameterName = 'lock' - udtName = 'lockType' - udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.locks.udt.schema.bicep" - link = "$avmInterfaceSpecsBase#resource-locks" - } - @{ - parameterName = 'managedIdentities' - udtName = 'managedIdentitiesType' - link = "$avmInterfaceSpecsBase#managed-identities" - } - @{ - parameterName = 'privateEndpoints' - udtName = 'privateEndpointType' - link = "$avmInterfaceSpecsBase#private-endpoints" - } - @{ - parameterName = 'customerManagedKey' - udtName = 'customerManagedKeyType' - link = "$avmInterfaceSpecsBase#customer-managed-keys" - } - ) - - foreach ($udtCase in $udtCases) { - $udtTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - templateFileContentBicep = Get-Content $templateFilePath - parameterName = $udtCase.parameterName - udtName = $udtCase.udtName - expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' - link = $udtCase.link - } - } - } - - - It "[] If template has a parameter [], it should implement the user-defined type []" -TestCases $udtTestCases { - - param( - [hashtable] $templateFileContent, - [string[]] $templateFileContentBicep, - [string] $parameterName, - [string] $udtName, - [string] $expectedUdtUrl, - [string] $link - ) - - if ($templateFileContent.parameters.Keys -contains $parameterName) { - $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For for information please review the [AVM Specs]($link)." - $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]. For for information please review the [AVM Specs]($link)." - - if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { - $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") - $implementedSchemaEndIndex = $implementedSchemaStartIndex + 1 - while ($templateFileContentBicep[$implementedSchemaEndIndex] -notmatch '^\}.*' -and $implementedSchemaEndIndex -lt $templateFileContentBicep.Length) { - $implementedSchemaEndIndex++ - } - if ($implementedSchemaEndIndex -eq $templateFileContentBicep.Length) { - throw "Failed to identify [$udtName] user-defined type in template." - } - $implementedSchema = $templateFileContentBicep[$implementedSchemaStartIndex..$implementedSchemaEndIndex] - - $expectedSchemaFull = (Invoke-WebRequest -Uri $expectedUdtUrl).Content -split "\n" - $expectedSchemaStartIndex = $expectedSchemaFull.IndexOf("type $udtName = {") - $expectedSchemaEndIndex = $expectedSchemaStartIndex + 1 - while ($expectedSchemaFull[$expectedSchemaEndIndex] -notmatch '^\}.*' -and $expectedSchemaEndIndex -lt $expectedSchemaFull.Length) { - $expectedSchemaEndIndex++ - } - if ($expectedSchemaEndIndex -eq $expectedSchemaFull.Length) { - throw "Failed to identify [$udtName] user-defined type in expected schema at URL [$expectedUdtUrl]." - } - $expectedSchema = $expectedSchemaFull[$expectedSchemaStartIndex..$expectedSchemaEndIndex] - - $formattedDiff = @() - foreach ($finding in (Compare-Object $implementedSchema $expectedSchema)) { - if ($finding.SideIndicator -eq '=>') { - $formattedDiff += ('+ {0}' -f $finding.InputObject) - } elseif ($finding.SideIndicator -eq '<=') { - $formattedDiff += ('- {0}' -f $finding.InputObject) - } - } - - if ($formattedDiff.Count -gt 0) { - $warningMessage = "The implemented user-defined type is not the same as the expected user-defined type ({0}) defined in the AVM specs ({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) - Write-Warning $warningMessage - - # Adding also to output to show in GitHub CI - $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' - $mdFormattedWarningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff
{2}
" -f $expectedUdtUrl, $link, $mdFormattedDiff - Write-Output @{ - Warning = $mdFormattedWarningMessage - } - } - } - } else { - Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." - } - } - - It "[] If a UDT definition [managedIdentitiesType] exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { - - param( - [hashtable] $templateFileContent - ) - - if ($templateFileContent.definitions.Keys -contains 'managedIdentitiesType' -and $templateFileContent.definitions.managedIdentitiesType.properties.keys -contains 'systemAssigned') { - $templateFileContent.outputs.Keys | Should -Contain 'systemAssignedMIPrincipalId' -Because 'The AVM specs require a this output. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#managed-identities).' - } else { - Set-ItResult -Skipped -Because "the module template has no [managedIdentitiesType] UDT definition or does not support system-assigned-identities." - } - } - - It "[] If a parameter [tags] exists it should be nullable." -TestCases $udtSpecificTestCases { - - param( - [hashtable] $templateFileContent - ) - - if ($templateFileContent.parameters.Keys -contains 'tags') { - $templateFileContent.parameters.tags.nullable | Should -Be $true -Because 'The AVM specs require a specific format. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#tags).' - } else { - Set-ItResult -Skipped -Because "the module template has no [tags] parameter." - } - } - } } Describe 'Test file tests' -Tag 'TestTemplate' { @@ -1101,7 +946,6 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// $deploymentTestFileTestCases += @{ - testName = Split-Path (Split-Path $testFilePath) -Leaf testFilePath = $testFilePath testFileContent = $testFileContent moduleFolderName = $resourceTypeIdentifier @@ -1110,79 +954,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files should contain a parameter [serviceShort]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' - } - - It "[] [] Bicep test deployment files in a [defaults] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*min" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*min''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files in a [max] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*max" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*max''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*waf" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files should contain a metadata string [name]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent | Out-String) | Should -Match "metadata name = .+" -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' - } - - It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent | Out-String) | Should -Match "metadata description = .+" -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' - } - - It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - - ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' - } - - It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1193,7 +965,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $testIndex -ne -1 | Should -Be $true -Because 'the module test invocation should be in the expected format to allow identification.' } - It '[] [] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { + It '[] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1204,7 +976,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $expectedNameFormat | Should -Be $true -Because 'the handle ''-test-'' should be part of the module test invocation''s resource name to allow identification.' } - It '[] [] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { + It '[] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1245,6 +1017,13 @@ Describe 'API version tests' -Tag 'ApiCheck' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -1389,4 +1168,4 @@ Describe 'API version tests' -Tag 'ApiCheck' { } } } -} +} \ No newline at end of file From 31213359a56dd36e38e4afc6b6a9537f9534ee16 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 14 Nov 2023 09:43:39 +0100 Subject: [PATCH 22/37] Update to latest --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index 3563bc5f4f..38f43808ee 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -293,4 +293,4 @@ function Set-PesterGitHubOutput { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } Write-Verbose "Create results file [$outputFilePath]" -} \ No newline at end of file +} From 09b3be5f436100a6120309c52c3f0b88737fca4c Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 12:45:54 +0100 Subject: [PATCH 23/37] Added post-validation for publishing --- .../templates/avm-publishModule/action.yml | 23 +++++- .../publish/Confirm-ModuleIsPublished.ps1 | 74 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index 2aa36f1dcf..f5576166b5 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -72,4 +72,25 @@ runs: Write-Output '::endgroup::' - # TODO Add publish validation (as per PBR pipeline template 'publish-module.yml') + - name: "Validate publish" + uses: azure/powershell@v1 + with: + azPSVersion: "latest" + inlineScript: | + # Grouping task logs + Write-Output '::group::Validate publish' + + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Confirm-ModuleIsPublished.ps1') + + $functionInput = @{ + $Version = "${{ steps.parse-tag.outputs.version }}" + $ModulePath = "${{ steps.parse-tag.outputs.module_path }}" + } + + Write-Verbose "Invoke function with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + Confirm-ModuleIsPublished @functionInput -Verbose + + Write-Output '::endgroup::' diff --git a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 new file mode 100644 index 0000000000..2b1fa55d5b --- /dev/null +++ b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 @@ -0,0 +1,74 @@ +<# +.SYNOPSIS +Check if a module in a given path is published in a given version + +.DESCRIPTION +Check if a module in a given path is published in a given version. Tries to find the module for a maximum of 6 minutes. + +.PARAMETER Version +Mandatory. The version of the module to check for. For example: '0.2.0' + +.PARAMETER ModulePath +Mandatory. The path of the module to check for. For example: 'avm/res/key-vault/vault' + +.EXAMPLE +Confirm-ModuleIsPublished -Version '0.2.0' -ModulePath 'avm/res/key-vault/vault' -Verbose + +Check if module 'key-vault/vault' has been published with version '0.2.0 +#> +function Confirm-ModuleIsPublished { + + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string] $Version, + + [Parameter(Mandatory)] + [string] $ModulePath + ) + + $catalogUrl = 'https://mcr.microsoft.com/v2/_catalog' + $time_limit_seconds = 3600 + $end_time = (Get-Date).AddSeconds($time_limit_seconds) + $retry_seconds = 5 + + + while ($true) { + $catalogContentRaw = (Invoke-WebRequest -Uri $catalogUrl -UseBasicParsing).Content + $bicepCatalogContent = ($catalogContentRaw | ConvertFrom-Json).repositories | Select-String 'bicep/' + Write-Verbose ("Bicep modules found in MCR catalog:`n{0}" -f ($bicepCatalogContent | Out-String)) + + if ($bicepCatalogContent -match "bicep/$ModulePath") { + Write-Verbose "Passed: Found module [$ModulePath] in the MCR catalog" -Verbose + break + } else { + Write-Error "Error: Module [$ModulePath] is not in the MCR catalog. Retrying in [$retry_seconds] seconds" + Start-Sleep -Seconds $retry_seconds + } + + if ((Get-Date) -ge $end_time) { + throw "Time limit reached. Failed to validate publish of module in path [$ModulePath] within the specified time." + } + } + + while ($true) { + $existingTagsUrl = "https://mcr.microsoft.com/v2/bicep/$ModulePath/tags/list" + $tagsContentRaw = (Invoke-WebRequest -Uri $existingTagsUrl -UseBasicParsing).Content + $tagsContent = ($tagsContentRaw | ConvertFrom-Json).tags + + Write-Verbose ("Tags for module in path [$ModulePath] found in MCR catalog:`n{0}" -f ($tagsContent | Out-String)) + + if ($tagsContent -match $Version) { + Write-Host "Passed: Found new tag [$Version] for published module" + break + } else { + Write-Host "Error: Could not find new tag [$Version] for published module. Retrying in [$retry_seconds] seconds" + Start-Sleep -Seconds $retry_seconds + } + + if ((Get-Date) -ge $end_time) { + Write-Host 'Time limit reached. Failed to validate publish within the specified time.' + exit 1 + } + } +} From 702572878fe2a3f93b1b4810d91a3460bc4bb474 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:16:47 +0100 Subject: [PATCH 24/37] Enabled publish test --- .../templates/avm-publishModule/action.yml | 11 +++++--- .github/workflows/avm.template.module.yml | 2 +- .../publish/Publish-ModuleFromPathToPBR.ps1 | 26 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index f5576166b5..c8732312ae 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -46,6 +46,7 @@ runs: bicep --version - name: "Publish module to public bicep registry" + id: publish_step uses: azure/powershell@v1 with: azPSVersion: "latest" @@ -68,12 +69,16 @@ runs: Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose # Get the modified child resources - Publish-ModuleFromPathToPBR @functionInput -Verbose + if($publishOutputs = Publish-ModuleFromPathToPBR @functionInput -Verbose) { + Write-Output ('{0}={1}' -f 'version', $publishOutputs.version) >> $env:GITHUB_OUTPUT + Write-Output ('{0}={1}' -f 'module_path', $publishOutputs.module_path) >> $env:GITHUB_OUTPUT + } Write-Output '::endgroup::' - name: "Validate publish" uses: azure/powershell@v1 + if: ${{ steps.publish_step.outputs.version != '' && steps.publish_step.outputs.module_path != '' }} with: azPSVersion: "latest" inlineScript: | @@ -84,8 +89,8 @@ runs: . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Confirm-ModuleIsPublished.ps1') $functionInput = @{ - $Version = "${{ steps.parse-tag.outputs.version }}" - $ModulePath = "${{ steps.parse-tag.outputs.module_path }}" + $Version = "${{ steps.publish_step.outputs.version }}" + $ModulePath = "${{ steps.publish_step.outputs.module_path }}" } Write-Verbose "Invoke function with" -Verbose diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index aa7095244a..9afb9cd225 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -112,7 +112,7 @@ jobs: job_publish_module: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. name: "Publishing" runs-on: ubuntu-20.04 - if: github.ref == 'refs/heads/main' && success() + # if: github.ref == 'refs/heads/main' && success() needs: - job_module_deploy_validation steps: diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index 1f5fc4a5c0..4ea5b8ed0a 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -41,18 +41,23 @@ function Publish-ModuleFromPathToPBR { $moduleFolderPath = Split-Path $TemplateFilePath -Parent $moduleJsonFilePath = Join-Path $moduleFolderPath 'main.json' - # 1. Test if module qualifies for publishing - if (-not (Get-ModulesToPublish -ModuleFolderPath $moduleFolderPath)) { - Write-Verbose "No changes detected. Skipping publishing" -Verbose - return - } - - # 2. Calculate the version that we would publish with + # 1. Calculate the version that we would publish with $targetVersion = Get-ModuleTargetVersion -ModuleFolderPath $moduleFolderPath - # 3. Get Target Published Module Name + # 2. Get Target Published Module Name $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath + # 3. Test if module qualifies for publishing + if (-not (Get-ModulesToPublish -ModuleFolderPath $moduleFolderPath)) { + Write-Verbose "No changes detected. Skipping publishing" -Verbose + + # TODO: Create output with previous version? + return @{ + version = $targetVersion + module_path = $publishedModuleName + } + } + # 4.Create release tag $tagName = New-ModuleReleaseTag -ModuleFolderPath $moduleFolderPath -TargetVersion $targetVersion @@ -96,4 +101,9 @@ function Publish-ModuleFromPathToPBR { Write-Verbose "Publish Input:`n $($publishInput | ConvertTo-Json -Depth 10)" -Verbose bicep publish @publishInput + + return @{ + version = $targetVersion + module_path = $publishedModuleName + } } From 1bb25d3f91bcae87456679e23c200b32795a8d01 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:17:29 +0100 Subject: [PATCH 25/37] Disabled pipeline steps for testing --- .github/workflows/avm.template.module.yml | 150 +++++++++++----------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index 9afb9cd225..79d5162a99 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -30,81 +30,81 @@ jobs: ######################### # Static validation # ######################### - job_module_static_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - name: "Static validation" - runs-on: ubuntu-20.04 - if: (fromJson(inputs.workflowInput)).staticValidation == 'true' - steps: - - name: "Checkout" - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set environment - uses: ./.github/actions/templates/avm-setEnvironment - - name: "Run tests" - uses: ./.github/actions/templates/avm-validateModulePester - with: - modulePath: "${{ inputs.modulePath }}" + # job_module_static_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + # name: "Static validation" + # runs-on: ubuntu-20.04 + # if: (fromJson(inputs.workflowInput)).staticValidation == 'true' + # steps: + # - name: "Checkout" + # uses: actions/checkout@v4 + # with: + # fetch-depth: 0 + # - name: Set environment + # uses: ./.github/actions/templates/avm-setEnvironment + # - name: "Run tests" + # uses: ./.github/actions/templates/avm-validateModulePester + # with: + # modulePath: "${{ inputs.modulePath }}" - ######################### - # PSRule validation # - ######################### - job_psrule_test: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - name: "PSRule validation" - runs-on: ubuntu-20.04 - if: (fromJson(inputs.workflowInput)).staticValidation == 'true' - strategy: - fail-fast: false - matrix: - moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set environment - uses: ./.github/actions/templates/avm-setEnvironment - - name: Set PSRule validation - uses: ./.github/actions/templates/avm-validateModulePSRule - with: - templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" - subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" - managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" - psrulePath: "avm/utilities/pipelines/staticValidation/psrule" #'${{ github.workspace }}/avm' + # ######################### + # # PSRule validation # + # ######################### + # job_psrule_test: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + # name: "PSRule validation" + # runs-on: ubuntu-20.04 + # if: (fromJson(inputs.workflowInput)).staticValidation == 'true' + # strategy: + # fail-fast: false + # matrix: + # moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + # - name: Set environment + # uses: ./.github/actions/templates/avm-setEnvironment + # - name: Set PSRule validation + # uses: ./.github/actions/templates/avm-validateModulePSRule + # with: + # templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" + # subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" + # managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" + # psrulePath: "avm/utilities/pipelines/staticValidation/psrule" #'${{ github.workspace }}/avm' - ############################# - # Deployment validation # - ############################# - job_module_deploy_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - name: "Deployment validation" - runs-on: ubuntu-20.04 - if: | - !cancelled() && - (fromJson(inputs.workflowInput)).deploymentValidation == 'true' && needs.job_module_static_validation.result != 'failure' - needs: - - job_module_static_validation - # - job_psrule_test # Ignoring dependency whilst PSRule gets bedded in, in this project - strategy: - fail-fast: false - matrix: - moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} - steps: - - name: "Checkout" - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set environment - uses: ./.github/actions/templates/avm-setEnvironment - with: - removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" - - name: "Using test file [${{ matrix.moduleTestFilePaths }}]" - uses: ./.github/actions/templates/avm-validateModuleDeployment - with: - templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" - location: "WestEurope" - subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" - managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" - removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + # ############################# + # # Deployment validation # + # ############################# + # job_module_deploy_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + # name: "Deployment validation" + # runs-on: ubuntu-20.04 + # if: | + # !cancelled() && + # (fromJson(inputs.workflowInput)).deploymentValidation == 'true' && needs.job_module_static_validation.result != 'failure' + # needs: + # - job_module_static_validation + # # - job_psrule_test # Ignoring dependency whilst PSRule gets bedded in, in this project + # strategy: + # fail-fast: false + # matrix: + # moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} + # steps: + # - name: "Checkout" + # uses: actions/checkout@v4 + # with: + # fetch-depth: 0 + # - name: Set environment + # uses: ./.github/actions/templates/avm-setEnvironment + # with: + # removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" + # - name: "Using test file [${{ matrix.moduleTestFilePaths }}]" + # uses: ./.github/actions/templates/avm-validateModuleDeployment + # with: + # templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" + # location: "WestEurope" + # subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" + # managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" + # removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" + # env: + # AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} ################## # Publishing # @@ -113,8 +113,8 @@ jobs: name: "Publishing" runs-on: ubuntu-20.04 # if: github.ref == 'refs/heads/main' && success() - needs: - - job_module_deploy_validation + # needs: + # - job_module_deploy_validation steps: - name: "Checkout" uses: actions/checkout@v4 From 9aca8ca5b4ed0eac95c133d8c24492c78248024c Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:24:11 +0100 Subject: [PATCH 26/37] Shuffled steps --- .../publish/Publish-ModuleFromPathToPBR.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index 4ea5b8ed0a..a9033c3754 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -41,23 +41,23 @@ function Publish-ModuleFromPathToPBR { $moduleFolderPath = Split-Path $TemplateFilePath -Parent $moduleJsonFilePath = Join-Path $moduleFolderPath 'main.json' - # 1. Calculate the version that we would publish with - $targetVersion = Get-ModuleTargetVersion -ModuleFolderPath $moduleFolderPath - - # 2. Get Target Published Module Name + # 1. Get Target Published Module Name $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath - # 3. Test if module qualifies for publishing + # 2. Test if module qualifies for publishing if (-not (Get-ModulesToPublish -ModuleFolderPath $moduleFolderPath)) { Write-Verbose "No changes detected. Skipping publishing" -Verbose # TODO: Create output with previous version? return @{ - version = $targetVersion + version = (Get-Content (Join-Path (Split-Path $TemplateFilePath) 'version.json')) | ConvertFrom-Json | Select-Object -ExpandProperty 'version' module_path = $publishedModuleName } } + # 3. Calculate the version that we would publish with + $targetVersion = Get-ModuleTargetVersion -ModuleFolderPath $moduleFolderPath + # 4.Create release tag $tagName = New-ModuleReleaseTag -ModuleFolderPath $moduleFolderPath -TargetVersion $targetVersion From 7856aec83ca1ebe6b37f9be11d59a82e9726190f Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:24:47 +0100 Subject: [PATCH 27/37] Disabled additional steps --- .../templates/avm-publishModule/action.yml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index c8732312ae..e4b3dd0f53 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -28,22 +28,22 @@ inputs: runs: using: "composite" steps: - - name: Log in to Azure - uses: azure/login@v1 - with: - client-id: ${{ env.PUBLISH_CLIENT_ID }} - tenant-id: ${{ env.PUBLISH_TENANT_ID }} - subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} + # - name: Log in to Azure + # uses: azure/login@v1 + # with: + # client-id: ${{ env.PUBLISH_CLIENT_ID }} + # tenant-id: ${{ env.PUBLISH_TENANT_ID }} + # subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - shell: bash - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version + # # Adding a step to explicitly install the latest Bicep CLI because there is + # # always a delay in updating Bicep CLI in the job runner environments. + # - name: Install the latest Bicep CLI + # shell: bash + # run: | + # curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + # chmod +x ./bicep + # sudo mv ./bicep /usr/local/bin/bicep + # bicep --version - name: "Publish module to public bicep registry" id: publish_step From d078a040a4ed0d88f0badc15a22cce91799c8d90 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:27:40 +0100 Subject: [PATCH 28/37] Update to latest --- avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 b/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 index 4c503b3809..14e1a1401e 100644 --- a/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 +++ b/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 @@ -21,7 +21,7 @@ function Get-ModifiedFileList { Write-Verbose 'Gathering modified files from the previous head' -Verbose $Diff = git diff --name-only --diff-filter=AM HEAD^ HEAD } - $ModifiedFiles = $Diff | Get-Item -Force + $ModifiedFiles = $Diff ? ($Diff | Get-Item -Force) : @() return $ModifiedFiles } From d66562252960ee03b701647dddfd77763f2d2a31 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 16:36:50 +0100 Subject: [PATCH 29/37] Update to latest --- .github/actions/templates/avm-publishModule/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index e4b3dd0f53..57c32be758 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -89,8 +89,8 @@ runs: . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Confirm-ModuleIsPublished.ps1') $functionInput = @{ - $Version = "${{ steps.publish_step.outputs.version }}" - $ModulePath = "${{ steps.publish_step.outputs.module_path }}" + Version = "${{ steps.publish_step.outputs.version }}" + ModulePath = "${{ steps.publish_step.outputs.module_path }}" } Write-Verbose "Invoke function with" -Verbose From 24a7a9a4ec4c68f2f76271911d6607111eae4888 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 22:30:50 +0100 Subject: [PATCH 30/37] undid temp test changes --- .github/workflows/avm.template.module.yml | 152 +++++++++--------- .../publish/Publish-ModuleFromPathToPBR.ps1 | 15 +- 2 files changed, 81 insertions(+), 86 deletions(-) diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index 79d5162a99..aa7095244a 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -30,81 +30,81 @@ jobs: ######################### # Static validation # ######################### - # job_module_static_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - # name: "Static validation" - # runs-on: ubuntu-20.04 - # if: (fromJson(inputs.workflowInput)).staticValidation == 'true' - # steps: - # - name: "Checkout" - # uses: actions/checkout@v4 - # with: - # fetch-depth: 0 - # - name: Set environment - # uses: ./.github/actions/templates/avm-setEnvironment - # - name: "Run tests" - # uses: ./.github/actions/templates/avm-validateModulePester - # with: - # modulePath: "${{ inputs.modulePath }}" + job_module_static_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + name: "Static validation" + runs-on: ubuntu-20.04 + if: (fromJson(inputs.workflowInput)).staticValidation == 'true' + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set environment + uses: ./.github/actions/templates/avm-setEnvironment + - name: "Run tests" + uses: ./.github/actions/templates/avm-validateModulePester + with: + modulePath: "${{ inputs.modulePath }}" - # ######################### - # # PSRule validation # - # ######################### - # job_psrule_test: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - # name: "PSRule validation" - # runs-on: ubuntu-20.04 - # if: (fromJson(inputs.workflowInput)).staticValidation == 'true' - # strategy: - # fail-fast: false - # matrix: - # moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - # - name: Set environment - # uses: ./.github/actions/templates/avm-setEnvironment - # - name: Set PSRule validation - # uses: ./.github/actions/templates/avm-validateModulePSRule - # with: - # templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" - # subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" - # managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" - # psrulePath: "avm/utilities/pipelines/staticValidation/psrule" #'${{ github.workspace }}/avm' + ######################### + # PSRule validation # + ######################### + job_psrule_test: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + name: "PSRule validation" + runs-on: ubuntu-20.04 + if: (fromJson(inputs.workflowInput)).staticValidation == 'true' + strategy: + fail-fast: false + matrix: + moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set environment + uses: ./.github/actions/templates/avm-setEnvironment + - name: Set PSRule validation + uses: ./.github/actions/templates/avm-validateModulePSRule + with: + templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" + subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" + managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" + psrulePath: "avm/utilities/pipelines/staticValidation/psrule" #'${{ github.workspace }}/avm' - # ############################# - # # Deployment validation # - # ############################# - # job_module_deploy_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. - # name: "Deployment validation" - # runs-on: ubuntu-20.04 - # if: | - # !cancelled() && - # (fromJson(inputs.workflowInput)).deploymentValidation == 'true' && needs.job_module_static_validation.result != 'failure' - # needs: - # - job_module_static_validation - # # - job_psrule_test # Ignoring dependency whilst PSRule gets bedded in, in this project - # strategy: - # fail-fast: false - # matrix: - # moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} - # steps: - # - name: "Checkout" - # uses: actions/checkout@v4 - # with: - # fetch-depth: 0 - # - name: Set environment - # uses: ./.github/actions/templates/avm-setEnvironment - # with: - # removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" - # - name: "Using test file [${{ matrix.moduleTestFilePaths }}]" - # uses: ./.github/actions/templates/avm-validateModuleDeployment - # with: - # templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" - # location: "WestEurope" - # subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" - # managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" - # removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" - # env: - # AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ############################# + # Deployment validation # + ############################# + job_module_deploy_validation: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. + name: "Deployment validation" + runs-on: ubuntu-20.04 + if: | + !cancelled() && + (fromJson(inputs.workflowInput)).deploymentValidation == 'true' && needs.job_module_static_validation.result != 'failure' + needs: + - job_module_static_validation + # - job_psrule_test # Ignoring dependency whilst PSRule gets bedded in, in this project + strategy: + fail-fast: false + matrix: + moduleTestFilePaths: ${{ fromJson(inputs.moduleTestFilePaths) }} + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set environment + uses: ./.github/actions/templates/avm-setEnvironment + with: + removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" + - name: "Using test file [${{ matrix.moduleTestFilePaths }}]" + uses: ./.github/actions/templates/avm-validateModuleDeployment + with: + templateFilePath: "${{ inputs.modulePath }}/${{ matrix.moduleTestFilePaths }}" + location: "WestEurope" + subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" + managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" + removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} ################## # Publishing # @@ -112,9 +112,9 @@ jobs: job_publish_module: # Note: Please don't change this job name. It is used by the setEnvironment action to define which PS modules to install on runners. name: "Publishing" runs-on: ubuntu-20.04 - # if: github.ref == 'refs/heads/main' && success() - # needs: - # - job_module_deploy_validation + if: github.ref == 'refs/heads/main' && success() + needs: + - job_module_deploy_validation steps: - name: "Checkout" uses: actions/checkout@v4 diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index a9033c3754..e53f0d79d1 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -41,20 +41,15 @@ function Publish-ModuleFromPathToPBR { $moduleFolderPath = Split-Path $TemplateFilePath -Parent $moduleJsonFilePath = Join-Path $moduleFolderPath 'main.json' - # 1. Get Target Published Module Name - $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath - - # 2. Test if module qualifies for publishing + # 1. Test if module qualifies for publishing if (-not (Get-ModulesToPublish -ModuleFolderPath $moduleFolderPath)) { Write-Verbose "No changes detected. Skipping publishing" -Verbose - - # TODO: Create output with previous version? - return @{ - version = (Get-Content (Join-Path (Split-Path $TemplateFilePath) 'version.json')) | ConvertFrom-Json | Select-Object -ExpandProperty 'version' - module_path = $publishedModuleName - } + return } + # 2. Get Target Published Module Name + $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath + # 3. Calculate the version that we would publish with $targetVersion = Get-ModuleTargetVersion -ModuleFolderPath $moduleFolderPath From 4b88eb0d9bdebe77edcb1af870af42909f3e298c Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 22:32:04 +0100 Subject: [PATCH 31/37] Update to latest --- .../templates/avm-publishModule/action.yml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index 57c32be758..6587602ef9 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -28,22 +28,22 @@ inputs: runs: using: "composite" steps: - # - name: Log in to Azure - # uses: azure/login@v1 - # with: - # client-id: ${{ env.PUBLISH_CLIENT_ID }} - # tenant-id: ${{ env.PUBLISH_TENANT_ID }} - # subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} + - name: Log in to Azure + uses: azure/login@v1 + with: + client-id: ${{ env.PUBLISH_CLIENT_ID }} + tenant-id: ${{ env.PUBLISH_TENANT_ID }} + subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} - # # Adding a step to explicitly install the latest Bicep CLI because there is - # # always a delay in updating Bicep CLI in the job runner environments. - # - name: Install the latest Bicep CLI - # shell: bash - # run: | - # curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - # chmod +x ./bicep - # sudo mv ./bicep /usr/local/bin/bicep - # bicep --version + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + shell: bash + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version - name: "Publish module to public bicep registry" id: publish_step From 3abc1a3d887bb7dfabfccd9b5cc90cc140b248ad Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 24 Nov 2023 22:32:54 +0100 Subject: [PATCH 32/37] Update to latest --- .../pipelines/publish/Publish-ModuleFromPathToPBR.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index e53f0d79d1..0d6d4297a6 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -47,12 +47,12 @@ function Publish-ModuleFromPathToPBR { return } - # 2. Get Target Published Module Name - $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath - - # 3. Calculate the version that we would publish with + # 2. Calculate the version that we would publish with $targetVersion = Get-ModuleTargetVersion -ModuleFolderPath $moduleFolderPath + # 3. Get Target Published Module Name + $publishedModuleName = Get-BRMRepositoryName -TemplateFilePath $TemplateFilePath + # 4.Create release tag $tagName = New-ModuleReleaseTag -ModuleFolderPath $moduleFolderPath -TargetVersion $targetVersion From 3d4f5c6bef1e492cd25a6d0c334088ab8afa49b7 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sun, 26 Nov 2023 11:18:23 +0100 Subject: [PATCH 33/37] Added pipeline to main for testing --- .../workflows/avm.platform.publish.tag.yml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/avm.platform.publish.tag.yml diff --git a/.github/workflows/avm.platform.publish.tag.yml b/.github/workflows/avm.platform.publish.tag.yml new file mode 100644 index 0000000000..e81a3c1c78 --- /dev/null +++ b/.github/workflows/avm.platform.publish.tag.yml @@ -0,0 +1,63 @@ +name: "Publish AVM module with tag" + +on: + workflow_dispatch: + inputs: + tag: + description: "The git tag of the module to publish." + required: true + type: string + +permissions: + id-token: write + contents: read + +jobs: + job_publish_module_with_tag: + runs-on: ubuntu-latest + name: "Publish module with tag" + steps: + - name: Checkout tag + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.tag }} + + - name: Log in to Azure + uses: azure/login@v1 + with: + client-id: ${{ env.PUBLISH_CLIENT_ID }} + tenant-id: ${{ env.PUBLISH_TENANT_ID }} + subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} + + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + shell: bash + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version + + - name: "Publish tagged module to public bicep registry" + uses: azure/powershell@v1 + with: + azPSVersion: "latest" + inlineScript: | + # Grouping task logs + Write-Output '::group::Publish tagged module to public bicep registry' + + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Publish-ModuleFromTagToPBR.ps1') + + $functionInput = @{ + ModuleReleaseTagName = '${{ github.event.inputs.tag }}' + PublicRegistryServer = ConvertTo-SecureString '${{ env.PUBLISH_REGISTRY_SERVER }}' -AsPlainText -Force + } + + Write-Verbose "Invoke function with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + Publish-ModuleFromTagToPBR @functionInput -Verbose + + Write-Output '::endgroup::' \ No newline at end of file From 768158f6666de119f132b9c4cc755755b33dd6d4 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 1 Dec 2023 17:09:53 +0100 Subject: [PATCH 34/37] Centralized urls --- .../pipelines/publish/Confirm-ModuleIsPublished.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 index 2b1fa55d5b..95d2643fd9 100644 --- a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 +++ b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 @@ -27,7 +27,10 @@ function Confirm-ModuleIsPublished { [string] $ModulePath ) - $catalogUrl = 'https://mcr.microsoft.com/v2/_catalog' + $baseUrl = 'https://mcr.microsoft.com/v2' + $catalogUrl = "$baseUrl/_catalog" + $moduleVersionsUrl = "$baseUrl/bicep/$ModulePath/tags/list" + $time_limit_seconds = 3600 $end_time = (Get-Date).AddSeconds($time_limit_seconds) $retry_seconds = 5 @@ -52,8 +55,7 @@ function Confirm-ModuleIsPublished { } while ($true) { - $existingTagsUrl = "https://mcr.microsoft.com/v2/bicep/$ModulePath/tags/list" - $tagsContentRaw = (Invoke-WebRequest -Uri $existingTagsUrl -UseBasicParsing).Content + $tagsContentRaw = (Invoke-WebRequest -Uri $moduleVersionsUrl -UseBasicParsing).Content $tagsContent = ($tagsContentRaw | ConvertFrom-Json).tags Write-Verbose ("Tags for module in path [$ModulePath] found in MCR catalog:`n{0}" -f ($tagsContent | Out-String)) From 50ec94e105a9ed341973097130ca4998c160a776 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 1 Dec 2023 17:10:48 +0100 Subject: [PATCH 35/37] Update to latest --- .../workflows/avm.platform.publish.tag.yml | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/avm.platform.publish.tag.yml diff --git a/.github/workflows/avm.platform.publish.tag.yml b/.github/workflows/avm.platform.publish.tag.yml deleted file mode 100644 index e81a3c1c78..0000000000 --- a/.github/workflows/avm.platform.publish.tag.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Publish AVM module with tag" - -on: - workflow_dispatch: - inputs: - tag: - description: "The git tag of the module to publish." - required: true - type: string - -permissions: - id-token: write - contents: read - -jobs: - job_publish_module_with_tag: - runs-on: ubuntu-latest - name: "Publish module with tag" - steps: - - name: Checkout tag - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.tag }} - - - name: Log in to Azure - uses: azure/login@v1 - with: - client-id: ${{ env.PUBLISH_CLIENT_ID }} - tenant-id: ${{ env.PUBLISH_TENANT_ID }} - subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} - - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - shell: bash - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version - - - name: "Publish tagged module to public bicep registry" - uses: azure/powershell@v1 - with: - azPSVersion: "latest" - inlineScript: | - # Grouping task logs - Write-Output '::group::Publish tagged module to public bicep registry' - - # Load used functions - . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Publish-ModuleFromTagToPBR.ps1') - - $functionInput = @{ - ModuleReleaseTagName = '${{ github.event.inputs.tag }}' - PublicRegistryServer = ConvertTo-SecureString '${{ env.PUBLISH_REGISTRY_SERVER }}' -AsPlainText -Force - } - - Write-Verbose "Invoke function with" -Verbose - Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose - - Publish-ModuleFromTagToPBR @functionInput -Verbose - - Write-Output '::endgroup::' \ No newline at end of file From a905528a19ae278fefafb1e8cfe47fcaca394e4c Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 1 Dec 2023 17:12:30 +0100 Subject: [PATCH 36/37] Update to latest --- .../pipelines/publish/Confirm-ModuleIsPublished.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 index 95d2643fd9..9a73565171 100644 --- a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 +++ b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 @@ -31,11 +31,13 @@ function Confirm-ModuleIsPublished { $catalogUrl = "$baseUrl/_catalog" $moduleVersionsUrl = "$baseUrl/bicep/$ModulePath/tags/list" - $time_limit_seconds = 3600 + $time_limit_seconds = 3600 # 1h $end_time = (Get-Date).AddSeconds($time_limit_seconds) $retry_seconds = 5 - + ##################################### + ## Confirm module is published ## + ##################################### while ($true) { $catalogContentRaw = (Invoke-WebRequest -Uri $catalogUrl -UseBasicParsing).Content $bicepCatalogContent = ($catalogContentRaw | ConvertFrom-Json).repositories | Select-String 'bicep/' @@ -54,6 +56,9 @@ function Confirm-ModuleIsPublished { } } + ############################################# + ## Confirm module version is published ## + ############################################# while ($true) { $tagsContentRaw = (Invoke-WebRequest -Uri $moduleVersionsUrl -UseBasicParsing).Content $tagsContent = ($tagsContentRaw | ConvertFrom-Json).tags From 18881b608b21012888c31042b43208cda124e3dc Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 2 Dec 2023 09:54:59 +0100 Subject: [PATCH 37/37] Addressed comments --- .../templates/avm-publishModule/action.yml | 8 ++++---- .../publish/Confirm-ModuleIsPublished.ps1 | 20 +++++++++---------- .../publish/Publish-ModuleFromPathToPBR.ps1 | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/actions/templates/avm-publishModule/action.yml b/.github/actions/templates/avm-publishModule/action.yml index 6587602ef9..a5c1ba60ac 100644 --- a/.github/actions/templates/avm-publishModule/action.yml +++ b/.github/actions/templates/avm-publishModule/action.yml @@ -71,14 +71,14 @@ runs: # Get the modified child resources if($publishOutputs = Publish-ModuleFromPathToPBR @functionInput -Verbose) { Write-Output ('{0}={1}' -f 'version', $publishOutputs.version) >> $env:GITHUB_OUTPUT - Write-Output ('{0}={1}' -f 'module_path', $publishOutputs.module_path) >> $env:GITHUB_OUTPUT + Write-Output ('{0}={1}' -f 'publishedModuleName', $publishOutputs.publishedModuleName) >> $env:GITHUB_OUTPUT } Write-Output '::endgroup::' - name: "Validate publish" uses: azure/powershell@v1 - if: ${{ steps.publish_step.outputs.version != '' && steps.publish_step.outputs.module_path != '' }} + if: ${{ steps.publish_step.outputs.version != '' && steps.publish_step.outputs.publishedModuleName != '' }} with: azPSVersion: "latest" inlineScript: | @@ -89,8 +89,8 @@ runs: . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Confirm-ModuleIsPublished.ps1') $functionInput = @{ - Version = "${{ steps.publish_step.outputs.version }}" - ModulePath = "${{ steps.publish_step.outputs.module_path }}" + Version = "${{ steps.publish_step.outputs.version }}" + PublishedModuleName = "${{ steps.publish_step.outputs.publishedModuleName }}" } Write-Verbose "Invoke function with" -Verbose diff --git a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 index 9a73565171..472600ae7b 100644 --- a/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 +++ b/avm/utilities/pipelines/publish/Confirm-ModuleIsPublished.ps1 @@ -3,16 +3,16 @@ Check if a module in a given path is published in a given version .DESCRIPTION -Check if a module in a given path is published in a given version. Tries to find the module for a maximum of 6 minutes. +Check if a module in a given path is published in a given version. Tries to find the module & version for a maximum of 60 minutes. .PARAMETER Version Mandatory. The version of the module to check for. For example: '0.2.0' -.PARAMETER ModulePath +.PARAMETER PublishedModuleName Mandatory. The path of the module to check for. For example: 'avm/res/key-vault/vault' .EXAMPLE -Confirm-ModuleIsPublished -Version '0.2.0' -ModulePath 'avm/res/key-vault/vault' -Verbose +Confirm-ModuleIsPublished -Version '0.2.0' -PublishedModuleName 'avm/res/key-vault/vault' -Verbose Check if module 'key-vault/vault' has been published with version '0.2.0 #> @@ -24,12 +24,12 @@ function Confirm-ModuleIsPublished { [string] $Version, [Parameter(Mandatory)] - [string] $ModulePath + [string] $PublishedModuleName ) $baseUrl = 'https://mcr.microsoft.com/v2' $catalogUrl = "$baseUrl/_catalog" - $moduleVersionsUrl = "$baseUrl/bicep/$ModulePath/tags/list" + $moduleVersionsUrl = "$baseUrl/bicep/$PublishedModuleName/tags/list" $time_limit_seconds = 3600 # 1h $end_time = (Get-Date).AddSeconds($time_limit_seconds) @@ -43,16 +43,16 @@ function Confirm-ModuleIsPublished { $bicepCatalogContent = ($catalogContentRaw | ConvertFrom-Json).repositories | Select-String 'bicep/' Write-Verbose ("Bicep modules found in MCR catalog:`n{0}" -f ($bicepCatalogContent | Out-String)) - if ($bicepCatalogContent -match "bicep/$ModulePath") { - Write-Verbose "Passed: Found module [$ModulePath] in the MCR catalog" -Verbose + if ($bicepCatalogContent -match "bicep/$PublishedModuleName") { + Write-Verbose "Passed: Found module [$PublishedModuleName] in the MCR catalog" -Verbose break } else { - Write-Error "Error: Module [$ModulePath] is not in the MCR catalog. Retrying in [$retry_seconds] seconds" + Write-Error "Error: Module [$PublishedModuleName] is not in the MCR catalog. Retrying in [$retry_seconds] seconds" Start-Sleep -Seconds $retry_seconds } if ((Get-Date) -ge $end_time) { - throw "Time limit reached. Failed to validate publish of module in path [$ModulePath] within the specified time." + throw "Time limit reached. Failed to validate publish of module in path [$PublishedModuleName] within the specified time." } } @@ -63,7 +63,7 @@ function Confirm-ModuleIsPublished { $tagsContentRaw = (Invoke-WebRequest -Uri $moduleVersionsUrl -UseBasicParsing).Content $tagsContent = ($tagsContentRaw | ConvertFrom-Json).tags - Write-Verbose ("Tags for module in path [$ModulePath] found in MCR catalog:`n{0}" -f ($tagsContent | Out-String)) + Write-Verbose ("Tags for module in path [$PublishedModuleName] found in MCR catalog:`n{0}" -f ($tagsContent | Out-String)) if ($tagsContent -match $Version) { Write-Host "Passed: Found new tag [$Version] for published module" diff --git a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 index a907e70c03..1cbbbf6d22 100644 --- a/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 +++ b/avm/utilities/pipelines/publish/Publish-ModuleFromPathToPBR.ps1 @@ -98,7 +98,7 @@ function Publish-ModuleFromPathToPBR { bicep publish @publishInput return @{ - version = $targetVersion - module_path = $publishedModuleName + version = $targetVersion + publishedModuleName = $publishedModuleName } }