|
| 1 | +#!/bin/bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +require() { |
| 5 | + if ! hash "$1" &>/dev/null; then |
| 6 | + echo "'$1' not found in PATH" |
| 7 | + exit 1 |
| 8 | + fi |
| 9 | +} |
| 10 | + |
| 11 | +cleanup() { |
| 12 | + if [[ "$?" == "124" ]]; then |
| 13 | + echo "timeout exceeded waiting for the developer portal to run" |
| 14 | + fi |
| 15 | + echo "stopping process for $$" |
| 16 | + cleanup_with_child $$ false |
| 17 | +} |
| 18 | + |
| 19 | +cleanup_with_child() { |
| 20 | + local pid="$1" |
| 21 | + local and_self="${2:-false}" |
| 22 | + |
| 23 | + echo "cleanup_with_child $pid" |
| 24 | + |
| 25 | + if children="$(pgrep -P "$pid")"; then |
| 26 | + for child in $children; do |
| 27 | + echo "stopping child $child (parent: $pid)" |
| 28 | + cleanup_with_child "$child" true |
| 29 | + done |
| 30 | + fi |
| 31 | + |
| 32 | + if [[ "$and_self" == true ]]; then |
| 33 | + echo "stopping self $pid" |
| 34 | + kill -9 "$pid" 2>/dev/null || true |
| 35 | + fi |
| 36 | +} |
| 37 | + |
| 38 | +trap cleanup EXIT |
| 39 | + |
| 40 | +## add broken-link-checker to PATH |
| 41 | +export PATH=$PATH:`pwd`/node_modules/broken-link-checker/bin |
| 42 | + |
| 43 | +require spin |
| 44 | +require timeout |
| 45 | +require blc |
| 46 | + |
| 47 | +echo "starting developer portal" |
| 48 | + |
| 49 | +## allow unpublished content during broken link checker |
| 50 | +export PREVIEW_MODE=1 |
| 51 | + |
| 52 | +## start the developer portal in background |
| 53 | +npm run spin >/dev/null 2>&1 & |
| 54 | + |
| 55 | +## wait for portal to be up and running |
| 56 | +export RESP_CODE="$(mktemp)" |
| 57 | +timeout 60s bash -c 'until curl -o /dev/null -s -w "%{http_code}\n" http://localhost:3000 > $RESP_CODE; do sleep 2; done' |
| 58 | + |
| 59 | +echo "checking website health via http://localhost:3000" |
| 60 | + |
| 61 | +[[ "$(< $RESP_CODE)" == "200" ]] && \ |
| 62 | + (echo "Success: website returned a 200 response code") || \ |
| 63 | + (echo "Failure: unexpected response code: $(< $RESP_CODE)" && exit 1) |
| 64 | + |
| 65 | +echo "starting link checker" |
| 66 | + |
| 67 | +## Run the broken link checker |
| 68 | +report="$(mktemp)" |
| 69 | +blc_error=false |
| 70 | +blc --recursive http://127.0.0.1:3000 \ |
| 71 | + \ |
| 72 | + `## Ignore searching Edit links` \ |
| 73 | + --exclude 'https://github.com/fermyon/developer/blob/main/content/*' \ |
| 74 | + \ |
| 75 | + `## returns 403` \ |
| 76 | + --exclude 'https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits' \ |
| 77 | + --exclude 'https://docs.github.com/en/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account' \ |
| 78 | + --exclude 'https://docs.github.com/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/remembering-your-github-username-or-email' \ |
| 79 | + --exclude 'https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification' \ |
| 80 | + --exclude 'https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template' \ |
| 81 | + --exclude 'https://twitter.com/fermyontech' \ |
| 82 | + --exclude 'https://twitter.com/fermyontech/status/1641537393818738710' \ |
| 83 | + --exclude 'https://www.godaddy.com' \ |
| 84 | + --exclude 'https://linux.die.net/man/1/which' \ |
| 85 | + \ |
| 86 | + `## false positives` \ |
| 87 | + --exclude 'https://www.gnu.org/software/coreutils/' \ |
| 88 | + --exclude 'https://events.hashicorp.com/hashitalksdeploy' \ |
| 89 | + --exclude 'https://dotnet.microsoft.com/en-us/download/dotnet/8.0' \ |
| 90 | + --exclude 'https://www.developerweek.com/' \ |
| 91 | + --exclude 'https://marketplace.visualstudio.com/items?itemName=fermyon.spin-vscode&ssr=false#overview' \ |
| 92 | + --exclude 'https://marketplace.visualstudio.com/items?itemName=fermyon.autobindle' \ |
| 93 | + --exclude 'https://crates.io/' \ |
| 94 | + --exclude 'https://crates.io/crates/bytes' \ |
| 95 | + --exclude 'https://crates.io/crates/http' \ |
| 96 | + --exclude 'https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one' \ |
| 97 | + --exclude 'https://events.hashicorp.com/hashitalksdeploy' \ |
| 98 | + --exclude 'https://www.instagram.com/fermyontech/' \ |
| 99 | + --exclude 'https://www.linkedin.com/company/fermyon/' \ |
| 100 | + --exclude 'https://support.google.com/webmasters/answer/7552505' \ |
| 101 | + --exclude 'https://www.namecheap.com/support/knowledgebase/article.aspx/767/10/how-to-change-dns-for-a-domain/' \ |
| 102 | + --exclude 'https://support.google.com/domains/answer/3290309?hl=en#' \ |
| 103 | + --exclude 'https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor' \ |
| 104 | + --exclude 'https://www.reddit.com/r/Clojure/comments/jkznto/web_assembly_clojure_current_state/' \ |
| 105 | + --exclude 'https://www.reddit.com/r/Rlanguage/comments/b4izog/compile_r_to_webassembly_and_use_as_a_data/' \ |
| 106 | + --exclude 'https://www.tutorialspoint.com/webassembly/webassembly_working_with_cplusplus.htm' \ |
| 107 | + --exclude 'http://localhost:16686/' \ |
| 108 | + --exclude 'http://localhost:5050/explore' \ |
| 109 | + --exclude 'http://localhost:5050/explore' \ |
| 110 | + --exclude 'https://stackshare.io/stackups/powershell-vs-webassembly' \ |
| 111 | + --exclude 'https://blog.cloudflare.com/cloudflare-workers-now-support-cobol/' \ |
| 112 | + --exclude 'https://support.google.com/webmasters/answer/9008080?hl=en' | tee "${report}" || blc_error=true |
| 113 | + |
| 114 | +cat "${report}" | grep "├─BROKEN─" > broken_links || true |
| 115 | + |
| 116 | +if [ -s broken_links ]; then |
| 117 | + echo "Some links are broken, retrying to check for transient errors" |
| 118 | + while read -r line; do |
| 119 | + url="$(echo $line | awk '{print $2}')" |
| 120 | + if curl --retry 5 --retry-all-errors --retry-delay 1 --output /dev/null --silent --head --fail "$url"; then |
| 121 | + echo "$url is not broken" |
| 122 | + else |
| 123 | + |
| 124 | + echo "$line" >> final_broken |
| 125 | + fi |
| 126 | + done <broken_links |
| 127 | + if [ -f "final_broken" ]; then |
| 128 | + echo -e "The list of broken links are\n" |
| 129 | + cat -n final_broken |
| 130 | + exit 1 |
| 131 | + else |
| 132 | + echo "All the errors were transient. The links are valid!" |
| 133 | + fi |
| 134 | +else |
| 135 | + if [ "${blc_error}" == "true" ]; then |
| 136 | + echo "Failure: error(s) encountered attempting to check website links" && exit 1 |
| 137 | + fi |
| 138 | + echo "All the links are valid!" |
| 139 | +fi |
0 commit comments