core/public/Resolve-JaxRunPlan.ps1
|
function Resolve-JaxRunPlan { [CmdletBinding()] param ( [object[]] $BuildEntities, [object[]] $ScenarioEntities, [object[]] $IndividualEntities, [switch] $NoBuild, [switch] $BuildChainOnly, [AllowNull()] $Only, [string] $From, [string] $To, [hashtable] $Context ) $commonParams = Get-JaxCommonParameters -BoundParameters $PSBoundParameters Write-Debug "FUNC: $($MyInvocation.MyCommand.Name) Args: $($PSBoundParameters | ConvertTo-Json -Depth 1 -Compress -WarningAction SilentlyContinue)" if ($NoBuild -and $BuildChainOnly) { throw "Cannot combine -NoBuild with -BuildChainOnly." } $plan = @() if (-not $NoBuild -and $null -ne $BuildEntities) { $plan += @($BuildEntities) } if (-not $BuildChainOnly -and $null -ne $ScenarioEntities) { $plan += @($ScenarioEntities) } $onlySelectors = @(Get-JaxOnlySelectors -Only $Only) $hasOnlySelector = $onlySelectors.Count -gt 0 $hasMultipleOnlySelectors = $onlySelectors.Count -gt 1 $singleOnlySelector = if ($onlySelectors.Count -eq 1) { $onlySelectors[0] } else { $null } $hasSliceRequest = -not [string]::IsNullOrWhiteSpace($From) -or -not [string]::IsNullOrWhiteSpace($To) function Resolve-OnlySelectorEntities { param( [Parameter(Mandatory = $true)] [string] $Selector, [switch] $ApplyLibrarySlice ) $selectorSelected = @(Select-JaxRunEntities -Entities $plan -Only $Selector) if ($null -ne $IndividualEntities) { $individualSelected = @(Select-JaxRunEntities -Entities $IndividualEntities -Only $Selector) if ($individualSelected.Count -gt 0) { $selectorSelected = Merge-JaxRunEntityList -Base $selectorSelected -Add $individualSelected } } # Library fallback: if a selector is not in the active plan/discovered entities, # resolve it from ScenarioLibrary so ad-hoc lists can include library items too. if (($null -eq $selectorSelected -or $selectorSelected.Count -eq 0) -and $null -ne $Context -and $Context.ContainsKey('ScenarioLibrary') -and $Context['ScenarioLibrary'] -is [System.Collections.IDictionary]) { $library = $Context['ScenarioLibrary'] $normalizedSelector = Convert-JaxRunEntityName -Name $Selector @commonParams $libKey = $null foreach ($k in $library.Keys) { $normalizedLibraryKey = Convert-JaxRunEntityName -Name $k @commonParams if ($normalizedLibraryKey -eq $normalizedSelector) { $libKey = $k break } } if ($null -ne $libKey) { Write-Debug "Resolve-JaxRunPlan: Found '$Selector' in ScenarioLibrary. Expanding..." $libValue = $library[$libKey] $libEntities = @() if ($libValue -is [System.Collections.IDictionary]) { $libEntities += ,(Convert-JaxScenarioItemToRunEntity -Key $libKey -Value $libValue -ScenarioName "Library:$Selector" -ProvenancePath 'Library' -Context $Context) } elseif ($libValue -is [System.Collections.IEnumerable] -and $libValue -isnot [string]) { $index = 0 foreach ($item in $libValue) { $libEntities += ,(Convert-JaxScenarioItemToRunEntity -Key "${libKey}_$index" -Value $item -ScenarioName "Library:$Selector" -ProvenancePath 'Library' -Context $Context) $index++ } } else { $libEntities += ,(Convert-JaxScenarioItemToRunEntity -Key $libKey -Value $libValue -ScenarioName "Library:$Selector" -ProvenancePath 'Library' -Context $Context) } if ($ApplyLibrarySlice -and $hasSliceRequest -and $libEntities.Count -gt 0) { $libraryScenario = [ordered]@{ Key = $Selector Runner = 'scenario' Entities = $libEntities } $slicedLibraryScenario = Get-SlicedScenarioEntity -Candidate $libraryScenario if ($null -ne $slicedLibraryScenario -and $slicedLibraryScenario.Contains('Entities')) { $libEntities = @($slicedLibraryScenario['Entities']) } else { $libEntities = @() } } if ($libEntities.Count -gt 0) { $selectorSelected = Merge-JaxRunEntityList -Base $selectorSelected -Add $libEntities } } } return @($selectorSelected) } function Get-SlicedScenarioEntity { param( [Parameter(Mandatory = $true)] $Candidate ) $candidateDict = $null if ($Candidate -is [System.Collections.IDictionary]) { $candidateDict = $Candidate } elseif ($null -ne $Candidate) { $props = $Candidate.PSObject.Properties if ($props -and $props.Count -gt 0) { $candidateDict = [ordered]@{} foreach ($p in $props) { $candidateDict[$p.Name] = $p.Value } } } if ($candidateDict -isnot [System.Collections.IDictionary]) { return $null } if (-not $candidateDict.Contains('Runner')) { return $null } $runner = Resolve-JaxRunnerName -Name ([string]$candidateDict['Runner']) @commonParams if ($runner -ne 'scenario') { return $null } if (-not $candidateDict.Contains('Entities') -or $null -eq $candidateDict['Entities']) { return $null } $children = @($candidateDict['Entities']) if ($children.Count -eq 0) { return @() } $normalizedFrom = if ([string]::IsNullOrWhiteSpace($From)) { $null } else { Convert-JaxRunEntityName -Name $From @commonParams } $normalizedTo = if ([string]::IsNullOrWhiteSpace($To)) { $null } else { Convert-JaxRunEntityName -Name $To @commonParams } $fromIndex = 0 if ($normalizedFrom) { $fromIndex = -1 for ($i = 0; $i -lt $children.Count; $i++) { if (Test-JaxRunEntityNameMatch -Entity $children[$i] -Name $From -MatchStartsWith) { $fromIndex = $i break } } if ($fromIndex -lt 0) { return @() } } $toIndex = $children.Count - 1 if ($normalizedTo) { $toIndex = -1 for ($i = $fromIndex; $i -lt $children.Count; $i++) { if (Test-JaxRunEntityNameMatch -Entity $children[$i] -Name $To -MatchStartsWith) { $toIndex = $i break } } if ($toIndex -lt 0) { return @() } } if ($fromIndex -gt $toIndex) { return @() } $sliced = @() for ($i = $fromIndex; $i -le $toIndex; $i++) { $sliced += $children[$i] } $cloneScenario = [ordered]@{} foreach ($k in $candidateDict.Keys) { $cloneScenario[$k] = $candidateDict[$k] } $cloneScenario['Entities'] = $sliced return $cloneScenario } if ($hasMultipleOnlySelectors) { $virtualScenarioChildren = @() foreach ($selector in $onlySelectors) { $selectorEntities = @(Resolve-OnlySelectorEntities -Selector $selector) if ($selectorEntities.Count -eq 0) { throw "Could not resolve -only selector '$selector' while building an ad-hoc scenario." } $virtualScenarioChildren += $selectorEntities } $virtualScenario = [ordered]@{ Key = "ad-hoc:$($onlySelectors -join ',')" Runner = 'scenario' Entities = $virtualScenarioChildren Scenario = 'ad-hoc' Provenance = 'cli' SourcePath = '-only' } if (-not $hasSliceRequest) { return @($virtualScenario) } $slicedVirtualScenario = Get-SlicedScenarioEntity -Candidate $virtualScenario if ($null -ne $slicedVirtualScenario) { return @($slicedVirtualScenario) } return @() } if ($hasOnlySelector) { $selected = @(Resolve-OnlySelectorEntities -Selector $singleOnlySelector -ApplyLibrarySlice) } else { $selected = @(Select-JaxRunEntities -Entities $plan -From $From -To $To) } if ($null -eq $selected) { return @() } if ($hasSliceRequest) { # Prefer slicing the entity selected by -Only (even when it came from IndividualEntities / library). if ($hasOnlySelector) { $onlyMatches = @() foreach ($item in @($selected)) { if (Test-JaxRunEntityNameMatch -Entity $item -Name $singleOnlySelector) { $onlyMatches += $item } } if ($onlyMatches.Count -eq 1) { $slicedScenario = Get-SlicedScenarioEntity -Candidate $onlyMatches[0] if ($null -ne $slicedScenario) { return @($slicedScenario) } } } # Fallback: if a single scenario was selected, slice within it. if ($selected.Count -eq 1) { $slicedScenario = Get-SlicedScenarioEntity -Candidate $selected[0] if ($null -ne $slicedScenario) { return @($slicedScenario) } } } return $selected } |