k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/hack/verify-golangci-lint.sh (about) 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 22 usage () { 23 cat <<EOF >&2 24 Usage: $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 35 EOF 36 exit 1 37 } 38 39 set -o errexit 40 set -o nounset 41 set -o pipefail 42 43 KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 44 source "${KUBE_ROOT}/hack/lib/init.sh" 45 source "${KUBE_ROOT}/hack/lib/util.sh" 46 47 kube::golang::setup_env 48 export GOBIN="${KUBE_OUTPUT_BIN}" 49 50 kube::util::require-jq 51 52 invocation=(./hack/verify-golangci-lint.sh "$@") 53 golangci=("${GOBIN}/golangci-lint" run) 54 golangci_config="${KUBE_ROOT}/hack/golangci.yaml" 55 base= 56 strict= 57 hints= 58 githubactions= 59 while 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 94 done 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. 105 if tty -s; then 106 golangci+=(--color=always) 107 fi 108 109 if [ "$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") 115 fi 116 117 # Filter out arguments that start with "-" and move them to the run flags. 118 shift $((OPTIND-1)) 119 targets=() 120 for arg; do 121 if [[ "${arg}" == -* ]]; then 122 golangci+=("${arg}") 123 else 124 targets+=("${arg}") 125 fi 126 done 127 128 # Install golangci-lint 129 echo "installing golangci-lint and logcheck plugin from hack/tools into ${GOBIN}" 130 go -C "${KUBE_ROOT}/hack/tools" install github.com/golangci/golangci-lint/cmd/golangci-lint 131 if [ "${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 136 fi 137 138 if [ "${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}") 152 fi 153 154 cd "${KUBE_ROOT}" 155 156 res=0 157 run () { 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. 169 run 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. 174 if [ "$githubactions" ]; then 175 golangci+=("--out-format=github-actions") 176 run >"$githubactions" 2>&1 177 fi 178 179 # print a message based on the result 180 if [ "$res" -eq 0 ]; then 181 echo 'Congratulations! All files are passing lint :-)' 182 else 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 219 fi 220 221 # preserve the result 222 exit "$res"