Skip to content

Commit 8fa878a

Browse files
⚙️ [Maintenance]: Public help-link checks now support any HTTPS host (#532)
Public command help-link validation now works with any HTTPS documentation host while preserving the required module and function path structure. Repositories can publish their command reference outside the PSModule documentation site without weakening the canonical URL contract. ## Changed: Public help-link validation Every public function must provide a first `.LINK` entry. The test fails immediately when no `.LINK` section is found. When a link is present, it must be an absolute HTTPS URL with a host and the canonical `/Module/Functions/<relative-command>/` path; query strings and fragments are rejected. The PowerShell module standard, framework-test reference, pre-review validation checklist, module-structuring guide, and skip-test guide now document this requirement using a configurable HTTPS documentation host. --- <details> <summary>Technical details</summary> - Changed `.github/actions/Test-PSModule/src/tests/SourceCode/PSModule/PSModule.Tests.ps1` to require a link, then parse the first `.LINK` URI and validate its scheme, host, path, query, and fragment instead of comparing against a hardcoded `psmodule.io` origin. - Updated one grouped command fixture in each test repository to use `https://docs.example.com`, proving the test does not depend on the PSModule host. - Documented `PublicHelpLink` in `docs/content/reference/powershell-module-standard.md` and `docs/content/reference/framework-test-ids.md`. - Added the requirement to `docs/content/guides/validating-before-review.md` and replaced fixed-host examples in the structuring and skip-test guides with `<DocumentationHost>`. - Validation: the targeted Pester 6.1.0 source-code suite passed 13 tests for both `tests/srcTestRepo` and `tests/srcWithManifestTestRepo`; `zensical build --strict` and `git diff --check` passed. | Changed surface | Standards checked | Framework docs checked | Result | | --- | --- | --- | --- | | `.github/actions/Test-PSModule/**` (PowerShell) | MSX PowerShell standard | Public command help-link contract | Aligned | | `tests/**` (PowerShell fixtures) | MSX PowerShell standard | Source-code test fixtures | Aligned | | `docs/content/reference/**` and `docs/content/guides/**` (Markdown) | MSX Documentation Model, Markdown | Module layout and framework-test guidance | Aligned | Issue convergence sweep: scoped to reusable public help-link validation and its contributor guidance. This change does not generate missing links during scaffolding or build, so the broader follow-up remains open. </details> <details> <summary>Relevant issues (or links)</summary> ### Related work - References #445 - References #453 </details> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent d4b270c commit 8fa878a

8 files changed

Lines changed: 25 additions & 13 deletions

File tree

.github/actions/Test-PSModule/src/tests/SourceCode/PSModule/PSModule.Tests.ps1

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ BeforeDiscovery {
5959

6060
@{
6161
DocumentationPath = $documentationPath
62-
ExpectedLink = "https://psmodule.io/$ModuleName/Functions/$documentationPath/"
6362
FilePath = $_.FullName
6463
}
6564
}
@@ -360,15 +359,25 @@ Describe 'PSModule - SourceCode tests' {
360359
$tokens.count -ne 0
361360
}
362361
}
363-
It 'Should put the canonical documentation link first for <DocumentationPath> (ID: PublicHelpLink)' -ForEach $publicHelpLinkTestCases {
364-
param($DocumentationPath, $ExpectedLink, $FilePath)
362+
It 'Should require a canonical documentation link for <DocumentationPath> (ID: PublicHelpLink)' -ForEach $publicHelpLinkTestCases {
363+
param($DocumentationPath, $FilePath)
365364

366365
$content = Get-Content -Path $FilePath -Raw
367366
$links = [regex]::Matches($content, '(?ms)^\s*\.LINK\s*\r?\n\s*(?<Uri>\S+)')
368367

369368
$links.Count | Should -BeGreaterThan 0 -Because "$DocumentationPath should have a documentation link"
370-
$links[0].Groups['Uri'].Value |
371-
Should -BeExactly $ExpectedLink -Because "$DocumentationPath should put its canonical documentation link first"
369+
$link = $links[0].Groups['Uri'].Value
370+
$parsedLink = $null
371+
[Uri]::TryCreate($link, [UriKind]::Absolute, [ref]$parsedLink) |
372+
Should -BeTrue -Because "$DocumentationPath should use an absolute documentation link"
373+
$parsedLink.Scheme |
374+
Should -BeExactly 'https' -Because "$DocumentationPath should use HTTPS for its documentation link"
375+
$parsedLink.Host |
376+
Should -Not -BeNullOrEmpty -Because "$DocumentationPath should specify a documentation host"
377+
$parsedLink.AbsolutePath |
378+
Should -BeExactly "/$ModuleName/Functions/$DocumentationPath/" -Because "$DocumentationPath should use the canonical documentation path"
379+
$parsedLink.Query | Should -BeNullOrEmpty -Because "$DocumentationPath should not add a query to its documentation link"
380+
$parsedLink.Fragment | Should -BeNullOrEmpty -Because "$DocumentationPath should not add a fragment to its documentation link"
372381
}
373382
It 'All public functions/filters have tests (ID: FunctionTest)' {
374383
$issues = @('')

docs/content/guides/skipping-framework-tests.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function Get-ComplexData {
6262
This file intentionally skips only the FunctionCount framework test.
6363
6464
.LINK
65-
https://psmodule.io/<ModuleName>/Functions/Get-ComplexData
65+
https://<DocumentationHost>/<ModuleName>/Functions/Get-ComplexData
6666
#>
6767
[OutputType([PSCustomObject])]
6868
[CmdletBinding()]
@@ -104,7 +104,7 @@ function Get-RawData {
104104
This function is a private helper for Get-ComplexData.
105105
106106
.LINK
107-
https://psmodule.io/<ModuleName>/Functions/Get-ComplexData
107+
https://<DocumentationHost>/<ModuleName>/Functions/Get-ComplexData
108108
#>
109109
[OutputType([string])]
110110
[CmdletBinding()]
@@ -145,7 +145,7 @@ function Format-ComplexData {
145145
This function is a private helper for Get-ComplexData.
146146
147147
.LINK
148-
https://psmodule.io/<ModuleName>/Functions/Get-ComplexData
148+
https://<DocumentationHost>/<ModuleName>/Functions/Get-ComplexData
149149
#>
150150
[OutputType([PSCustomObject])]
151151
[CmdletBinding()]
@@ -163,7 +163,7 @@ function Format-ComplexData {
163163
}
164164
```
165165

166-
Replace `<ModuleName>` with the module's published name. If the public function belongs to a group, insert `<Group>/` between `Functions/` and `Get-ComplexData`.
166+
Replace `<DocumentationHost>` with the HTTPS host that publishes the module documentation and `<ModuleName>` with the module's published name. If the public function belongs to a group, insert `<Group>/` between `Functions/` and `Get-ComplexData`.
167167

168168
The skip exempts only `FunctionCount`. Every function in the file must still follow the [PowerShell function standard](https://msx.no/docs/Coding-Standards/PowerShell/Functions/), including complete comment-based help, matching `[OutputType()]` and `.OUTPUTS` metadata, typed parameters, and implicit output.
169169

docs/content/guides/structuring-your-module.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ Key expectations:
6767
- A group's overview page (`<Category>/<Category>.md` named after the folder, or `<Category>/index.md`) becomes that group's section landing page in the docs navigation.
6868
- The build step compiles `src/` into a root module file and removes the original project layout from the artifact.
6969
- Documentation generation mirrors the `src/functions/public` hierarchy so help content always aligns with source.
70-
- Put the canonical public help URL first in each public command's comment-based help. For a command at `src/functions/public/<Group>/<Name>.ps1`, use `https://psmodule.io/<ModuleName>/Functions/<Group>/<Name>/`. `Test-PSModule` enforces this as `PublicHelpLink`; additional `.LINK` entries may follow.
70+
- Put the canonical public help URL first in each public command's comment-based help. For a command at `src/functions/public/<Group>/<Name>.ps1`, use `https://<DocumentationHost>/<ModuleName>/Functions/<Group>/<Name>/` with the HTTPS host that publishes the module documentation. `Test-PSModule` enforces this as `PublicHelpLink`; additional `.LINK` entries may follow.
7171
- Point each private helper's `.LINK` entry to the public command it supports, using that command's canonical grouped URL.
7272

7373
### Grouping and published help URLs
7474

75-
Process-PSModule generates command help and publishes each page to mirror the relative path under `src/functions/public/`. Moving an existing command into a group therefore changes its published URL from `https://psmodule.io/<ModuleName>/Functions/<Name>/` to `https://psmodule.io/<ModuleName>/Functions/<Group>/<Name>/`.
75+
Process-PSModule generates command help and publishes each page to mirror the relative path under `src/functions/public/`. Moving an existing command into a group therefore changes its published URL from `https://<DocumentationHost>/<ModuleName>/Functions/<Name>/` to `https://<DocumentationHost>/<ModuleName>/Functions/<Group>/<Name>/`.
7676

7777
When regrouping a command, update its first public `.LINK`, every private-helper `.LINK` that points to it, and any other references to the old URL in the same change. Process-PSModule does not create redirects for the old path; arrange a redirect separately in the publishing layer when existing links must continue to work.
7878

docs/content/guides/validating-before-review.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR
5555

5656
- comment-based help is present for every changed function, including private helpers
5757
- help sections, examples, `.INPUTS`, `.OUTPUTS`, and parameter documentation match the function contract from [MSX PowerShell Functions](https://msx.no/docs/Coding-Standards/PowerShell/Functions/)
58+
- every public function has a first `.LINK` entry using an absolute HTTPS URL whose path matches the generated command documentation path
5859
- public-function links and usage examples are current enough that generated documentation will stay accurate
5960

6061
Do not treat help as optional cleanup. In PSModule repositories, the function help is part of the delivered behavior.

docs/content/reference/framework-test-ids.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Run by the [Test source code](pipeline-stages.md#test-source-code) job against f
2626
| `CmdletBinding` | Functions (Generic) | Functions should include the `[CmdletBinding()]` attribute. | `#SkipTest:CmdletBinding:Simple helper function` |
2727
| `ParamBlock` | Functions (Generic) | Functions should have a parameter block (`param()`). | `#SkipTest:ParamBlock:No parameters needed` |
2828
| `FunctionTest` | Functions (Public) | All public functions and filters should have corresponding tests. | `#SkipTest:FunctionTest:Test in development` |
29+
| `PublicHelpLink` | Functions (Public) | Every public function and filter should have a first `.LINK` entry with an absolute HTTPS URL whose path matches its generated command documentation path. | `#SkipTest:PublicHelpLink:Legacy documentation link` |
2930

3031
## Module tests
3132

docs/content/reference/powershell-module-standard.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ The CI pipeline automatically tests every source file against the following rule
358358
| `CmdletBinding` | Every function must have `[CmdletBinding()]` |
359359
| `ParamBlock` | Every function must have a `param()` block |
360360
| `FunctionTest` | Every public function must be referenced by the tests; its behavior must be covered whether the suite is per-command or grouped |
361+
| `PublicHelpLink` | Every public function must have a first `.LINK` entry with an absolute HTTPS URL whose path is `/Module/Functions/<relative-command>/` |
361362

362363
To skip a specific rule for one file only, add a comment at the very top of that file:
363364

tests/srcTestRepo/src/functions/public/PSModule/Get-PSModuleTest.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function Get-PSModuleTest {
1717
"Hello, World!"
1818
1919
.LINK
20-
https://psmodule.io/PSModuleTest2/Functions/PSModule/Get-PSModuleTest/
20+
https://docs.example.com/PSModuleTest2/Functions/PSModule/Get-PSModuleTest/
2121
#>
2222
[CmdletBinding()]
2323
param (

tests/srcWithManifestTestRepo/src/functions/public/PSModule/Get-PSModuleTest.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function Get-PSModuleTest {
1717
"Hello, World!"
1818
1919
.LINK
20-
https://psmodule.io/PSModuleTest/Functions/PSModule/Get-PSModuleTest/
20+
https://docs.example.com/PSModuleTest/Functions/PSModule/Get-PSModuleTest/
2121
#>
2222
[CmdletBinding()]
2323
param (

0 commit comments

Comments
 (0)