...

Text file src/k8s.io/kubernetes/hack/verify-golangci-lint.sh

Documentation: k8s.io/kubernetes/hack

     1#!/usr/bin/env bash
     2
     3# Copyright 2021 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 checks the coding style for the Go language files using
    18# golangci-lint. Which checks are enabled depends on command line flags. The
    19# default is a minimal set of checks that all existing code passes without
    20# issues.
    21
    22usage () {
    23  cat <<EOF >&2
    24Usage: $0 [-r <revision>|-a] [-s] [-c none|<config>] [-- <golangci-lint run flags>] [packages]"
    25   -r <revision>: only report issues in code added since that revision
    26   -a: automatically select the common base of origin/master and HEAD
    27       as revision
    28   -s: select a strict configuration for new code
    29   -n: in addition to strict checking, also enable hints (aka nits) that may are may not
    30       be useful
    31   -g <github action file>: also write results with --out-format=github-actions
    32       to a separate file
    33   -c <config|"none">: use the specified configuration or none instead of the default hack/golangci.yaml
    34   [packages]: check specific packages or directories instead of everything
    35EOF
    36  exit 1
    37}
    38
    39set -o errexit
    40set -o nounset
    41set -o pipefail
    42
    43KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
    44source "${KUBE_ROOT}/hack/lib/init.sh"
    45source "${KUBE_ROOT}/hack/lib/util.sh"
    46
    47kube::golang::setup_env
    48export GOBIN="${KUBE_OUTPUT_BIN}"
    49
    50kube::util::require-jq
    51
    52invocation=(./hack/verify-golangci-lint.sh "$@")
    53golangci=("${GOBIN}/golangci-lint" run)
    54golangci_config="${KUBE_ROOT}/hack/golangci.yaml"
    55base=
    56strict=
    57hints=
    58githubactions=
    59while getopts "ar:sng:c:" o; do
    60  case "${o}" in
    61    a)
    62      base="$(git merge-base origin/master HEAD)"
    63      ;;
    64    r)
    65      base="${OPTARG}"
    66      if [ ! "$base" ]; then
    67        echo "ERROR: -c needs a non-empty parameter" >&2
    68        echo >&2
    69        usage
    70      fi
    71      ;;
    72    s)
    73      golangci_config="${KUBE_ROOT}/hack/golangci-strict.yaml"
    74      strict=1
    75      ;;
    76    n)
    77      golangci_config="${KUBE_ROOT}/hack/golangci-hints.yaml"
    78      hints=1
    79      ;;
    80    g)
    81      githubactions="${OPTARG}"
    82      ;;
    83    c)
    84      if [ "${OPTARG}" = "none" ]; then
    85        golangci_config=""
    86      else
    87        golangci_config="${OPTARG}"
    88      fi
    89      ;;
    90   *)
    91     usage
    92     ;;
    93  esac
    94done
    95
    96# Below the output of golangci-lint is going to be piped into sed to add
    97# a prefix to each output line. This helps make the output more visible
    98# in the Prow log viewer ("error" is a key word there) and ensures that
    99# only those lines get included as failure message in a JUnit file
   100# by "make verify".
   101#
   102# The downside is that the automatic detection whether to colorize output
   103# doesn't work anymore, so here we force it ourselves when connected to
   104# a tty.
   105if tty -s; then
   106    golangci+=(--color=always)
   107fi
   108
   109if [ "$base" ]; then
   110    # Must be a something that git can resolve to a commit.
   111    # "git rev-parse --verify" checks that and prints a detailed
   112    # error.
   113    base="$(git rev-parse --verify "$base")"
   114    golangci+=(--new --new-from-rev="$base")
   115fi
   116
   117# Filter out arguments that start with "-" and move them to the run flags.
   118shift $((OPTIND-1))
   119targets=()
   120for arg; do
   121  if [[ "${arg}" == -* ]]; then
   122    golangci+=("${arg}")
   123  else
   124    targets+=("${arg}")
   125  fi
   126done
   127
   128# Install golangci-lint
   129echo "installing golangci-lint and logcheck plugin from hack/tools into ${GOBIN}"
   130go -C "${KUBE_ROOT}/hack/tools" install github.com/golangci/golangci-lint/cmd/golangci-lint
   131if [ "${golangci_config}" ]; then
   132  # This cannot be used without a config.
   133  # This uses `go build` because `go install -buildmode=plugin` doesn't work
   134  # (on purpose: https://github.com/golang/go/issues/64964).
   135  go -C "${KUBE_ROOT}/hack/tools" build -o "${GOBIN}/logcheck.so" -buildmode=plugin sigs.k8s.io/logtools/logcheck/plugin
   136fi
   137
   138if [ "${golangci_config}" ]; then
   139  # The relative path to _output/local/bin only works if that actually is the
   140  # GOBIN. If not, then we have to make a temporary copy of the config and
   141  # replace the path with an absolute one. This could be done also
   142  # unconditionally, but the invocation that is printed below is nicer if we
   143  # don't to do it when not required.
   144  if grep -q 'path: ../_output/local/bin/' "${golangci_config}" &&
   145     [ "${GOBIN}" != "${KUBE_ROOT}/_output/local/bin" ]; then
   146    kube::util::ensure-temp-dir
   147    patched_golangci_config="${KUBE_TEMP}/$(basename "${golangci_config}")"
   148    sed -e "s;path: ../_output/local/bin/;path: ${GOBIN}/;" "${golangci_config}" >"${patched_golangci_config}"
   149    golangci_config="${patched_golangci_config}"
   150  fi
   151  golangci+=(--config="${golangci_config}")
   152fi
   153
   154cd "${KUBE_ROOT}"
   155
   156res=0
   157run () {
   158  if [[ "${#targets[@]}" -eq 0 ]]; then
   159    # Doing it this way is MUCH faster than simply saying "all", and there doesn't
   160    # seem to be a simpler way to express "this whole workspace".
   161    kube::util::read-array targets < <(
   162        go work edit -json | jq -r '.Use[].DiskPath + "/..."'
   163    )
   164  fi
   165  echo "running ${golangci[*]} ${targets[*]}" >&2
   166  "${golangci[@]}" "${targets[@]}" 2>&1 | sed -e 's;^;ERROR: ;' >&2 || res=$?
   167}
   168# First run with normal output.
   169run
   170
   171# Then optionally do it again with github-actions as format.
   172# Because golangci-lint caches results, this is faster than the
   173# initial invocation.
   174if [ "$githubactions" ]; then
   175  golangci+=("--out-format=github-actions")
   176  run >"$githubactions" 2>&1
   177fi
   178
   179# print a message based on the result
   180if [ "$res" -eq 0 ]; then
   181  echo 'Congratulations! All files are passing lint :-)'
   182else
   183  {
   184    echo
   185    echo "Please review the above warnings. You can test via \"${invocation[*]}\""
   186    echo 'If the above warnings do not make sense, you can exempt this warning with a comment'
   187    echo ' (if your reviewer is okay with it).'
   188    if [ "$strict" ]; then
   189        echo
   190        echo 'golangci-strict.yaml was used as configuration. Warnings must be fixed in'
   191        echo 'new or modified code.'
   192    elif [ "$hints" ]; then
   193        echo
   194        echo 'golangci-hints.yaml was used as configuration. Some of the reported issues may'
   195        echo 'have to be fixed while others can be ignored, depending on the circumstances'
   196        echo 'and/or personal preferences. To determine which issues have to be fixed, check'
   197        echo 'the report that uses golangci-strict.yaml (= pull-kubernetes-verify-lint).'
   198    fi
   199    if [ "$strict" ] || [ "$hints" ]; then
   200        echo
   201        echo 'If you feel that this warns about issues that should be ignored by default,'
   202        echo 'then please discuss with your reviewer and propose'
   203        echo 'a change for hack/golangci.yaml.in as part of your PR.'
   204        echo
   205        echo 'Please do not create PRs which fix these issues in existing code just'
   206        echo 'because the linter warns about them. Often they are harmless and not'
   207        echo 'worth the cost associated with a PR (time required to review, code churn).'
   208        echo 'Instead, propose to fix certain linter issues in an issue first and'
   209        echo 'discuss there with maintainers. PRs are welcome if they address a real'
   210        echo 'problem, which then needs to be explained in the PR.'
   211    fi
   212    echo
   213    echo 'In general please prefer to fix the error, we have already disabled specific lints'
   214    echo ' that the project chooses to ignore.'
   215    echo 'See: https://golangci-lint.run/usage/false-positives/'
   216    echo
   217  } >&2
   218  exit 1
   219fi
   220
   221# preserve the result
   222exit "$res"

View as plain text