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