2020-03-24 19:08:37 +01:00
|
|
|
# Copyright (c) Microsoft Corporation.
|
2019-01-16 01:20:45 +01:00
|
|
|
# Licensed under the MIT License.
|
|
|
|
|
|
|
|
Describe "Verify Markdown Links" {
|
|
|
|
BeforeAll {
|
2019-01-16 23:28:10 +01:00
|
|
|
if(!(Get-Command -Name 'markdown-link-check' -ErrorAction SilentlyContinue))
|
|
|
|
{
|
|
|
|
Write-Verbose "installing markdown-link-check ..." -Verbose
|
2019-02-02 03:03:12 +01:00
|
|
|
start-nativeExecution {
|
2019-07-04 05:08:52 +02:00
|
|
|
sudo yarn global add markdown-link-check@3.7.2
|
|
|
|
}
|
2019-01-16 23:28:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!(Get-Module -Name 'ThreadJob' -ListAvailable -ErrorAction SilentlyContinue))
|
|
|
|
{
|
|
|
|
Install-Module -Name ThreadJob -Scope CurrentUser
|
|
|
|
}
|
2019-01-16 01:20:45 +01:00
|
|
|
|
|
|
|
# Cleanup jobs for reliability
|
2020-05-07 14:00:30 +02:00
|
|
|
Get-Job | Remove-Job -Force
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
AfterAll {
|
|
|
|
# Cleanup jobs to leave the process the same
|
2020-05-07 14:00:30 +02:00
|
|
|
Get-Job | Remove-Job -Force
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
|
2019-01-16 23:28:10 +01:00
|
|
|
$groups = Get-ChildItem -Path "$PSScriptRoot\..\..\..\*.md" -Recurse | Where-Object {$_.DirectoryName -notlike '*node_modules*'} | Group-Object -Property directory
|
2019-01-16 01:20:45 +01:00
|
|
|
|
|
|
|
$jobs = @{}
|
|
|
|
# start all link verification in parallel
|
|
|
|
Foreach($group in $groups)
|
|
|
|
{
|
2020-05-07 14:00:30 +02:00
|
|
|
Write-Verbose -Verbose "starting jobs for $($group.Name) ..."
|
2019-01-16 23:28:10 +01:00
|
|
|
$job = Start-ThreadJob {
|
2019-01-16 01:20:45 +01:00
|
|
|
param([object] $group)
|
|
|
|
foreach($file in $group.Group)
|
|
|
|
{
|
|
|
|
$results = markdown-link-check $file 2>&1
|
|
|
|
Write-Output ([PSCustomObject]@{
|
|
|
|
file = $file
|
|
|
|
results = $results
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} -ArgumentList @($group)
|
|
|
|
$jobs.add($group.name,$job)
|
|
|
|
}
|
|
|
|
|
2020-05-07 14:00:30 +02:00
|
|
|
Write-Verbose -Verbose "Getting results ..."
|
2019-01-16 01:20:45 +01:00
|
|
|
# Get the results and verify
|
|
|
|
foreach($key in $jobs.keys)
|
|
|
|
{
|
|
|
|
$job = $jobs.$key
|
|
|
|
$results = Receive-Job -Job $job -Wait
|
2020-05-07 14:00:30 +02:00
|
|
|
Remove-Job -Job $Job
|
2019-01-16 01:20:45 +01:00
|
|
|
foreach($jobResult in $results)
|
|
|
|
{
|
|
|
|
$file = $jobResult.file
|
|
|
|
$result = $jobResult.results
|
|
|
|
Context "Verify links in $file" {
|
|
|
|
# failures look like `[✖] https://someurl` (perhaps without the https://)
|
|
|
|
# passes look like `[✓] https://someurl` (perhaps without the https://)
|
2019-01-16 23:28:10 +01:00
|
|
|
$failures = $result -like '*[✖]*' | ForEach-Object { $_.Substring(4).Trim() }
|
2019-01-16 01:20:45 +01:00
|
|
|
$passes = $result -like '*[✓]*' | ForEach-Object {
|
2019-01-16 23:28:10 +01:00
|
|
|
@{url=$_.Substring(4).Trim() }
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
$trueFailures = @()
|
|
|
|
$verifyFailures = @()
|
|
|
|
foreach ($failure in $failures) {
|
|
|
|
if($failure -like 'https://www.amazon.com*')
|
|
|
|
{
|
|
|
|
# In testing amazon links often failed when they are valid
|
|
|
|
# Verify manually
|
|
|
|
$verifyFailures += @{url = $failure}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$trueFailures += @{url = $failure}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# must have some code in the test for it to pass
|
|
|
|
function noop {
|
|
|
|
}
|
|
|
|
|
|
|
|
if($passes)
|
|
|
|
{
|
2020-05-07 14:00:30 +02:00
|
|
|
It "<url> should work" -TestCases $passes {
|
2019-01-16 01:20:45 +01:00
|
|
|
noop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if($trueFailures)
|
|
|
|
{
|
2020-05-07 14:00:30 +02:00
|
|
|
It "<url> should work" -TestCases $trueFailures {
|
2019-01-16 23:28:10 +01:00
|
|
|
param($url)
|
|
|
|
|
2019-08-16 01:13:53 +02:00
|
|
|
# there could be multiple reasons why a failure is ok
|
|
|
|
# check against the allowed failures
|
2020-01-06 21:18:20 +01:00
|
|
|
$allowedFailures = [System.Net.HttpStatusCode[]](
|
|
|
|
503, # Service Unavailable
|
|
|
|
504 # Gateway Timeout
|
|
|
|
)
|
2019-08-16 01:13:53 +02:00
|
|
|
|
2019-01-16 23:28:10 +01:00
|
|
|
$prefix = $url.Substring(0,7)
|
|
|
|
|
2019-01-29 04:54:23 +01:00
|
|
|
# Logging for diagnosability. Azure DevOps sometimes redacts the full url.
|
2019-01-16 23:28:10 +01:00
|
|
|
Write-Verbose "prefix: '$prefix'" -Verbose
|
2019-01-16 01:20:45 +01:00
|
|
|
if($url -match '^http(s)?:')
|
|
|
|
{
|
2019-11-08 21:28:06 +01:00
|
|
|
# If invoke-WebRequest can handle the URL, re-verify, with 6 retries
|
2019-06-17 21:10:56 +02:00
|
|
|
try
|
|
|
|
{
|
2020-05-07 14:00:30 +02:00
|
|
|
$null = Invoke-WebRequest -Uri $url -RetryIntervalSec 10 -MaximumRetryCount 6
|
2019-01-16 23:28:10 +01:00
|
|
|
}
|
2020-01-03 19:40:27 +01:00
|
|
|
catch [Microsoft.PowerShell.Commands.HttpResponseException]
|
2019-01-16 23:28:10 +01:00
|
|
|
{
|
2019-08-16 01:13:53 +02:00
|
|
|
if ( $allowedFailures -notcontains $_.Exception.Response.StatusCode ) {
|
2020-01-03 19:40:27 +01:00
|
|
|
throw "Failed to complete request to `"$url`". $($_.Exception.Message)"
|
2019-08-16 01:13:53 +02:00
|
|
|
}
|
2019-01-16 23:28:10 +01:00
|
|
|
}
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-01-29 04:54:23 +01:00
|
|
|
throw "Tool reported URL as unreachable."
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if($verifyFailures)
|
|
|
|
{
|
2020-05-07 14:00:30 +02:00
|
|
|
It "<url> should work" -TestCases $verifyFailures -Pending {
|
2019-01-16 01:20:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$passes -and !$trueFailures -and !$verifyFailures)
|
|
|
|
{
|
|
|
|
It "has no links" {
|
|
|
|
noop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|