Forked from alan-null/UnicornDependencyGraphGenerator.ps1
Created
January 29, 2023 13:39
-
-
Save sebastiantecsi/b7efcfdf07afd0fd91d637d982547780 to your computer and use it in GitHub Desktop.
Generate unicorn dependency graph using PowerShell. Analyse and improve your configurations or easily fix existing issues
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-ComputedDependencyGraphUrl { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Hashtable]$allDependenciesClean | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-ComputedDependencyGraphUrl - Begin" | |
} | |
process { | |
$r = "" | |
$allDependenciesClean.Keys | ?{ $allDependenciesClean[$_] -ne $null } | %{ | |
$configName = $_ | |
$computedDependencies = $allDependenciesClean[$configName] | ? { $_ -ne $configName} | |
$configReport = ($computedDependencies | % { "[$configName]-->[$_]" }) -join "," | |
$r = $r, $configReport -join "," | |
} | |
"https://yuml.me/diagram/nofunky/class/$r" | |
} | |
end { | |
Write-Verbose "Cmdlet Get-ComputedDependencyGraphUrl - End" | |
} | |
} | |
function Get-ConfigDependencyGraphUrl { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Hashtable]$allDependenciesClean, | |
[Parameter(Mandatory=$true, Position=1 )] | |
[object[]]$allUnicornConfigs | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-ConfigDependencyGraphUrl - Begin" | |
} | |
process { | |
$r = "" | |
$allDependenciesClean.Keys | ?{ $allDependenciesClean[$_] -ne $null } | %{ | |
$configName = $_ | |
$configDependencies = ($allUnicornConfigs | ? { $_.Name -eq $configName } | Select-Object -First 1).Dependencies | |
$configReport = ($configDependencies | % { "[$configName]-->[$_]" }) -join "," | |
$r = $r, $configReport -join "," | |
} | |
"https://yuml.me/diagram/nofunky/class/$r" | |
} | |
end { | |
Write-Verbose "Cmdlet Get-ConfigDependencyGraphUrl - End" | |
} | |
} | |
function Get-DiffDependencyGraphUrl { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Hashtable]$allDependenciesClean, | |
[Parameter(Mandatory=$true, Position=1 )] | |
[object[]]$allUnicornConfigs | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-DiffDependencyGraphUrl - Begin" | |
} | |
process { | |
$r = "" | |
$allDependenciesClean.Keys | ?{ $allDependenciesClean[$_] -ne $null } | %{ | |
$configName = $_ | |
$computedDependencies = $allDependenciesClean[$configName] | ? { $_ -ne $configName} | |
$configDependencies = ($allUnicornConfigs | ? { $_.Name -eq $configName } | Select-Object -First 1).Dependencies | |
$missing = Compare-Object $configDependencies $computedDependencies -IncludeEqual | ? { $_.SideIndicator -eq "=>" } | %{ $_.InputObject } | |
$missingFormated = ($missing | % { "[$configName]-->[$_]" }) -join "," | |
$redundant = Compare-Object $configDependencies $computedDependencies -IncludeEqual | ? { $_.SideIndicator -eq "<=" } | %{ $_.InputObject } | |
$redundantFormated = ($redundant | % { "[$configName]-.-^[$_]" }) -join "," | |
$configReport = $missingFormated, $redundantFormated -join "," | |
$r = $r, $configReport -join "," | |
} | |
"https://yuml.me/diagram/nofunky/class/$r" | |
} | |
end { | |
Write-Verbose "Cmdlet Get-DiffDependencyGraphUrl - End" | |
} | |
} | |
function Get-ItemDataChildren { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Rainbow.Model.IItemData]$IItemData, | |
[Parameter(Mandatory=$true, Position=1 )] | |
[Unicorn.Data.ISourceDataStore]$ISourceDataStore, | |
[Parameter(Mandatory=$true, Position=2 )] | |
[Unicorn.Predicates.IPredicate]$IPredicate | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-ItemDataChildren - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Get-ItemDataChildren - Process" | |
$ISourceDataStore.GetChildren($IItemData) | %{ | |
if($IPredicate.Includes($_).IsIncluded){ | |
$_ | |
Get-ItemDataChildren $_ $ISourceDataStore $IPredicate | |
} | |
} | |
} | |
end { | |
Write-Verbose "Cmdlet Get-ItemDataChildren - End" | |
} | |
} | |
function Get-ItemsData { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Unicorn.Configuration.IConfiguration]$Configuration | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-ItemsData - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Get-ItemsData - Process" | |
$method = $Configuration.GetType().GetMethods() | ? { $_.Name -eq "Resolve"} | ? { $_.ReturnType.Name -eq "T" } | Select-Object -First 1 | |
$predicateRootPathResolver = $method.MakeGenericMethod([Unicorn.Predicates.PredicateRootPathResolver]).Invoke($Configuration, $null) | |
$sourceDataStore = $method.MakeGenericMethod([Unicorn.Data.ISourceDataStore]).Invoke($Configuration, $null) | |
$predicate = $method.MakeGenericMethod([Unicorn.Predicates.IPredicate]).Invoke($Configuration, $null) | |
foreach($IItemData in $predicateRootPathResolver.GetRootSourceItems()){ | |
$IItemData | |
Get-ItemDataChildren $IItemData $sourceDataStore $predicate | |
} | |
} | |
end { | |
Write-Verbose "Cmdlet Get-ItemsData - End" | |
} | |
} | |
function Get-UnicornConfiguration { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$false, Position=0 )] | |
[string]$ConfigurationName = "" | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-UnicornConfiguration - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Get-UnicornConfiguration - Process" | |
[Unicorn.ControlPanel.ControlPanelUtility]::ResolveConfigurationsFromQueryParameter($ConfigurationName) | |
} | |
end { | |
Write-Verbose "Cmdlet Get-UnicornConfiguration - End" | |
} | |
} | |
function Get-PredicateIncludes { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Unicorn.Configuration.IConfiguration]$Configuration | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-PredicateIncludes - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Get-PredicateIncludes - Process" | |
$method = $Configuration.GetType().GetMethods() | ? { $_.Name -eq "Resolve"} | ? { $_.ReturnType.Name -eq "T" } | Select-Object -First 1 | |
$predicateRootPathResolver = $method.MakeGenericMethod([Unicorn.Predicates.PredicateRootPathResolver]).Invoke($Configuration, $null) | |
$predicateRootPathResolver.GetRootPaths() | |
} | |
end { | |
Write-Verbose "Cmdlet Get-PredicateIncludes - End" | |
} | |
} | |
function Get-ComparableObjects { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Unicorn.Configuration.IConfiguration[]]$Configurations | |
) | |
begin { | |
Write-Verbose "Cmdlet Add-Files - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Add-Files - Process" | |
$result = New-Object System.Collections.ArrayList | |
$Configurations | ForEach-Object { | |
$configName = $_ | |
Get-ItemsData $configName | ForEach-Object { | |
$obj = @{} | |
$obj.ItemData = $_ | |
$obj.Config = $configName | |
$result.Add($obj) | Out-Null | |
} | |
} | |
$result | |
} | |
end { | |
Write-Verbose "Cmdlet Add-Files - End" | |
} | |
} | |
function Get-TemplateDependency { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
$currentItemData | |
) | |
begin { | |
Write-Verbose "Cmdlet Add-Files - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Add-Files - Process" | |
$templateIdKey = $currentItemData.ItemData.TemplateId.ToString() | |
if ($global_invalidTemplateIDs[$templateIdKey] -eq $null) { | |
$result = $global_templateIdToItemDataMapping[$templateIdKey] | |
if ($result -ne $null) { | |
$result | |
}else { | |
$objectForDifferentConfigs = $global_allObjects | Where-Object { $_.Config.Name -ne $currentItemData.Config.Name} | |
$result = $objectForDifferentConfigs | Where-Object {$_.ItemData.ID -eq $currentItemData.ItemData.TemplateId } | Select-Object -First 1 | |
if ($result -ne $null) { | |
$global_templateIdToItemDataMapping.Add($templateIdKey, $result) | |
$result | |
}else { | |
$global_invalidTemplateIDs.Add($templateIdKey,1) | |
} | |
} | |
} | |
} | |
end { | |
Write-Verbose "Cmdlet Add-Files - End" | |
} | |
} | |
function Get-Depependencies($configName, $allDependencies){ | |
$start2 = Get-Date | |
# check depndencies by path include | |
$global_predicateIncludes[$configName].Path | % { | |
$currentPath = $_ | |
$global_predicateIncludes.Keys | %{ | |
$globalConfig = $_ | |
if($globalConfig -ne $configName){ | |
$global_predicateIncludes[$globalConfig].Path | %{ | |
if($currentPath.Contains($_)){ | |
$allDependencies[$configName].Add($globalConfig) | Out-Null | |
} | |
} | |
} | |
} | |
} | |
# check depndencies by template | |
$configurationObjects = $global_allObjects | Where-Object { $_.Config.Name -eq $configName} | |
$configurationObjects | ForEach-Object { | |
$result = Get-TemplateDependency $_ | |
if ($result -ne $null) { | |
$allDependencies[$configName].Add($result.Config.Name) | Out-Null | |
} | |
} | |
Write-Verbose "Processing | |
[$((Get-Date) - $start2)] $configName" | |
} | |
function Show-Dialog { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Unicorn.Configuration.IConfiguration[]]$Configurations | |
) | |
begin { | |
Write-Verbose "Cmdlet Add-Files - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Add-Files - Process" | |
$dialogOptions = @{} | |
$Configurations.Name | ForEach-Object { $dialogOptions.Add($_, $_) } | |
$preSelectedConfigurations = $Configurations.Name | |
$result = Read-Variable -Parameters ` | |
@{ Name = "preSelectedConfigurations"; Title = "Configurations"; Options = $dialogOptions; Editor = "checklist"; Tip = "Select which configuration should be used to generate dependency graph"; Height = "330px"; Tab = "General"; } ` | |
-Description "This script will go through the selected unicorn configurations and generate dependency report" ` | |
-Title "Generate Unicorn configurations dependency graph" -Width 500 -Height 600 ` | |
-OkButtonName "OK" -CancelButtonName "Cancel" ` | |
if ($result -ne "ok") { | |
Close-Window | |
exit | |
} | |
$Configurations | Where-Object {$preSelectedConfigurations.Contains($_.Name)} | |
} | |
end { | |
Write-Verbose "Cmdlet Add-Files - End" | |
} | |
} | |
function Show-ResultsDialog { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0 )] | |
[Hashtable]$allDependenciesClean, | |
[Parameter(Mandatory=$true, Position=1 )] | |
[object[]]$allUnicornConfigs | |
) | |
begin { | |
Write-Verbose "Cmdlet Show-ResultsDialog - Begin" | |
} | |
process { | |
$result= "ok" | |
$graphModes = [ordered]@{} | |
$graphModes['Mixed dependency graph (redundant, missing dependencies)'] = "mixed" | |
$graphModes['Computed dependency graph'] = "computed" | |
$graphModes['Configuration based dependency graph'] = "config" | |
while($result -eq "ok"){ | |
$result = Read-Variable -Parameters ` | |
@{ Name = "Description"; Title=" "; Value="Please select graph you want to see and click Show button"; editor="info";}, ` | |
@{ Name = "graphMode"; Options=$graphModes; Value=""; Title="Graph mode"; } ` | |
-Description "This script will go through the selected unicorn configurations and generate dependency report" ` | |
-Title "Generate Unicorn configurations dependency graph" -Width 500 -Height 300 ` | |
-OkButtonName "Show" -CancelButtonName "Exit" | |
if($result -eq "cancel"){ | |
Exit | |
} | |
switch ($graphMode) { | |
"computed" { | |
$url = Get-ComputedDependencyGraphUrl $allDependenciesClean | |
$description = "Dependency graph based on item path/id dependency" | |
$legend = "This graph represents desired dependency determined based on item's id/path dependencies between each module." | |
} | |
"config" { | |
$url = Get-ConfigDependencyGraphUrl $allDependenciesClean $allUnicornConfigs | |
$description = "Configuration based dependency graph" | |
$legend = "This graph represents dependency that is currently set in your unicorn configuration files" | |
} | |
"mixed" { | |
$url = Get-DiffDependencyGraphUrl $allDependenciesClean $allUnicornConfigs | |
$description = "Mixed graph" | |
$legend = "Shows what you should do with your config files to fix dependency erros <br/> <b>Solid line</b> - missing dependency <br/> <b>Dotted line</b> - redundant dependency" | |
} | |
Default { | |
$url = "https://alan-null.github.io" | |
} | |
} | |
$result2 = Read-Variable -Parameters ` | |
@{ Name="Info0"; Title=""; Value='<img src="'+ $url +'""/>'; editor="info" }, ` | |
@{ Name="Info1"; Title="Legend:"; Value=$legend; editor="info" } ` | |
-Description $description -Title "Dependency Graph" -Width 1000 -Height 800 ` | |
-OkButtonName "Show different" -CancelButtonName "Exit" | |
if($result2 -eq "cancel"){ | |
Exit | |
} | |
} | |
} | |
end { | |
Write-Verbose "Cmdlet Show-ResultsDialog - End" | |
} | |
} | |
# initialize global variables | |
$start = Get-Date | |
$global_templateIdToItemDataMapping = @{} | |
$global_invalidTemplateIDs = @{} | |
$global_invalidTemplateIDs.Add("962b53c4-f93b-4df9-9821-415c867b8903",1) | |
$global_invalidTemplateIDs.Add("f1828a2c-7e5d-4bbd-98ca-320474871548",1) | |
[System.Collections.ArrayList]$dependencies = New-Object "System.Collections.ArrayList" | |
[System.Xml.XmlNode[]]$allConfigs = [Sitecore.Configuration.Factory]::GetConfigNodes("/sitecore/unicorn/configurations/configuration") | |
$allUnicornConfigs = $allConfigs | ForEach-Object { Get-UnicornConfiguration $_.Name } | |
$configsToProcess = Show-Dialog $allUnicornConfigs | |
$global_progress = 0.0 | |
$global_allObjects = $allUnicornConfigs | ForEach-Object { | |
Write-Progress -Activity "Initializing objects" ` | |
-Status "Creating comparable objects for $($_.Name)" ` | |
-PercentComplete ($global_progress) | |
$global_progress= $global_progress + 100.0 / ($allUnicornConfigs.Count) | |
Get-ComparableObjects $_ | |
} | |
$global_predicateIncludes = @{} | |
$global_progress = 0.0 | |
$allUnicornConfigs | ForEach-Object{ $global_predicateIncludes.Add("$($_.Name)", $(Get-PredicateIncludes $_)) } | |
(Get-Date) - $start | |
# initialize result tables | |
$allDependencies = @{} | |
$allDependenciesClean = @{} | |
$allUnicornConfigs.Name | ForEach-Object { $allDependencies.Add("$($_)", $(New-Object "System.Collections.ArrayList"))} | |
$allUnicornConfigs.Name | ForEach-Object { $allDependenciesClean.Add("$($_)", $null)} | |
$start = Get-Date | |
$configsToProcess | ForEach-Object { | |
Write-Progress -Activity "Analysing dependencies for $($_.Name)" ` | |
-Status "Checking path/id dependencies" ` | |
-PercentComplete ($global_progress) | |
$global_progress= $global_progress + 100.0 / ($configsToProcess.Count) | |
Get-Depependencies $_.Name $allDependencies | |
} | |
(Get-Date) - $start | |
# print results | |
$allDependencies.Keys | %{ | |
$allDependenciesClean[$_] = $allDependencies[$_] | Sort-Object | Get-Unique -AsString | |
} | |
if((Show-Confirm -Title "Would you like to generate dependency report which can be then exported?") -eq "yes"){ | |
$allDependenciesClean.Keys | ?{ $allDependenciesClean[$_] -ne $null } | Show-ListView -InfoTitle "Desired unicorn dependency configuration" ` | |
-PageSize 25 ` | |
-Property ` | |
@{Label='Configuration'; Expression={$_} }, | |
@{Label='Dependencies'; Expression={$allDependenciesClean[$_] -join ','} } | |
} | |
Show-ResultsDialog $allDependenciesClean $allUnicornConfigs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment