Improve table and tool versions comparison for new Software Report module (#6729)

This commit is contained in:
Maxim Lobanov
2022-12-13 16:54:41 +01:00
committed by GitHub
parent 656d9522e0
commit 6033af8dd1
8 changed files with 120 additions and 135 deletions

View File

@@ -18,7 +18,9 @@ Param (
[Parameter(Mandatory=$true)]
[string] $CurrentJsonReportPath,
[Parameter(Mandatory=$true)]
[string] $OutputFile
[string] $OutputFile,
[Parameter(Mandatory=$false)]
[string] $ImageDocsUrl
)
$ErrorActionPreference = "Stop"
@@ -45,4 +47,9 @@ $currentReport = Read-SoftwareReport -JsonReportPath $CurrentJsonReportPath
$comparer = [SoftwareReportComparer]::new($previousReport, $currentReport)
$comparer.CompareReports()
$diff = $comparer.GetMarkdownReport()
if ($ImageDocsUrl) {
$diff += "`n`n`n For comprehensive list of software installed on this image please click [here]($ImageDocsUrl)."
}
$diff | Out-File -Path $OutputFile -Encoding utf8NoBOM

View File

@@ -5,7 +5,7 @@
# Abstract base class for all nodes
class BaseNode {
[Boolean] ShouldBeIncludedToDiff() {
return $False
return $false
}
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
@@ -26,7 +26,7 @@ class BaseToolNode: BaseNode {
}
[Boolean] ShouldBeIncludedToDiff() {
return $True
return $true
}
[String] GetValue() {
@@ -35,7 +35,7 @@ class BaseToolNode: BaseNode {
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
if ($this.GetType() -ne $OtherNode.GetType()) {
return $False
return $false
}
return $this.ToolName -eq $OtherNode.ToolName

View File

@@ -37,7 +37,13 @@ class SoftwareReportComparer {
# Nodes are identical, nothing changed, just ignore it
} elseif ($sameNodeInPreviousReport) {
# Nodes are equal but not identical, so something was changed
$this.ChangedItems.Add([ReportDifferenceItem]::new($sameNodeInPreviousReport, $currentReportNode, $Headers))
if ($currentReportNode -is [TableNode]) {
$this.CompareSimilarTableNodes($sameNodeInPreviousReport, $currentReportNode, $Headers)
} elseif ($currentReportNode -is [ToolVersionsNode]) {
$this.CompareSimilarToolVersionsListNodes($sameNodeInPreviousReport, $currentReportNode, $Headers)
} else {
$this.ChangedItems.Add([ReportDifferenceItem]::new($sameNodeInPreviousReport, $currentReportNode, $Headers))
}
} else {
# Node was not found in previous report, new node was added
$this.AddedItems.Add([ReportDifferenceItem]::new($null, $currentReportNode, $Headers))
@@ -60,6 +66,43 @@ class SoftwareReportComparer {
}
}
hidden [void] CompareSimilarTableNodes([TableNode] $PreviousReportNode, [TableNode] $CurrentReportNode, [Array] $Headers) {
$addedRows = $CurrentReportNode.Rows | Where-Object { $_ -notin $PreviousReportNode.Rows }
$deletedRows = $PreviousReportNode.Rows | Where-Object { $_ -notin $CurrentReportNode.Rows }
if (($addedRows.Count -gt 0) -and ($deletedRows.Count -eq 0)) {
$this.AddedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
} elseif (($deletedRows.Count -gt 0) -and ($addedRows.Count -eq 0)) {
$this.DeletedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
} else {
$this.ChangedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
}
}
hidden [void] CompareSimilarToolVersionsListNodes([ToolVersionsNode] $PreviousReportNode, [ToolVersionsNode] $CurrentReportNode, [Array] $Headers) {
$previousReportMajorVersions = $PreviousReportNode.Versions | ForEach-Object { $PreviousReportNode.ExtractMajorVersion($_) }
$currentReportMajorVersion = $CurrentReportNode.Versions | ForEach-Object { $CurrentReportNode.ExtractMajorVersion($_) }
$addedVersions = $CurrentReportNode.Versions | Where-Object { $CurrentReportNode.ExtractMajorVersion($_) -notin $previousReportMajorVersions }
$deletedVersions = $PreviousReportNode.Versions | Where-Object { $PreviousReportNode.ExtractMajorVersion($_) -notin $currentReportMajorVersion }
$changedPreviousVersions = $PreviousReportNode.Versions | Where-Object { ($PreviousReportNode.ExtractMajorVersion($_) -in $currentReportMajorVersion) -and ($_ -notin $CurrentReportNode.Versions) }
$changedCurrentVersions = $CurrentReportNode.Versions | Where-Object { ($CurrentReportNode.ExtractMajorVersion($_) -in $previousReportMajorVersions) -and ($_ -notin $PreviousReportNode.Versions) }
if ($addedVersions.Count -gt 0) {
$this.AddedItems.Add([ReportDifferenceItem]::new($null, [ToolVersionsNode]::new($CurrentReportNode.ToolName, $addedVersions, $CurrentReportNode.MajorVersionRegex, $true), $Headers))
}
if ($deletedVersions.Count -gt 0) {
$this.DeletedItems.Add([ReportDifferenceItem]::new([ToolVersionsNode]::new($PreviousReportNode.ToolName, $deletedVersions, $PreviousReportNode.MajorVersionRegex, $true), $null, $Headers))
}
$previousChangedNode = ($changedPreviousVersions.Count -gt 0) ? [ToolVersionsNode]::new($PreviousReportNode.ToolName, $changedPreviousVersions, $PreviousReportNode.MajorVersionRegex, $true) : $null
$currentChangedNode = ($changedCurrentVersions.Count -gt 0) ? [ToolVersionsNode]::new($CurrentReportNode.ToolName, $changedCurrentVersions, $CurrentReportNode.MajorVersionRegex, $true) : $null
if ($previousChangedNode -and $currentChangedNode) {
$this.ChangedItems.Add([ReportDifferenceItem]::new($previousChangedNode, $currentChangedNode, $Headers))
}
}
[String] GetMarkdownReport() {
$reporter = [SoftwareReportComparerReport]::new()
$report = $reporter.GenerateMarkdownReport($this.CurrentReport, $this.PreviousReport, $this.AddedItems, $this.ChangedItems, $this.DeletedItems)
@@ -69,10 +112,10 @@ class SoftwareReportComparer {
hidden [Boolean] FilterExcludedNodes([BaseNode] $Node) {
# We shouldn't show "Image Version" diff because it is already shown in report header
if (($Node -is [ToolNode]) -and ($Node.ToolName -eq "Image Version:")) {
return $False
return $false
}
return $True
return $true
}
}
@@ -89,7 +132,7 @@ class SoftwareReportComparerReport {
### Render report header ####
#############################
$sb.AppendLine("# :desktop_computer: $($rootNode.Title)")
$sb.AppendLine("# :desktop_computer: Actions Runner Image: $($rootNode.Title)")
# ToolNodes on root level contains main image description so just copy-paste them to final report
$rootNode.Children | Where-Object { $_ -is [BaseToolNode] } | ForEach-Object {
@@ -107,7 +150,7 @@ class SoftwareReportComparerReport {
if ($addedItemsExcludeTables.Count -gt 0) {
$tableItems = $addedItemsExcludeTables | ForEach-Object {
[PSCustomObject]@{
"Category" = $this.RenderCategory($_.Headers, $True);
"Category" = $this.RenderCategory($_.Headers, $true);
"Tool name" = $this.RenderToolName($_.CurrentReportNode.ToolName);
"Current ($imageVersion)" = $_.CurrentReportNode.GetValue();
}
@@ -115,7 +158,6 @@ class SoftwareReportComparerReport {
$sb.AppendLine("### Added :heavy_plus_sign:")
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
$sb.AppendLine()
}
# Render added tables separately
@@ -131,7 +173,7 @@ class SoftwareReportComparerReport {
if ($deletedItemsExcludeTables.Count -gt 0) {
$tableItems = $deletedItemsExcludeTables | ForEach-Object {
[PSCustomObject]@{
"Category" = $this.RenderCategory($_.Headers, $True);
"Category" = $this.RenderCategory($_.Headers, $true);
"Tool name" = $this.RenderToolName($_.PreviousReportNode.ToolName);
"Previous ($previousImageVersion)" = $_.PreviousReportNode.GetValue();
}
@@ -139,7 +181,11 @@ class SoftwareReportComparerReport {
$sb.AppendLine("### Deleted :heavy_minus_sign:")
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
$sb.AppendLine()
}
# Render deleted tables separately
$DeletedItems | Where-Object { $_.IsTableNode() } | ForEach-Object {
$sb.AppendLine($this.RenderTableNodesDiff($_))
}
#############################
@@ -150,7 +196,7 @@ class SoftwareReportComparerReport {
if ($changedItemsExcludeTables.Count -gt 0) {
$tableItems = $changedItemsExcludeTables | ForEach-Object {
[PSCustomObject]@{
"Category" = $this.RenderCategory($_.Headers, $True);
"Category" = $this.RenderCategory($_.Headers, $true);
"Tool name" = $this.RenderToolName($_.CurrentReportNode.ToolName);
"Previous ($previousImageVersion)" = $_.PreviousReportNode.GetValue();
"Current ($imageVersion)" = $_.CurrentReportNode.GetValue();
@@ -159,7 +205,6 @@ class SoftwareReportComparerReport {
$sb.AppendLine("### Updated")
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
$sb.AppendLine()
}
# Render updated tables separately
@@ -167,11 +212,6 @@ class SoftwareReportComparerReport {
$sb.AppendLine($this.RenderTableNodesDiff($_))
}
# Render deleted tables separately
$DeletedItems | Where-Object { $_.IsTableNode() } | ForEach-Object {
$sb.AppendLine($this.RenderTableNodesDiff($_))
}
return $sb.ToString()
}
@@ -187,7 +227,6 @@ class SoftwareReportComparerReport {
$sb.AppendLine(" </thead>")
$sb.AppendLine(" <tbody>")
$tableRowSpans = $this.CalculateHtmlTableRowSpan($Table, $RowSpanColumnName)
for ($rowIndex = 0; $rowIndex -lt $Table.Count; $rowIndex++) {
$row = $Table[$rowIndex]
@@ -246,7 +285,7 @@ class SoftwareReportComparerReport {
}
$sb = [System.Text.StringBuilder]::new()
$sb.AppendLine("#### $($this.RenderCategory($DiffItem.Headers, $False))")
$sb.AppendLine("#### $($this.RenderCategory($DiffItem.Headers, $false))")
$sb.AppendLine([TableNode]::new($tableHeaders, $tableRows).ToMarkdown(0))
return $sb.ToString()
}

View File

@@ -35,7 +35,7 @@ class HeaderNode: BaseNode {
}
[Boolean] ShouldBeIncludedToDiff() {
return $True
return $true
}
[void] AddNode([BaseNode] $node) {
@@ -63,8 +63,8 @@ class HeaderNode: BaseNode {
$this.AddNode([ToolNode]::new($ToolName, $Version))
}
[void] AddToolVersionsNode([String] $ToolName, [Array] $Version) {
$this.AddNode([ToolVersionsNode]::new($ToolName, $Version))
[void] AddToolVersionsNode([String] $ToolName, [Array] $Version, [String] $MajorVersionRegex, [Boolean] $InlineList) {
$this.AddNode([ToolVersionsNode]::new($ToolName, $Version, $MajorVersionRegex, $InlineList))
}
[void] AddTableNode([Array] $Table) {
@@ -155,12 +155,21 @@ class ToolNode: BaseToolNode {
# Node type to describe the tool with multiple versions "Toolcache Node.js 14.17.6 16.2.0 18.2.3"
class ToolVersionsNode: BaseToolNode {
[Array] $Versions
[Regex] $MajorVersionRegex
[String] $ListType
ToolVersionsNode([String] $ToolName, [Array] $Versions): base($ToolName) {
ToolVersionsNode([String] $ToolName, [Array] $Versions, [String] $MajorVersionRegex, [Boolean] $InlineList): base($ToolName) {
$this.Versions = $Versions
$this.MajorVersionRegex = [Regex]::new($MajorVersionRegex)
$this.ListType = $InlineList ? "Inline" : "List"
$this.ValidateMajorVersionRegex()
}
[String] ToMarkdown($level) {
if ($this.ListType -eq "Inline") {
return "- $($this.ToolName): $($this.Versions -join ', ')"
}
$sb = [System.Text.StringBuilder]::new()
$sb.AppendLine()
$sb.AppendLine("$("#" * $level) $($this.ToolName)")
@@ -175,16 +184,35 @@ class ToolVersionsNode: BaseToolNode {
return $this.Versions -join ', '
}
[String] ExtractMajorVersion([String] $Version) {
$match = $this.MajorVersionRegex.Match($Version)
if ($match.Success -ne $true) {
throw "Version '$Version' doesn't match regex '$($this.PrimaryVersionRegex)'"
}
return $match.Groups[0].Value
}
[PSCustomObject] ToJsonObject() {
return [PSCustomObject]@{
NodeType = $this.GetType().Name
ToolName = $this.ToolName
Versions = $this.Versions
MajorVersionRegex = $this.MajorVersionRegex.ToString()
ListType = $this.ListType
}
}
static [ToolVersionsNode] FromJsonObject($jsonObj) {
return [ToolVersionsNode]::new($jsonObj.ToolName, $jsonObj.Versions)
return [ToolVersionsNode]::new($jsonObj.ToolName, $jsonObj.Versions, $jsonObj.MajorVersionRegex, $jsonObj.ListType -eq "Inline")
}
hidden [void] ValidateMajorVersionRegex() {
$this.Versions | Group-Object { $this.ExtractMajorVersion($_) } | ForEach-Object {
if ($_.Count -gt 1) {
throw "Multiple versions from list $($this.GetValue()) return the same result from regex '$($this.MajorVersionRegex)': $($_.Name)"
}
}
}
}
@@ -200,7 +228,7 @@ class TableNode: BaseNode {
}
[Boolean] ShouldBeIncludedToDiff() {
return $True
return $true
}
static [TableNode] FromObjectsArray([Array] $Table) {