Revision 9887848e690d2cc564d5f02d2acdab222cfdce53 authored by André Martins on 01 September 2022, 15:08:45 UTC, committed by André Martins on 01 September 2022, 16:55:01 UTC
Signed-off-by: André Martins <andre@cilium.io>
1 parent d7264ff
Raw File
check-build.sh
#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

# This was ported from the makefile, it can probably be converted
# to Python (see e.g. https://stackoverflow.com/a/47657926), that
# way we might be able to call Sphinx only once and make it quicker
# Update 2022-05: It seems that Sphinx cannot run multiple builders
# (e.g. html + spelling) at once so we're stuck calling it multiple
# times anyway.

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
root_dir="$(dirname "${script_dir}")"

build_dir="${script_dir}/_build"
warnings="${build_dir}/warnings.txt"
spelldir="${build_dir}/spelling"

target="${1:-"html"}"
shift

cd "${script_dir}"
mkdir -p "${build_dir}"
rm -f -- "${warnings}"

has_spelling_errors() {
    # If spelling errors were found, Sphinx wrote them to files under
    # ${spelldir}. Let's check whether the directory is empty.
    test -n "$(ls "${spelldir}")"
}

# Filter out some undesirable warnings:
#   - Spelling (we already have individual warnings for each word)
filter_warnings() {
    [ -s "${warnings}" ] || return
    grep -v -E \
        -e 'Found .* misspelled words' \
        -e "/_api/v1/.*/README\.md:[0-9]+: WARNING: 'myst' reference target not found:" \
        "${warnings}"
}

# Returns non-0 if we have relevant build warnings
has_build_warnings() {
    filter_warnings > /dev/null
}

describe_spelling_errors() {
    local new_words

    # Show all misspelled words; display source path relative to root repository
    find "${spelldir}" -type f -print0 | xargs -0 sed 's/^/* Documentation\//'

    # Print a hint on how to add new correct words to the list of good words
    new_words="$(find "${spelldir}" -type f -print0 | \
        xargs -0 sed -E "s/^([^:]+:){2} \(([^ ]+)\).*/\2/g" | \
        sort -u | \
        tr '\r\n' ' ' | \
        sed "s/'/\\\\\\\\'/g")"
    printf "\nIf the words are not misspelled, run:\n%s %s\n" \
        "Documentation/update-spelling_wordlist.sh" "${new_words}"
}

build_with_spellchecker() {
    # The spell checker runs some Git commands to retreive the name of authors
    # and consider them as acceptable words.
    #
    # Recent Git versions refuse to work by default if the repository owner is
    # different from the user. This is the case when we run this script in a
    # container on macOS, because pass --user "uid:gid", and these values
    # differ from what Linux is used to (The gid from macOS seems to be 20,
    # which corresponds to the "dialout" group in the container). We pass
    # --user "uid:gid" to have the "install" command work in the workaround for
    # versionwarning above.
    #
    # If running in a container, tell Git that the repository is safe.
    set +o nounset
    if [[ -n "$MAKE_GIT_REPO_SAFE" ]]; then
        git config --global --add safe.directory "${root_dir}"
    fi
    set -o nounset

    rm -rf "${spelldir}"
    # Call with -q -W --keep-going: suppresses regular output (keeps warning;
    # -Q would suppress warnings as well including those we write to a file),
    # consider warnings as errors for exit status, but keep going on
    # warning/errors so that we get the full list of errors.
    sphinx-build -b spelling \
        -d "${build_dir}/doctrees" . "${spelldir}" \
        -E -n --color -q -w "${warnings}" -W --keep-going 2>/dev/null
}

build_with_linkchecker() {
    sphinx-build -b linkcheck -d "${build_dir}/doctrees" . "${spelldir}" -q -E
}

run_linter() {
    local CONF_PY_ROLES CONF_PY_SUBSTITUTIONS ignored_messages

    CONF_PY_ROLES=$(sed -n "/^extlinks = {$/,/^}$/ s/^ *'\([^']\+\)':.*/\1/p" conf.py | tr '\n' ',')
    CONF_PY_SUBSTITUTIONS="$(sed -n 's/^\.\. |\([^|]\+\)|.*/\1/p' conf.py | tr '\n' ',')release"
    ignored_messages="("
    ignored_messages="${ignored_messages}bpf.rst:.*: \(INFO/1\) Enumerated list start value not ordinal"
    ignored_messages="${ignored_messages}|Hyperlink target .*is not referenced\."
    ignored_messages="${ignored_messages}|Duplicate implicit target name:"
    ignored_messages="${ignored_messages}|Malformed table\."
    ignored_messages="${ignored_messages})"
    rstcheck \
        --report info \
        --ignore-language bash \
        --ignore-message "${ignored_messages}" \
        --ignore-directives tabs \
        --ignore-roles "${CONF_PY_ROLES}" \
        --ignore-substitutions "${CONF_PY_SUBSTITUTIONS}" \
        -r .
}

read_all_opt=""

if [ -n "${SKIP_LINT-}" ]; then
  # Read all files for final build if we don't read them all with linting
  read_all_opt="-E"

  echo "Skipping syntax and spelling validations..."
else
  echo "Running linter..."
  run_linter

  echo "Validating documentation (syntax, spelling)..."
  if ! build_with_spellchecker ; then
    status_ok=0
    if has_build_warnings ; then
        printf "\nPlease fix the following documentation warnings:\n"
        filter_warnings
        status_ok=1
    fi

    if has_spelling_errors ; then
        printf "\nPlease fix the following spelling mistakes:\n"
        describe_spelling_errors
        status_ok=1
    fi

    if [ "${status_ok}" -ne 0 ] ; then
        exit 1
    fi
  fi
fi

# TODO: Fix broken links and re-enable this
# (https://github.com/cilium/cilium/issues/10601)
# echo "Checking links..."
# if ! build_with_linkchecker ; then
#     echo "Link check failed!"
#     exit 1
# fi

echo "Building documentation (${target})..."
sphinx-build -M "${target}" "${script_dir}" "${build_dir}" $@ \
    ${read_all_opt} -n --color -q -w "${warnings}" 2>/dev/null

# We can have warnings but no errors here, or sphinx-build would return non-0
# and we would have exited because of "set -o errexit".
if has_build_warnings ; then
    echo "Please fix the documentation warnings below"
    filter_warnings
    exit 1
fi
back to top