From 13a3197ef5a0de4380cd831479a7699478b9f45c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 8 Jul 2026 01:35:53 +0200 Subject: [PATCH] docs: name GitHub Action helper modules after the action Bundled helper modules named generically (Helpers) collide with shared or sibling modules in the runner's single module session, breaking module resolution and Mock -ModuleName. Require action-scoped names (action-name.Helpers). Declares the standard from issue #24. --- src/docs/Coding-Standards/GitHub-Actions.md | 21 +++++++++++++++++++ .../Coding-Standards/PowerShell/Scripts.md | 1 + 2 files changed, 22 insertions(+) diff --git a/src/docs/Coding-Standards/GitHub-Actions.md b/src/docs/Coding-Standards/GitHub-Actions.md index 1b331f4..5d2956f 100644 --- a/src/docs/Coding-Standards/GitHub-Actions.md +++ b/src/docs/Coding-Standards/GitHub-Actions.md @@ -514,6 +514,27 @@ appears. `main.` sits at the action root for a single-file action, or under `src/` as the entry point alongside the other modules. +### Name helper modules after the action + +- **A helper module bundled inside an action is named after the action**, not + given a generic name. For a `publish-docs` action the module is + `publish-docs.Helpers` in `publish-docs.Helpers.psm1`, imported by path from + the entry script. +- **Why it matters:** every module imported during a job shares one session on + the runner. A generic name — `Helpers`, `Utils`, `Common` — collides with a + shared module of the same name (an ecosystem often installs a shared helper + module that actions import by name) or with another action's helper loaded in + the same job. Once two loaded modules share a name they can no longer be told + apart: module resolution is ambiguous, and unit tests that target a module by + name — mocking a command *inside* the module, say — fail because the framework + cannot choose which copy to patch. +- **An action-scoped name is unambiguous, mockable, and traceable.** It never + clashes, tests can address it by name, and it identifies the owning action in + loaded-module listings, errors, and stack traces. +- **The exception is a module published for sharing.** A helper whose whole + purpose is to be installed and imported by many actions keeps its shared, + stable name; only an action's *private* helper module is action-scoped. + ## Toolchain Two linters enforce this standard in CI, and their configuration is derived from diff --git a/src/docs/Coding-Standards/PowerShell/Scripts.md b/src/docs/Coding-Standards/PowerShell/Scripts.md index 98e726a..90c0be2 100644 --- a/src/docs/Coding-Standards/PowerShell/Scripts.md +++ b/src/docs/Coding-Standards/PowerShell/Scripts.md @@ -46,6 +46,7 @@ $ErrorActionPreference = 'Stop' ## Rules - **Name scripts `Verb-Noun.ps1`** to match the function convention. +- **Name a helper module bundled inside a GitHub Action after the action** (`action-name.Helpers`), never a generic name like `Helpers` — a generic name collides with shared or sibling modules in the runner's shared session. See [GitHub Actions](../GitHub-Actions.md#name-helper-modules-after-the-action). - **No side effects on load.** A script runs top to bottom when invoked; it should not do work merely by being dot-sourced. - **Return objects**, so the script composes in a pipeline like any other command.