feat!: Raise the Pester floor to 6.0.0 and drop the 5.x matrix - #182
Merged
Conversation
Closes #172. Part of #120 (Phase 3). BREAKING CHANGE: Pester 5.x is no longer supported. RequiredModules is enforced at import, so a consumer with only Pester 5.x installed cannot import the module, and Test-PSBuildPester refuses to run under an already-loaded 5.x. Same principle as the psake floor in #181: the declared minimum should be what CI actually tests. Nothing exercised a Pester 5 consumer except the matrix leg, which existed only to keep that claim honest. Two real defects go with it. Test-PSBuildPester declared a 5.0.0 minimum it could never honor. Verified by downloading that version: Pester 5.0.0 does not export New-PesterConfiguration and has no Run.SkipRemainingOnFailure, and the function calls both. The guard admitted versions that then failed with a CommandNotFoundException instead of the clear error it exists to produce. The requirements.psd1 pin moves 6.0.0 -> 6.1.0. Note the original #172 premise was wrong and is corrected on the issue: CI does honor the pin, running exactly 6.0.0 on all four legs. What is true is narrower -- the pin holds only because 6.0.0 is the highest Pester on the runner, and a newer one in a future image would silently override it. Dropping 5.x support removes machinery rather than adding it: requirements.pester-matrix.psd1 is deleted, build.ps1 loses its second Invoke-PSDepend call, and the Test-PSBuildPester matrix collapses from two majors to one. The discovery loop is kept rather than hardcoded, so a second supported major can return without rebuilding it, and it now throws when no supported major is installed instead of silently producing no tests. Consumer cost is smaller than a major bump implies: Pester 6 keeps the v5 Should -Be assertions, since Should.DisableV5 defaults to false. The one behavioral change worth flagging is Run.FailOnNullOrEmptyForEach, which now defaults to true. Suite: 463 passed, 0 failed. The drop from 472 is the removed Pester 5 matrix leg, not a regression. Test-ModuleManifest validates against the raised floor. The one analyzer finding on Test-PSBuildPester is pre-existing on main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012AKaM9i6NyMFDcJNeC34h5
Test Results 4 files ± 0 744 suites ±0 2m 27s ⏱️ - 3m 20s Results for commit e2da4d3. ± Comparison against base commit 8cb163c. This pull request removes 16 and adds 12 tests. Note that renamed tests count towards both.This pull request skips 1 test.♻️ This comment has been updated with latest results. |
…d guard The floor is stated in three places -- RequiredModules, and twice inside Test-PSBuildPester -- plus the message the guard throws. They drifted and nobody noticed for months: the manifest said 5.6.1 while the function said 5.0.0, a version that cannot run the function at all. That is the defect this pull request fixes, and nothing would have caught it recurring. The alternative was to read the floor from the manifest at runtime. Verified as workable and cheap -- Import-PowerShellDataFile on <ModuleBase>/<Name>.psd1 returns 6.0.0, about 0.4 ms a call -- but rejected. It adds a lookup that returns nothing when the module is loaded from an unusual path, and a floor of $null makes "$version -lt $null" false, so the guard would vanish silently. That is the same shape as Get-Command -Module $null applying no filter (#174) and the empty ExternalHelpFile aborting a MAML export. A hardcoded fallback would not help either: the constant would still exist, alongside a new branch that can pick the wrong one. Note $m.RequiredModules is not a route to this at all -- it reports the loaded version, not the declared minimum, so a guard built on it would compare Pester against itself. Asserting the agreement catches drift when it is introduced, in CI, with no runtime coupling and no way to fail open. Proven to work: temporarily desyncing the guard to 5.0.0 fails exactly one test, "uses the manifest floor everywhere the function states it". One of the four tests guards the test itself. If the function is refactored so neither the -MinimumVersion nor the [version] literal pattern matches, an empty match set would satisfy the comparison and prove nothing, so the count is asserted first. Also documents why "honors the Pester version that is already loaded" now skips in CI. It needs two installed Pester versions to distinguish "used the loaded one" from "imported the newest", and dropping the 5.x matrix left one. Restoring it would mean reinstating install-only machinery this pull request deletes, so it is skipped deliberately rather than by oversight. Suite: 467 passed, 0 failed. Analyzer clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012AKaM9i6NyMFDcJNeC34h5
This was referenced Aug 27, 2026
Closed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #172. Part of #120 (Phase 3).
Breaking.
RequiredModulesnow requires Pester 6.0.0 or newer, previously5.6.1, andTest-PSBuildPesterrefuses to run under anything older. With this, every dependency floor matcheswhat CI actually tests.
Why
Same principle as the psake floor in #181: the declared minimum should be what is tested.
Nothing exercised a Pester 5 consumer except the matrix leg that existed to keep the claim honest.
5.6.1Two real defects fixed alongside
Test-PSBuildPesterdeclared a floor it could never honor. Verified by downloading the versionin question:
The function calls both. So the guard admitted versions that could not work, and the caller got a
CommandNotFoundExceptioninstead of the clear "version not supported" error the guard exists toproduce.
The
requirements.psd1pin moves 6.0.0 → 6.1.0. Worth being explicit that this issue'soriginal premise was wrong, and it is corrected on #172: CI does honor the pin, running exactly
Pester v6.0.0on all four legs. I had generalized from my own machine, which has 6.1.0 installedfrom elsewhere and autoloads it. What survives is narrower and latent — the pin holds only because
6.0.0 is currently the highest Pester on the runner, and a newer one in a future image would
silently override it.
This removes machinery rather than adding it
requirements.pester-matrix.psd1build.ps1Invoke-PSDependcall deletedtests/Test-PSBuildPester.tests.ps1Test-PSBuildPester.ps1The discovery loop is deliberately kept rather than hardcoded to
6, so a second supportedmajor can return without rebuilding it. It now also throws when no supported major is installed,
instead of silently producing zero matrix legs — the same silent-nothing failure mode #174 was
about.
Consumer cost, which is smaller than a major bump implies
Should -Beand the v5 assertions still work. Pester 6'sShould.DisableV5defaults to$false, so existing suites are not forced onto theShould-*family. Verified directly.Run.FailOnNullOrEmptyForEachnow defaults to$true, where Pester 5 skipped an empty-ForEachsilently. That can turn a green suite red — usually by surfacing a test that never ranand never said so.
-AllowNullOrEmptyForEachis the escape for collections that can legitimatelybe empty.
floor, so it adds no engine constraint.
The honest argument against, recorded so it is weighed rather than buried: Pester 6.0.0 is seven
weeks old, and Pester 5.9.1 shipped two weeks ago — upstream still maintains 5.x. This requires a
recent major of the tool that runs consumers' own test suites, which is a larger imposition than a
build task runner. That was the substance of #120's July decision to keep ≥ 5.x, and this reverses
it deliberately.
Verification
regression — the matrix now reports one context,
with inner Pester 6.1.0Test-ModuleManifestvalidates against the raised floorTest-PSBuildPesteris pre-existing onmain(confirmed bystashing and re-running)
repository-specific.instructions.mdcorrected,since it still described the old 5.0.0 contract