diff --git a/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 b/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 index f2f8a9ff68..0837c0442a 100644 --- a/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 +++ b/utilities/pipelines/resourceDeployment/New-TemplateDeployment.ps1 @@ -153,9 +153,6 @@ function New-TemplateDeploymentInner { begin { Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) - - # Load helper - . (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') } process { @@ -375,6 +372,9 @@ Optional. Maximum retry limit if the deployment fails. Default is 3. .PARAMETER doNotThrow Optional. Do not throw an exception if it failed. Still returns the error message though +.PARAMETER RepoRoot +Optional. The path to the repository's root + .EXAMPLE New-TemplateDeployment -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' @@ -422,11 +422,17 @@ function New-TemplateDeployment { [switch] $doNotThrow, [Parameter(Mandatory = $false)] - [int]$retryLimit = 3 + [int]$retryLimit = 3, + + [Parameter(Mandatory = $false)] + [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName ) begin { Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) + + # Load helper + . (Join-Path $RepoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') } process { diff --git a/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 b/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 index 2593de5df6..bfe19d4538 100644 --- a/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 +++ b/utilities/pipelines/resourceDeployment/Test-TemplateDeployment.ps1 @@ -30,6 +30,9 @@ Optional. Name of the management group to deploy into. Mandatory if deploying in .PARAMETER additionalParameters Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' } +.PARAMETER RepoRoot +Optional. The path to the repository's root + .EXAMPLE Test-TemplateDeployment -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' @@ -68,17 +71,40 @@ function Test-TemplateDeployment { [string] $managementGroupId, [Parameter(Mandatory = $false)] - [Hashtable] $additionalParameters + [Hashtable] $additionalParameters, + + [Parameter(Mandatory = $false)] + [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName ) begin { Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) # Load helper - . (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') + . (Join-Path $RepoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') } process { + $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase + if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { + $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) + } + + $modulesRegex = '.+[\\|\/]modules[\\|\/]' + if ($templateFilePath -match $modulesRegex) { + # If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type + $shortPathElem = (($templateFilePath -split $modulesRegex)[1] -replace '\\', '/') -split '/' # e.g., app-configuration, configuration-store, .test, common, main.test.bicep + $providerNamespace = $shortPathElem[0] # e.g., app-configuration + $providerNamespaceShort = ($providerNamespace -split '-' | ForEach-Object { $_[0] }) -join '' # e.g., ac + + $resourceType = $shortPathElem[1] # e.g., configuration-store + $resourceTypeShort = ($resourceType -split '-' | ForEach-Object { $_[0] }) -join '' # e.g. cs + + $testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common + + $deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common + } + $DeploymentInputs = @{ TemplateFile = $templateFilePath Verbose = $true @@ -96,24 +122,6 @@ function Test-TemplateDeployment { $deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose - $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase - if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { - $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) - } - if ($templateFilePath -match '.*(\\|\/)Microsoft.+') { - # If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type - $shortPathElem = (($templateFilePath -split 'Microsoft\.')[1] -replace '\\', '/') -split '/' # e.g., AppConfiguration, configurationStores, .test, common, main.test.bicep - $providerNamespace = $shortPathElem[0] # e.g., AppConfiguration - $providerNamespaceShort = ($providerNamespace -creplace '[^A-Z]').ToLower() # e.g., ac - - $resourceType = $shortPathElem[1] # e.g., configurationStores - $resourceTypeShort = ('{0}{1}' -f ($resourceType.ToLower())[0], ($resourceType -creplace '[^A-Z]')).ToLower() # e.g. cs - - $testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common - - $deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common - } - # Generate a valid deployment name. Must match ^[-\w\._\(\)]+$ do { $deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join '' diff --git a/utilities/tools/Test-ModuleLocally.ps1 b/utilities/tools/Test-ModuleLocally.ps1 index 4e7d37c073..fcc91d5fdb 100644 --- a/utilities/tools/Test-ModuleLocally.ps1 +++ b/utilities/tools/Test-ModuleLocally.ps1 @@ -37,31 +37,7 @@ Optional. A hashtable parameter that contains custom tokens to be replaced in th $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\parameters.json' - PesterTest = $false - DeploymentTest = $false - WhatIfTest = $false - ValidationTest = $true - ValidateOrDeployParameters = @{ - Location = 'westeurope' - ResourceGroupName = 'validation-rg' - SubscriptionId = '00000000-0000-0000-0000-000000000000' - ManagementGroupId = '00000000-0000-0000-0000-000000000000' - RemoveDeployment = $false - } - AdditionalTokens = @{ - tenantId = '00000000-0000-0000-0000-000000000000' - } -} -Test-ModuleLocally @TestModuleLocallyInput -Verbose - -Run a Test-Az*Deployment using a specific parameter-template combination with the provided tokens - -.EXAMPLE - -$TestModuleLocallyInput = @{ - TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' + ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' PesterTest = $false DeploymentTest = $false WhatIfTest = $false @@ -84,7 +60,7 @@ Run a Test-Az*Deployment using a test file with the provided tokens $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\parameters.json' + ModuleTestFilePath = 'C:\network\route-table\tests\e2e\defaults\main.test.bicep' PesterTest = $false DeploymentTest = $false WhatIfTest = $true @@ -102,13 +78,13 @@ $TestModuleLocallyInput = @{ } Test-ModuleLocally @TestModuleLocallyInput -Verbose -Get What-If deployment result using a specific parameter-template combination with the provided tokens +Get What-If deployment result using a specific test-template combination with the provided tokens .EXAMPLE $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' - ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' + ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' PesterTest = $false DeploymentTest = $false WhatIfTest = $true @@ -190,7 +166,7 @@ function Test-ModuleLocally { [string] $TemplateFilePath, [Parameter(Mandatory = $false)] - [string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) '.test'), + [string] $ModuleTestFilePath = (Join-Path (Split-Path $TemplateFilePath -Parent) 'tests'), [Parameter(Mandatory = $false)] [string] $PesterTestFilePath = 'utilities/pipelines/staticValidation/module.tests.ps1', @@ -224,7 +200,7 @@ function Test-ModuleLocally { # Load Modules Validation / Deployment Scripts . (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'New-TemplateDeployment.ps1') . (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'Test-TemplateDeployment.ps1') - . (Join-Path $utilitiesFolderPath 'pipelines' 'resourceDeployment' 'Get-TemplateDeploymenWhatIf.ps1') + . (Join-Path $PSScriptRoot 'helper' 'Get-TemplateDeploymentWhatIf.ps1') } process { @@ -327,12 +303,7 @@ function Test-ModuleLocally { # Loop through test files foreach ($moduleTestFile in $moduleTestFiles) { Write-Verbose ('Validating module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose - if ((Split-Path $moduleTestFile -Extension) -eq '.json') { - Test-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile - } else { - $functionInput['TemplateFilePath'] = $moduleTestFile - Test-TemplateDeployment @functionInput - } + Test-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile } } # What-If validation for template @@ -341,12 +312,7 @@ function Test-ModuleLocally { # Loop through test files foreach ($moduleTestFile in $moduleTestFiles) { Write-Verbose ('Get Deployment What-If result for module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose - if ((Split-Path $moduleTestFile -Extension) -eq '.json') { - Get-TemplateDeploymenWhatIf @functionInput -ParameterFilePath $moduleTestFile - } else { - $functionInput['TemplateFilePath'] = $moduleTestFile - Get-TemplateDeploymenWhatIf @functionInput - } + Get-TemplateDeploymentWhatIf @functionInput -TemplateFilePath $moduleTestFile } } # Deploy template @@ -356,15 +322,8 @@ function Test-ModuleLocally { # Loop through test files foreach ($moduleTestFile in $moduleTestFiles) { Write-Verbose ('Deploy Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)) -Verbose - if ((Split-Path $moduleTestFile -Extension) -eq '.json') { - if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { - New-TemplateDeployment @functionInput -ParameterFilePath $moduleTestFile - } - } else { - $functionInput['TemplateFilePath'] = $moduleTestFile - if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { - New-TemplateDeployment @functionInput - } + if ($PSCmdlet.ShouldProcess(('Module [{0}] with test file [{1}]' -f $ModuleName, (Split-Path $moduleTestFile -Leaf)), 'Deploy')) { + New-TemplateDeployment @functionInput -TemplateFilePath $moduleTestFile } } } diff --git a/utilities/pipelines/resourceDeployment/Get-TemplateDeploymenWhatIf.ps1 b/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 similarity index 82% rename from utilities/pipelines/resourceDeployment/Get-TemplateDeploymenWhatIf.ps1 rename to utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 index 5e6e3ec0f6..8570507784 100644 --- a/utilities/pipelines/resourceDeployment/Get-TemplateDeploymenWhatIf.ps1 +++ b/utilities/tools/helper/Get-TemplateDeploymentWhatIf.ps1 @@ -30,22 +30,25 @@ Optional. Name of the management group to deploy into. Mandatory if deploying in .PARAMETER additionalParameters Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' } +.PARAMETER RepoRoot +Optional. The path to the repository's root + .EXAMPLE -Get-TemplateDeploymenWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -parameterFilePath 'C:/key-vault/vault/.test/parameters.json' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' Get What-If deployment result for the main.bicep of the KeyVault module with the parameter file 'parameters.json' using the resource group 'aLegendaryRg' in location 'WestEurope' .EXAMPLE -Get-TemplateDeploymenWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/key-vault/vault/main.bicep' -location 'WestEurope' -resourceGroupName 'aLegendaryRg' Get What-If deployment result for the main.bicep of the KeyVault module using the resource group 'aLegendaryRg' in location 'WestEurope' .EXAMPLE -Get-TemplateDeploymenWhatIf -templateFilePath 'C:/resources/resource-group/main.json' -parameterFilePath 'C:/resources/resource-group/.test/parameters.json' -location 'WestEurope' +Get-TemplateDeploymentWhatIf -templateFilePath 'C:/resources/resource-group/main.json' -parameterFilePath 'C:/resources/resource-group/.test/parameters.json' -location 'WestEurope' Get What-If deployment result for the main.json of the ResourceGroup module with the parameter file 'parameters.json' in location 'WestEurope' #> -function Get-TemplateDeploymenWhatIf { +function Get-TemplateDeploymentWhatIf { [CmdletBinding(SupportsShouldProcess)] param ( @@ -68,17 +71,40 @@ function Get-TemplateDeploymenWhatIf { [string] $managementGroupId, [Parameter(Mandatory = $false)] - [Hashtable] $additionalParameters + [Hashtable] $additionalParameters, + + [Parameter(Mandatory = $false)] + [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.FullName ) begin { Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) # Load helper - . (Join-Path (Get-Item -Path $PSScriptRoot).parent.FullName 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') + . (Join-Path $repoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-ScopeOfTemplateFile.ps1') } process { + $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase + if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { + $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) + } + + $modulesRegex = '.+[\\|\/]modules[\\|\/]' + if ($templateFilePath -match $modulesRegex) { + # If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type + $shortPathElem = (($templateFilePath -split $modulesRegex)[1] -replace '\\', '/') -split '/' # e.g., app-configuration, configuration-store, .test, common, main.test.bicep + $providerNamespace = $shortPathElem[0] # e.g., app-configuration + $providerNamespaceShort = ($providerNamespace -split '-' | ForEach-Object { $_[0] }) -join '' # e.g., ac + + $resourceType = $shortPathElem[1] # e.g., configuration-store + $resourceTypeShort = ($resourceType -split '-' | ForEach-Object { $_[0] }) -join '' # e.g. cs + + $testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common + + $deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common + } + $DeploymentInputs = @{ TemplateFile = $templateFilePath Verbose = $true @@ -96,24 +122,6 @@ function Get-TemplateDeploymenWhatIf { $deploymentScope = Get-ScopeOfTemplateFile -TemplateFilePath $templateFilePath -Verbose - $deploymentNamePrefix = Split-Path -Path (Split-Path $templateFilePath -Parent) -LeafBase - if ([String]::IsNullOrEmpty($deploymentNamePrefix)) { - $deploymentNamePrefix = 'templateDeployment-{0}' -f (Split-Path $templateFilePath -LeafBase) - } - if ($templateFilePath -match '.*(\\|\/)Microsoft.+') { - # If we can assume we're operating in a module structure, we can further fetch the provider namespace & resource type - $shortPathElem = (($templateFilePath -split 'Microsoft\.')[1] -replace '\\', '/') -split '/' # e.g., AppConfiguration, configurationStores, .test, common, main.test.bicep - $providerNamespace = $shortPathElem[0] # e.g., AppConfiguration - $providerNamespaceShort = ($providerNamespace -creplace '[^A-Z]').ToLower() # e.g., ac - - $resourceType = $shortPathElem[1] # e.g., configurationStores - $resourceTypeShort = ('{0}{1}' -f ($resourceType.ToLower())[0], ($resourceType -creplace '[^A-Z]')).ToLower() # e.g. cs - - $testFolderShort = Split-Path (Split-Path $templateFilePath -Parent) -Leaf # e.g., common - - $deploymentNamePrefix = "$providerNamespaceShort-$resourceTypeShort-$testFolderShort" # e.g., ac-cs-common - } - # Generate a valid deployment name. Must match ^[-\w\._\(\)]+$ do { $deploymentName = ('{0}-{1}' -f $deploymentNamePrefix, (Get-Date -Format 'yyyyMMddTHHMMssffffZ'))[0..63] -join ''