#!/usr/bin/env bash
# Copyright © 2023 OpenIM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script lints each shell script by `shellcheck`.
# Usage: `scripts/verify-shellcheck.sh`.
OPENIM_ROOT = $( dirname " ${ BASH_SOURCE [0] } " ) /..
source " ${ OPENIM_ROOT } /scripts/lib/init.sh "
# allow overriding docker cli, which should work fine for this script
DOCKER = " ${ DOCKER :- docker } "
# required version for this script, if not installed on the host we will
# use the official docker image instead. keep this in sync with SHELLCHECK_IMAGE
SHELLCHECK_VERSION = "0.8.0"
SHELLCHECK_IMAGE = "docker.io/koalaman/shellcheck-alpine:v0.8.0@sha256:f42fde76d2d14a645a848826e54a4d650150e151d9c81057c898da89a82c8a56"
# disabled lints
disabled = (
# this lint disallows non-constant source, which we use extensively without
# any known bugs
1090
# this lint warns when shellcheck cannot find a sourced file
# this wouldn't be a bad idea to warn on, but it fails on lots of path
# dependent sourcing, so just disable enforcing it
1091
# this lint prefers command -v to which, they are not the same
2230
# Error SC2155 indicates that you should separate variable declaration and assignment to avoid masking the return value of the command.
# In Bash scripts, when you declare and assign a local variable at the same time a command is executed, you only get the output of the command, but not the exit status (return value) of the command. #
2155
# ShellCheck issues SC2086 warnings when you refer to a variable in a script but don't put it in double quotes.This can lead to unexpected behavior when scripts encounter Spaces,
# newlines, and wildcards in file names or other data.
2086
2206
# TODO: 需要修复,然后开启
2034
2048
2148
2059
2214
2145
2128
2550
2046
2181
1102
2045
2068
2145
2207
2231
2013
2154
2120
1083
2001
2012
2016
2164
2223
2166
2119
2162
2295
2002
2004
2202
2178
2064
2260
2043
2178
2044
2153
)
# comma separate for passing to shellcheck
join_by( ) {
local IFS = " $1 " ;
shift;
echo " $* " ;
}
SHELLCHECK_DISABLED = " $( join_by , " ${ disabled [@] } " ) "
readonly SHELLCHECK_DISABLED
# ensure we're linting the k8s source tree
cd " ${ OPENIM_ROOT } "
# Find all shell scripts excluding:
# - Anything git-ignored - No need to lint untracked files.
# - ./_* - No need to lint output directories.
# - ./.git/* - Ignore anything in the git object store.
# - ./vendor* - Vendored code should be fixed upstream instead.
# - ./third_party/*, but re-include ./third_party/forked/* - only code we
# forked should be linted and fixed.
all_shell_scripts = ( )
while IFS = $'\n' read -r script;
do git check-ignore -q " $script " || all_shell_scripts += ( " $script " ) ;
done < <( find . -name "*.sh" \
-not \( \
-path ./_\* -o \
-path ./.git\* -o \
-path ./Godeps\* -o \
-path ./_output\* -o \
-path ./components\* -o \
-path ./logs\* -o \
-path ./vendor\* -o \
\( -path ./third_party\* -a -not -path ./third_party/forked\* \) \
\) -print 2>/dev/null)
# detect if the host machine has the required shellcheck version installed
# if so, we will use that instead.
HAVE_SHELLCHECK = false
if which shellcheck & >/dev/null; then
detected_version = " $( shellcheck --version | grep 'version: .*' ) "
if [ [ " ${ detected_version } " = " version: ${ SHELLCHECK_VERSION } " ] ] ; then
HAVE_SHELLCHECK = true
fi
fi
# if KUBE_JUNIT_REPORT_DIR is set, disable colorized output.
# Colorized output causes malformed XML in the JUNIT report.
SHELLCHECK_COLORIZED_OUTPUT = "auto"
if [ [ -n " ${ KUBE_JUNIT_REPORT_DIR :- } " ] ] ; then
SHELLCHECK_COLORIZED_OUTPUT = "never"
fi
# common arguments we'll pass to shellcheck
SHELLCHECK_OPTIONS = (
# allow following sourced files that are not specified in the command,
# we need this because we specify one file at a time in order to trivially
# detect which files are failing
"--external-sources"
# include our disabled lints
" --exclude= ${ SHELLCHECK_DISABLED } "
# set colorized output
" --color= ${ SHELLCHECK_COLORIZED_OUTPUT } "
)
# tell the user which we've selected and lint all scripts
# The shellcheck errors are printed to stdout by default, hence they need to be redirected
# to stderr in order to be well parsed for Junit representation by juLog function
res = 0
if ${ HAVE_SHELLCHECK } ; then
openim::log::info " Using host shellcheck ${ SHELLCHECK_VERSION } binary. "
shellcheck " ${ SHELLCHECK_OPTIONS [@] } " " ${ all_shell_scripts [@] } " >& 2 || res = $?
else
openim::log::info " Using shellcheck ${ SHELLCHECK_VERSION } docker image. "
" ${ DOCKER } " run \
--rm -v " ${ OPENIM_ROOT } : ${ OPENIM_ROOT } " -w " ${ OPENIM_ROOT } " \
" ${ SHELLCHECK_IMAGE } " \
shellcheck " ${ SHELLCHECK_OPTIONS [@] } " " ${ all_shell_scripts [@] } " >& 2 || res = $?
fi
# print a message based on the result
if [ $res -eq 0 ] ; then
echo 'Congratulations! All shell files are passing lint :-)'
else
{
echo
echo 'Please review the above warnings. You can test via "./scripts/verify-shellcheck.sh"'
echo 'If the above warnings do not make sense, you can exempt this warning with a comment'
echo ' (if your reviewer is okay with it).'
echo 'In general please prefer to fix the error, we have already disabled specific lints'
echo ' that the project chooses to ignore.'
echo 'See: https://github.com/koalaman/shellcheck/wiki/Ignore#ignoring-one-specific-instance-in-a-file'
echo
} >& 2
exit 1
fi
# preserve the result
exit $res