diff --git a/gh-md-toc b/gh-md-toc index ed53a51..5547fff 100755 --- a/gh-md-toc +++ b/gh-md-toc @@ -77,27 +77,67 @@ gh_toc_md2html() { fi # echo $URL 1>&2 + # append the HTTP status code as the last line of the output, so API + # errors are detected by status rather than by the rendered markdown OUTPUT=$(curl -s \ --user-agent "$gh_user_agent" \ --data-binary @"$gh_tmp_file_md" \ -H "Content-Type:text/plain" \ -H "$AUTHORIZATION" \ + -w '\n%{http_code}' \ "$URL") local curl_status=$? + local http_code=${OUTPUT##*$'\n'} + OUTPUT=${OUTPUT%$'\n'*} rm -f "${gh_file_md}~~" if [ "$curl_status" != "0" ]; then echo "XXNetworkErrorXX" - fi - if [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then + elif [ "$http_code" = "401" ]; then + echo "XXBadCredentialsXX" + elif [ "$http_code" != "200" ] && [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then echo "XXRateLimitXX" + elif [ "$http_code" != "200" ]; then + echo "XXApiErrorXX ${http_code}" else echo "${OUTPUT}" fi } +# +# Prints an error and exits if gh_toc_md2html returned an error marker +# +gh_toc_check_api_error() { + if [ "$1" == "XXNetworkErrorXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Please make sure curl is installed and check your network connectivity" + exit 1 + elif [ "$1" == "XXRateLimitXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting" + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + echo "or place GitHub auth token here: ${TOKEN_FILE}" + exit 1 + elif [ "$1" == "XXBadCredentialsXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Error: GitHub API rejected the auth token (HTTP 401 Bad credentials)" + if [ -n "$GH_TOC_TOKEN" ]; then + echo "Check the GitHub auth token in the GH_TOC_TOKEN environment variable" + else + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + echo "Check the GitHub auth token here: ${TOKEN_FILE}" + fi + exit 1 + elif [[ "$1" == "XXApiErrorXX "* ]]; then + echo "Parsing local markdown file requires access to github API" + echo "Error: GitHub API request failed (HTTP ${1#XXApiErrorXX })" + exit 1 + fi +} + + # # Is passed string url # @@ -157,18 +197,7 @@ gh_toc(){ else local rawhtml rawhtml=$(gh_toc_md2html "$gh_src" "$skip_header") - if [ "$rawhtml" == "XXNetworkErrorXX" ]; then - echo "Parsing local markdown file requires access to github API" - echo "Please make sure curl is installed and check your network connectivity" - exit 1 - fi - if [ "$rawhtml" == "XXRateLimitXX" ]; then - echo "Parsing local markdown file requires access to github API" - echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting" - TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" - echo "or place GitHub auth token here: ${TOKEN_FILE}" - exit 1 - fi + gh_toc_check_api_error "$rawhtml" local toc toc=$(echo "$rawhtml" | gh_toc_grab "$gh_src_copy" "$indent" "$depth" "$numbered") echo "$toc" @@ -423,7 +452,10 @@ gh_toc_app() { while read -r input; do echo "$input" >> "$gh_tmp_md" done - gh_toc_md2html "$gh_tmp_md" | gh_toc_grab "" "$indent" "$depth" "$numbered" + local rawhtml + rawhtml=$(gh_toc_md2html "$gh_tmp_md") + gh_toc_check_api_error "$rawhtml" + echo "$rawhtml" | gh_toc_grab "" "$indent" "$depth" "$numbered" return fi diff --git a/tests/test directory/test_api_error_text.md b/tests/test directory/test_api_error_text.md new file mode 100644 index 0000000..eb46f7e --- /dev/null +++ b/tests/test directory/test_api_error_text.md @@ -0,0 +1,7 @@ +# Bad credentials + +Docs that mention GitHub API errors must still render. + +## API rate limit exceeded + +Blabla... diff --git a/tests/tests.bats b/tests/tests.bats index 86ab465..6215eef 100755 --- a/tests/tests.bats +++ b/tests/tests.bats @@ -245,6 +245,45 @@ test_help() { assert_equal "${lines[3]}" "Please make sure curl is installed and check your network connectivity" } +@test "Error for local file with invalid GitHub token" { + GH_TOC_TOKEN=invalid run $BATS_TEST_DIRNAME/../gh-md-toc tests/test\ directory/test_plussign.md + assert_fail + + assert_equal "${lines[2]}" "Parsing local markdown file requires access to github API" + assert_equal "${lines[3]}" "Error: GitHub API rejected the auth token (HTTP 401 Bad credentials)" + assert_equal "${lines[4]}" "Check the GitHub auth token in the GH_TOC_TOKEN environment variable" +} + +@test "Error for markdown from stdin with invalid GitHub token" { + printf '# A\n' | { + GH_TOC_TOKEN=invalid run $BATS_TEST_DIRNAME/../gh-md-toc - + assert_fail + + assert_equal "${lines[0]}" "Parsing local markdown file requires access to github API" + assert_equal "${lines[1]}" "Error: GitHub API rejected the auth token (HTTP 401 Bad credentials)" + assert_equal "${lines[2]}" "Check the GitHub auth token in the GH_TOC_TOKEN environment variable" + } +} + +@test "Error for markdown from stdin without network access" { + printf '# A\n' | { + # route curl through a closed port to simulate a network failure + HTTPS_PROXY=http://127.0.0.1:9 run $BATS_TEST_DIRNAME/../gh-md-toc - + assert_fail + + assert_equal "${lines[0]}" "Parsing local markdown file requires access to github API" + assert_equal "${lines[1]}" "Please make sure curl is installed and check your network connectivity" + } +} + +@test "TOC for local file mentioning API error messages" { + run $BATS_TEST_DIRNAME/../gh-md-toc tests/test\ directory/test_api_error_text.md + assert_success + + assert_equal "${lines[2]}" "* [Bad credentials](#bad-credentials)" + assert_equal "${lines[3]}" " * [API rate limit exceeded](#api-rate-limit-exceeded)" +} + @test "TOC with depth for local file, #25" { run $BATS_TEST_DIRNAME/../gh-md-toc --depth 2 tests/test\ directory/test_depth.md assert_success