diff --git a/test-requirements.txt b/test-requirements.txt index 9d356e238..ec28eb63b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,3 +2,4 @@ hacking < 4.0.1 bashate >= 0.2 bandit!=1.6.0,>=1.1.0,<2.0.0;python_version>="3.0" # GPLv2 +shellcheck-py;python_version>="3.0" # MIT diff --git a/tox.ini b/tox.ini index 61b3db7f9..6230f5786 100644 --- a/tox.ini +++ b/tox.ini @@ -18,10 +18,68 @@ deps = whitelist_externals = bash +[testenv:shellcheck] +basepython = python3 +# The following are currently suppressed: +# SC1083: This '{' or '}' is literal. Check expression (missing ;/\n?) or quote it. +# SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead. +# SC2004: $/${} is unnecessary on arithmetic variables. +# SC2005: Useless echo? Instead of 'echo $(cmd)', just use 'cmd'. +# SC2006: Use $(...) notation instead of legacy backticked `...`. +# SC2012: Use find instead of ls to better handle non-alphanumeric filenames. +# SC2034: variable appears unused. Verify use (or export if used externally). +# SC2044: For loops over find output are fragile. Use find -exec or a while read loop. +# SC2046: Quote this to prevent word splitting +# SC2068: Double quote array expansions to avoid re-splitting elements. +# SC2076: Remove quotes from right-hand side of =~ to match as a regex rather than literally. +# SC2086: Double quote to prevent globbing and word splitting +# SC2091: Remove surrounding $() to avoid executing output (or use eval if intentional). +# SC2115: Use "${var:?}" to ensure this never expands to /* . +# SC2148: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive. +# SC2154: i is referenced but not assigned. +# SC2155: Declare and assign separately to avoid masking return values. +# SC2162: read without -r will mangle backslashes +# SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined. +# SC2181: Check exit code directly with e.g. if mycmd; not indirectly with $? +# SC2199: Arrays implicitly concatenate in [[ ]]. Use a loop (or explicit * instead of @). +# SC2206: Quote to prevent word splitting/globbing, or use mapfile or read -a. +# SC2207: Prefer mapfile or read -a to split command output (or quote to avoid splitting) +# SC2219: Instead of 'let expr', prefer (( expr )) +# SC2254: Quote expansions in case patterns to match literally rather than as a glob. + +# shellcheck is called twice, to handle shell scripts that do not end in .sh +commands = + bash -c "find {toxinidir} \ + -not \( -type d -name .?\* -prune \) \ + -type f \ + -not -name \*~ \ + -not -name \*.md \ + -name \*.sh \ + -print0 | xargs -r -n 1 -0 shellcheck \ + -eSC1083 -eSC2002 -eSC2004 -eSC2005 -eSC2006 -eSC2012 -eSC2034 \ + -eSC2044 -eSC2046 -eSC2068 -eSC2076 -eSC2086 -eSC2091 -eSC2115 \ + -eSC2148 -eSC2154 -eSC2155 -eSC2162 -eSC2166 -eSC2181 -eSC2199 \ + -eSC2206 -eSC2207 -eSC2219 -eSC2254" + bash -c "find {toxinidir} \ + -not \( -type d -name .?\* -prune \) \ + -type f \ + -not -name \*~ \ + -not -name \*.md \ + \( -exec bash -c 'file \{\} | grep -q shell' \; \ + -a ! -name '*.sh' \) \ + -print0 | xargs -r -n 1 -0 shellcheck \ + -eSC1083 -eSC2002 -eSC2004 -eSC2005 -eSC2006 -eSC2012 -eSC2034 \ + -eSC2044 -eSC2046 -eSC2068 -eSC2076 -eSC2086 -eSC2091 -eSC2115 \ + -eSC2148 -eSC2154 -eSC2155 -eSC2162 -eSC2166 -eSC2181 -eSC2199 \ + -eSC2206 -eSC2207 -eSC2219 -eSC2254" + [testenv:bashate] # Treat all E* codes as Errors rather than warnings using: -e 'E*' # The following codes are being suppressed: # E006 Line too long +# E011 Then keyword is not on same line as if or elif keyword +# bashate is called twice, to handle shell scripts that do not end in .sh +# the suppression lists are different (eventually nothing will be suppressed) commands = bash -c "find {toxinidir} \ -not \( -type d -name .?\* -prune \) \ @@ -32,6 +90,18 @@ commands = -print0 | xargs -r -n 1 -0 bashate -v \ -i E006 \ -e 'E*'" + bash -c "find {toxinidir} \ + -not \( -type d -name .?\* -prune \) \ + -type f \ + -not -name \*~ \ + -not -name \*.md \ + -not -name \*.ldif \ + \( -exec bash -c 'file \{\} | grep -q shell' \; \ + -a ! -name '*.sh' \) \ + -print0 | xargs -r -n 1 -0 bashate -v \ + -i E006,E011 \ + -e 'E*'" + [testenv:bindep] # Do not install any requirements. We want this to be fast and work even if @@ -42,6 +112,7 @@ deps = bindep commands = bindep test [testenv:linters] +basepython = python3 # Note: centos developer env requires ruby-devel # Ubuntu developer env requires ruby-dev whitelist_externals = @@ -59,6 +130,7 @@ commands = -name \*.pp -print0 \ | xargs -0 puppet-lint --fail-on-warnings {[testenv:linters]skip_tests}" {[testenv:bashate]commands} + {[testenv:shellcheck]commands} [testenv:pep8] basepython = python3