...
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
20set -o errexit
21set -o nounset
22set -o pipefail
23
24KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
25source "${KUBE_ROOT}/hack/lib/init.sh"
26source "${KUBE_ROOT}/hack/lib/util.sh"
27
28# allow overriding docker cli, which should work fine for this script
29DOCKER="${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
33SHELLCHECK_VERSION="0.9.0"
34SHELLCHECK_IMAGE="docker.io/koalaman/shellcheck-alpine:v0.9.0@sha256:e19ed93c22423970d56568e171b4512c9244fc75dd9114045016b4a0073ac4b7"
35
36# disabled lints
37disabled=(
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
49join_by() {
50 local IFS="$1";
51 shift;
52 echo "$*";
53}
54SHELLCHECK_DISABLED="$(join_by , "${disabled[@]}")"
55readonly SHELLCHECK_DISABLED
56
57# ensure we're linting the k8s source tree
58cd "${KUBE_ROOT}"
59
60scripts_to_check=("$@")
61if [[ "$#" == 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 \))
78fi
79
80# detect if the host machine has the required shellcheck version installed
81# if so, we will use that instead.
82HAVE_SHELLCHECK=false
83if 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
88fi
89
90# if KUBE_JUNIT_REPORT_DIR is set, disable colorized output.
91# Colorized output causes malformed XML in the JUNIT report.
92SHELLCHECK_COLORIZED_OUTPUT="auto"
93if [[ -n "${KUBE_JUNIT_REPORT_DIR:-}" ]]; then
94 SHELLCHECK_COLORIZED_OUTPUT="never"
95fi
96
97# common arguments we'll pass to shellcheck
98SHELLCHECK_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
112res=0
113if ${HAVE_SHELLCHECK}; then
114 echo "Using host shellcheck ${SHELLCHECK_VERSION} binary."
115 shellcheck "${SHELLCHECK_OPTIONS[@]}" "${scripts_to_check[@]}" >&2 || res=$?
116else
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=$?
122fi
123
124# print a message based on the result
125if [ $res -eq 0 ]; then
126 echo 'Congratulations! All shell files are passing lint :-)'
127else
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
139fi
140
141# preserve the result
142exit $res
View as plain text