From f5016441c938ab9816a5d83ef5aba988dc082443 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Sun, 3 May 2026 19:24:51 -0400 Subject: [PATCH 1/2] fix(build): target staged output for code coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pester reports 0% coverage on every module scaffolded from this template because the coverage globs point at the source tree (`{{ModuleName}}/{Public,Private}/*.ps1`) but the test files Import-Module from the staged build output (`Output///`). Pester treats the two paths as different files, so every executed line counts as "missed." The natural fix — using `$Env:BHBuildOutput` directly — does not work: PowerShellBuild only rewrites that variable to the staged version path later, inside its own tasks. At psake `properties`-evaluation time, `$Env:BHBuildOutput` is still BuildHelpers' default `/BuildOutput`, which doesn't exist yet and would cause Pester to bail with "Could not resolve coverage path." Compute the staged path explicitly from the manifest version (read via `$Env:BHPSModuleManifest`, which BuildHelpers populates before psake runs). This also drops the `{{ModuleName}}` placeholder from the coverage section entirely, since the path is now derived from the already-substituted BuildHelpers env vars. Verified downstream in JsmOperations: Pester goes from 0% / 75% to 100% / 75% on the same test suite, with no test changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- build.psake.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/build.psake.ps1 b/build.psake.ps1 index 009e259..b5bc448 100644 --- a/build.psake.ps1 +++ b/build.psake.ps1 @@ -14,9 +14,16 @@ properties { $PSBPreference.Test.OutputFile = [IO.Path]::Combine($PSScriptRoot, 'out', 'testResults.xml') $PSBPreference.Test.OutputFormat = 'NUnitXml' $PSBPreference.Test.CodeCoverage.Enabled = $true + # Coverage must target the staged build output, not the source tree — tests + # Import-Module from Output//, so Pester only records hits + # against those paths. $Env:BHBuildOutput points at /BuildOutput at + # properties-evaluation time (PowerShellBuild rewrites it later inside its + # tasks), so we compute the staged path from the manifest version here. + $_moduleVersion = (Import-PowerShellDataFile -Path $Env:BHPSModuleManifest).ModuleVersion + $_stagedOutput = Join-Path $PSScriptRoot "Output/$Env:BHProjectName/$_moduleVersion" $PSBPreference.Test.CodeCoverage.Files = @( - "$PSScriptRoot/{{ModuleName}}/Public/*.ps1" - "$PSScriptRoot/{{ModuleName}}/Private/*.ps1" + "$_stagedOutput/Public/*.ps1" + "$_stagedOutput/Private/*.ps1" ) $PSBPreference.Test.CodeCoverage.Threshold = 0 # Threshold enforced by Codecov $PSBPreference.Test.CodeCoverage.OutputFile = [IO.Path]::Combine($PSScriptRoot, 'out', 'codeCoverage.xml') From e445d7faf265f00021c98a3258ba068184af5fb2 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Sun, 3 May 2026 20:02:15 -0400 Subject: [PATCH 2/2] fix(build): guard coverage env vars and normalize path style Address PR #19 review feedback: - Guard against missing $Env:BHPSModuleManifest / $Env:BHProjectName so bypassing build.ps1 (and Set-BuildEnvironment) fails fast with an actionable message instead of an obscure Import-PowerShellDataFile null-binding error. (Copilot review) - Switch the staged-output assembly from Join-Path with embedded forward slashes to [IO.Path]::Combine to match the rest of the properties block and avoid mixed separators on Windows. (CodeRabbit review) Co-Authored-By: Claude Opus 4.7 (1M context) --- build.psake.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.psake.ps1 b/build.psake.ps1 index b5bc448..b575ff7 100644 --- a/build.psake.ps1 +++ b/build.psake.ps1 @@ -19,8 +19,11 @@ properties { # against those paths. $Env:BHBuildOutput points at /BuildOutput at # properties-evaluation time (PowerShellBuild rewrites it later inside its # tasks), so we compute the staged path from the manifest version here. + if (-not $Env:BHPSModuleManifest -or -not $Env:BHProjectName) { + throw 'Coverage configuration requires BuildHelpers env vars. Run via ./build.ps1 or call Set-BuildEnvironment first.' + } $_moduleVersion = (Import-PowerShellDataFile -Path $Env:BHPSModuleManifest).ModuleVersion - $_stagedOutput = Join-Path $PSScriptRoot "Output/$Env:BHProjectName/$_moduleVersion" + $_stagedOutput = [IO.Path]::Combine($PSScriptRoot, 'Output', $Env:BHProjectName, $_moduleVersion) $PSBPreference.Test.CodeCoverage.Files = @( "$_stagedOutput/Public/*.ps1" "$_stagedOutput/Private/*.ps1"