mirror of https://github.com/raandree/NTFSSecurity
Browse Source
* fix(help): ship the generated help file so Get-Help works Get-Help showed only the syntax of the cmdlets: the module shipped a pre-4.x MAML file for the old command names under the wrong name (NTFSSecurity-Help.xml), while PowerShell looks for en-US\NTFSSecurity.dll-Help.xml. - Generate en-US\NTFSSecurity.dll-Help.xml from Docs/Cmdlets with New-ExternalHelp and commit it. The csproj copies it to the output, so every build ships it, including the local Debug builds that releases are published from. - List all runtime files, including the help file, in FileList. - Remove the stale NTFSSecurity-Help.xml and the unused help editor project NTFSSecurity\Help\NTFSSecurity.Help.pshproj. - Add Tests\Help.Tests.ps1 (Pester 5): Get-Help shows the synopsis, parameters, examples, and online link of every page, and Get-Help -Online resolves to the GitHub page. - Reword six sentences in five cmdlet pages so that each link ends its sentence: platyPS drops the space after a link in the help text. - CI regenerates the help file and fails when it differs from the committed file, then runs the Pester tests. - Document the regeneration step and the link rule in the contributor guide. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> * ci: report each Pester test once on AppVeyor AppVeyor build 54834154 passed all 218 Pester tests but listed 870 on its Tests tab: the NUnit import files a Pester 5 test under every block that contains it (Pester, test file, Describe, and Context). Report the results through the build worker API instead (POST api/tests/batch): one entry per test with its outcome, duration, and error message. Outside AppVeyor, and when no test ran, the step sends nothing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com>pull/94/head
committed by
GitHub
20 changed files with 10348 additions and 5163 deletions
@ -0,0 +1,26 @@ |
|||
--- |
|||
status: accepted |
|||
date: 2026-10-02 |
|||
last-verified: 2026-10-02 |
|||
owner: shared |
|||
source: maintainer choice in work package 2 (option A) |
|||
--- |
|||
|
|||
# Decision 8: Commit the generated help file and check it in CI |
|||
|
|||
- Choice: `NTFSSecurity\en-US\NTFSSecurity.dll-Help.xml` is generated from |
|||
`Docs/Cmdlets` with `New-ExternalHelp` (platyPS 0.14.2, Windows |
|||
PowerShell 5.1) and committed. `NTFSSecurity.csproj` copies it to the |
|||
output as `Content`, the manifest `FileList` lists it, and `appveyor.yml` |
|||
regenerates it and fails on `git status --porcelain -- NTFSSecurity/en-US`. |
|||
- Rationale: Releases are built locally in Visual Studio (Debug, written to |
|||
`C:\Program Files\WindowsPowerShell\Modules\NTFSSecurity`) and published |
|||
by hand with `Publish-Module`. A committed file ships with every build |
|||
and needs no tool on the build machine. Generating it in an MSBuild step |
|||
would need platyPS on every build machine, or would silently ship without |
|||
help when platyPS is missing. |
|||
- Consequence: every change to `Docs/Cmdlets` must be followed by |
|||
`New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath .\NTFSSecurity\en-US |
|||
-Force`. The output is deterministic (byte-identical between runs), so |
|||
the CI check is exact. |
|||
- Rejected: an MSBuild `AfterBuild` target that runs platyPS. |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,115 @@ |
|||
<# |
|||
Tests that Get-Help shows the help that is generated from Docs/Cmdlets for |
|||
every cmdlet of the module built in NTFSSecurity\bin\Release. |
|||
#> |
|||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute( |
|||
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.' |
|||
)] |
|||
param () |
|||
|
|||
BeforeDiscovery { |
|||
$pagePath = Join-Path -Path $PSScriptRoot -ChildPath '..\Docs\Cmdlets' |
|||
$sectionPattern = '(?ms)^## (?<Heading>[A-Z ]+?)\s*$(?<Text>.*?)(?=^## |\z)' |
|||
|
|||
$helpPages = foreach ($page in Get-ChildItem -Path $pagePath -Filter '*.md') { |
|||
$content = Get-Content -LiteralPath $page.FullName -Raw |
|||
$sections = @{} |
|||
foreach ($match in [regex]::Matches($content, $sectionPattern)) { |
|||
$sections[$match.Groups['Heading'].Value] = $match.Groups['Text'].Value |
|||
} |
|||
|
|||
$parameterNames = [regex]::Matches("$($sections['PARAMETERS'])", '(?m)^### -(?<Name>\w+)') | |
|||
ForEach-Object -Process { $_.Groups['Name'].Value } |
|||
|
|||
@{ |
|||
CommandName = $page.BaseName |
|||
Synopsis = "$($sections['SYNOPSIS'])".Trim() |
|||
ExampleCount = [regex]::Matches("$($sections['EXAMPLES'])", '(?m)^### ').Count |
|||
ParameterNames = @($parameterNames) |
|||
OnlineUri = [regex]::Match($content, '(?m)^online version: (?<Uri>\S+)').Groups['Uri'].Value |
|||
} |
|||
} |
|||
} |
|||
|
|||
Describe 'Help of the NTFSSecurity cmdlets' { |
|||
BeforeAll { |
|||
$modulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\NTFSSecurity\bin\Release\NTFSSecurity.psd1' |
|||
$module = Import-Module -Name $modulePath -Force -PassThru -ErrorAction Stop |
|||
$pagePath = Join-Path -Path $PSScriptRoot -ChildPath '..\Docs\Cmdlets' |
|||
|
|||
<# |
|||
With this test hook, Get-Help -Online returns the URI instead of opening a browser. In PowerShell 7, |
|||
the hook also makes Get-Help ignore the help file, so this test runs only in Windows PowerShell. |
|||
#> |
|||
$testHooks = [psobject].Assembly.GetType('System.Management.Automation.Internal.InternalTestHooks') |
|||
$bypassOnlineHelp = if ($testHooks -and $PSVersionTable.PSEdition -ne 'Core') { |
|||
$testHooks.GetField('BypassOnlineHelpRetrieval', [Reflection.BindingFlags] 'NonPublic, Static') |
|||
} |
|||
} |
|||
|
|||
AfterAll { |
|||
Remove-Module -Name NTFSSecurity -Force -ErrorAction SilentlyContinue |
|||
} |
|||
|
|||
It 'Should ship the help file in the en-US folder' { |
|||
Join-Path -Path $module.ModuleBase -ChildPath 'en-US\NTFSSecurity.dll-Help.xml' | Should -Exist |
|||
} |
|||
|
|||
It 'Should have a page in Docs/Cmdlets for every exported cmdlet' { |
|||
$pageNames = (Get-ChildItem -Path $pagePath -Filter '*.md').BaseName | Sort-Object |
|||
$cmdletNames = (Get-Command -Module NTFSSecurity -CommandType Cmdlet).Name | Sort-Object |
|||
|
|||
$cmdletNames -join ', ' | Should -BeExactly ($pageNames -join ', ') |
|||
} |
|||
|
|||
Context '<CommandName>' -ForEach $helpPages { |
|||
BeforeAll { |
|||
$help = Get-Help -Name $CommandName -Full |
|||
} |
|||
|
|||
It 'Should show the synopsis from Docs/Cmdlets' { |
|||
"$($help.Synopsis)".Trim() | Should -BeExactly $Synopsis |
|||
} |
|||
|
|||
It 'Should describe the parameters from Docs/Cmdlets' { |
|||
$describedParameterNames = foreach ($parameter in $help.parameters.parameter) { |
|||
if (($parameter.description.Text -join '').Trim()) { |
|||
$parameter.name |
|||
} |
|||
} |
|||
|
|||
($describedParameterNames | Sort-Object) -join ', ' | |
|||
Should -BeExactly (($ParameterNames | Sort-Object) -join ', ') |
|||
} |
|||
|
|||
It 'Should show the <ExampleCount> examples from Docs/Cmdlets' { |
|||
@($help.examples.example | Where-Object -FilterScript { $_ }) | Should -HaveCount $ExampleCount |
|||
} |
|||
|
|||
It 'Should link to the online version from Docs/Cmdlets' { |
|||
@($help.relatedLinks.navigationLink)[0].uri | Should -BeExactly $OnlineUri |
|||
} |
|||
|
|||
It 'Should keep the space after each link in the help text' { |
|||
# platyPS writes an inline link as "text (url)" and drops the space that follows it. |
|||
$help | Out-String -Width 4096 | Should -Not -Match '\((?:\.\./|https?://)[^)\s]+\)\w' |
|||
} |
|||
|
|||
It 'Should open the online version with Get-Help -Online' { |
|||
if (-not $bypassOnlineHelp) { |
|||
$reason = 'the test hook for Get-Help -Online reads the help file only in Windows PowerShell' |
|||
Set-ItResult -Skipped -Because $reason |
|||
return |
|||
} |
|||
|
|||
$bypassOnlineHelp.SetValue($null, $true) |
|||
try { |
|||
$onlineHelp = Get-Help -Name $CommandName -Online |
|||
} finally { |
|||
$bypassOnlineHelp.SetValue($null, $false) |
|||
} |
|||
|
|||
"$onlineHelp" | Should -Match ('{0}$' -f [regex]::Escape($OnlineUri)) |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue