mirror of https://github.com/raandree/NTFSSecurity
Browse Source
- .github/scripts/Export-WikiContent.ps1 converts Docs, except the contributor guide, into flat wiki pages: Docs/README.md becomes Home, cmdlet pages lose their platyPS metadata, links point to wiki pages or to the files on GitHub, and links in code stay unchanged. It writes a sidebar from the cmdlet groups of Docs/README.md, a footer, and the former page How-to-install, and keeps the page name Version-History that the release notes link to. - Tests/Wiki.Tests.ps1 checks the conversion rules with a sample of Docs and every link and anchor of the wiki generated from the real Docs. - README, CHANGELOG, and the version history mention the wiki again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com>pull/96/head
5 changed files with 519 additions and 2 deletions
@ -0,0 +1,279 @@ |
|||
<# |
|||
.SYNOPSIS |
|||
Converts the documentation in the Docs folder into the pages of the GitHub wiki. |
|||
|
|||
.DESCRIPTION |
|||
Writes a wiki page for every page in Docs except the contributor guide (Contributing.md and the Contributing |
|||
folder). Docs/README.md becomes the page Home, and every other page keeps its file name, so a page in |
|||
Docs/Cmdlets becomes a page named after its cmdlet. The platyPS metadata at the top of the cmdlet pages is |
|||
removed. Relative links point to the wiki pages; links to other files of the repository point to the files on |
|||
GitHub. Links in code stay unchanged. |
|||
|
|||
The script also writes the sidebar, which lists the cmdlets in the groups of the cmdlet list in Docs/README.md; |
|||
the footer; and the page How-to-install, which keeps the address of the former wiki page working. |
|||
|
|||
The script removes everything in DestinationPath except the .git folder, so that pages that no longer exist in |
|||
Docs disappear from the wiki. |
|||
|
|||
.PARAMETER Path |
|||
Specifies the Docs folder of the repository. |
|||
|
|||
.PARAMETER DestinationPath |
|||
Specifies the folder to write the wiki pages to, usually a clone of the wiki repository. The script creates the |
|||
folder if it doesn't exist. |
|||
|
|||
.PARAMETER RepositoryUrl |
|||
Specifies the address of the repository on GitHub, for links to files that aren't wiki pages. |
|||
|
|||
.PARAMETER Branch |
|||
Specifies the branch for links to files that aren't wiki pages. |
|||
|
|||
.EXAMPLE |
|||
git clone https://github.com/raandree/NTFSSecurity.wiki.git $env:TEMP\wiki |
|||
.\.github\scripts\Export-WikiContent.ps1 -Path .\Docs -DestinationPath $env:TEMP\wiki |
|||
git -C $env:TEMP\wiki status |
|||
|
|||
Writes the wiki pages into a clone of the wiki and shows which pages change. |
|||
#> |
|||
[CmdletBinding(SupportsShouldProcess)] |
|||
param ( |
|||
[Parameter(Mandatory)] |
|||
[ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })] |
|||
[string] |
|||
$Path, |
|||
|
|||
[Parameter(Mandatory)] |
|||
[ValidateNotNullOrEmpty()] |
|||
[string] |
|||
$DestinationPath, |
|||
|
|||
[Parameter()] |
|||
[ValidateNotNullOrEmpty()] |
|||
[string] |
|||
$RepositoryUrl = 'https://github.com/raandree/NTFSSecurity', |
|||
|
|||
[Parameter()] |
|||
[ValidateNotNullOrEmpty()] |
|||
[string] |
|||
$Branch = 'master' |
|||
) |
|||
|
|||
$ErrorActionPreference = 'Stop' |
|||
|
|||
function Resolve-RepositoryPath { |
|||
<# |
|||
Returns the path of a link target relative to the repository root, with / as separator, or nothing if the |
|||
link leaves the repository. |
|||
#> |
|||
param ( |
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Directory, |
|||
|
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Link |
|||
) |
|||
|
|||
$segments = New-Object -TypeName 'System.Collections.Generic.List[string]' |
|||
foreach ($segment in (('{0}/{1}' -f $Directory, $Link) -split '/')) { |
|||
if ($segment -eq '..') { |
|||
if ($segments.Count -eq 0) { |
|||
return |
|||
} |
|||
$segments.RemoveAt($segments.Count - 1) |
|||
} elseif ($segment -and $segment -ne '.') { |
|||
$segments.Add($segment) |
|||
} |
|||
} |
|||
|
|||
$segments -join '/' |
|||
} |
|||
|
|||
function ConvertTo-WikiLink { |
|||
<# |
|||
Returns the wiki address of a link on a page in Directory: the name of a wiki page, the address of a file of |
|||
the repository on GitHub, or the link itself if it is absolute or points to the same page. |
|||
#> |
|||
param ( |
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Url, |
|||
|
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Directory |
|||
) |
|||
|
|||
if ($Url -match '^(?:[a-zA-Z][a-zA-Z0-9+.-]*:|//|#)') { |
|||
return $Url |
|||
} |
|||
|
|||
$linkPath, $anchor = $Url -split '#', 2 |
|||
$target = Resolve-RepositoryPath -Directory $Directory -Link ([uri]::UnescapeDataString($linkPath)) |
|||
if (-not $target) { |
|||
return $Url |
|||
} |
|||
|
|||
$fragment = if ($anchor) { '#' + $anchor } else { '' } |
|||
if ($pageNames.ContainsKey($target)) { |
|||
return $pageNames[$target] + $fragment |
|||
} |
|||
|
|||
$view = if (Test-Path -LiteralPath (Join-Path -Path $repositoryRoot -ChildPath $target) -PathType Container) { |
|||
'tree' |
|||
} else { |
|||
'blob' |
|||
} |
|||
'{0}/{1}/{2}/{3}{4}' -f $RepositoryUrl.TrimEnd('/'), $view, $Branch, $target, $fragment |
|||
} |
|||
|
|||
function Convert-MarkdownLink { |
|||
<# |
|||
Returns the Markdown text with the links of a page in Directory converted to wiki addresses. Links in code |
|||
spans and fenced code blocks stay unchanged. |
|||
#> |
|||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute( |
|||
'PSReviewUnusedParameter', 'Directory', Justification = 'The match evaluator script block uses it.' |
|||
)] |
|||
param ( |
|||
[Parameter(Mandatory)] |
|||
[AllowEmptyString()] |
|||
[string] |
|||
$Markdown, |
|||
|
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Directory |
|||
) |
|||
|
|||
$inlinePattern = '(?<code>(?<ticks>`+).+?\k<ticks>)|(?<prefix>!?\[(?:[^\[\]`]|`[^`]*`)*\]\()(?<url>[^)\s]+)(?<suffix>(?:\s+"[^"]*")?\))' |
|||
$definitionPattern = '^(?<prefix>\s{0,3}\[[^\]]+\]:\s*)(?<url>\S+)(?<suffix>.*)$' |
|||
$convertLink = { |
|||
param ($match) |
|||
|
|||
if ($match.Groups['code'].Success) { |
|||
return $match.Value |
|||
} |
|||
$match.Groups['prefix'].Value + (ConvertTo-WikiLink -Url $match.Groups['url'].Value -Directory $Directory) + |
|||
$match.Groups['suffix'].Value |
|||
} |
|||
|
|||
$fence = $null |
|||
$lines = foreach ($line in ($Markdown -split '\r?\n')) { |
|||
if ($line -match '^\s{0,3}(?<fence>`{3,}|~{3,})') { |
|||
if (-not $fence) { |
|||
$fence = $Matches['fence'] |
|||
} elseif ($Matches['fence'].StartsWith($fence)) { |
|||
$fence = $null |
|||
} |
|||
$line |
|||
continue |
|||
} |
|||
if ($fence) { |
|||
$line |
|||
continue |
|||
} |
|||
|
|||
$line = [regex]::Replace($line, $inlinePattern, $convertLink) |
|||
[regex]::Replace($line, $definitionPattern, $convertLink) |
|||
} |
|||
|
|||
$lines -join "`n" |
|||
} |
|||
|
|||
$docsRoot = (Resolve-Path -LiteralPath $Path).ProviderPath.TrimEnd('\', '/') |
|||
$repositoryRoot = Split-Path -Path $docsRoot -Parent |
|||
$docsName = Split-Path -Path $docsRoot -Leaf |
|||
$destinationRoot = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($DestinationPath).TrimEnd('\', '/') |
|||
|
|||
# Refuse a destination that contains the documentation, such as the repository itself. |
|||
$separator = [IO.Path]::DirectorySeparatorChar |
|||
if (($docsRoot + $separator).StartsWith($destinationRoot + $separator, [StringComparison]::OrdinalIgnoreCase)) { |
|||
throw "The destination '$destinationRoot' contains the documentation in '$docsRoot'. Specify a clone of the wiki." |
|||
} |
|||
|
|||
# Collect the pages: Docs/README.md is the home page, and the contributor guide stays in the repository. |
|||
$pageNames = @{} |
|||
$pages = foreach ($file in Get-ChildItem -LiteralPath $docsRoot -Filter '*.md' -File -Recurse) { |
|||
$repositoryPath = $file.FullName.Substring($repositoryRoot.Length + 1) -replace '\\', '/' |
|||
if ($repositoryPath -match ('^{0}/Contributing(?:\.md$|/)' -f [regex]::Escape($docsName))) { |
|||
continue |
|||
} |
|||
|
|||
$name = if ($repositoryPath -eq "$docsName/README.md") { 'Home' } else { $file.BaseName } |
|||
if ($pageNames.Values -contains $name) { |
|||
throw "Two pages in '$docsRoot' would become the wiki page '$name'." |
|||
} |
|||
$pageNames[$repositoryPath] = $name |
|||
|
|||
$content = Get-Content -LiteralPath $file.FullName -Raw -Encoding UTF8 |
|||
$title = if ($content -match '(?m)^#\s+(?<title>.+?)\s*$') { $Matches['title'] } else { $name -replace '-', ' ' } |
|||
[pscustomobject]@{ |
|||
Name = $name |
|||
Title = $title |
|||
Directory = $repositoryPath.Substring(0, $repositoryPath.LastIndexOf('/')) |
|||
Content = $content |
|||
} |
|||
} |
|||
|
|||
# Remove the old pages, but keep the history of the wiki. |
|||
if (Test-Path -LiteralPath $destinationRoot) { |
|||
foreach ($item in Get-ChildItem -LiteralPath $destinationRoot -Force | Where-Object -Property Name -NE -Value '.git') { |
|||
if ($PSCmdlet.ShouldProcess($item.FullName, 'Remove')) { |
|||
Remove-Item -LiteralPath $item.FullName -Recurse -Force |
|||
} |
|||
} |
|||
} elseif ($PSCmdlet.ShouldProcess($destinationRoot, 'Create folder')) { |
|||
New-Item -ItemType Directory -Path $destinationRoot | Out-Null |
|||
} |
|||
|
|||
$wikiPages = [ordered]@{} |
|||
foreach ($page in $pages) { |
|||
$content = [regex]::Replace($page.Content, '\A---\r?\n.*?\r?\n---[ \t]*(?:\r?\n|\z)\s*', '', 'Singleline') |
|||
$wikiPages[$page.Name] = Convert-MarkdownLink -Markdown $content -Directory $page.Directory |
|||
} |
|||
|
|||
# The sidebar links the other pages and the cmdlets, grouped like the cmdlet list of the home page. |
|||
$homePage = $pages | Where-Object -Property Name -EQ -Value 'Home' |
|||
$sidebar = New-Object -TypeName 'System.Collections.Generic.List[string]' |
|||
$sidebar.Add('### [Home](Home)') |
|||
$sidebar.Add('') |
|||
foreach ($page in $pages | Where-Object { $_.Directory -eq $docsName -and $_.Name -ne 'Home' } | Sort-Object -Property Name) { |
|||
$sidebar.Add(('- [{0}]({1})' -f $page.Title, $page.Name)) |
|||
} |
|||
if ($homePage) { |
|||
$section = $null |
|||
foreach ($line in ($homePage.Content -split '\r?\n')) { |
|||
if ($line -match '^##\s+(?<title>.+?)\s*$') { |
|||
$section = $Matches['title'] |
|||
if ($section -eq 'Cmdlets') { |
|||
$sidebar.Add('') |
|||
$sidebar.Add('### Cmdlets') |
|||
} |
|||
} elseif ($section -eq 'Cmdlets' -and $line -match '^###\s+(?<title>.+?)\s*$') { |
|||
$sidebar.Add('') |
|||
$sidebar.Add(('**{0}**' -f $Matches['title'])) |
|||
$sidebar.Add('') |
|||
} elseif ($section -eq 'Cmdlets' -and $line -match '^\|\s*\[(?<name>[^\]]+)\]\((?<url>[^)\s]+)\)') { |
|||
$sidebar.Add(('- [{0}]({1})' -f $Matches['name'], (ConvertTo-WikiLink -Url $Matches['url'] -Directory $docsName))) |
|||
} |
|||
} |
|||
} |
|||
$wikiPages['_Sidebar'] = $sidebar -join "`n" |
|||
|
|||
$wikiPages['_Footer'] = ('This wiki is generated from the [{0}]({1}/tree/{2}/{0}) folder of the repository. ' + |
|||
'To change a page, edit its file there; changes made in the wiki are overwritten.') -f $docsName, $RepositoryUrl.TrimEnd('/'), $Branch |
|||
|
|||
# The former wiki page How-to-install is linked from outside; it now points to the installation steps. |
|||
if ($homePage -and $homePage.Content -match '(?m)^##\s+Installation\s*$') { |
|||
$wikiPages['How-to-install'] = "# How to install`n`nThe installation steps are in the [Installation](Home#installation) section of the [Home](Home) page." |
|||
} |
|||
|
|||
$encoding = New-Object -TypeName 'System.Text.UTF8Encoding' -ArgumentList $false |
|||
foreach ($name in $wikiPages.Keys) { |
|||
$file = Join-Path -Path $destinationRoot -ChildPath "$name.md" |
|||
if ($PSCmdlet.ShouldProcess($file, 'Write wiki page')) { |
|||
[IO.File]::WriteAllText($file, $wikiPages[$name].TrimEnd() + "`n", $encoding) |
|||
} |
|||
} |
|||
@ -0,0 +1,228 @@ |
|||
<# |
|||
Tests .github\scripts\Export-WikiContent.ps1, which converts the documentation in Docs into the pages of the |
|||
GitHub wiki: with a small sample of Docs for the conversion rules, and with the real Docs for complete pages and |
|||
working links. |
|||
#> |
|||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute( |
|||
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.' |
|||
)] |
|||
param () |
|||
|
|||
BeforeAll { |
|||
$exportScript = Join-Path -Path $PSScriptRoot -ChildPath '..\.github\scripts\Export-WikiContent.ps1' |
|||
|
|||
function Get-GitHubAnchor { |
|||
# Returns the anchors that GitHub generates for the headings of a Markdown text. |
|||
param ( |
|||
[Parameter(Mandatory)] |
|||
[string] |
|||
$Markdown |
|||
) |
|||
|
|||
$text = [regex]::Replace($Markdown, '(?ms)^```.*?^```', '') |
|||
$seen = @{} |
|||
foreach ($match in [regex]::Matches($text, '(?m)^#{1,6}\s+(.+?)\s*#*\s*$')) { |
|||
$heading = $match.Groups[1].Value -replace '\[([^\]]*)\]\([^)]*\)', '$1' -replace '[`*]', '' |
|||
$anchor = [regex]::Replace($heading.Trim().ToLowerInvariant(), '[^\p{L}\p{Nd}\s_-]', '') -replace ' ', '-' |
|||
if ($seen.ContainsKey($anchor)) { |
|||
$seen[$anchor]++ |
|||
'{0}-{1}' -f $anchor, $seen[$anchor] |
|||
} else { |
|||
$seen[$anchor] = 0 |
|||
$anchor |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Describe 'Export-WikiContent.ps1' { |
|||
Context 'When it converts a sample of Docs' { |
|||
BeforeAll { |
|||
$repositoryPath = Join-Path -Path $TestDrive -ChildPath 'repository' |
|||
$docsPath = Join-Path -Path $repositoryPath -ChildPath 'Docs' |
|||
$wikiPath = Join-Path -Path $TestDrive -ChildPath 'wiki' |
|||
foreach ($folder in "$docsPath\Cmdlets", "$docsPath\Contributing", "$wikiPath\.git") { |
|||
New-Item -ItemType Directory -Path $folder -Force | Out-Null |
|||
} |
|||
|
|||
# A clone of the wiki with pages that Docs doesn't have |
|||
Set-Content -LiteralPath "$wikiPath\.git\config" -Value '[core]' |
|||
Set-Content -LiteralPath "$wikiPath\Version-History.textile" -Value '* 4.2.4' |
|||
Set-Content -LiteralPath "$wikiPath\Old-Page.md" -Value '# Old page' |
|||
|
|||
Set-Content -LiteralPath "$repositoryPath\CHANGELOG.md" -Value '# Changelog' |
|||
Set-Content -LiteralPath "$docsPath\Contributing.md" -Value '# Contributing' |
|||
Set-Content -LiteralPath "$docsPath\Contributing\01-Getting-Started.md" -Value '# Get started' |
|||
Set-Content -LiteralPath "$docsPath\Concepts.md" -Value "# Concepts`n`n## Rights`n`nSee [Home](README.md)." |
|||
Set-Content -LiteralPath "$docsPath\README.md" -Value @' |
|||
# Thing |
|||
|
|||
[Concepts](Concepts.md#rights), [Get-Thing](Cmdlets/Get-Thing.md), and [`Set-Thing`](Cmdlets/Set-Thing.md). |
|||
[Changelog](../CHANGELOG.md), [guide](Contributing.md), and [first steps](Contributing/01-Getting-Started.md). |
|||
[Example site](https://example.com/page.md) and [cmdlets](#cmdlets). |
|||
Code keeps its links: `[Concepts](Concepts.md)`. |
|||
|
|||
```powershell |
|||
# [Concepts](Concepts.md) |
|||
``` |
|||
|
|||
## Installation |
|||
|
|||
Install the module. |
|||
|
|||
## Cmdlets |
|||
|
|||
### Getting |
|||
|
|||
| Cmdlet | Description | |
|||
| --- | --- | |
|||
| [Get-Thing](Cmdlets/Get-Thing.md) | Gets a thing. | |
|||
|
|||
### Setting |
|||
|
|||
| Cmdlet | Description | |
|||
| --- | --- | |
|||
| [Set-Thing](Cmdlets/Set-Thing.md) | Sets a thing. | |
|||
'@ |
|||
$metadata = "---`nexternal help file: Thing.dll-Help.xml`nonline version: https://example.com`nschema: 2.0.0`n---`n`n" |
|||
Set-Content -LiteralPath "$docsPath\Cmdlets\Get-Thing.md" -Value ($metadata + |
|||
"# Get-Thing`n`nSee [rights](../Concepts.md#rights), [Set-Thing](Set-Thing.md), and [home](../README.md).") |
|||
Set-Content -LiteralPath "$docsPath\Cmdlets\Set-Thing.md" -Value ($metadata + |
|||
"# Set-Thing`n`nSee [Get-Thing](Get-Thing.md).") |
|||
|
|||
& $exportScript -Path $docsPath -DestinationPath $wikiPath -RepositoryUrl 'https://github.com/contoso/Thing' -Branch 'main' |
|||
|
|||
$homePage = Get-Content -LiteralPath "$wikiPath\Home.md" -Raw |
|||
$sidebar = Get-Content -LiteralPath "$wikiPath\_Sidebar.md" -Raw |
|||
} |
|||
|
|||
It 'Should write Home, Concepts, the cmdlet pages, How-to-install, the sidebar, and the footer' { |
|||
$expected = 'Home.md', 'Concepts.md', 'Get-Thing.md', 'Set-Thing.md', 'How-to-install.md', '_Sidebar.md', '_Footer.md' |
|||
|
|||
((Get-ChildItem -LiteralPath $wikiPath -File).Name | Sort-Object) -join ', ' | |
|||
Should -BeExactly (($expected | Sort-Object) -join ', ') |
|||
} |
|||
|
|||
It 'Should keep the .git folder and remove the pages that Docs does not have' { |
|||
"$wikiPath\.git\config" | Should -Exist |
|||
"$wikiPath\Version-History.textile" | Should -Not -Exist |
|||
"$wikiPath\Old-Page.md" | Should -Not -Exist |
|||
} |
|||
|
|||
It 'Should not publish the contributor guide' { |
|||
Get-ChildItem -LiteralPath $wikiPath -Recurse -File -Filter '*Get*Started*' | Should -BeNullOrEmpty |
|||
"$wikiPath\Contributing.md" | Should -Not -Exist |
|||
} |
|||
|
|||
It 'Should convert <Link> on <Page> into <Expected>' -ForEach @( |
|||
@{ Page = 'Home'; Link = '[Concepts](Concepts.md#rights)'; Expected = '[Concepts](Concepts#rights)' } |
|||
@{ Page = 'Home'; Link = '[Get-Thing](Cmdlets/Get-Thing.md)'; Expected = '[Get-Thing](Get-Thing)' } |
|||
@{ Page = 'Home'; Link = '[`Set-Thing`](Cmdlets/Set-Thing.md)'; Expected = '[`Set-Thing`](Set-Thing)' } |
|||
@{ Page = 'Home'; Link = '[Changelog](../CHANGELOG.md)'; Expected = '[Changelog](https://github.com/contoso/Thing/blob/main/CHANGELOG.md)' } |
|||
@{ Page = 'Home'; Link = '[guide](Contributing.md)'; Expected = '[guide](https://github.com/contoso/Thing/blob/main/Docs/Contributing.md)' } |
|||
@{ Page = 'Home'; Link = '[first steps](Contributing/01-Getting-Started.md)'; Expected = '[first steps](https://github.com/contoso/Thing/blob/main/Docs/Contributing/01-Getting-Started.md)' } |
|||
@{ Page = 'Home'; Link = '[Example site](https://example.com/page.md)'; Expected = '[Example site](https://example.com/page.md)' } |
|||
@{ Page = 'Home'; Link = '[cmdlets](#cmdlets)'; Expected = '[cmdlets](#cmdlets)' } |
|||
@{ Page = 'Concepts'; Link = '[Home](README.md)'; Expected = '[Home](Home)' } |
|||
@{ Page = 'Get-Thing'; Link = '[rights](../Concepts.md#rights)'; Expected = '[rights](Concepts#rights)' } |
|||
@{ Page = 'Get-Thing'; Link = '[Set-Thing](Set-Thing.md)'; Expected = '[Set-Thing](Set-Thing)' } |
|||
@{ Page = 'Get-Thing'; Link = '[home](../README.md)'; Expected = '[home](Home)' } |
|||
) { |
|||
$content = Get-Content -LiteralPath "$wikiPath\$Page.md" -Raw |
|||
|
|||
$content | Should -Match ([regex]::Escape($Expected)) |
|||
if ($Link -ne $Expected) { |
|||
$content | Should -Not -Match ([regex]::Escape($Link)) |
|||
} |
|||
} |
|||
|
|||
It 'Should keep links in code unchanged' { |
|||
$homePage | Should -Match ([regex]::Escape('`[Concepts](Concepts.md)`')) |
|||
$homePage | Should -Match ([regex]::Escape('# [Concepts](Concepts.md)')) |
|||
} |
|||
|
|||
It 'Should remove the platyPS metadata from the cmdlet pages' { |
|||
Get-Content -LiteralPath "$wikiPath\Get-Thing.md" -TotalCount 1 | Should -BeExactly '# Get-Thing' |
|||
} |
|||
|
|||
It 'Should link Home and the other pages in the sidebar' { |
|||
$sidebar | Should -Match ([regex]::Escape('[Home](Home)')) |
|||
$sidebar | Should -Match ([regex]::Escape('[Concepts](Concepts)')) |
|||
} |
|||
|
|||
It 'Should list the cmdlets in the sidebar under the groups of Docs/README.md' { |
|||
$sidebar | Should -Match '(?s)Getting.*\[Get-Thing\]\(Get-Thing\).*Setting.*\[Set-Thing\]\(Set-Thing\)' |
|||
} |
|||
|
|||
It 'Should say in the footer that the wiki is generated from Docs' { |
|||
Get-Content -LiteralPath "$wikiPath\_Footer.md" -Raw | |
|||
Should -Match ([regex]::Escape('(https://github.com/contoso/Thing/tree/main/Docs)')) |
|||
} |
|||
|
|||
It 'Should keep the address of the former page How-to-install' { |
|||
Get-Content -LiteralPath "$wikiPath\How-to-install.md" -Raw | Should -Match ([regex]::Escape('(Home#installation)')) |
|||
} |
|||
} |
|||
|
|||
Context 'When it converts the documentation of the repository' { |
|||
BeforeAll { |
|||
$repositoryPath = Join-Path -Path $PSScriptRoot -ChildPath '..' |
|||
$docsPath = Join-Path -Path $repositoryPath -ChildPath 'Docs' |
|||
$wikiPath = Join-Path -Path $TestDrive -ChildPath 'wiki-of-the-repository' |
|||
|
|||
& $exportScript -Path $docsPath -DestinationPath $wikiPath |
|||
|
|||
$pages = Get-ChildItem -LiteralPath $wikiPath -Filter '*.md' |
|||
$cmdletNames = (Get-ChildItem -LiteralPath (Join-Path -Path $docsPath -ChildPath 'Cmdlets') -Filter '*.md').BaseName |
|||
} |
|||
|
|||
It 'Should write a page for every page in Docs except the contributor guide, and one for every cmdlet' { |
|||
$topPages = (Get-ChildItem -LiteralPath $docsPath -Filter '*.md' | |
|||
Where-Object -Property Name -NotIn -Value 'README.md', 'Contributing.md').BaseName |
|||
$expected = @('Home', 'How-to-install', '_Sidebar', '_Footer') + $topPages + $cmdletNames |
|||
|
|||
($pages.BaseName | Sort-Object) -join ', ' | Should -BeExactly (($expected | Sort-Object) -join ', ') |
|||
} |
|||
|
|||
It 'Should keep the page name Version-History, which the release notes of 4.2.4 and 4.2.6 link to' { |
|||
Join-Path -Path $wikiPath -ChildPath 'Version-History.md' | Should -Exist |
|||
} |
|||
|
|||
It 'Should list every cmdlet in the sidebar' { |
|||
$sidebar = Get-Content -LiteralPath (Join-Path -Path $wikiPath -ChildPath '_Sidebar.md') -Raw |
|||
|
|||
$cmdletNames | Where-Object -FilterScript { $sidebar -notmatch ('\]\({0}\)' -f [regex]::Escape($_)) } | |
|||
Should -BeNullOrEmpty |
|||
} |
|||
|
|||
It 'Should link only to existing wiki pages, their anchors, and existing files of the repository' { |
|||
$anchors = @{} |
|||
foreach ($page in $pages) { |
|||
$anchors[$page.BaseName] = @(Get-GitHubAnchor -Markdown (Get-Content -LiteralPath $page.FullName -Raw)) |
|||
} |
|||
|
|||
$brokenLinks = foreach ($page in $pages) { |
|||
$text = [regex]::Replace((Get-Content -LiteralPath $page.FullName -Raw), '(?ms)^```.*?^```', '') |
|||
$text = [regex]::Replace($text, '`[^`\n]+`', '') |
|||
foreach ($match in [regex]::Matches($text, '\]\((?<url>[^)\s]+)\)')) { |
|||
$url = $match.Groups['url'].Value |
|||
if ($url -match '^https://github\.com/raandree/NTFSSecurity/(?:blob|tree)/master/(?<path>[^#]+)') { |
|||
if (-not (Test-Path -LiteralPath (Join-Path -Path $repositoryPath -ChildPath $Matches['path']))) { |
|||
'{0}: {1}' -f $page.BaseName, $url |
|||
} |
|||
} elseif ($url -notmatch '^[a-z]+:') { |
|||
$target, $anchor = $url -split '#', 2 |
|||
if (-not $target) { |
|||
$target = $page.BaseName |
|||
} |
|||
if (-not $anchors.ContainsKey($target) -or ($anchor -and $anchors[$target] -notcontains $anchor)) { |
|||
'{0}: {1}' -f $page.BaseName, $url |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
$brokenLinks | Should -BeNullOrEmpty |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue