AzLocal.UpdateManagement v0.8.7 - on-prem solution-update sideloading automation (5 new cmdlets, Step.6 pipeline, de-numbered filenames) #9
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
| name: AzLocal.UpdateManagement - Pester | |
| # Runs the AzLocal.UpdateManagement Pester unit suite on every PR + push to main | |
| # that touches the module. Live-tagged Azure integration tests are excluded | |
| # (they need az login + the AdaptiveCloudLab subscription and are gated by | |
| # -IncludeLive in the local Invoke-Tests.ps1). | |
| # | |
| # Runner choice: windows-latest is required so the tests exercise the same | |
| # Windows PowerShell 5.1 + .NET 4.x surface that the published module targets. | |
| # Cost mitigation: path-filtered to AzLocal.UpdateManagement/** only, and only | |
| # fires on the three useful PR activities (opened, synchronize, reopened). | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - 'AzLocal.UpdateManagement/**' | |
| - '.github/workflows/AzLocal.UpdateManagement-pester.yml' | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'AzLocal.UpdateManagement/**' | |
| - '.github/workflows/AzLocal.UpdateManagement-pester.yml' | |
| workflow_dispatch: | |
| concurrency: | |
| group: azlocal-updatemanagement-pester-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| checks: write | |
| pull-requests: write | |
| jobs: | |
| pester: | |
| name: Pester (Windows PowerShell 5.1) | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| defaults: | |
| run: | |
| shell: powershell | |
| working-directory: AzLocal.UpdateManagement | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Show PowerShell + Pester baseline | |
| run: | | |
| $PSVersionTable | Format-List | Out-String | Write-Host | |
| Get-Module Pester -ListAvailable | Select-Object Name, Version, Path | Format-Table -AutoSize | Out-String | Write-Host | |
| - name: Install Pester 5.x | |
| run: | | |
| $needed = $true | |
| $installed = Get-Module Pester -ListAvailable | Where-Object { $_.Version -ge [version]'5.0.0' } | Sort-Object Version -Descending | Select-Object -First 1 | |
| if ($installed) { | |
| Write-Host "Pester $($installed.Version) already available at $($installed.Path)" | |
| $needed = $false | |
| } | |
| if ($needed) { | |
| Write-Host 'Installing Pester 5.x from PSGallery (CurrentUser scope)' | |
| Install-Module Pester -MinimumVersion 5.5.0 -Force -SkipPublisherCheck -Scope CurrentUser | |
| } | |
| Import-Module Pester -MinimumVersion 5.0.0 -Force | |
| (Get-Module Pester).Version | Write-Host | |
| - name: Install powershell-yaml | |
| # Required by one Describe block ('ITSM: Get-AzLocalItsmConfig normalises | |
| # non-Hashtable YAML dictionaries') which Mock-overrides ConvertFrom-Yaml. | |
| # Mock can only intercept commands that exist, so the source module must | |
| # be present even though no actual YAML parsing happens at test time. | |
| run: | | |
| if (-not (Get-Module powershell-yaml -ListAvailable)) { | |
| Write-Host 'Installing powershell-yaml from PSGallery (CurrentUser scope)' | |
| Install-Module powershell-yaml -Force -SkipPublisherCheck -Scope CurrentUser | |
| } else { | |
| Write-Host 'powershell-yaml already available' | |
| } | |
| (Get-Module powershell-yaml -ListAvailable | Select-Object -First 1).Version | Write-Host | |
| - name: Import module (smoke test) | |
| run: | | |
| Get-Module AzLocal.UpdateManagement -All | Remove-Module -Force -ErrorAction SilentlyContinue | |
| Import-Module .\AzLocal.UpdateManagement.psd1 -Force -ErrorAction Stop | |
| $m = Get-Module AzLocal.UpdateManagement | |
| Write-Host "Loaded module $($m.Name) $($m.Version) with $($m.ExportedFunctions.Count) exported functions" | |
| - name: Run Pester (unit suite, Live excluded) | |
| run: | | |
| New-Item -ItemType Directory -Path Tests\TestResults -Force | Out-Null | |
| Get-Module AzLocal.UpdateManagement -All | Remove-Module -Force -ErrorAction SilentlyContinue | |
| $config = New-PesterConfiguration | |
| $config.Run.Path = '.\Tests' | |
| $config.Run.PassThru = $true | |
| $config.Run.Exit = $false | |
| $config.Filter.ExcludeTag = @('Live') | |
| $config.TestResult.Enabled = $true | |
| $config.TestResult.OutputPath = 'Tests\TestResults\pester-junit.xml' | |
| # JUnitXml is supported by Pester 5.4+ and is consumable by | |
| # dorny/test-reporter with reporter=jest-junit below. | |
| $config.TestResult.OutputFormat = 'JUnitXml' | |
| $config.Output.Verbosity = 'Normal' | |
| $result = Invoke-Pester -Configuration $config | |
| "Passed=$($result.PassedCount) Failed=$($result.FailedCount) Skipped=$($result.SkippedCount) Duration=$($result.Duration)" | Tee-Object -FilePath Tests\TestResults\summary.txt | |
| if ($result.FailedCount -gt 0) { | |
| $result.Failed | ForEach-Object { "FAIL: $($_.ExpandedPath) :: $($_.ErrorRecord.Exception.Message)" } | Out-File Tests\TestResults\failures.txt | |
| Write-Error "Pester reported $($result.FailedCount) failing test(s)." | |
| exit 1 | |
| } | |
| - name: Strip UTF-8 BOM from JUnit XML | |
| # Windows PowerShell 5.1's UTF-8 writer (which Pester uses for the | |
| # JUnit output) emits a 3-byte BOM. The EnricoMi publish-test-results | |
| # action's lxml parser rejects it with: "Start tag expected, '<' not | |
| # found, line 1, column 1" / "missing toplevel element". Re-write the | |
| # file without BOM (read with BOM-aware UTF-8, write with BOM-less | |
| # UTF-8). Idempotent: if the file is already BOM-less this is a no-op. | |
| if: always() | |
| run: | | |
| $xml = 'Tests\TestResults\pester-junit.xml' | |
| if (Test-Path -LiteralPath $xml) { | |
| $bytes = [System.IO.File]::ReadAllBytes($xml) | |
| $hasBom = ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) | |
| if ($hasBom) { | |
| $text = [System.IO.File]::ReadAllText($xml, [System.Text.UTF8Encoding]::new($true)) | |
| [System.IO.File]::WriteAllText($xml, $text, [System.Text.UTF8Encoding]::new($false)) | |
| Write-Host "Stripped UTF-8 BOM from $xml (was $($bytes.Length) bytes, now $((Get-Item -LiteralPath $xml).Length) bytes)" | |
| } else { | |
| Write-Host "$xml has no BOM; nothing to strip." | |
| } | |
| } else { | |
| Write-Host "$xml not found; skipping BOM strip." | |
| } | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pester-results-${{ github.run_id }} | |
| path: AzLocal.UpdateManagement/Tests/TestResults/ | |
| if-no-files-found: warn | |
| retention-days: 14 | |
| - name: Publish test report (PR check) | |
| # EnricoMi/publish-unit-test-result-action understands Pester's | |
| # JUnitXml output natively. dorny/test-reporter was rejected because | |
| # its 'jest-junit' parser threw `stackTrace.split is not a function` | |
| # on Pester's stackTrace shape (Pester serialises it as a multi-line | |
| # string array, not the single-string shape jest produces). | |
| if: always() && github.event_name == 'pull_request' | |
| uses: EnricoMi/publish-unit-test-result-action/windows@v2 | |
| with: | |
| check_name: AzLocal.UpdateManagement Pester | |
| junit_files: AzLocal.UpdateManagement/Tests/TestResults/pester-junit.xml | |
| comment_mode: off | |
| ignore_runs: true |