From ed6e3ebd30aaaeaa0f6819c57c2de710fb4a5611 Mon Sep 17 00:00:00 2001 From: Georg Lauterbach <44545919+aendeavor@users.noreply.github.com> Date: Sun, 4 Oct 2020 19:34:15 +0200 Subject: [PATCH] Outsourced linting tests into its own file (#1636) * outsourced linting tests into its own file * trigger rebuild * added SCRIPT variable to setup.sh * trigger rebuild again * major test rewrite * outsourced `hadolint` too * rewrote some parts of the linting logic due to a logic bug * adjusted TravisCI * corrected .bats test line * corrected logging in linting tests * updated `hadolint` --- .travis.yml | 6 +- Makefile | 29 +-- setup.sh | 24 ++- .hadolint.yaml => test/linting/.hadolint.yaml | 0 test/linting/lint.sh | 176 ++++++++++++++++++ test/tests.bats | 4 +- 6 files changed, 207 insertions(+), 32 deletions(-) rename .hadolint.yaml => test/linting/.hadolint.yaml (100%) create mode 100755 test/linting/lint.sh diff --git a/.travis.yml b/.travis.yml index 8b133114..9190cd23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ sudo: required env: global: - - HADOLINT_VERSION=1.17.1 + - HADOLINT_VERSION=1.18.0 - SHELLCHECK_VERSION=0.7.1 - ECLINT_VERSION=2.1.0 @@ -33,12 +33,12 @@ before_install: - sudo chmod +x /usr/bin/eclint install: - - make lint - travis_retry travis_wait make build script: - - make shellcheck - make eclint + - make hadolint + - make shellcheck - make generate-accounts run generate-accounts-after-run fixtures tests after_script: diff --git a/Makefile b/Makefile index 8e4073ce..6833a4bb 100644 --- a/Makefile +++ b/Makefile @@ -141,11 +141,6 @@ tests: test/%.bats: ALWAYS_RUN ./test/bats/bin/bats $@ -lint: -# List files which name starts with 'Dockerfile' -# eg. Dockerfile, Dockerfile.build, etc. - -@ git ls-files --exclude='Dockerfile*' --ignored | xargs --max-lines=1 hadolint - clean: # remove running and stopped test containers -@ docker ps -a | grep -E "docker-mailserver:testing|ldap_for_mail" | cut -f 1-1 -d ' ' | xargs --no-run-if-empty docker rm -f @@ -159,23 +154,13 @@ clean: fi -@ sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem test/config/dovecot-lmtp/dh.pem test/config/relay-hosts/dovecot-quotas.cf test/config/user-patches.sh test/alias/config/postfix-virtual.cf test/quota/config/dovecot-quotas.cf test/quota/config/postfix-accounts.cf test/relay/config/postfix-relaymap.cf test/relay/config/postfix-sasl-password.cf +lint: eclint hadolint shellcheck + +hadolint: + @ ./test/linting/lint.sh hadolint + shellcheck: - @ echo -e "Testing shell / bash scripts with shellcheck\n" - @ /usr/bin/shellcheck --version - @ echo '' - @ if find -iname "*.sh" -not -path "./test/*" -not -path "./target/docker-configomat/*" -exec /usr/bin/shellcheck -S style -Cauto -o all -e SC2154 -W 50 {} \; | grep .; then\ - echo -e "\nError" ;\ - exit 1 ;\ - else\ - echo -e '\nSuccess' ;\ - fi + @ ./test/linting/lint.sh shellcheck eclint: - @ echo -e "Testing file formatting according to .editorconfig\n" - @ printf "Version %s\n\n" "$$(/usr/bin/eclint --version)" - @ if /usr/bin/eclint -exclude "\.bats$$" | grep .; then\ - echo -e "\nError" ;\ - exit 1 ;\ - else\ - echo -e '\nSuccess' ;\ - fi + @ ./test/linting/lint.sh eclint diff --git a/setup.sh b/setup.sh index 1b602e7c..34c1f13f 100755 --- a/setup.sh +++ b/setup.sh @@ -3,12 +3,24 @@ # Wrapper for various setup scripts # included in the docker-mailserver -set -euEo pipefail -trap '_report_err ${_} ${LINENO} ${?}' ERR +SCRIPT='SETUP' -function _report_err +set -euEo pipefail +trap '__log_err ${FUNCNAME[0]:-"?"} ${_:-"?"} ${LINENO:-"?"} ${?:-"?"}' ERR + +function __log_err { - echo "ERROR occured :: source ${1} ; line ${2} ; exit code ${3} ;;" >&2 + local FUNC_NAME LINE EXIT_CODE + FUNC_NAME="${1} / ${2}" + LINE="${3}" + EXIT_CODE="${4}" + + printf "\n––– \e[1m\e[31mUNCHECKED ERROR\e[0m\n%s\n%s\n%s\n%s\n\n" \ + " – script = ${SCRIPT,,}.sh" \ + " – function = ${FUNC_NAME}" \ + " – line = ${LINE}" \ + " – exit code = ${EXIT_CODE}" + _unset_vars } @@ -88,7 +100,9 @@ function _inspect function _usage { - echo "Usage: ${0} [-i IMAGE_NAME] [-c CONTAINER_NAME] [args] + echo "${SCRIPT,,}.sh + +Usage: ${0} [-i IMAGE_NAME] [-c CONTAINER_NAME] [args] OPTIONS: diff --git a/.hadolint.yaml b/test/linting/.hadolint.yaml similarity index 100% rename from .hadolint.yaml rename to test/linting/.hadolint.yaml diff --git a/test/linting/lint.sh b/test/linting/lint.sh new file mode 100755 index 00000000..56f45e0e --- /dev/null +++ b/test/linting/lint.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash + +# version v0.1.0 stable +# executed by TravisCI / manually +# task checks files agains linting targets + +SCRIPT="LINT TESTS" + +function _get_current_directory +{ + if dirname "$(readlink -f "${0}")" &>/dev/null + then + CDIR="$(cd "$(dirname "$(readlink -f "${0}")")" && pwd)" + elif realpath -e -L "${0}" &>/dev/null + then + CDIR="$(realpath -e -L "${0}")" + CDIR="${CDIR%/setup.sh}" + fi +} + +CDIR="$(pwd)" +_get_current_directory + +# ? ––––––––––––––––––––––––––––––––––––––––––––– ERRORS + +set -eEuo pipefail +trap '__log_err ${FUNCNAME[0]:-"?"} ${_:-"?"} ${LINENO:-"?"} ${?:-"?"}' ERR + +function __log_err +{ + local FUNC_NAME LINE EXIT_CODE + FUNC_NAME="${1} / ${2}" + LINE="${3}" + EXIT_CODE="${4}" + + printf "\n––– \e[1m\e[31mUNCHECKED ERROR\e[0m\n%s\n%s\n%s\n%s\n\n" \ + " – script = ${SCRIPT}" \ + " – function = ${FUNC_NAME}" \ + " – line = ${LINE}" \ + " – exit code = ${EXIT_CODE}" + + unset CDIR SCRIPT OS VERSION +} + +# ? ––––––––––––––––––––––––––––––––––––––––––––– LOG + +function __log_info +{ + printf "\n––– \e[34m%s\e[0m\n%s\n%s\n\n" \ + "${SCRIPT}" \ + " – type = INFO" \ + " – message = ${*}" +} + +function __log_warning +{ + printf "\n––– \e[93m%s\e[0m\n%s\n%s\n\n" \ + "${SCRIPT}" \ + " – type = WARNING" \ + " – message = ${*}" +} + +function __log_abort +{ + printf "\n––– \e[91m%s\e[0m\n%s\n%s\n\n" \ + "${SCRIPT}" \ + " – type = ABORT" \ + " – message = ${*:-"errors encountered"}" +} + +function __log_success +{ + printf "\n––– \e[32m%s\e[0m\n%s\n%s\n\n" \ + "${SCRIPT}" \ + " – type = SUCCESS" \ + " – message = ${*}" +} + +function __in_path { __which "${@}" && return 0 ; return 1 ; } +function __which { command -v "${@}" &>/dev/null ; } + +function _eclint +{ + local LINT=(eclint -exclude "(.*\.git.*|.*\.md$|\.bats$)") + + if ! __in_path "${LINT[0]}" + then + __log_abort 'linter not in PATH' + return 102 + fi + + __log_info \ + 'type: editorconfig' \ + '(linter version:' "$(${LINT[0]} --version))" + + local SCRIPT='EDITORCONFIG LINTER' + if "${LINT[@]}" + then + __log_success 'no errors detected' + else + __log_abort + return 101 + fi +} + +function _hadolint +{ + local LINT=(hadolint -c "${CDIR}/.hadolint.yaml") + + if ! __in_path "${LINT[0]}" + then + __log_abort 'linter not in PATH' + return 102 + fi + + __log_info \ + 'type: Dockerfile' \ + '(linter version:' "$(${LINT[0]} --version | grep -E -o "v[0-9\.]*"))" + + local SCRIPT='HADOLINT' + if git ls-files --exclude='Dockerfile*' --ignored | \ + xargs --max-lines=1 "${LINT[@]}" + then + __log_success 'no errors detected' + else + __log_abort + return 101 + fi +} + +function _shellcheck +{ + local LINT=(/usr/bin/shellcheck -S style -Cauto -o all -e SC2154 -W 50) + + if ! __in_path "${LINT[0]}" + then + __log_abort 'linter not in PATH' + return 102 + fi + + __log_info \ + 'type: shellcheck' '(linter version:' \ + "$(${LINT[0]} --version | grep -m 2 -o "[0-9.]*"))" + + local FIND=( + find . -iname "*.sh" + -not -path "./test/*" + -not -path "./target/docker-configomat/*" + -exec "${LINT[@]}" {} \;) + + local SCRIPT='SHELLCHECK' + if "${FIND[@]}" | grep -q . + then + "${FIND[@]}" + __log_abort + return 101 + else + __log_success 'no errors detected' + fi +} + +function _main +{ + case ${1:- } in + 'eclint' ) _eclint ;; + 'hadolint' ) _hadolint ;; + 'shellcheck' ) _shellcheck ;; + *) + __log_abort \ + "init.sh: '${1}' is not a command nor an option. See 'make help'." + exit 11 + ;; + esac +} + +_main "${@}" || exit ${?} diff --git a/test/tests.bats b/test/tests.bats index 0d77ae5c..5635fecc 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -1206,13 +1206,13 @@ EOF @test "checking setup.sh: Without arguments: status 1, show help text" { run ./setup.sh assert_failure - [ "${lines[0]}" = "Usage: ./setup.sh [-i IMAGE_NAME] [-c CONTAINER_NAME] [args]" ] + [ "${lines[1]}" = "Usage: ./setup.sh [-i IMAGE_NAME] [-c CONTAINER_NAME] [args]" ] } @test "checking setup.sh: Wrong arguments" { run ./setup.sh lol troll assert_failure - [ "${lines[0]}" = "Usage: ./setup.sh [-i IMAGE_NAME] [-c CONTAINER_NAME] [args]" ] + [ "${lines[1]}" = "Usage: ./setup.sh [-i IMAGE_NAME] [-c CONTAINER_NAME] [args]" ] } # email