Files
weave-scope/lint
Bryan Boreham a0d60e4de9 Squashed 'tools/' changes from ec369f58d..f041a74ff
f041a74ff Undo some quoting that broke the test script (#160)
b1c21a068 Merge pull request #158 from weaveworks/go-1-13
d5c7dd0cd Run shell-lint during CI, and fix warnings
6db1abd14 Update to Go 1.13.1
d6cc704a2 Fix comment
7139116ae Revert "Push comments to the left so they don't appear in scripts"
e47e58f7b Push comments to the left so they don't appear in scripts
3945fcec8 Remove nonexistent env var GIT_TAG
cd6299284 Merge pull request #156 from weaveworks/drop-quay
af0eb5119 Merge pull request #157 from weaveworks/fix-image-tag-prefix-length
0b9aee4f2 Fix image-tag object name prefix length to 8 chars.
813c28fe7 Move from CircleCI 1.0 to 2.0
425cf4ef1 Move from quay.io to Dockerhub
87ccf4fd1 Merge pull request #155 from weaveworks/go-1-12
c31bc2865 Update lint script to work with Go 1.12
ed8e380d7 Update to Go 1.12.1

git-subtree-dir: tools
git-subtree-split: f041a74ffbf273b627d6c960f17357108d0dbd1c
2019-10-02 14:34:20 +00:00

268 lines
7.0 KiB
Bash
Executable File

#!/bin/bash
# This scipt lints files for common errors.
#
# For go files, it runs gofmt and go vet, and optionally golint and
# gocyclo, if they are installed.
#
# For shell files, it runs shfmt. If you don't have that installed, you can get
# it with:
# curl -fsSLo shfmt https://github.com/mvdan/sh/releases/download/v1.3.0/shfmt_v1.3.0_linux_amd64
# chmod +x shfmt
#
# With no arguments, it lints the current files staged
# for git commit. Or you can pass it explicit filenames
# (or directories) and it will lint them.
#
# To use this script automatically, run:
# ln -s ../../bin/lint .git/hooks/pre-commit
set -e
LINT_IGNORE_FILE=${LINT_IGNORE_FILE:-".lintignore"}
IGNORE_LINT_COMMENT=
IGNORE_SPELLINGS=
while true; do
case "$1" in
-nocomment)
IGNORE_LINT_COMMENT=1
shift 1
;;
-notestpackage)
# NOOP, still accepted for backwards compatibility
shift 1
;;
-ignorespelling)
IGNORE_SPELLINGS="$2,$IGNORE_SPELLINGS"
shift 2
;;
*)
break
;;
esac
done
spell_check() {
local filename="$1"
local lint_result=0
# misspell is completely optional. If you don't like it
# don't have it installed.
if ! type misspell >/dev/null 2>&1; then
return $lint_result
fi
if ! misspell -error -i "$IGNORE_SPELLINGS" "${filename}"; then
lint_result=1
fi
return $lint_result
}
lint_go() {
# This function is called on a whole directory containing Go files
local filename="$1"
local lint_result=0
if [ -n "$(gofmt -s -l "${filename}")" ]; then
lint_result=1
echo "${filename}: run gofmt -s -w ${filename}"
fi
go vet "${filename}" || lint_result=$?
# golint is completely optional. If you don't like it
# don't have it installed.
if type golint >/dev/null 2>&1; then
# golint doesn't set an exit code it seems
if [ -z "$IGNORE_LINT_COMMENT" ]; then
lintoutput=$(golint "${filename}")
else
lintoutput=$(golint "${filename}" | grep -vE 'comment|dot imports|ALL_CAPS')
fi
if [ -n "$lintoutput" ]; then
lint_result=1
echo "$lintoutput"
fi
fi
# gocyclo is completely optional. If you don't like it
# don't have it installed. Also never blocks a commit,
# it just warns.
if type gocyclo >/dev/null 2>&1; then
gocyclo -over 25 "${filename}" | while read -r line; do
echo "${filename}": higher than 25 cyclomatic complexity - "${line}"
done
fi
return $lint_result
}
lint_sh() {
local filename="$1"
local lint_result=0
# Skip shfmt validation, if not installed
if type shfmt >/dev/null 2>&1; then
if ! diff -u "${filename}" <(shfmt -i 4 "${filename}"); then
lint_result=1
echo "${filename}: run shfmt -i 4 -w ${filename}"
fi
fi
# the shellcheck is completely optional. If you don't like it
# don't have it installed.
if type shellcheck >/dev/null 2>&1; then
shellcheck "${filename}" || lint_result=1
fi
return $lint_result
}
lint_tf() {
local filename="$1"
local lint_result=0
if ! diff -u <(hclfmt "${filename}") "${filename}"; then
lint_result=1
echo "${filename}: run hclfmt -w ${filename}"
fi
return $lint_result
}
lint_md() {
local filename="$1"
local lint_result=0
for i in '=======' '>>>>>>>'; do
if grep -q "${i}" "${filename}"; then
lint_result=1
echo "${filename}: bad merge/rebase!"
fi
done
return $lint_result
}
lint_py() {
local filename="$1"
local lint_result=0
if yapf --diff "${filename}" | grep -qE '^[+-]'; then
lint_result=1
echo "${filename} needs reformatting. Run: yapf --in-place ${filename}"
else
# Only run flake8 if yapf passes, since they pick up a lot of similar issues
flake8 "${filename}" || lint_result=1
fi
return $lint_result
}
lint() {
filename="$1"
ext="${filename##*\.}"
local lint_result=0
# Don't lint deleted files
if [ ! -f "$filename" ]; then
return
fi
# Don't lint specific files
case "$(basename "${filename}")" in
static.go) return ;;
coverage.html) return ;;
*.pb.go) return ;;
esac
mimetype=$(file --mime-type "${filename}" | awk '{print $2}')
case "$mimetype.$ext" in
text/x-shellscript.*) lint_sh "${filename}" || lint_result=1 ;;
*.go) ;; # done at directory level
*.tf) lint_tf "${filename}" || lint_result=1 ;;
*.md) lint_md "${filename}" || lint_result=1 ;;
*.py) lint_py "${filename}" || lint_result=1 ;;
esac
# we don't want to spell check tar balls, binaries, Makefile and json files
case "$mimetype.$ext" in
*.tar | *.gz | *.json) ;;
*.req | *.key | *.pem | *.crt) ;;
application/x-executable.*) ;;
text/x-makefile.*) ;;
*) spell_check "${filename}" || lint_result=1 ;;
esac
return $lint_result
}
lint_files() {
local lint_result=0
while read -r filename; do
lint "${filename}" || lint_result=1
done
return $lint_result
}
matches_any() {
local filename="$1"
local patterns="$2"
while read -r pattern; do
# shellcheck disable=SC2053
# Use the [[ operator without quotes on $pattern
# in order to "glob" the provided filename:
[[ "$filename" == $pattern ]] && return 0
done <<<"$patterns"
return 1
}
filter_out() {
local patterns_file="$1"
if [ -n "$patterns_file" ] && [ -r "$patterns_file" ]; then
local patterns
patterns=$(sed '/^#.*$/d ; /^\s*$/d' "$patterns_file") # Remove blank lines and comments before we start iterating.
[ -n "$DEBUG" ] && echo >&2 "> Filters:" && echo >&2 "$patterns"
local filtered_out=()
while read -r filename; do
matches_any "$filename" "$patterns" && filtered_out+=("$filename") || echo "$filename"
done
[ -n "$DEBUG" ] && echo >&2 "> Files filtered out (i.e. NOT linted):" && printf >&2 '%s\n' "${filtered_out[@]}"
else
cat # No patterns provided: simply propagate stdin to stdout.
fi
}
lint_directory() {
local dirname="$1"
local lint_result=0
# This test is just checking if there are any Go files in the directory
if compgen -G "$dirname/*.go" >/dev/null; then
lint_go "${dirname}" || lint_result=1
fi
find . -maxdepth 1 "$dirname" | filter_out "$LINT_IGNORE_FILE" | lint_files
return $lint_result
}
lint_directories() {
local lint_result=0
while read -r dirname; do
lint_directory "${dirname}" || lint_result=1
done
exit $lint_result
}
list_directories() {
if [ $# -gt 0 ]; then
find "$@" \( -name vendor -o -name .git -o -name .cache -o -name .pkg \) -prune -o -type d
fi
}
if [ $# = 1 ] && [ -f "$1" ]; then
lint "$1"
else
list_directories "$@" | lint_directories
fi