From 34464d695e8c630aebea3c095b248012b54081dd Mon Sep 17 00:00:00 2001 From: fadwen <110697945+fadwen@users.noreply.github.com> Date: Tue, 6 Oct 2026 01:52:16 -0700 Subject: [PATCH] ci: test results and coverage as artifacts, and the integration suite under 5.1 The tests job computed coverage and gated on it but wrote no file, and no job kept its test results: a failure had to be read out of the log, and coverage could not be compared between runs. The 5.1 job ran the unit suites only, so a 5.1 trap in the harness, a stderr line turned into a terminating error, a Group-Object order, showed on a device before it showed in CI. Every test job now writes its results as NUnit XML and the tests job its coverage as JaCoCo XML, both uploaded as artifacts whether the job passes or fails. The 5.1 job runs Tests/Integration as well: the runner is elevated, so the SYSTEM-context tests run there as they do under pwsh. The result files are ignored by git. --- .github/workflows/quality-gates.yml | 48 +++++++++++++++++++++++++++-- .gitignore | 1 + CHANGELOG.md | 3 ++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quality-gates.yml b/.github/workflows/quality-gates.yml index 73b3fee..ec1d370 100644 --- a/.github/workflows/quality-gates.yml +++ b/.github/workflows/quality-gates.yml @@ -14,7 +14,13 @@ # device, and so does the module: the manifest declares CompatiblePSEditions Desktop # and the root module carries #Requires -Version 5.1. A ternary, a null-coalescing # operator or a ForEach-Object -Parallel parses cleanly under 7 and breaks every -# command under 5.1, and nothing but a 5.1 host notices. The unit suites run here too. +# command under 5.1, and nothing but a 5.1 host notices. The unit and integration +# suites run here too: the harness launches 5.1 hosts, and a 5.1 trap in it (a stderr +# line turned into a terminating error, a Group-Object order) shows only here. +# +# Every test job writes its results as NUnit XML and the tests job its coverage as JaCoCo XML, +# uploaded as artifacts whether the job passes or fails, so a failure can be read without +# scrolling the log and the coverage can be compared between runs. # # arm64 Windows on ARM. The runtime harness picks a PowerShell host per architecture, and # on an ARM64 device the answers differ from x64: the System32 host is native ARM64, @@ -119,6 +125,10 @@ jobs: $cfg.CodeCoverage.Path = './Public/*.ps1', './Private/*.ps1', './Private/Rules/*.ps1' # CoveragePercentTarget only reports; the gate below is what enforces it. $cfg.CodeCoverage.CoveragePercentTarget = 80 + # Written before the gates below run, so a failed run still leaves both files to upload + $cfg.CodeCoverage.OutputPath = 'coverage.xml' + $cfg.TestResult.Enabled = $true + $cfg.TestResult.OutputPath = 'testResults.xml' $result = Invoke-Pester -Configuration $cfg @@ -137,6 +147,16 @@ jobs: throw "Code coverage $coverage% is below the 80% gate." } + - name: Upload test results and coverage + if: always() + uses: actions/upload-artifact@v7 + with: + name: tests-and-analysis + path: | + testResults.xml + coverage.xml + if-no-files-found: warn + desktop: name: 'Windows PowerShell 5.1' runs-on: windows-latest @@ -185,16 +205,30 @@ jobs: $ErrorActionPreference = 'Stop' Import-Module Pester -MinimumVersion 6.2.0 $cfg = New-PesterConfiguration - $cfg.Run.Path = './Tests/Unit', './Validation/Tests/Unit' + # The integration suite as well: it launches the 5.1 hosts the harness uses on a device, + # and the runner is elevated, so the SYSTEM-context tests run here as they do under pwsh + $cfg.Run.Path = './Tests/Unit', './Tests/Integration', './Validation/Tests/Unit' $cfg.Run.PassThru = $true $cfg.Output.Verbosity = 'Normal' $cfg.Should.DisableV5 = $true + $cfg.TestResult.Enabled = $true + $cfg.TestResult.OutputPath = 'testResults-desktop.xml' $result = Invoke-Pester -Configuration $cfg + "## Pester under Windows PowerShell 5.1`n`nPassed $($result.PassedCount), failed $($result.FailedCount), " + + "skipped $($result.SkippedCount)." | Out-File -Append -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 if ($result.FailedCount -gt 0 -or $result.FailedContainersCount -gt 0) { throw "$($result.FailedCount) test(s) and $($result.FailedContainersCount) container(s) failed under Windows PowerShell 5.1." } Write-Host "Passed $($result.PassedCount), skipped $($result.SkippedCount) under Windows PowerShell 5.1." + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: windows-powershell-5-1 + path: testResults-desktop.xml + if-no-files-found: warn + arm64: name: 'Windows on ARM' runs-on: windows-11-arm @@ -221,6 +255,8 @@ jobs: $cfg.Run.PassThru = $true $cfg.Output.Verbosity = 'Normal' $cfg.Should.DisableV5 = $true + $cfg.TestResult.Enabled = $true + $cfg.TestResult.OutputPath = 'testResults-arm64.xml' $result = Invoke-Pester -Configuration $cfg "## Pester on Windows on ARM`n`nPassed $($result.PassedCount), failed $($result.FailedCount), " + "skipped $($result.SkippedCount)." | Out-File -Append -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 @@ -228,6 +264,14 @@ jobs: throw "$($result.FailedCount) test(s) and $($result.FailedContainersCount) container(s) failed on ARM64." } + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: windows-on-arm + path: testResults-arm64.xml + if-no-files-found: warn + help: name: 'Command help' runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 0949dba..b584ce4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Pester / coverage output coverage.xml testResults.xml +testResults-*.xml *.trx # Raw validation results: every Collect writes Graph run states, device registry dumps, probe diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf1656..d70c033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ release notes. ### Changed +- CI: the Windows PowerShell 5.1 job runs the integration suite as well as the unit suites, so a 5.1 trap in the + harness fails a pull request rather than a device run. Every test job writes its results as NUnit XML and the + pwsh job its coverage as JaCoCo XML, uploaded as artifacts whether the job passes or fails. - The in-box module table `IslModuleDependency` reports from is held against the Windows client the tests run on: every listed module must be under the host's system module paths, except the engine module and the seven a Home edition lacks, and nothing may be under the Windows module folder that the table or the test does not