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