diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7748d..a5c27fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ own `CHANGELOG.md` (generated from `CHANGELOG.template.md` during init). - Renamed required PowerShell Gallery publish secret `PS_GALLERY_KEY` → `PSGALLERY_API_KEY` so the secret name matches the env var name PowerShellBuild reads (eliminating the previous mapping caveat). New modules created from the template after this change pick up the new name automatically. **Migration for existing modules:** create a new `PSGALLERY_API_KEY` repo secret with the same value, update `.github/workflows/PublishModuleToPowerShellGallery.yaml` to reference `secrets.PSGALLERY_API_KEY`, then delete the old `PS_GALLERY_KEY` secret. - Test scaffolding (`tests/Help.tests.ps1`, `tests/Manifest.tests.ps1`, `tests/Meta.tests.ps1`, `tests/MetaFixers.psm1`, and the `tests/Unit/` templates) no longer names parameters on single-argument calls (e.g. `Test-Path $path`, `Get-Module $name`, `Get-Help $command`), matching the scoped named-parameter rule — name parameters only when a call passes two or more arguments. A trailing switch counts as an argument, so `Split-Path -Path $x -Parent`, `Get-Content -Path $x -Raw`, and `Get-ChildItem -Path $x -Recurse` keep their names, as do genuinely multi-value calls (`Join-Path`, `Get-Command -Name … -CommandType …`) and `Test-Path -LiteralPath`. +- `tests/Manifest.tests.ps1` and the `tests/Unit/` templates now use the same standalone build-bootstrap approach introduced for `tests/Help.tests.ps1` (#38): their `BHBuildOutput`-missing guards delegate to `build.ps1 -Task 'Build' -Bootstrap` (invoked with `&`, not dot-sourced, so its terminating `exit` is contained) instead of calling `Invoke-psake` against `build.psake.ps1` directly. This routes dependency bootstrap and BuildHelpers environment setup through the canonical entry point, so these tests can be run standalone (e.g. from an editor or by an agent) without first running `./build.ps1`. No effect on CI or `./build.ps1` runs — the guard only fires when `BHBuildOutput` is unset. ## [2026.04.29] - 2026-04-29 diff --git a/tests/Manifest.tests.ps1 b/tests/Manifest.tests.ps1 index dd7d7bf..ddf7a18 100644 --- a/tests/Manifest.tests.ps1 +++ b/tests/Manifest.tests.ps1 @@ -57,19 +57,25 @@ param() BeforeDiscovery { + # Resolve the project root once (tests/ -> repo root); used both to locate + # build.ps1 below and to compute the staged build output path. + $projectRoot = Split-Path -Path $PSScriptRoot -Parent + # Check if the BHBuildOutput environment variable exists to determine if this test is running in a psake # build or not. If it does not exist, it is not running in a psake build, so build the module. if ($null -eq $Env:BHBuildOutput) { - $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\build.psake.ps1' - $invokePsakeParameters = @{ - TaskList = 'Build' - BuildFile = $buildFilePath - } - Invoke-psake @invokePsakeParameters + # Standalone run (e.g. Invoke-Pester on this file directly, or an agent + # running one test): the module isn't built and the BuildHelpers env vars + # aren't set. Defer to build.ps1 -- the canonical entry point -- to bootstrap + # dependencies, set the BuildHelpers environment, and stage the module. + # Invoke with & (not dot-sourcing): build.ps1 ends in an exit statement, and + # the call operator contains it to the script boundary instead of ending the + # whole Pester run. + $buildScript = Join-Path -Path $projectRoot -ChildPath 'build.ps1' + & $buildScript -Task 'Build' -Bootstrap } # PowerShellBuild outputs to Output///, override BHBuildOutput - $projectRoot = Split-Path -Path $PSScriptRoot -Parent $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" $moduleVersion = (Import-PowerShellDataFile $sourceManifest).ModuleVersion $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion" @@ -96,19 +102,25 @@ BeforeDiscovery { $isTemplate = Test-Path -LiteralPath (Join-Path -Path $Env:BHProjectPath -ChildPath 'CHANGELOG.template.md') } BeforeAll { + # Resolve the project root once (tests/ -> repo root); used both to locate + # build.ps1 below and to compute the staged build output path. + $projectRoot = Split-Path -Path $PSScriptRoot -Parent + # Check if the BHBuildOutput environment variable exists to determine if this test is running in a psake # build or not. If it does not exist, it is not running in a psake build, so build the module. if ($null -eq $Env:BHBuildOutput) { - $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\build.psake.ps1' - $invokePsakeParameters = @{ - TaskList = 'Build' - BuildFile = $buildFilePath - } - Invoke-psake @invokePsakeParameters + # Standalone run (e.g. Invoke-Pester on this file directly, or an agent + # running one test): the module isn't built and the BuildHelpers env vars + # aren't set. Defer to build.ps1 -- the canonical entry point -- to bootstrap + # dependencies, set the BuildHelpers environment, and stage the module. + # Invoke with & (not dot-sourcing): build.ps1 ends in an exit statement, and + # the call operator contains it to the script boundary instead of ending the + # whole Pester run. + $buildScript = Join-Path -Path $projectRoot -ChildPath 'build.ps1' + & $buildScript -Task 'Build' -Bootstrap } # PowerShellBuild outputs to Output///, override BHBuildOutput - $projectRoot = Split-Path -Path $PSScriptRoot -Parent $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" $moduleVersion = (Import-PowerShellDataFile $sourceManifest).ModuleVersion $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion" diff --git a/tests/Unit/Private/Invoke-{{Prefix}}Helper.tests.ps1 b/tests/Unit/Private/Invoke-{{Prefix}}Helper.tests.ps1 index 0811a60..d577e29 100644 --- a/tests/Unit/Private/Invoke-{{Prefix}}Helper.tests.ps1 +++ b/tests/Unit/Private/Invoke-{{Prefix}}Helper.tests.ps1 @@ -6,18 +6,24 @@ param() BeforeDiscovery { + # Resolve the project root once (tests/Unit// -> repo root, three levels up); + # used both to locate build.ps1 below and to compute the staged build output path. + $projectRoot = Split-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -Parent + # Build module if not running in psake build if ($null -eq $Env:BHBuildOutput) { - $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\..\build.psake.ps1' - $invokePsakeParameters = @{ - TaskList = 'Build' - BuildFile = $buildFilePath - } - Invoke-psake @invokePsakeParameters + # Standalone run (e.g. Invoke-Pester on this file directly, or an agent + # running one test): the module isn't built and the BuildHelpers env vars + # aren't set. Defer to build.ps1 -- the canonical entry point -- to bootstrap + # dependencies, set the BuildHelpers environment, and stage the module. + # Invoke with & (not dot-sourcing): build.ps1 ends in an exit statement, and + # the call operator contains it to the script boundary instead of ending the + # whole Pester run. + $buildScript = Join-Path -Path $projectRoot -ChildPath 'build.ps1' + & $buildScript -Task 'Build' -Bootstrap } # PowerShellBuild outputs to Output/// - $projectRoot = Split-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -Parent $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" $moduleVersion = (Import-PowerShellDataFile $sourceManifest).ModuleVersion $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion" diff --git a/tests/Unit/Public/Get-{{Prefix}}Example.tests.ps1 b/tests/Unit/Public/Get-{{Prefix}}Example.tests.ps1 index 5763829..7672096 100644 --- a/tests/Unit/Public/Get-{{Prefix}}Example.tests.ps1 +++ b/tests/Unit/Public/Get-{{Prefix}}Example.tests.ps1 @@ -6,18 +6,24 @@ param() BeforeDiscovery { + # Resolve the project root once (tests/Unit// -> repo root, three levels up); + # used both to locate build.ps1 below and to compute the staged build output path. + $projectRoot = Split-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -Parent + # Build module if not running in psake build if ($null -eq $Env:BHBuildOutput) { - $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\..\build.psake.ps1' - $invokePsakeParameters = @{ - TaskList = 'Build' - BuildFile = $buildFilePath - } - Invoke-psake @invokePsakeParameters + # Standalone run (e.g. Invoke-Pester on this file directly, or an agent + # running one test): the module isn't built and the BuildHelpers env vars + # aren't set. Defer to build.ps1 -- the canonical entry point -- to bootstrap + # dependencies, set the BuildHelpers environment, and stage the module. + # Invoke with & (not dot-sourcing): build.ps1 ends in an exit statement, and + # the call operator contains it to the script boundary instead of ending the + # whole Pester run. + $buildScript = Join-Path -Path $projectRoot -ChildPath 'build.ps1' + & $buildScript -Task 'Build' -Bootstrap } # PowerShellBuild outputs to Output/// - $projectRoot = Split-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -Parent $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" $moduleVersion = (Import-PowerShellDataFile $sourceManifest).ModuleVersion $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion"