5454 . PARAMETER requestTimeoutSec
5555 The number of seconds before we timeout when sending an individual web request. Default is 15 seconds.
5656
57+ . PARAMETER allowRelativeLinksFile
58+ Path to a file containing file path patterns (supporting wildcards) for which relative links are permitted even when
59+ checkLinkGuidance is true. Relative links in matching files are still verified for correctness. One pattern per line;
60+ lines beginning with '#' are treated as comments.
61+
5762 . EXAMPLE
5863 PS> .\Verify-Links.ps1 C:\README.md
5964
@@ -80,7 +85,8 @@ param (
8085 [string ] $localGithubClonedRoot = " " ,
8186 [string ] $localBuildRepoName = " " ,
8287 [string ] $localBuildRepoPath = " " ,
83- [string ] $requestTimeoutSec = 15
88+ [string ] $requestTimeoutSec = 15 ,
89+ [string ] $allowRelativeLinksFile = (Join-Path $PSScriptRoot " allow-relative-links.txt" )
8490)
8591
8692Set-StrictMode - Version 3.0
@@ -247,8 +253,9 @@ function ResolveUri ([System.Uri]$referralUri, [string]$link)
247253
248254 $linkUri = [System.Uri ]$link ;
249255 # Our link guidelines do not allow relative links so only resolve them when we are not
250- # validating links against our link guidelines (i.e. !$checkLinkGuideance)
251- if ($checkLinkGuidance -and ! $linkUri.IsAbsoluteUri ) {
256+ # validating links against our link guidelines (i.e. !$checkLinkGuidance) or when
257+ # relative links are explicitly allowed for the current page.
258+ if ($checkLinkGuidance -and ! $allowRelativeLinksForCurrentPage -and ! $linkUri.IsAbsoluteUri ) {
252259 return $linkUri
253260 }
254261
@@ -428,7 +435,7 @@ function CheckLink ([System.Uri]$linkUri, $allowRetry=$true)
428435 $linkValid = $false
429436 }
430437 # Check if the url is relative links, suppress the archor link validation.
431- if (! $linkUri.IsAbsoluteUri -and ! $link.StartsWith (" #" )) {
438+ if (! $allowRelativeLinksForCurrentPage -and ! $ linkUri.IsAbsoluteUri -and ! $link.StartsWith (" #" )) {
432439 LogWarning " DO NOT use relative link $linkUri . Please use absolute link instead. Check here for more information: https://aka.ms/azsdk/guideline/links"
433440 $linkValid = $false
434441 }
@@ -512,12 +519,41 @@ if ($PSVersionTable.PSVersion.Major -lt 6)
512519}
513520$ignoreLinks = @ ();
514521if (Test-Path $ignoreLinksFile ) {
515- $ignoreLinks = (Get-Content $ignoreLinksFile ).Where ({ $_.Trim () -ne " " -and ! $_.StartsWith (" #" ) })
522+ $ignoreLinks = (Get-Content $ignoreLinksFile ).Where ({ $_.Trim () -ne " " -and ! $_.Trim ().StartsWith(" #" ) })
523+ }
524+
525+ $allowRelativeLinkRegexes = @ ()
526+ if ($allowRelativeLinksFile -and (Test-Path $allowRelativeLinksFile )) {
527+ $allowRelativeLinkRegexes = (Get-Content $allowRelativeLinksFile ).Where ({ $_.Trim () -ne " " -and ! $_.Trim ().StartsWith(" #" ) }) | ForEach-Object {
528+ $normalizedPattern = $_.Trim ().Replace(' \' , ' /' )
529+ # Convert glob pattern to regex: ** matches anything including separators, * matches within a segment
530+ $regexStr = " ^.*" + [regex ]::Escape($normalizedPattern ).Replace(" \*\*" , " .*" ).Replace(" \*" , " [^/]*" ) + " .*$"
531+ @ {
532+ Pattern = $normalizedPattern
533+ Regex = [System.Text.RegularExpressions.Regex ]::new($regexStr , [System.Text.RegularExpressions.RegexOptions ]::IgnoreCase)
534+ }
535+ }
536+ Write-Verbose " Loaded $ ( $allowRelativeLinkRegexes.Count ) allow-relative-links pattern(s) from '$allowRelativeLinksFile '."
537+ }
538+
539+ function Test-PageUriMatchesRelativeLinkPattern ([System.Uri ]$pageUri ) {
540+ if ($allowRelativeLinkRegexes.Count -eq 0 ) { return $false }
541+ $pathToCheck = if ($pageUri.IsFile ) { $pageUri.LocalPath } else { $pageUri.ToString () }
542+ # Normalize separators for consistent matching
543+ $pathToCheck = $pathToCheck.Replace (' \' , ' /' )
544+ foreach ($entry in $allowRelativeLinkRegexes ) {
545+ if ($entry.Regex.IsMatch ($pathToCheck )) {
546+ Write-Verbose " Page '$pathToCheck ' matches allow-relative-links pattern '$ ( $entry.Pattern ) '."
547+ return $true
548+ }
549+ }
550+ return $false
516551}
517552
518553# Use default hashtable constructor instead of @{} because we need them to be case sensitive
519554$checkedPages = New-Object Hashtable
520555$checkedLinks = New-Object Hashtable
556+ $allowRelativeLinksForCurrentPage = $false
521557
522558if ($inputCacheFile )
523559{
@@ -535,7 +571,7 @@ if ($inputCacheFile)
535571 elseif (Test-Path $inputCacheFile ) {
536572 $cacheContent = Get-Content $inputCacheFile - Raw
537573 }
538- $goodLinks = $cacheContent.Split (" `n " ).Where ({ $_.Trim () -ne " " -and ! $_.StartsWith (" #" ) })
574+ $goodLinks = $cacheContent.Split (" `n " ).Where ({ $_.Trim () -ne " " -and ! $_.Trim (). StartsWith(" #" ) })
539575
540576 foreach ($goodLink in $goodLinks ) {
541577 $goodLink = $goodLink.Trim ()
@@ -558,8 +594,6 @@ foreach ($url in $urls) {
558594
559595LogGroupStart " Link checking details"
560596
561- $originalcheckLinkGuidance = $checkLinkGuidance
562-
563597while ($pageUrisToCheck.Count -ne 0 )
564598{
565599 $pageUri = $pageUrisToCheck.Dequeue ();
@@ -568,10 +602,10 @@ while ($pageUrisToCheck.Count -ne 0)
568602 if ($checkedPages.ContainsKey ($pageUri )) { continue }
569603 $checkedPages [$pageUri ] = $true ;
570604
571- # copilot instructions require the use of relative links which is against our general guidance
572- # but we mainly care about those guidelines for docs publishing and not copilot instructions
573- # so we can disable the guidelines while validating copilot instruction files .
574- if ($pageUri -match " instructions.md$ " ) { $checkLinkGuidance = $false }
605+ # Allow relative links for pages matching patterns in the allow-relative-links configuration file.
606+ # The links themselves are still checked for correctness, only the relative-link restriction is lifted.
607+ # Other link guidance (e.g. http vs https, uppercase anchors, locale) continues to apply .
608+ if ($checkLinkGuidance -and ( Test-PageUriMatchesRelativeLinkPattern $pageUri )) { $allowRelativeLinksForCurrentPage = $true }
575609
576610 [string []] $linkUris = GetLinks $pageUri
577611 Write-Host " Checking $ ( $linkUris.Count ) links found on page $pageUri " ;
@@ -597,7 +631,7 @@ while ($pageUrisToCheck.Count -ne 0)
597631 Write-Host " Exception encountered while processing pageUri $pageUri : $ ( $_.Exception ) "
598632 throw
599633 } finally {
600- $checkLinkGuidance = $originalcheckLinkGuidance
634+ $allowRelativeLinksForCurrentPage = $false
601635 }
602636}
603637
0 commit comments