Problem
Several PSModule actions ship a private helper script module named generically Helpers.psm1 (module name Helpers). That name collides with the shared framework Helpers module that:
PSModule/Install-PSModuleHelpers installs and most actions import via Import-Module -Name 'Helpers', and
PSModule/Invoke-Pester loads into the test session.
When two modules named Helpers are loaded in the same runner session, PowerShell can no longer disambiguate them by name. This is not theoretical:
Generic names are also poor for traceability: from Get-Module, an error, or a stack trace you cannot tell which action a Helpers module belongs to.
Proposed standard
An action's own helper/script module MUST be named after the action repository it belongs to:
Examples:
| Action repo |
Module file |
Module name |
Build-PSModule |
Build-PSModule.Helpers.psm1 |
Build-PSModule.Helpers |
Invoke-Pester |
Invoke-Pester.Helpers.psm1 |
Invoke-Pester.Helpers |
Resolve-PSModuleVersion |
Resolve-PSModuleVersion.Helpers.psm1 |
Resolve-PSModuleVersion.Helpers |
Rules:
- Import the module by path from the action's entry script, e.g.
Import-Module -Name "$PSScriptRoot/<ActionRepo>.Helpers.psm1" -Force.
- Tests mock the module's internal calls with the unambiguous module name, e.g.
Mock -CommandName SomeCommand -ModuleName '<ActionRepo>.Helpers'.
- The one shared module distributed by
PSModule/Install-PSModuleHelpers stays the single canonical Helpers module (it is imported by name across actions). That is the only permitted Helpers; every per-action helper module must be action-scoped.
Rationale
- No collisions — an action-scoped name never clashes with the shared
Helpers module or with another action's helper module loaded in the same session.
- Mockable —
Mock -ModuleName '<ActionRepo>.Helpers' is unambiguous, so unit tests can intercept module-internal calls.
- Traceable — the name identifies the owning action in
Get-Module, errors, and stack traces.
Is this general?
The hard requirement — a helper/script module bundled inside a GitHub Action must be uniquely named after the action — comes from the shared runner module session (all imported modules coexist in one session, so a generic name can shadow a shared one). It is primarily a GitHub Actions concern, but "do not ship a generically-named module that can shadow a shared module" is good hygiene generally, so state it as a general principle with the action naming as the concrete rule.
Where this lands
- Add the rule where PowerShell module/script naming is defined:
src/docs/Coding-Standards/PowerShell/Scripts.md (helper/script modules used by actions) and/or src/docs/Coding-Standards/Naming.md.
- Cross-reference it from
src/docs/Coding-Standards/GitHub-Actions.md (authoring actions).
Acceptance criteria
Ecosystem rollout
Applying this to the existing PSModule actions is tracked separately in PSModule/Process-PSModule (companion issue linked below).
Problem
Several PSModule actions ship a private helper script module named generically
Helpers.psm1(module nameHelpers). That name collides with the shared frameworkHelpersmodule that:PSModule/Install-PSModuleHelpersinstalls and most actions import viaImport-Module -Name 'Helpers', andPSModule/Invoke-Pesterloads into the test session.When two modules named
Helpersare loaded in the same runner session, PowerShell can no longer disambiguate them by name. This is not theoretical:Resolve-PSModuleVersiontests failed in CI withRuntimeException: Multiple script or manifest modules named 'Helpers' are currently loadedbecause Pester'sMock -CommandName Find-PSResource -ModuleName Helperscould not tell the twoHelpersmodules apart. It passed locally (no frameworkHelpersloaded) and failed in CI (frameworkHelperspresent). Fixed by renaming the module — see 🚀 [Feature]: Version output always emitted regardless of publish decision PSModule/Resolve-PSModuleVersion#4.Generic names are also poor for traceability: from
Get-Module, an error, or a stack trace you cannot tell which action aHelpersmodule belongs to.Proposed standard
An action's own helper/script module MUST be named after the action repository it belongs to:
Examples:
Build-PSModuleBuild-PSModule.Helpers.psm1Build-PSModule.HelpersInvoke-PesterInvoke-Pester.Helpers.psm1Invoke-Pester.HelpersResolve-PSModuleVersionResolve-PSModuleVersion.Helpers.psm1Resolve-PSModuleVersion.HelpersRules:
Import-Module -Name "$PSScriptRoot/<ActionRepo>.Helpers.psm1" -Force.Mock -CommandName SomeCommand -ModuleName '<ActionRepo>.Helpers'.PSModule/Install-PSModuleHelpersstays the single canonicalHelpersmodule (it is imported by name across actions). That is the only permittedHelpers; every per-action helper module must be action-scoped.Rationale
Helpersmodule or with another action's helper module loaded in the same session.Mock -ModuleName '<ActionRepo>.Helpers'is unambiguous, so unit tests can intercept module-internal calls.Get-Module, errors, and stack traces.Is this general?
The hard requirement — a helper/script module bundled inside a GitHub Action must be uniquely named after the action — comes from the shared runner module session (all imported modules coexist in one session, so a generic name can shadow a shared one). It is primarily a GitHub Actions concern, but "do not ship a generically-named module that can shadow a shared module" is good hygiene generally, so state it as a general principle with the action naming as the concrete rule.
Where this lands
src/docs/Coding-Standards/PowerShell/Scripts.md(helper/script modules used by actions) and/orsrc/docs/Coding-Standards/Naming.md.src/docs/Coding-Standards/GitHub-Actions.md(authoring actions).Acceptance criteria
<ActionRepo>.Helpersnaming rule for action helper modules, with rationale and theInstall-PSModuleHelperscarve-out.GitHub-Actions.mdreferences the rule.Ecosystem rollout
Applying this to the existing PSModule actions is tracked separately in
PSModule/Process-PSModule(companion issue linked below).