k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/hack/verify-shellcheck.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copyright 2018 The Kubernetes Authors.
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #     http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  
    17  # This script lints each shell script by `shellcheck`.
    18  # Usage: `hack/verify-shellcheck.sh`.
    19  
    20  set -o errexit
    21  set -o nounset
    22  set -o pipefail
    23  
    24  KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
    25  source "${KUBE_ROOT}/hack/lib/init.sh"
    26  source "${KUBE_ROOT}/hack/lib/util.sh"
    27  
    28  # allow overriding docker cli, which should work fine for this script
    29  DOCKER="${DOCKER:-docker}"
    30  
    31  # required version for this script, if not installed on the host we will
    32  # use the official docker image instead. keep this in sync with SHELLCHECK_IMAGE
    33  SHELLCHECK_VERSION="0.9.0"
    34  SHELLCHECK_IMAGE="docker.io/koalaman/shellcheck-alpine:v0.9.0@sha256:e19ed93c22423970d56568e171b4512c9244fc75dd9114045016b4a0073ac4b7"
    35  
    36  # disabled lints
    37  disabled=(
    38    # this lint disallows non-constant source, which we use extensively without
    39    # any known bugs
    40    1090
    41    # this lint warns when shellcheck cannot find a sourced file
    42    # this wouldn't be a bad idea to warn on, but it fails on lots of path
    43    # dependent sourcing, so just disable enforcing it
    44    1091
    45    # this lint prefers command -v to which, they are not the same
    46    2230
    47  )
    48  # comma separate for passing to shellcheck
    49  join_by() {
    50    local IFS="$1";
    51    shift;
    52    echo "$*";
    53  }
    54  SHELLCHECK_DISABLED="$(join_by , "${disabled[@]}")"
    55  readonly SHELLCHECK_DISABLED
    56  
    57  # ensure we're linting the k8s source tree
    58  cd "${KUBE_ROOT}"
    59  
    60  scripts_to_check=("$@")
    61  if [[ "$#" == 0 ]]; then
    62    # Find all shell scripts excluding:
    63    # - Anything git-ignored - No need to lint untracked files.
    64    # - ./_* - No need to lint output directories.
    65    # - ./.git/* - Ignore anything in the git object store.
    66    # - ./vendor* - Vendored code should be fixed upstream instead.
    67    # - ./third_party/*, but re-include ./third_party/forked/*  - only code we
    68    #    forked should be linted and fixed.
    69    while IFS=$'\n' read -r script;
    70      do git check-ignore -q "$script" || scripts_to_check+=("$script");
    71    done < <(find . -name "*.sh" \
    72      -not \( \
    73        -path ./_\*      -o \
    74        -path ./.git\*   -o \
    75        -path ./vendor\* -o \
    76        \( -path ./third_party\* -a -not -path ./third_party/forked\* \) \
    77      \))
    78  fi
    79  
    80  # detect if the host machine has the required shellcheck version installed
    81  # if so, we will use that instead.
    82  HAVE_SHELLCHECK=false
    83  if which shellcheck &>/dev/null; then
    84    detected_version="$(shellcheck --version | grep 'version: .*')"
    85    if [[ "${detected_version}" = "version: ${SHELLCHECK_VERSION}" ]]; then
    86      HAVE_SHELLCHECK=true
    87    fi
    88  fi
    89  
    90  # if KUBE_JUNIT_REPORT_DIR is set, disable colorized output.
    91  # Colorized output causes malformed XML in the JUNIT report.
    92  SHELLCHECK_COLORIZED_OUTPUT="auto"
    93  if [[ -n "${KUBE_JUNIT_REPORT_DIR:-}" ]]; then
    94    SHELLCHECK_COLORIZED_OUTPUT="never"
    95  fi
    96  
    97  # common arguments we'll pass to shellcheck
    98  SHELLCHECK_OPTIONS=(
    99    # allow following sourced files that are not specified in the command,
   100    # we need this because we specify one file at a time in order to trivially
   101    # detect which files are failing
   102    "--external-sources"
   103    # include our disabled lints
   104    "--exclude=${SHELLCHECK_DISABLED}"
   105    # set colorized output
   106    "--color=${SHELLCHECK_COLORIZED_OUTPUT}"
   107  )
   108  
   109  # tell the user which we've selected and lint all scripts
   110  # The shellcheck errors are printed to stdout by default, hence they need to be redirected
   111  # to stderr in order to be well parsed for Junit representation by juLog function
   112  res=0
   113  if ${HAVE_SHELLCHECK}; then
   114    echo "Using host shellcheck ${SHELLCHECK_VERSION} binary."
   115    shellcheck "${SHELLCHECK_OPTIONS[@]}" "${scripts_to_check[@]}" >&2 || res=$?
   116  else
   117    echo "Using shellcheck ${SHELLCHECK_VERSION} docker image."
   118    "${DOCKER}" run \
   119      --rm -v "${KUBE_ROOT}:${KUBE_ROOT}" -w "${KUBE_ROOT}" \
   120      "${SHELLCHECK_IMAGE}" \
   121    shellcheck "${SHELLCHECK_OPTIONS[@]}" "${scripts_to_check[@]}" >&2 || res=$?
   122  fi
   123  
   124  # print a message based on the result
   125  if [ $res -eq 0 ]; then
   126    echo 'Congratulations! All shell files are passing lint :-)'
   127  else
   128    {
   129      echo
   130      echo 'Please review the above warnings. You can test via "./hack/verify-shellcheck.sh"'
   131      echo 'If the above warnings do not make sense, you can exempt this warning with a comment'
   132      echo ' (if your reviewer is okay with it).'
   133      echo 'In general please prefer to fix the error, we have already disabled specific lints'
   134      echo ' that the project chooses to ignore.'
   135      echo 'See: https://github.com/koalaman/shellcheck/wiki/Ignore#ignoring-one-specific-instance-in-a-file'
   136      echo
   137    } >&2
   138    exit 1
   139  fi
   140  
   141  # preserve the result
   142  exit $res