Feature dna 363 - #15
Conversation
…nvironment filtering and optional variable set retrieval
…ons for improved variable handling and add new Get-VariableTemplate and New-TenantCommonVariablePayload functions
…CommonTenantVariable functions; add IsSensitive parameter and improve payload creation logic
…-CommonTenantVariable function
… function and fix variable name typo in Set-CommonTenantVariable function
…improved clarity and performance
…TenantVariable function
… and error handling for scoped variables
…rent version details
…by explicitly passing parameters for temporary value assignment
There was a problem hiding this comment.
Pull request overview
This PR enhances the Set-CommonTenantVariable function to support environment-scoped tenant variables with intelligent scope conflict resolution. It also improves Get-CommonTenantVariable to optionally filter by environment and retrieve variables across all variable sets.
- Enhanced tenant variable management with support for environment scoping and automatic scope conflict handling (disjoint, overlapping, equal, contained scenarios)
- Added new helper functions for scope comparison and payload creation
- Improved existing functions with better error handling and additional filtering capabilities
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| OctopusDeploy/Public/Set-CommonTenantVariable.ps1 | Major enhancement adding environment scoping support, intelligent scope conflict handling, comprehensive validation, and detailed documentation |
| OctopusDeploy/Public/Get-CommonTenantVariable.ps1 | Made VariableSet parameter optional, added Environment filter parameter, improved output format with scope information |
| OctopusDeploy/Public/GetCommonTenantVariable.ps1 | New internal function that implements the core variable retrieval logic with environment filtering support |
| OctopusDeploy/Public/Compare-EnvironmentScope.ps1 | New utility function to compare environment scopes and determine relationship (Equal, Disjoint, Overlap, Contained) |
| OctopusDeploy/Private/New-TenantCommonVariablePayload.ps1 | New helper function to create TenantCommonVariablePayload objects with proper type handling |
| OctopusDeploy/Private/Get-VariableTemplate.ps1 | New utility function to retrieve variable templates from variable sets |
| OctopusDeploy/Public/Invoke-RunbookRun.ps1 | Removed early return statements to allow proper error handling flow |
| OctopusDeploy/Public/Get-Task.ps1 | Added support for DeploymentResource objects, improved code formatting |
| OctopusDeploy/Public/Add-RoleToMachine.ps1 | Enhanced with return value checking and verbose logging |
| CHANGELOG.md | Restructured and updated with new changes under Unreleased section |
| GettingStarted.md | Added examples for new Environment filtering capabilities |
| .github/workflows/release.yaml | Enhanced with automatic changelog extraction and commit functionality |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| $payloads += $payload | ||
|
|
||
| # there seems to be and issue with setting sensitive variables to empty string in overlapping scope scenario |
There was a problem hiding this comment.
The comment "there seems to be and issue" contains a grammatical error. It should be "there seems to be an issue".
| # there seems to be and issue with setting sensitive variables to empty string in overlapping scope scenario | |
| # there seems to be an issue with setting sensitive variables to empty string in overlapping scope scenario |
| # Check that all the variables are defined in Variable Set | ||
| foreach ($h in $VariableHash.GetEnumerator()) { | ||
| if ($VariableSet.Templates.name -notcontains $h.Name) { | ||
| if ($currentVariables.Name -notcontains $h.Name) { | ||
| $message = "Couldn't find {0} in variable set {1}" -f $h.Name, $VariableSet.Name | ||
| throw $message | ||
| } else { | ||
| $err = [System.Management.Automation.ErrorRecord]::new( | ||
| [System.Management.Automation.ItemNotFoundException]::new("$message"), | ||
| 'NotSpecified', | ||
| 'InvalidData', | ||
| "$($Variableset.name) / $($h.name)" | ||
| ) | ||
| $errorDetails = [System.Management.Automation.ErrorDetails]::new("$message") | ||
| $errorDetails.RecommendedAction = "Check variable exists in variable set" | ||
| $err.ErrorDetails = $errorDetails | ||
| $PSCmdlet.ThrowTerminatingError($err) | ||
| } | ||
| else { | ||
| $message = "Found variable {0} in variable set {1}" -f $h.Name, $VariableSet.Name | ||
| Write-Verbose $message | ||
| } | ||
| } |
There was a problem hiding this comment.
There's a duplicate validation check here. Lines 152-171 already check that all variables exist in the variable set. This second check at lines 174-192 performs the same validation but with slightly different error handling. One of these checks should be removed to avoid redundant validation.
| IsSensitive = $_.DefaultValue.IsSensitive | ||
| VariableId = $null | ||
| LibraryVariableSetId = $vSet.Id | ||
| origObject = $_ |
There was a problem hiding this comment.
The property name "origObject" uses inconsistent casing compared to other property names in the same object. All other properties use PascalCase (VariableSetName, Name, Value, etc.), but this one uses camelCase. Consider renaming to "OrigObject" for consistency.
| @@ -0,0 +1,101 @@ | |||
| function GetCommonTenantVariable { | |||
There was a problem hiding this comment.
This function is missing comment-based help documentation. Internal/private functions should include at minimum a SYNOPSIS and DESCRIPTION to explain the function's purpose and behavior, especially when they implement complex logic.
| function GetCommonTenantVariable { | |
| <# | |
| .SYNOPSIS | |
| Retrieves common tenant variables for the specified tenant, library variable set, and environment. | |
| .DESCRIPTION | |
| GetCommonTenantVariable validates the Octopus Deploy connection and then retrieves tenant-scoped | |
| variables from the server. It can optionally scope the returned variables to a specific library | |
| variable set and environment when they are provided. | |
| .PARAMETER Tenant | |
| The Octopus Deploy tenant resource for which common variables will be retrieved. This parameter is mandatory. | |
| .PARAMETER VariableSet | |
| An optional Octopus Deploy library variable set resource used to filter the tenant variables. | |
| .PARAMETER Environment | |
| An optional Octopus Deploy environment resource used to filter the tenant variables by environment. | |
| #> | |
| function GetCommonTenantVariable { |
| $variableToPreserve = $currentVariables | Where-Object { ($_.name.ToLower() -notin $VariableHash.Keys.ToLower() -and -not $_.IsDefaultValue -and $_.LibraryVariableSetId -eq $VariableSet.id ) -or | ||
| (-not $_.IsDefaultValue -and $_.LibraryVariableSetId -ne $VariableSet.id ) } |
There was a problem hiding this comment.
The case-insensitive comparison on line 206 is calling ToLower() on a collection (VariableHash.Keys), which won't work as intended. The ToLower() method should be called on individual strings within a comparison operation, not on the collection itself. Consider using the -notin operator with proper case handling, such as: Where-Object { $VariableHash.Keys -notcontains $_.name } with case-insensitive comparison logic, or restructure to compare individual elements.
| $variableToPreserve = $currentVariables | Where-Object { ($_.name.ToLower() -notin $VariableHash.Keys.ToLower() -and -not $_.IsDefaultValue -and $_.LibraryVariableSetId -eq $VariableSet.id ) -or | |
| (-not $_.IsDefaultValue -and $_.LibraryVariableSetId -ne $VariableSet.id ) } | |
| $variableToPreserve = $currentVariables | Where-Object { ( $_.Name -notin $VariableHash.Keys -and -not $_.IsDefaultValue -and $_.LibraryVariableSetId -eq $VariableSet.Id ) -or | |
| ( -not $_.IsDefaultValue -and $_.LibraryVariableSetId -ne $VariableSet.Id ) } |
| TemplateId = $var.TemplateId | ||
| Value = $VariableHash[$var.Name] | ||
| IsSensitive = $var.IsSensitive | ||
| Scope = if (-not $null -eq $comparison.ExistingScope) { $($comparison.ExistingScope) }else { $($comparison.NewScope) } |
There was a problem hiding this comment.
The null comparison is using the wrong order. In PowerShell, the recommended pattern is to place the value being tested on the left side, not the null check. The condition should be "$comparison.ExistingScope -ne $null" or "($null -ne $comparison.ExistingScope)" for better readability and correctness.
| Scope = if (-not $null -eq $comparison.ExistingScope) { $($comparison.ExistingScope) }else { $($comparison.NewScope) } | |
| Scope = if ($comparison.ExistingScope -ne $null) { $comparison.ExistingScope } else { $comparison.NewScope } |
|
|
||
| } | ||
| } | ||
| # if an environment was specified, return all scoped variables for that environment and unscoped variables a far the variable has no environment scope |
There was a problem hiding this comment.
The comment "a far the variable" contains a spelling error. It should be "as far as the variable".
| # if an environment was specified, return all scoped variables for that environment and unscoped variables a far the variable has no environment scope | |
| # if an environment was specified, return all scoped variables for that environment and unscoped variables as far as the variable has no environment scope |
| IsSensitive = $_.Value.IsSensitive | ||
| VariableId = $_.Id | ||
| LibraryVariableSetId = $_.LibraryVariableSetId | ||
| origObject = $_ |
There was a problem hiding this comment.
The property name "origObject" uses inconsistent casing compared to other property names in the same object. All other properties use PascalCase (VariableSetName, Name, Value, etc.), but this one uses camelCase. Consider renaming to "OrigObject" for consistency.
| @@ -0,0 +1,35 @@ | |||
| function Compare-EnvironmentScope { | |||
There was a problem hiding this comment.
This function is missing comment-based help documentation. Public functions should include a SYNOPSIS, DESCRIPTION, parameter descriptions, and usage examples to help users understand how to use the function.
| function Compare-EnvironmentScope { | |
| <# | |
| .SYNOPSIS | |
| Compares an existing environment scope with a new environment scope and describes their relationship. | |
| .DESCRIPTION | |
| Compare-EnvironmentScope normalizes and compares two sets of environment identifiers to determine how | |
| the new scope relates to the existing scope. It returns an object with a Status property that indicates | |
| the relationship, and properties that show which environments are considered part of each side. | |
| The Status property can have one of the following values: | |
| - Equal : Both scopes contain the same environments (after sorting and removing duplicates). | |
| - Disjoint : The scopes share no environments in common. | |
| - Overlap : The scopes share some environments, but the existing scope includes environments that are | |
| not present in the new scope. | |
| - Contained : All environments in the existing scope are present in the new scope. | |
| Both ExistingScope and NewScope may be null or empty to represent an unscoped value. | |
| .PARAMETER ExistingScope | |
| The current set of environment IDs or names that represent the existing scope. This parameter | |
| can be null or an empty collection to indicate that the value is currently unscoped. | |
| .PARAMETER NewScope | |
| The proposed set of environment IDs or names that represent the new scope. This parameter | |
| can be null or an empty collection to indicate that the value should be unscoped. | |
| .EXAMPLE | |
| PS C:\> Compare-EnvironmentScope -ExistingScope @('Dev','Test') -NewScope @('Dev','Test') | |
| Returns: | |
| Status ExistingScope NewScope | |
| ------ ------------- ------- | |
| Equal {Dev, Test} null | |
| This indicates that the new scope is identical to the existing scope. | |
| .EXAMPLE | |
| PS C:\> Compare-EnvironmentScope -ExistingScope @('Dev','Test','Prod') -NewScope @('Test','Prod') | |
| Returns: | |
| Status ExistingScope NewScope | |
| ------ ------------- ------- | |
| Overlap {Dev} {Test, Prod} | |
| This indicates that the scopes partially overlap and that the existing scope includes environments | |
| that are not present in the new scope. | |
| #> | |
| function Compare-EnvironmentScope { |
Description
Added a new PowerShell function Set-CommonTenantVariable to manage common tenant variables in Octopus Deploy. This function provides support for setting or resetting tenant variables with optional environment scoping.
Key features:
Set single or multiple variables using hashtables
Scope variables to specific environments or leave unscoped
Intelligent scope conflict handling (disjoint, overlapping, equal, contained)
Reset variables to default with empty string values
Preserves non-modified tenant variables
Atomic operations - all changes succeed or none are applied