Skip to content

build: add standard psake bootstrap (Init/Clean/Build/Test/Analyze/Publish) - #493

Merged
HeyItsGilbert merged 4 commits into
mainfrom
build/psake-bootstrap
Sep 17, 2026
Merged

HeyItsGilbert merged 4 commits into
mainfrom
build/psake-bootstrap

Conversation

@HeyItsGilbert

@HeyItsGilbert HeyItsGilbert commented Sep 17, 2026

Copy link
Copy Markdown
Member

Goal

Add the standard psake bootstrap described by Phase 3b of the revival playbook, mirroring PSDepend's requirements.psd1 + build.ps1 + psakeFile.ps1 convention.

Closes #485

What's here

  • requirements.psd1 / build.ps1 / psakeFile.ps1 at repo root, matching PSDepend's psake+PowerShellBuild+PSDepend layout.
  • psakeFile.ps1 uses -FromModule PowerShellBuild, adding Init, Clean, StageFiles, Build, Analyze, Pester, Test, BuildHelp, Publish, and ?. Invoke-psake ? lists all tasks.
  • GenerateFormatData task runs ahead of StageFiles since the manifest's FormatsToProcess entry (PSKoans.format.ps1xml) is EZOut-generated and gitignored — the module can't even import without it.
  • .gitignore extended for Output/**, Tests/out/**, testResults.xml.

Test suite bootstrap

Replaced #Requires -Modules PSKoans across all 26 Tests/**/*.Tests.ps1 files with a BeforeDiscovery block that builds (if needed) and imports the staged module from Output/, matching PSDepend's own staged-import test convention. This surfaced and fixed real, pre-existing bugs:

  • Unscoped mocks across ~13 test files: without -ModuleName 'PSKoans' a Mock never intercepts calls made from inside the module, so real cmdlets ran instead — including Start-Process launching a real editor during a local test run.
  • Data-corruption bug: Reset-PSKoan.Tests.ps1 and Update-PSKoanFile.Tests.ps1 called (Get-PSKoan -Scope Module).Path directly from test scope. Module-scoped mocks don't intercept direct test-scope calls, so the real cmdlet ran and Set-Content overwrote every staged koan file with fixture content. Fixed by computing paths into variables instead of depending on mock interception outside module scope.
  • requirements.psd1's Pester pin relaxed (no exact version): PowerShellBuild's Test-PSBuildPester unconditionally does Import-Module Pester -MinimumVersion 5.0.0, which throws if a different Pester major is already loaded in-process (reproduced deterministically outside psake).
  • Added a $env:PSModulePath entry for the staged module root so using module PSKoans resolves during koan file parsing/execution — without it, KoanValidation.Tests.ps1's static parse checks failed for every real koan topic.
  • Fixed a handful of Pester 6 strictness regressions surfaced by the above (unmatched -ParameterFilter mocks, empty -TestCases arrays crashing discovery).

Documentation

Restored comment-based help for all 13 exported functions, ported straight from the existing docs/*.md PlatyPS output (parameter sets verified to still match current source — no drift), matching the style already used in PSKoans/Private/*.ps1. Fixes the ModuleHelp.Tests.ps1 documentation-content checks.

Verification

./build.ps1 Test runs clean end to end — no hangs, no crashes: 739 passed / 10 failed.

All 10 remaining failures trace to one pre-existing, out-of-scope bug: Invoke-Koan.ps1 builds @{ Script = ... } and splats it into Invoke-Pester, but Pester 5+ removed the legacy -Script parameter. This is a real product bugGet-Karma/Show-Karma will throw for real users whenever the koan-execution path is actually exercised. Worth its own issue; flagging here since it's severe, but it's unrelated to this build-tooling change and I didn't touch Invoke-Koan.ps1.

Acceptance criteria

  • Root psakeFile.ps1 exposes Init, Clean, Build, Test, Analyze, and Publish.
  • Invoke-psake ? lists the tasks.
  • Invoke-psake Test runs the Pester suite successfully.

…blish)

Mirrors PSDepend's psake+PowerShellBuild+PSDepend build convention:

- requirements.psd1 / build.ps1 / psakeFile.ps1 at repo root.
- psakeFile.ps1 uses -FromModule PowerShellBuild, adding Init, Clean,
  StageFiles, Build, Analyze, Pester, Test, BuildHelp, Publish, and ?.
  GenerateFormatData task added ahead of StageFiles since the manifest's
  FormatsToProcess entry (PSKoans.format.ps1xml) is EZOut-generated and
  gitignored, so the module can't even import without it.
- .gitignore extended for Output/**, Tests/out/**, testResults.xml.

Test suite bootstrap (Tests/**/*.Tests.ps1):

- Replaced #Requires -Modules PSKoans with a BeforeDiscovery block that
  builds (if needed) and imports the staged module from Output/, matching
  PSDepend's own staged-import test convention.
- Fixed unscoped Mocks across ~13 test files: without -ModuleName 'PSKoans'
  a Mock never intercepts calls made from inside the module, so real
  cmdlets ran instead -- including Start-Process launching a real editor.
- Fixed a real data-corruption bug: Reset-PSKoan.Tests.ps1 and
  Update-PSKoanFile.Tests.ps1 called (Get-PSKoan -Scope Module).Path
  directly from test scope; since module-scoped mocks don't intercept
  direct test-scope calls, the real cmdlet ran and Set-Content overwrote
  every staged koan file with fixture content. Fixed by computing paths
  into variables instead of depending on mock interception outside module
  scope.
- requirements.psd1's Pester pin relaxed (no exact version): PowerShellBuild's
  Test-PSBuildPester unconditionally does Import-Module -MinimumVersion,
  which throws if a different Pester major is already loaded in-process.
- Added $env:PSModulePath entry for the staged module root so `using
  module PSKoans` resolves during koan file parsing/execution.
- Fixed several Pester 6 strictness regressions surfaced by the above
  (unmatched ParameterFilter mocks, empty -TestCases arrays).

Invoke-psake Test now runs cleanly (no hangs/crashes): 631 passed / 100
failed. All 100 remaining failures are pre-existing and out of scope:
~90 are missing comment-based help content (ModuleHelp.Tests.ps1), and
~9 trace to Invoke-Koan.ps1 splatting a legacy Pester 3/4 `-Script`
parameter that Pester 5+ removed -- a real product bug affecting
Get-Karma/Show-Karma at runtime, filed separately from this build change.

Closes #485
Copilot AI lite review requested due to automatic review settings September 17, 2026 05:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The build bootstrap has path, task-list initialization, generated-file, and nested-process termination issues.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a standard psake/PowerShellBuild bootstrap and updates tests to validate the staged module output.

Changes:

  • Adds dependency, build, psake, and cleanup configuration.
  • Adds staged-module initialization to the Pester suite.
  • Scopes mocks to PSKoans and fixes fixture path handling.
File summaries
File Description
requirements.psd1 Declares build dependencies.
psakeFile.ps1 Defines build and test tasks.
build.ps1 Adds the build entry point.
.gitignore Ignores build artifacts.
Tests/ModuleValidation.Tests.ps1 Stages and imports the module.
Tests/ModuleHelp.Tests.ps1 Updates help test bootstrap.
Tests/KoanValidation.Tests.ps1 Updates koan validation bootstrap.
Tests/Functions/Public/Update-PSKoan.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Show-Karma.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Show-Advice.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 Updates test bootstrap.
Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Reset-PSKoan.Tests.ps1 Fixes fixture path handling and mocks.
Tests/Functions/Public/Register-Advice.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Get-PSKoan.Tests.ps1 Uses staged test data.
Tests/Functions/Public/Get-Karma.Tests.ps1 Fixes module-scoped mocks.
Tests/Functions/Public/Get-Blank.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 Fixes fixture path handling.
Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/New-KoanRunspace.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Measure-Koan.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Invoke-Koan.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Get-KoanIt.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Get-KoanAst.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 Updates test bootstrap.
Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 Updates test bootstrap.
Review details
  • Files reviewed: 29/30 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread build.ps1 Outdated
Comment thread build.ps1
Comment thread psakeFile.ps1 Outdated
Copies the existing PlatyPS-generated docs/*.md content back into
comment-based help blocks for all 13 exported functions, matching the
style already used throughout PSKoans/Private/*.ps1 (help block as the
first statement inside the function body).

Verified every function's declared parameter set still matches what's
documented in docs/*.md (no drift), so this is a straight port, not a
rewrite.

Fixes the ~90 ModuleHelp.Tests.ps1 failures from PR #493 by supplying
Synopsis, Description, per-parameter descriptions, examples with
remarks, and an Author note for each function.

Invoke-psake Test: 739 passed / 10 failed (down from 631/100). The 10
remaining failures are all the pre-existing Invoke-Koan -Script/Pester 5
incompatibility already called out in #493 -- unrelated to this change.
- build.ps1: resolve requirements.psd1/psakeFile.ps1 against $PSScriptRoot
  instead of the caller's CWD, so the entry point works when invoked from
  another working directory.
- Tests/**/*.Tests.ps1: run the nested `build.ps1 -Task Build` bootstrap
  (triggered when a test file is run directly, outside the full psake
  pipeline) in a child pwsh process instead of in-process. build.ps1 ends
  with `exit`, which was terminating the hosting PowerShell/Pester process
  when the build ran nested. The parent now calls Set-BuildEnvironment
  itself after a successful child build, since env vars set inside the
  child don't propagate back.
- psakeFile.ps1: resolve Test.RootDir from $PSScriptRoot instead of
  $env:BHProjectPath, which is only populated by Set-BuildEnvironment in
  build.ps1. A bare `Invoke-psake -BuildFile ./psakeFile.ps1 -TaskList ?`
  in a fresh session was passing $null to Join-Path and failing before
  listing tasks.

Verified: `Invoke-psake ?` works in a fresh session with no prior
BuildHelpers init; build.ps1 works when invoked from a different CWD;
a single test file run via raw Invoke-Pester (no prior build) no longer
kills the host process. Full suite unchanged: 739 passed / 10 failed
(same pre-existing Invoke-Koan issue from #493).
@HeyItsGilbert

Copy link
Copy Markdown
Member Author

Addressed all three findings in 16bc2c7:

  1. build.ps1 CWD-relative paths: requirements.psd1 and psakeFile.ps1 are now resolved via Join-Path $PSScriptRoot ... instead of bare ./.... Verified & 'D:/PSKoans/build.ps1' -Help works correctly when invoked from an unrelated CWD.

  2. exit killing the host process: confirmed this was real — build.ps1 ends with exit, and the BeforeDiscovery blocks' nested .\build.ps1 -Task Build ran in-process, so a direct Invoke-Pester run on any test file (without going through the full psake pipeline first) would terminate the calling PowerShell/Pester process entirely. Fixed by running the nested build in a child pwsh process and checking $LASTEXITCODE; the parent then calls Set-BuildEnvironment -Force itself since the child's env var changes don't propagate back. Verified a single test file run via raw Invoke-Pester now completes and returns control to the caller.

  3. $env:BHProjectPath null in Properties block: confirmed — a bare Invoke-psake -BuildFile ./psakeFile.ps1 -TaskList ? in a fresh session (no prior Set-BuildEnvironment) passed $null to Join-Path and failed before listing tasks. Switched Test.RootDir to resolve from $PSScriptRoot instead, which is always available. Verified Invoke-psake ? now lists all tasks with zero prior setup.

Full suite re-verified after all three fixes: 739 passed / 10 failed, same baseline as before (10 remaining failures are the pre-existing Invoke-Koan -Script/Pester 5 incompatibility called out in the PR description, unrelated to these fixes).

Invoke-Koan splats its ParameterSplat straight into Invoke-Pester inside
a child runspace. Every caller populated the splat with a 'Script' key,
which was Pester v3/v4's parameter for the tests to run. Pester 5+
renamed this to -Path, so every koan execution (Get-Karma, Show-Karma)
threw ParameterBindingException: "A parameter cannot be found that
matches parameter name 'Script'."

Renamed Script -> Path in Invoke-Koan.ps1 (both the internal
ScriptRequirements AST parse and the doc example), its caller in
Get-Karma.ps1, and the test splats in Invoke-Koan.Tests.ps1. Also fixed
an unrelated latent test bug in the same file: `Invoke-Koan ... |
Should -Not -Throw` piped a value into -Throw, which requires a
scriptblock -- wrapped the call in `{ }`.

Verified: full suite 749 passed / 0 failed (up from 739/10), Analyze
task still clean (pre-existing Warnings only, no Errors).
@HeyItsGilbert

Copy link
Copy Markdown
Member Author

Fixed the pre-existing `Invoke-Koan` bug in 54b84d4: it splatted `Script` (a Pester v3/v4 parameter) into `Invoke-Pester`, which Pester 5+ renamed to `Path`. This broke every real koan execution path (`Get-Karma`, `Show-Karma`) with `ParameterBindingException`.

Renamed `Script` → `Path` in `Invoke-Koan.ps1` (source + doc example), its caller in `Get-Karma.ps1`, and the test splats in `Invoke-Koan.Tests.ps1`. Also fixed a latent test bug in the same file — `Invoke-Koan ... | Should -Not -Throw` piped a value instead of a scriptblock into `-Throw`.

Full suite now 749 passed / 0 failed (up from 739/10). `Analyze` still clean (pre-existing Warnings only, no Errors).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add standard psake build entry points

2 participants