v1.0.5#19
Conversation
…d add changelog entry for version 1.0.5
…ration - Add Add-HtmlTableCell private function that builds Graphviz HTML <TR><TD> markup from Hashtable, OrderedDictionary, PSCustomObject, or string array input - Accept all formatting parameters: FontName, FontSize, FontColor, FontBold, FontItalic, FontUnderline, FontStrikeThrough, Align, ColSpan, CellPadding, CellBorder, CellBackgroundColor, Port, IconDebug/DraftMode - Export Add-HtmlTableCell in module manifest (FunctionsToExport) - Add 26 Pester tests covering all input types, formatting options, and composability with Format-HtmlTable - Add Example18.ps1 demonstrating all four input type variations - Add .github/copilot-instructions.md for future Copilot sessions - Mark Todo.md items complete Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Created tests for Add-NodeSpacer, Add-NodeText, Add-RightLShapeLine, Add-RightTShapeLine, Add-TShapeLine, Add-VerticalLine, Export-AbrDiagram, Get-AbrNodeIP, Get-ImagePercent, Get-RandomColorInHex, Get-RandomPastelColorInHex, Remove-SpecialCharacter, Split-ArrayElement, Test-AbrImage, and Test-AbrLogo. - Each test file includes BeforeAll setup to initialize necessary scripts and variables. - Tests cover various scenarios including valid inputs, expected outputs, and error handling.
…opacity adjustment
…termarkToSvg cmdlet
…e coverage support
…et-BestImageAspectRatio function
There was a problem hiding this comment.
PSScriptAnalyzer found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
There was a problem hiding this comment.
Pull request overview
Release prep for v1.0.5 of AsBuiltReport.Diagram, adding new HTML-cell formatting and image/SVG processing capabilities, plus a large expansion of Pester coverage and CI test execution changes.
Changes:
- Add HTML cell builder (
Format-HtmlCell) and extend node image rendering with opacity support. - Add/extend .NET cmdlets for image opacity and SVG watermarking (net8.0 + net48).
- Expand Pester suite and update CI workflow to run tests via a repo script (with optional code coverage output).
Reviewed changes
Copilot reviewed 27 out of 60 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Todo.md | Updates TODO items (now marking some as complete). |
| CHANGELOG.md | Adds v1.0.5 release notes. |
| AsBuiltReport.Diagram/AsBuiltReport.Diagram.psd1 | Bumps module version and updates exported functions list. |
| AsBuiltReport.Diagram/Src/Private/Format-HtmlCell.ps1 | Adds new helper to generate Graphviz HTML <TR><TD> cell markup. |
| AsBuiltReport.Diagram/Src/Private/Add-NodeImage.ps1 | Adds ImageOpacityPercent support when embedding node images. |
| AsBuiltReport.Diagram/Src/Private/Add-NodeEdge.ps1 | Expands EdgeLength validation range (0–50). |
| AsBuiltReport.Diagram/Src/Private/Get-BestImageAspectRatio.ps1 | Refactors aspect-ratio calculation logic. |
| AsBuiltReport.Diagram/Src/Private/Resize-Image.ps1 | Changes smoothing behavior control. |
| AsBuiltReport.Diagram/Src/Private/ConvertTo-Svg.ps1 | Adjusts watermark opacity handling when calling Add-WatermarkToSvg. |
| AsBuiltReport.Diagram/Src/Private/ConvertTo-Dot.ps1 | Forces Export-PSGraph failures to throw (-ErrorAction Stop). |
| Tests/_InitializeTests.ps1 | Updates Graphviz path + assembly paths; adds Test-AbrBase64 helper. |
| Tests/Invoke-Tests.ps1 | New test runner script (optional results XML + code coverage). |
| Tests/Export-AbrDiagram.Tests.ps1 | Relaxes Base64 assertion to validate “is Base64” instead of exact string match. |
| Tests/Add-NodeImage.Tests.ps1 | Adds coverage for new ImageOpacityPercent behavior. |
| Tests/Format-HtmlCell.Tests.ps1 | Adds coverage for new Format-HtmlCell helper. |
| Tests/Test-AbrLogo.Tests.ps1 | Adds Pester coverage for Test-AbrLogo. |
| Tests/Test-AbrImage.Tests.ps1 | Adds Pester coverage for Test-AbrImage. |
| Tests/Split-ArrayElement.Tests.ps1 | Adds Pester coverage for Split-ArrayElement. |
| Tests/Remove-SpecialCharacter.Tests.ps1 | Adds Pester coverage for Remove-SpecialCharacter. |
| Tests/Get-RandomPastelColorInHex.Tests.ps1 | Adds Pester coverage for pastel color helper. |
| Tests/Get-RandomColorInHex.Tests.ps1 | Adds Pester coverage for color helper. |
| Tests/Get-ImagePercent.Tests.ps1 | Adds Pester coverage for image sizing by percent. |
| Tests/Get-AbrNodeIP.Tests.ps1 | Adds Pester coverage for hostname->IP helper. |
| Tests/Add-NodeEdge.Tests.ps1 | Adds/expands edge-generation tests. |
| Tests/Add-NodeIcon.Tests.ps1 | Adds Pester coverage for icon node builder. |
| Tests/Add-NodeText.Tests.ps1 | Adds Pester coverage for text node builder. |
| Tests/Add-NodeShape.Tests.ps1 | Adds Pester coverage for shape node builder. |
| Tests/Add-NodeSpacer.Tests.ps1 | Adds Pester coverage for spacer node builder. |
| Tests/Add-HtmlLabel.Tests.ps1 | Adds Pester coverage for label table builder. |
| Tests/Add-HtmlTable.Tests.ps1 | Adds Pester coverage for HTML table builder. |
| Tests/Add-HtmlNodeTable.Tests.ps1 | Adds Pester coverage for node table builder. |
| Tests/Add-HtmlSubGraph.Tests.ps1 | Adds Pester coverage for subgraph HTML construction. |
| Tests/Add-HtmlSignatureTable.Tests.ps1 | Adds Pester coverage for signature table builder. |
| Tests/Add-HorizontalLine.Tests.ps1 | Adds Pester coverage for horizontal line helper. |
| Tests/Add-VerticalLine.Tests.ps1 | Adds Pester coverage for vertical line helper. |
| Tests/Add-LShapeLine.Tests.ps1 | Adds Pester coverage for L-shape line helper. |
| Tests/Add-RightLShapeLine.Tests.ps1 | Adds Pester coverage for right L-shape line helper. |
| Tests/Add-LeftLShapeLine.Tests.ps1 | Adds Pester coverage for left L-shape line helper. |
| Tests/Add-TShapeLine.Tests.ps1 | Adds Pester coverage for T-shape line helper. |
| Tests/Add-RightTShapeLine.Tests.ps1 | Adds Pester coverage for right T-shape line helper. |
| Tests/Add-LeftTShapeLine.Tests.ps1 | Adds Pester coverage for left T-shape line helper. |
| Tests/Add-InvertedTShapeLine.Tests.ps1 | Adds Pester coverage for inverted T-shape line helper. |
| Tests/Add-InvertedLShapeLine.Tests.ps1 | Adds Pester coverage for inverted L-shape line helper. |
| Tests/Add-CrossShapeLine.Tests.ps1 | Adds Pester coverage for cross-shape line helper. |
| Tests/Add-AbrWatermarkToImage.Tests.ps1 | Adds Pester coverage for watermarking images. |
| Sources/Diagrammer/ImageProcessor.cs | Adds ImageSharp-based SetImageOpacity implementation. |
| Sources/Diagrammer/PowershellCmdlets/SetImageOpacityPwsh.cs | Adds Set-ImageOpacity PowerShell cmdlet (net8.0). |
| Sources/Diagrammer/AbrDiagrammer.csproj | Bumps library version + updates Newtonsoft.Json version. |
| Sources/DiaConvertImageToPDF/ImageProcessor.cs | Adds net48 SVG watermark + opacity processing helpers. |
| Sources/DiaConvertImageToPDF/PowershellCmdlets/SetImageOpacityPwsh.cs | Adds Set-ImageOpacity PowerShell cmdlet (net48). |
| Sources/DiaConvertImageToPDF/PowershellCmdlets/AddWatermarkToSvgPwsh.cs | Adds Add-WatermarkToSvg cmdlet (net48). |
| Sources/DiaConvertImageToPDF/AbrDiaConvertImageToPDF.csproj | Adds explicit framework references for drawing/XML. |
| Sources/DiaConvertImageToPDF/Todo.md | Adds DiaConvertImageToPDF todo notes. |
| .github/workflows/Pester.yml | Switches CI test execution to Tests/Invoke-Tests.ps1 and uploads results XML. |
| .github/copilot-instructions.md | Adds repo-specific Copilot/build/test guidance. |
| .vscode/tasks.json | Updates task labels/paths for renamed csproj files. |
| .vscode/launch.json | Adds launch profiles for debugging PowerShell cmdlets. |
| .gitignore | Stops ignoring launch.json; keeps ignoring .cache. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $originalWidth = $Image.Width | ||
| $originalHeight = $Image.Height | ||
| $aspectRatio = $originalWidth / $originalHeight | ||
|
|
||
| # Determine new dimensions based on constraints | ||
| if ($MaxWidth -and $originalWidth -gt $MaxWidth) { | ||
| $newWidth = $MaxWidth | ||
| $newHeight = [int]($newWidth / $aspectRatio) | ||
| } elseif ($MaxHeight -and $originalHeight -gt $MaxHeight) { | ||
| $newHeight = $MaxHeight | ||
| $newWidth = [int]($newHeight * $aspectRatio) | ||
| } else { | ||
| $newWidth = $originalWidth | ||
| $newHeight = $originalHeight | ||
| } | ||
| $ratioX = $MaxWidth / $OriginalWidth | ||
| $ratioY = $MaxHeight / $OriginalHeight | ||
| $ratio = [Math]::Min($ratioX, $ratioY) | ||
|
|
||
| $ImagePrty = @{ | ||
| 'Width' = $newWidth | ||
| 'Height' = $newHeight | ||
| 'Width' = [int]($OriginalWidth * $ratio) | ||
| 'Height' = [int]($OriginalHeight * $ratio) |
There was a problem hiding this comment.
The new aspect-ratio calculation always scales using $MaxWidth/$MaxHeight, but both parameters are optional. When either is omitted/0, the ratio becomes 0 and the function returns Width/Height = 0. It can also upscale images when MaxWidth/MaxHeight are larger than the original. Consider only applying scaling when constraints are provided, and cap the ratio at 1.0 to avoid upscaling.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| default { Join-Path -Path $ProjectRoot -ChildPath 'AsBuiltReport.Diagram\Tools\Graphviz\bin\dot.exe' } | ||
| } |
There was a problem hiding this comment.
The Windows Graphviz path uses a ChildPath string with doubled backslashes (AsBuiltReport.Diagram\\Tools\\Graphviz...). This works inconsistently depending on how the path is normalized and is harder to read. Prefer building the path via Join-Path segments (or a single-backslash literal) to avoid accidental \\ in the final path.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| <# | ||
| .SYNOPSIS | ||
| Invoke Pester tests for AsBuiltReport.Microsoft.AD module | ||
|
|
||
| .DESCRIPTION | ||
| This script runs Pester tests with optional code coverage analysis. | ||
| It's designed to work with CI/CD pipelines and local development. |
There was a problem hiding this comment.
The header comment says this runs tests for AsBuiltReport.Microsoft.AD, but this repository/module is AsBuiltReport.Diagram (as used later in the script). Please update the synopsis to avoid confusion for contributors and CI logs.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| [Parameter( | ||
| ParameterSetName = 'Image', | ||
| Mandatory = $false, | ||
| HelpMessage = 'Applies fixedsize="true" with the given Width and Height to the TD cell.' | ||
| )] | ||
| [switch] $FixedSize, | ||
|
|
||
| [Parameter( | ||
| ParameterSetName = 'Image', | ||
| Mandatory = $false, | ||
| HelpMessage = 'Cell width in pixels. Requires -FixedSize.' | ||
| )] | ||
| [int] $Width, | ||
|
|
||
| [Parameter( | ||
| ParameterSetName = 'Image', | ||
| Mandatory = $false, | ||
| HelpMessage = 'Cell height in pixels. Requires -FixedSize.' | ||
| )] | ||
| [int] $Height, |
There was a problem hiding this comment.
-FixedSize is documented as requiring -Width and -Height, but neither is enforced. If a caller sets -FixedSize without width/height, the function will emit width="0" height="0", producing invalid/unexpected Graphviz HTML. Consider making Width/Height mandatory when -FixedSize is set (or validate > 0 at runtime and throw).
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| - [ ] Add pester to test this funtionality | ||
| - [ ] Add documentation for this funtionality | ||
| - [ ] Add example for this funtionality | ||
| - [ ] Add function to dinamically build Table cells based on input hashtable use Format-HTMLTable as example | ||
| - [ ] Add pester to test this funtionality | ||
| - [ ] Add documentation for this funtionality | ||
| - [ ] Add example for this funtionality | ||
| - [x] Add function to dinamically build Table cells based on input use Format-HTMLTable as example | ||
| - [x] Add pester to test this funtionality | ||
| - [x] Add documentation for this funtionality | ||
| - [x] Add example for this funtionality |
There was a problem hiding this comment.
Spelling: “dinamically” should be “dynamically”, and “funtionality” should be “functionality”. Updating these improves readability of the project todo list.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 60 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $ratioX = $MaxWidth / $OriginalWidth | ||
| $ratioY = $MaxHeight / $OriginalHeight | ||
| $ratio = [Math]::Min($ratioX, $ratioY) | ||
|
|
||
| $ImagePrty = @{ | ||
| 'Width' = $newWidth | ||
| 'Height' = $newHeight | ||
| 'Width' = [int]($OriginalWidth * $ratio) | ||
| 'Height' = [int]($OriginalHeight * $ratio) | ||
| } |
There was a problem hiding this comment.
The updated scaling logic will return Width/Height = 0 when either -MaxWidth or -MaxHeight is omitted (they default to 0, so the min ratio becomes 0). It can also upscale images when both max values exceed the original size. Consider treating unspecified constraints as “no limit” and capping the computed ratio at 1.0 so you only downscale (or fall back to original dimensions when both are unset).
| HelpMessage = 'Cell width in pixels. Requires -FixedSize.' | ||
| )] | ||
| [int] $Width, | ||
|
|
||
| [Parameter( | ||
| ParameterSetName = 'Image', | ||
| Mandatory = $false, | ||
| HelpMessage = 'Cell height in pixels. Requires -FixedSize.' | ||
| )] |
There was a problem hiding this comment.
-FixedSize is documented as requiring -Width and -Height, but there is no enforcement or validation. If callers pass -FixedSize without dimensions (or with 0/negative values), the function will emit width/height attributes with invalid values, which can break Graphviz HTML label rendering. Make Width/Height mandatory when -FixedSize is set (or throw when they are not > 0).
| HelpMessage = 'Cell width in pixels. Requires -FixedSize.' | |
| )] | |
| [int] $Width, | |
| [Parameter( | |
| ParameterSetName = 'Image', | |
| Mandatory = $false, | |
| HelpMessage = 'Cell height in pixels. Requires -FixedSize.' | |
| )] | |
| HelpMessage = 'Cell width in pixels. Requires -FixedSize and must be greater than 0.' | |
| )] | |
| [ValidateRange(1, [int]::MaxValue)] | |
| [int] $Width, | |
| [Parameter( | |
| ParameterSetName = 'Image', | |
| Mandatory = $false, | |
| HelpMessage = 'Cell height in pixels. Requires -FixedSize and must be greater than 0.' | |
| )] | |
| [ValidateRange(1, [int]::MaxValue)] |
| [Parameter(Mandatory = $False, ParameterSetName = 'Absolute')][Int]$Width, | ||
| [Parameter(Mandatory = $False, ParameterSetName = 'Percent')][Double]$Percentage, | ||
| [Parameter(Mandatory = $False)][System.Drawing.Drawing2D.SmoothingMode]$SmoothingMode = 'HighQuality', | ||
| [Parameter(Mandatory = $False)][Switch]$SmoothingMode, |
There was a problem hiding this comment.
The SmoothingMode parameter was changed from a System.Drawing.Drawing2D.SmoothingMode value (default HighQuality) to a [switch]. This is a breaking change for any callers passing an enum value, and it also contradicts the help text that says the default is HighQuality (now HighQuality is only applied when the switch is present). Consider restoring the enum parameter (with default HighQuality) or updating the parameter name/docs to reflect the new behavior (e.g., -HighQualitySmoothing).
| [Parameter(Mandatory = $False)][Switch]$SmoothingMode, | |
| [Parameter(Mandatory = $False)][System.Drawing.Drawing2D.SmoothingMode]$SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality, |
| # Apply opacity to a temp file when requested | ||
| $IconSrc = $ICON | ||
| if ($ImageOpacityPercent -lt 100) { | ||
| if (-not $IconPath) { | ||
| throw 'IconPath is required when ImageOpacityPercent is less than 100.' | ||
| } | ||
| $sourcePath = Join-Path -Path $IconPath -ChildPath $ICON | ||
| $ext = [System.IO.Path]::GetExtension($ICON) | ||
| $tempFileName = [System.IO.Path]::GetRandomFileName() | ||
| $IconSrc = [System.IO.Path]::ChangeExtension((Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFileName), $ext) | ||
| Set-ImageOpacity -SourceImageFilePath $sourcePath -OutputImageFilePath $IconSrc -Opacity $ImageOpacityPercent | Out-Null |
There was a problem hiding this comment.
When ImageOpacityPercent < 100, $IconSrc becomes an absolute temp-file path and is embedded directly into the . This can create two issues: (1) temp files are never cleaned up, and (2) downstream SVG post-processing that regex-replaces image hrefs can break when the matched string contains backslashes/regex metacharacters. Consider writing the opacity-adjusted image into a known module temp folder and returning just the leaf filename (or ensure the later replace step escapes the match string), and add a cleanup strategy.
| # Apply opacity to a temp file when requested | |
| $IconSrc = $ICON | |
| if ($ImageOpacityPercent -lt 100) { | |
| if (-not $IconPath) { | |
| throw 'IconPath is required when ImageOpacityPercent is less than 100.' | |
| } | |
| $sourcePath = Join-Path -Path $IconPath -ChildPath $ICON | |
| $ext = [System.IO.Path]::GetExtension($ICON) | |
| $tempFileName = [System.IO.Path]::GetRandomFileName() | |
| $IconSrc = [System.IO.Path]::ChangeExtension((Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFileName), $ext) | |
| Set-ImageOpacity -SourceImageFilePath $sourcePath -OutputImageFilePath $IconSrc -Opacity $ImageOpacityPercent | Out-Null | |
| # Apply opacity to a module-scoped temp file when requested. | |
| # Keep the HTML img src as a leaf filename so later SVG post-processing | |
| # does not have to handle absolute paths with regex metacharacters. | |
| $IconSrc = $ICON | |
| if ($ImageOpacityPercent -lt 100) { | |
| if (-not $IconPath) { | |
| throw 'IconPath is required when ImageOpacityPercent is less than 100.' | |
| } | |
| $sourcePath = Join-Path -Path $IconPath -ChildPath $ICON | |
| $moduleTempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'AsBuiltReport.Diagram\NodeImageOpacity' | |
| if (-not (Test-Path -Path $moduleTempPath)) { | |
| New-Item -Path $moduleTempPath -ItemType Directory -Force | Out-Null | |
| } | |
| # Opportunistically remove stale generated images to avoid leaking temp files. | |
| Get-ChildItem -Path $moduleTempPath -File -ErrorAction SilentlyContinue | | |
| Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-1) } | | |
| Remove-Item -Force -ErrorAction SilentlyContinue | |
| $ext = [System.IO.Path]::GetExtension($ICON) | |
| $baseName = [System.IO.Path]::GetFileNameWithoutExtension($ICON) | |
| $generatedFileName = '{0}-{1}{2}' -f $baseName, ([guid]::NewGuid().ToString('N')), $ext | |
| $generatedIconPath = Join-Path -Path $moduleTempPath -ChildPath $generatedFileName | |
| Set-ImageOpacity -SourceImageFilePath $sourcePath -OutputImageFilePath $generatedIconPath -Opacity $ImageOpacityPercent | Out-Null | |
| $IconSrc = [System.IO.Path]::GetFileName($generatedIconPath) |
|
@copilot apply changes based on the comments in this thread |
[1.0.5] - 2026-03-24
🧰 Added
🔃 Changed
🔧 Fixed