From 5f55a7a74a496606247db44da0143734d46d70af Mon Sep 17 00:00:00 2001 From: Guy Pritchard Date: Tue, 18 Apr 2023 16:54:58 +0100 Subject: [PATCH 1/4] Getting things started --- .../Private/Build-ALZDeploymentEnvFile.ps1 | 4 -- .../Edit-ALZConfigurationFilesInPlace.ps1 | 27 +---------- src/ALZ/Private/Update-ComputedParameters.ps1 | 39 ++++++++++++++++ src/ALZ/Public/New-ALZEnvironment.ps1 | 1 + .../Update-ComputedParameters.Tests.ps1 | 46 +++++++++++++++++++ 5 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 src/ALZ/Private/Update-ComputedParameters.ps1 create mode 100644 src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 diff --git a/src/ALZ/Private/Build-ALZDeploymentEnvFile.ps1 b/src/ALZ/Private/Build-ALZDeploymentEnvFile.ps1 index b74def46..40f5a695 100644 --- a/src/ALZ/Private/Build-ALZDeploymentEnvFile.ps1 +++ b/src/ALZ/Private/Build-ALZDeploymentEnvFile.ps1 @@ -26,10 +26,6 @@ function Build-ALZDeploymentEnvFile { if ($target.Destination -eq "Environment") { $formattedValue = $configurationValue.Value.Value - if ($configurationValue.Value.Type -eq "Computed") { - $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configurationValue.Value.Value -configuration $configuration - } - Add-Content -Path $envFile -Value "$($($target.Name))=`"$formattedValue`"" | Out-String | Write-Verbose } } diff --git a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 index c5a16951..4ba7eef9 100644 --- a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 +++ b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 @@ -65,32 +65,7 @@ function Edit-ALZConfigurationFilesInPlace { if ($target.Destination -eq "Parameters" -and $null -ne $bicepConfigNode) { $leafPropertyName = $propertyNames[-1] - if ($configKey.Value.Type -eq "Computed") { - # If the value type is computed we replace the value with another which already exists in the configuration hierarchy. - if ($configKey.Value.Value -is [array]) { - $formattedValues = @() - foreach($formatString in $configKey.Value.Value) { - $formattedValues += Format-TokenizedConfigurationString -tokenizedString $formatString -configuration $configuration - } - - if ($null -ne $configKey.Value.Process) { - $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) - $formattedValues = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValues - $formattedValues = @($formattedValues) - } - - $bicepConfigNode[$leafPropertyName] = $formattedValues - } else { - - $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration - - if ($null -ne $configKey.Value.Process) { - $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) - $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue - } - - $bicepConfigNode[$leafPropertyName] = $formattedValue - } + } else { $bicepConfigNode[$leafPropertyName] = $configKey.Value.Value } diff --git a/src/ALZ/Private/Update-ComputedParameters.ps1 b/src/ALZ/Private/Update-ComputedParameters.ps1 new file mode 100644 index 00000000..18cbab8f --- /dev/null +++ b/src/ALZ/Private/Update-ComputedParameters.ps1 @@ -0,0 +1,39 @@ +# If the value type is computed we replace the value with another which already exists in the configuration hierarchy. +function Update-ComputedParameters { + param ( + [Parameter(Mandatory = $true)] + [PSCustomObject] $configuration + ) + + foreach ($configKey in $configuration.PsObject.Properties.Parameters) { + if ($configKey.Value.Type -eq "Computed") { + $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configurationValue.Value.Value -configuration $configuration + } + + if ($configKey.Value.Value -is [array]) { + $formattedValues = @() + foreach($formatString in $configKey.Value.Value) { + $formattedValues += Format-TokenizedConfigurationString -tokenizedString $formatString -configuration $configuration + } + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValues = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValues + $formattedValues = @($formattedValues) + } + + $bicepConfigNode[$leafPropertyName] = $formattedValues + } else { + + $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue + } + + $bicepConfigNode[$leafPropertyName] = $formattedValue + + } + } +} \ No newline at end of file diff --git a/src/ALZ/Public/New-ALZEnvironment.ps1 b/src/ALZ/Public/New-ALZEnvironment.ps1 index 919b2115..d4b54098 100644 --- a/src/ALZ/Public/New-ALZEnvironment.ps1 +++ b/src/ALZ/Public/New-ALZEnvironment.ps1 @@ -59,6 +59,7 @@ function New-ALZEnvironment { $configuration = Request-ALZEnvironmentConfig -configurationParameters $bicepConfig.parameters + Update-ComputedParameters -configuration $configuration -Destination $alzEnvironmentDestination | Out-String | Write-Verbose Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination $alzEnvironmentDestination -configuration $configuration | Out-String | Write-Verbose Build-ALZDeploymentEnvFile -configuration $configuration -Destination $alzEnvironmentDestination | Out-String | Write-Verbose diff --git a/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 b/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 new file mode 100644 index 00000000..326dc53b --- /dev/null +++ b/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------- +Set-Location -Path $PSScriptRoot +#------------------------------------------------------------------------- +$ModuleName = 'ALZ' +$PathToManifest = [System.IO.Path]::Combine('..', '..', '..', $ModuleName, "$ModuleName.psd1") +#------------------------------------------------------------------------- +if (Get-Module -Name $ModuleName -ErrorAction 'SilentlyContinue') { + #if the module is already in memory, remove it + Remove-Module -Name $ModuleName -Force +} +Import-Module $PathToManifest -Force +#------------------------------------------------------------------------- + +InModuleScope 'ALZ' { + Describe 'Update-ComputedParameters Private Function Tests' -Tag Unit { + BeforeAll { + $WarningPreference = 'SilentlyContinue' + $ErrorActionPreference = 'SilentlyContinue' + } + Context 'Update-ComputedParameters should update the configuration correctly' { + It 'Handles Computed values correctly.' { + $configuration = [pscustomobject]@{ + Setting1 = [pscustomobject]@{ + Targets = @( + [pscustomobject]@{ + Name = "Setting1" + Destination = "Environment" + }) + Value = "Test" + } + Setting2 = [pscustomobject]@{ + Targets = @( + [pscustomobject]@{ + Name = "Setting2" + Destination = "Environment" + }) + Type = "Computed" + Value = "{%Setting1%}" + } + } + + Update-ComputedParameters -configuration $configuration + } + } + } +} \ No newline at end of file From 9b04e32e74966f391111799643aad54f23d1c80e Mon Sep 17 00:00:00 2001 From: Guy Pritchard Date: Wed, 19 Apr 2023 16:36:12 +0100 Subject: [PATCH 2/4] Adding some tests --- .../Edit-ALZConfigurationFilesInPlace.ps1 | 7 +- ...ers.ps1 => Edit-ComputedConfiguration.ps1} | 13 +- .../Private/New-ALZDirectoryEnvironment.ps1 | 1 - src/ALZ/Public/New-ALZEnvironment.ps1 | 2 +- .../Build-ALZDeploymentEnvFile.Tests.ps1 | 32 --- ...dit-ALZConfigurationFilesInPlace.Tests.ps1 | 234 +----------------- .../Edit-ComputedConfiguration.Tests.ps1 | 155 ++++++++++++ .../Update-ComputedParameters.Tests.ps1 | 46 ---- 8 files changed, 164 insertions(+), 326 deletions(-) rename src/ALZ/Private/{Update-ComputedParameters.ps1 => Edit-ComputedConfiguration.ps1} (73%) create mode 100644 src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 delete mode 100644 src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 diff --git a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 index 4ba7eef9..3e7f834b 100644 --- a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 +++ b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 @@ -64,12 +64,7 @@ function Edit-ALZConfigurationFilesInPlace { # If we're here, we can modify this file and we've got an actual object specified by the Name path value - and we can modify values on it. if ($target.Destination -eq "Parameters" -and $null -ne $bicepConfigNode) { $leafPropertyName = $propertyNames[-1] - - - } else { - $bicepConfigNode[$leafPropertyName] = $configKey.Value.Value - } - + $bicepConfigNode[$leafPropertyName] = $configKey.Value.Value $modified = $true } } diff --git a/src/ALZ/Private/Update-ComputedParameters.ps1 b/src/ALZ/Private/Edit-ComputedConfiguration.ps1 similarity index 73% rename from src/ALZ/Private/Update-ComputedParameters.ps1 rename to src/ALZ/Private/Edit-ComputedConfiguration.ps1 index 18cbab8f..c8ce2d26 100644 --- a/src/ALZ/Private/Update-ComputedParameters.ps1 +++ b/src/ALZ/Private/Edit-ComputedConfiguration.ps1 @@ -1,13 +1,13 @@ # If the value type is computed we replace the value with another which already exists in the configuration hierarchy. -function Update-ComputedParameters { +function Edit-ComputedConfiguration { param ( [Parameter(Mandatory = $true)] [PSCustomObject] $configuration ) - foreach ($configKey in $configuration.PsObject.Properties.Parameters) { - if ($configKey.Value.Type -eq "Computed") { - $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configurationValue.Value.Value -configuration $configuration + foreach ($configKey in $configuration.PsObject.Properties) { + if ($configKey.Value.Type -ne "Computed") { + continue; } if ($configKey.Value.Value -is [array]) { @@ -22,7 +22,7 @@ function Update-ComputedParameters { $formattedValues = @($formattedValues) } - $bicepConfigNode[$leafPropertyName] = $formattedValues + $configKey.Value.Value = $formattedValues } else { $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration @@ -32,8 +32,7 @@ function Update-ComputedParameters { $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue } - $bicepConfigNode[$leafPropertyName] = $formattedValue - + $configKey.Value.Value = $formattedValue } } } \ No newline at end of file diff --git a/src/ALZ/Private/New-ALZDirectoryEnvironment.ps1 b/src/ALZ/Private/New-ALZDirectoryEnvironment.ps1 index e08ee11f..e074449e 100644 --- a/src/ALZ/Private/New-ALZDirectoryEnvironment.ps1 +++ b/src/ALZ/Private/New-ALZDirectoryEnvironment.ps1 @@ -18,5 +18,4 @@ function New-ALZDirectoryEnvironment { New-Item -ItemType Directory -Path $config -Force | Out-String | Write-Verbose New-Item -ItemType Directory -Path $upstream -Force | Out-String | Write-Verbose New-Item -ItemType Directory -Path $configModules -Force | Out-String | Write-Verbose - } \ No newline at end of file diff --git a/src/ALZ/Public/New-ALZEnvironment.ps1 b/src/ALZ/Public/New-ALZEnvironment.ps1 index d4b54098..76f7881c 100644 --- a/src/ALZ/Public/New-ALZEnvironment.ps1 +++ b/src/ALZ/Public/New-ALZEnvironment.ps1 @@ -59,7 +59,7 @@ function New-ALZEnvironment { $configuration = Request-ALZEnvironmentConfig -configurationParameters $bicepConfig.parameters - Update-ComputedParameters -configuration $configuration -Destination $alzEnvironmentDestination | Out-String | Write-Verbose + Edit-ComputedConfiguration -configuration $configuration | Out-String | Write-Verbose Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination $alzEnvironmentDestination -configuration $configuration | Out-String | Write-Verbose Build-ALZDeploymentEnvFile -configuration $configuration -Destination $alzEnvironmentDestination | Out-String | Write-Verbose diff --git a/src/Tests/Unit/Private/Build-ALZDeploymentEnvFile.Tests.ps1 b/src/Tests/Unit/Private/Build-ALZDeploymentEnvFile.Tests.ps1 index a344ccee..4d9cc9e3 100644 --- a/src/Tests/Unit/Private/Build-ALZDeploymentEnvFile.Tests.ps1 +++ b/src/Tests/Unit/Private/Build-ALZDeploymentEnvFile.Tests.ps1 @@ -77,38 +77,6 @@ InModuleScope 'ALZ' { Should -Invoke New-Item -ParameterFilter { $Path -match ".env$" } -Scope It -Times 1 -Exactly Should -Invoke Add-Content -Scope It -Times 1 -Exactly } - - It 'Handles Computed values correctly and adds to the .env file.' { - - Mock -CommandName New-Item - Mock -CommandName Add-Content - - $configuration = [pscustomobject]@{ - Setting1 = [pscustomobject]@{ - Targets = @( - [pscustomobject]@{ - Name = "Setting1" - Destination = "Environment" - }) - Value = "Test" - } - Setting2 = [pscustomobject]@{ - Targets = @( - [pscustomobject]@{ - Name = "Setting2" - Destination = "Environment" - }) - Type = "Computed" - Value = "{%Setting1%}" - } - } - - Build-ALZDeploymentEnvFile -configuration $configuration -destination "test" - - Should -Invoke New-Item -ParameterFilter { $Path -match ".env$" } -Scope It -Times 1 -Exactly - Should -Invoke Add-Content -ParameterFilter { $Value -match "^Setting1=`"Test`"$" } -Scope It -Times 1 -Exactly - Should -Invoke Add-Content -ParameterFilter { $Value -match "^Setting2=`"Test`"$" } -Scope It -Times 1 -Exactly - } } } } \ No newline at end of file diff --git a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 index b158caad..f122594a 100644 --- a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 +++ b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 @@ -460,6 +460,7 @@ InModuleScope 'ALZ' { $secondFileContent } + Edit-ComputedConfiguration -configuration $defaultConfig Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $defaultConfig Should -Invoke -CommandName Out-File -Scope It -Times 2 @@ -483,239 +484,6 @@ InModuleScope 'ALZ' { Should -Invoke -CommandName Out-File -ParameterFilter { $FilePath -eq "test2.parameters.json" -and $InputObject -eq $contentStringAfterParsing } -Scope It } - It 'Computed, Processed array values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | Select-Object -Unique)' - Value = @( - "1", - "1", - "3" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "1", "3" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed array values replace values correctly in a case insensitive deduplication.' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | ForEach-Object { $_.ToLower() } | Select-Object -Unique)' - Value = @( - "A", - "a", - "A", - "a" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "a" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed array values replace values correctly and keep array type when only one item remains.' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | Select-Object -Unique)' - Value = @( - "1", - "1", - "1" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "1" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '($args[0] -eq "eastus") ? "eastus2" : ($args[0] -eq "eastus2") ? "eastus" : $args[0]' - Value = "eastus" - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": "replace_me" - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": "eastus2" - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '($args[0] -eq "goodbye") ? "Hello" : "Goodbye"' - Value = "goodbye" - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": "replace_me" - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": "Hello" - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - It 'Multiple files with file specific configuration should be changed correctly' { $defaultConfig = [pscustomobject]@{ Value1 = [pscustomobject]@{ diff --git a/src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 b/src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 new file mode 100644 index 00000000..bf839a30 --- /dev/null +++ b/src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 @@ -0,0 +1,155 @@ +#------------------------------------------------------------------------- +Set-Location -Path $PSScriptRoot +#------------------------------------------------------------------------- +$ModuleName = 'ALZ' +$PathToManifest = [System.IO.Path]::Combine('..', '..', '..', $ModuleName, "$ModuleName.psd1") +#------------------------------------------------------------------------- +if (Get-Module -Name $ModuleName -ErrorAction 'SilentlyContinue') { + #if the module is already in memory, remove it + Remove-Module -Name $ModuleName -Force +} +Import-Module $PathToManifest -Force +#------------------------------------------------------------------------- + +InModuleScope 'ALZ' { + Describe 'Edit-ComputedConfiguration Private Function Tests' -Tag Unit { + BeforeAll { + $WarningPreference = 'SilentlyContinue' + $ErrorActionPreference = 'SilentlyContinue' + } + Context 'Edit-ComputedConfiguration should update the configuration correctly' { + It 'Handles Computed values correctly.' { + $configuration = [pscustomobject]@{ + Setting1 = [pscustomobject]@{ + Targets = @( + [pscustomobject]@{ + Name = "Setting1" + Destination = "Environment" + }) + Value = "Test" + } + Setting2 = [pscustomobject]@{ + Targets = @( + [pscustomobject]@{ + Name = "Setting2" + Destination = "Environment" + }) + Type = "Computed" + Value = "{%Setting1%}" + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Setting2.Value | Should -BeExactly "Test" + } + + It 'Computed, Processed array values replace values correctly' { + $configuration = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '@($args | Select-Object -Unique)' + Value = @( + "1", + "1", + "3" + ) + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Nested.Value | Should -BeExactly @("1", "3") + } + + It 'Computed, Processed array values replace values correctly in a case insensitive deduplication.' { + $configuration = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '@($args | ForEach-Object { $_.ToLower() } | Select-Object -Unique)' + Value = @( + "A", + "a", + "A", + "a" + ) + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Nested.Value | Should -BeExactly @("a") + } + + It 'Computed, Processed array values replace values correctly and keep array type when only one item remains.' { + $configuration = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '@($args | Select-Object -Unique)' + Value = @( + "1", + "1", + "1" + ) + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Nested.Value | Should -BeExactly @("1") + } + + It 'Computed, Processed values replace values correctly' { + $configuration = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '($args[0] -eq "eastus") ? "eastus2" : ($args[0] -eq "eastus2") ? "eastus" : $args[0]' + Value = "eastus" + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Nested.Value | Should -BeExactly "eastus2" + } + + It 'Computed, Processed values replace values correctly' { + $configuration = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '($args[0] -eq "goodbye") ? "Hello" : "Goodbye"' + Value = "goodbye" + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + Edit-ComputedConfiguration -configuration $configuration + $configuration.Nested.Value | Should -BeExactly "Hello" + } + } + } +} \ No newline at end of file diff --git a/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 b/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 deleted file mode 100644 index 326dc53b..00000000 --- a/src/Tests/Unit/Private/Update-ComputedParameters.Tests.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -#------------------------------------------------------------------------- -Set-Location -Path $PSScriptRoot -#------------------------------------------------------------------------- -$ModuleName = 'ALZ' -$PathToManifest = [System.IO.Path]::Combine('..', '..', '..', $ModuleName, "$ModuleName.psd1") -#------------------------------------------------------------------------- -if (Get-Module -Name $ModuleName -ErrorAction 'SilentlyContinue') { - #if the module is already in memory, remove it - Remove-Module -Name $ModuleName -Force -} -Import-Module $PathToManifest -Force -#------------------------------------------------------------------------- - -InModuleScope 'ALZ' { - Describe 'Update-ComputedParameters Private Function Tests' -Tag Unit { - BeforeAll { - $WarningPreference = 'SilentlyContinue' - $ErrorActionPreference = 'SilentlyContinue' - } - Context 'Update-ComputedParameters should update the configuration correctly' { - It 'Handles Computed values correctly.' { - $configuration = [pscustomobject]@{ - Setting1 = [pscustomobject]@{ - Targets = @( - [pscustomobject]@{ - Name = "Setting1" - Destination = "Environment" - }) - Value = "Test" - } - Setting2 = [pscustomobject]@{ - Targets = @( - [pscustomobject]@{ - Name = "Setting2" - Destination = "Environment" - }) - Type = "Computed" - Value = "{%Setting1%}" - } - } - - Update-ComputedParameters -configuration $configuration - } - } - } -} \ No newline at end of file From 09501782a3570199e0fbe4cc0e93028bd69734df Mon Sep 17 00:00:00 2001 From: Guy Pritchard Date: Fri, 12 May 2023 16:22:41 +0100 Subject: [PATCH 3/4] Removing moved tests --- ...dit-ALZConfigurationFilesInPlace.Tests.ps1 | 236 ------------------ 1 file changed, 236 deletions(-) diff --git a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 index 7fb0b042..136e4db3 100644 --- a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 +++ b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 @@ -470,242 +470,6 @@ InModuleScope 'ALZ' { Should -Invoke -CommandName Out-File -ParameterFilter { $FilePath -eq "test2.parameters.json" -and $InputObject -eq $contentStringAfterParsing } -Scope It } -<<<<<<< HEAD -======= - It 'Computed, Processed array values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | Select-Object -Unique)' - Value = @( - "1", - "1", - "3" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "1", "3" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed array values replace values correctly in a case insensitive deduplication.' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | ForEach-Object { $_.ToLower() } | Select-Object -Unique)' - Value = @( - "A", - "a", - "A", - "a" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "a" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed array values replace values correctly and keep array type when only one item remains.' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '@($args | Select-Object -Unique)' - Value = @( - "1", - "1", - "1" - ) - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": [] - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": [ "1" ] - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '($args[0] -eq "eastus") ? "eastus2" : ($args[0] -eq "eastus2") ? "eastus" : $args[0]' - Value = "eastus" - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": "replace_me" - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": "eastus2" - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - - It 'Computed, Processed values replace values correctly' { - $config = [pscustomobject]@{ - Nested = [pscustomobject]@{ - Type = "Computed" - Description = "A Test Value" - Process = '($args[0] -eq "goodbye") ? "Hello" : "Goodbye"' - Value = "goodbye" - Targets = @( - [pscustomobject]@{ - Name = "parValue.value" - Destination = "Parameters" - }) - } - } - - $fileContent = '{ - "parameters": { - "parValue": { - "value": "replace_me" - } - } - }' - - $expectedContent = '{ - "parameters": { - "parValue": { - "value": "Hello" - } - } - }' - - Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { - $fileContent - } - - $expectedContent = Format-ExpectedResult -expectedJson $expectedContent - - Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config - - Should -Invoke -CommandName Out-File ` - -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` - -Scope It - } - ->>>>>>> 21d2e0442c3bd96cc8db505a8e18eb771bc63f84 It 'Multiple files with file specific configuration should be changed correctly' { $defaultConfig = [pscustomobject]@{ Value1 = [pscustomobject]@{ From f5fa5022bb913651a8ad69d72ff7c883c9f9eb28 Mon Sep 17 00:00:00 2001 From: Guy Pritchard Date: Fri, 12 May 2023 16:33:00 +0100 Subject: [PATCH 4/4] Renaming the computed calculation function --- .../Private/Edit-ComputedConfiguration.ps1 | 38 ----------------- src/ALZ/Private/Set-ComputedConfiguration.ps1 | 41 +++++++++++++++++++ src/ALZ/Public/New-ALZEnvironment.ps1 | 4 +- ...dit-ALZConfigurationFilesInPlace.Tests.ps1 | 2 +- ...s1 => Set-ComputedConfiguration.Tests.ps1} | 16 ++++---- 5 files changed, 52 insertions(+), 49 deletions(-) delete mode 100644 src/ALZ/Private/Edit-ComputedConfiguration.ps1 create mode 100644 src/ALZ/Private/Set-ComputedConfiguration.ps1 rename src/Tests/Unit/Private/{Edit-ComputedConfiguration.Tests.ps1 => Set-ComputedConfiguration.Tests.ps1} (91%) diff --git a/src/ALZ/Private/Edit-ComputedConfiguration.ps1 b/src/ALZ/Private/Edit-ComputedConfiguration.ps1 deleted file mode 100644 index c8ce2d26..00000000 --- a/src/ALZ/Private/Edit-ComputedConfiguration.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -# If the value type is computed we replace the value with another which already exists in the configuration hierarchy. -function Edit-ComputedConfiguration { - param ( - [Parameter(Mandatory = $true)] - [PSCustomObject] $configuration - ) - - foreach ($configKey in $configuration.PsObject.Properties) { - if ($configKey.Value.Type -ne "Computed") { - continue; - } - - if ($configKey.Value.Value -is [array]) { - $formattedValues = @() - foreach($formatString in $configKey.Value.Value) { - $formattedValues += Format-TokenizedConfigurationString -tokenizedString $formatString -configuration $configuration - } - - if ($null -ne $configKey.Value.Process) { - $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) - $formattedValues = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValues - $formattedValues = @($formattedValues) - } - - $configKey.Value.Value = $formattedValues - } else { - - $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration - - if ($null -ne $configKey.Value.Process) { - $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) - $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue - } - - $configKey.Value.Value = $formattedValue - } - } -} \ No newline at end of file diff --git a/src/ALZ/Private/Set-ComputedConfiguration.ps1 b/src/ALZ/Private/Set-ComputedConfiguration.ps1 new file mode 100644 index 00000000..1dbadf9c --- /dev/null +++ b/src/ALZ/Private/Set-ComputedConfiguration.ps1 @@ -0,0 +1,41 @@ +# If the value type is computed we replace the value with another which already exists in the configuration hierarchy. +function Set-ComputedConfiguration { + [CmdletBinding(SupportsShouldProcess = $true)] + param ( + [Parameter(Mandatory = $true)] + [PSCustomObject] $configuration + ) + + if ($PSCmdlet.ShouldProcess("ALZ-Bicep computed configuration.", "calculate computed values")) { + foreach ($configKey in $configuration.PsObject.Properties) { + if ($configKey.Value.Type -ne "Computed") { + continue; + } + + if ($configKey.Value.Value -is [array]) { + $formattedValues = @() + foreach($formatString in $configKey.Value.Value) { + $formattedValues += Format-TokenizedConfigurationString -tokenizedString $formatString -configuration $configuration + } + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValues = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValues + $formattedValues = @($formattedValues) + } + + $configKey.Value.Value = $formattedValues + } else { + + $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue + } + + $configKey.Value.Value = $formattedValue + } + } + } +} \ No newline at end of file diff --git a/src/ALZ/Public/New-ALZEnvironment.ps1 b/src/ALZ/Public/New-ALZEnvironment.ps1 index b47ed72e..7159536a 100644 --- a/src/ALZ/Public/New-ALZEnvironment.ps1 +++ b/src/ALZ/Public/New-ALZEnvironment.ps1 @@ -54,14 +54,14 @@ function New-ALZEnvironment { $alzEnvironmentDestinationInternalCode = Join-Path $alzEnvironmentDestination "upstream-releases" Get-ALZGithubRelease -directoryForReleases $alzEnvironmentDestinationInternalCode -githubRepoUrl $bicepConfig.module_url -releases @($bicepConfig.version) | Out-String | Write-Verbose - + Write-InformationColored "Copying ALZ-Bicep module to $alzEnvironmentDestinationInternalCode" -ForegroundColor Green -InformationAction Continue Copy-ALZParametersFile -alzEnvironmentDestination $alzEnvironmentDestination -upstreamReleaseDirectory $(Join-Path $alzEnvironmentDestinationInternalCode $bicepConfig.version) -configFiles $bicepConfig.config_files | Out-String | Write-Verbose Write-InformationColored "ALZ-Bicep source directory: $alzBicepSourceDirectory" -ForegroundColor Green -InformationAction Continue $configuration = Request-ALZEnvironmentConfig -configurationParameters $bicepConfig.parameters - Edit-ComputedConfiguration -configuration $configuration | Out-String | Write-Verbose + Set-ComputedConfiguration -configuration $configuration | Out-String | Write-Verbose Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination $alzEnvironmentDestination -configuration $configuration | Out-String | Write-Verbose Build-ALZDeploymentEnvFile -configuration $configuration -Destination $alzEnvironmentDestination | Out-String | Write-Verbose diff --git a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 index 136e4db3..5adbcac1 100644 --- a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 +++ b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 @@ -447,7 +447,7 @@ InModuleScope 'ALZ' { $secondFileContent } - Edit-ComputedConfiguration -configuration $defaultConfig + Set-ComputedConfiguration -configuration $defaultConfig Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $defaultConfig Should -Invoke -CommandName Out-File -Scope It -Times 2 diff --git a/src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 b/src/Tests/Unit/Private/Set-ComputedConfiguration.Tests.ps1 similarity index 91% rename from src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 rename to src/Tests/Unit/Private/Set-ComputedConfiguration.Tests.ps1 index bf839a30..34cfa001 100644 --- a/src/Tests/Unit/Private/Edit-ComputedConfiguration.Tests.ps1 +++ b/src/Tests/Unit/Private/Set-ComputedConfiguration.Tests.ps1 @@ -12,12 +12,12 @@ Import-Module $PathToManifest -Force #------------------------------------------------------------------------- InModuleScope 'ALZ' { - Describe 'Edit-ComputedConfiguration Private Function Tests' -Tag Unit { + Describe 'Set-ComputedConfiguration Private Function Tests' -Tag Unit { BeforeAll { $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'SilentlyContinue' } - Context 'Edit-ComputedConfiguration should update the configuration correctly' { + Context 'Set-ComputedConfiguration should update the configuration correctly' { It 'Handles Computed values correctly.' { $configuration = [pscustomobject]@{ Setting1 = [pscustomobject]@{ @@ -39,7 +39,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Setting2.Value | Should -BeExactly "Test" } @@ -62,7 +62,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Nested.Value | Should -BeExactly @("1", "3") } @@ -86,7 +86,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Nested.Value | Should -BeExactly @("a") } @@ -109,7 +109,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Nested.Value | Should -BeExactly @("1") } @@ -128,7 +128,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Nested.Value | Should -BeExactly "eastus2" } @@ -147,7 +147,7 @@ InModuleScope 'ALZ' { } } - Edit-ComputedConfiguration -configuration $configuration + Set-ComputedConfiguration -configuration $configuration $configuration.Nested.Value | Should -BeExactly "Hello" } }