mirror of
https://github.com/super-linter/super-linter.git
synced 2024-12-22 23:32:10 -05:00
5219feefab
- Remove the SKIP_FLAG variable and check for the length of the arrays of files to lint directly. - Remove the LIST_FILES variable, and use the FILE_ARRAY variable directly. - Remove the corner case for RENOVATE because renovate-config-validator supports passing the path to the file to lint using an argument as the default case does. - Remove the corner case for ANSIBLE not having 'bad' tests because it has them now. - Set TF_DATA_DIR to avoid any modification to any existing Terraform data directory that users might have in their workspace. - Aggregate GO_MODULES and ANSIBLE corner cases because they are the same. - Remove the corner case for ANSIBLE to add a trailing slash to TEST_CASE_FOLDER (similar reason as the previous point about ANSIBLE corner case). - Simplify log messages by removing color markers because they are already handled in log.sh. - Simplify linterVersions by removing redundant checks and functions. - Avoid printing debug logs in the versions file.
213 lines
8.1 KiB
Bash
Executable file
213 lines
8.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
function LintCodebase() {
|
|
FILE_TYPE="${1}" && shift
|
|
LINTER_NAME="${1}" && shift
|
|
LINTER_COMMAND="${1}" && shift
|
|
FILTER_REGEX_INCLUDE="${1}" && shift
|
|
FILTER_REGEX_EXCLUDE="${1}" && shift
|
|
TEST_CASE_RUN="${1}" && shift
|
|
FILE_ARRAY=("$@")
|
|
|
|
# Array to track directories where tflint was run
|
|
declare -A TFLINT_SEEN_DIRS
|
|
|
|
# To count how many files were checked for a given FILE_TYPE
|
|
INDEX=0
|
|
|
|
# To check how many "bad" and "good" test cases we ran
|
|
BAD_TEST_CASES_COUNT=0
|
|
GOOD_TEST_CASES_COUNT=0
|
|
|
|
WORKSPACE_PATH="${GITHUB_WORKSPACE}"
|
|
if [ "${TEST_CASE_RUN}" == "true" ]; then
|
|
WORKSPACE_PATH="${GITHUB_WORKSPACE}/${TEST_CASE_FOLDER}"
|
|
fi
|
|
debug "Workspace path: ${WORKSPACE_PATH}"
|
|
|
|
info ""
|
|
info "----------------------------------------------"
|
|
info "----------------------------------------------"
|
|
debug "Running LintCodebase. FILE_TYPE: ${FILE_TYPE}. Linter name: ${LINTER_NAME}, linter command: ${LINTER_COMMAND}, TEST_CASE_RUN: ${TEST_CASE_RUN}, FILTER_REGEX_INCLUDE: ${FILTER_REGEX_INCLUDE}, FILTER_REGEX_EXCLUDE: ${FILTER_REGEX_EXCLUDE}, files to lint: ${FILE_ARRAY[*]}"
|
|
info "Linting ${FILE_TYPE} files..."
|
|
info "----------------------------------------------"
|
|
info "----------------------------------------------"
|
|
|
|
for FILE in "${FILE_ARRAY[@]}"; do
|
|
info "Checking file: ${FILE}"
|
|
|
|
if [[ "${TEST_CASE_RUN}" == "true" ]]; then
|
|
# Folder for specific tests. By convention, the last part of the path is the lowercased FILE_TYPE
|
|
local TEST_CASE_DIRECTORY
|
|
TEST_CASE_DIRECTORY="${TEST_CASE_FOLDER}/${FILE_TYPE,,}/"
|
|
debug "TEST_CASE_DIRECTORY for ${FILE}: ${TEST_CASE_DIRECTORY}"
|
|
|
|
if [[ ${FILE} != *"${TEST_CASE_DIRECTORY}"* ]]; then
|
|
debug "Skipping ${FILE} because it's not in the test case directory for ${FILE_TYPE}..."
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
local FILE_NAME
|
|
FILE_NAME=$(basename "${FILE}" 2>&1)
|
|
debug "FILE_NAME for ${FILE}: ${FILE_NAME}"
|
|
|
|
local DIR_NAME
|
|
DIR_NAME=$(dirname "${FILE}" 2>&1)
|
|
debug "DIR_NAME for ${FILE}: ${DIR_NAME}"
|
|
|
|
(("INDEX++"))
|
|
|
|
LINTED_LANGUAGES_ARRAY+=("${FILE_TYPE}")
|
|
local LINT_CMD
|
|
LINT_CMD=''
|
|
|
|
if [[ ${FILE_TYPE} == "POWERSHELL" ]] || [[ ${FILE_TYPE} == "ARM" ]]; then
|
|
# Need to run PowerShell commands using pwsh -c, also exit with exit code from inner subshell
|
|
LINT_CMD=$(
|
|
cd "${WORKSPACE_PATH}" || exit
|
|
pwsh -NoProfile -NoLogo -Command "${LINTER_COMMAND} \"${FILE}\"; if (\${Error}.Count) { exit 1 }"
|
|
exit $? 2>&1
|
|
)
|
|
elif [[ ${FILE_TYPE} == "R" ]]; then
|
|
local r_dir
|
|
if [ ! -f "${DIR_NAME}/.lintr" ]; then
|
|
r_dir="${WORKSPACE_PATH}"
|
|
else
|
|
r_dir="${DIR_NAME}"
|
|
fi
|
|
LINT_CMD=$(
|
|
cd "$r_dir" || exit
|
|
R --slave -e "lints <- lintr::lint('$FILE');print(lints);errors <- purrr::keep(lints, ~ .\$type == 'error');quit(save = 'no', status = if (length(errors) > 0) 1 else 0)" 2>&1
|
|
)
|
|
elif [[ ${FILE_TYPE} == "CSHARP" ]]; then
|
|
# Because the C# linter writes to tty and not stdout
|
|
LINT_CMD=$(
|
|
cd "${DIR_NAME}" || exit
|
|
${LINTER_COMMAND} "${FILE_NAME}" | tee /dev/tty2 2>&1
|
|
exit "${PIPESTATUS[0]}"
|
|
)
|
|
elif [[ ${FILE_TYPE} == "ANSIBLE" ]] ||
|
|
[[ ${FILE_TYPE} == "GO_MODULES" ]]; then
|
|
debug "Linting ${FILE_TYPE}. Changing the working directory to ${FILE} before running the linter."
|
|
# Because it expects that the working directory is a Go module (GO_MODULES) or
|
|
# because we want to enable ansible-lint autodetection mode.
|
|
# Ref: https://ansible-lint.readthedocs.io/usage
|
|
LINT_CMD=$(
|
|
cd "${FILE}" || exit 1
|
|
${LINTER_COMMAND} 2>&1
|
|
)
|
|
elif [[ ${FILE_TYPE} == "KOTLIN" ]]; then
|
|
# Because it needs to change directory to where the file to lint is
|
|
LINT_CMD=$(
|
|
cd "${DIR_NAME}" || exit
|
|
${LINTER_COMMAND} "${FILE_NAME}" 2>&1
|
|
)
|
|
elif [[ ${FILE_TYPE} == "TERRAFORM_TFLINT" ]]; then
|
|
# Check the cache to see if we've already prepped this directory for tflint
|
|
if [[ ! -v "TFLINT_SEEN_DIRS[${DIR_NAME}]" ]]; then
|
|
debug "Configuring Terraform data directory for ${DIR_NAME}"
|
|
|
|
# Define the path to an empty Terraform data directory
|
|
# (def: https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_data_dir)
|
|
# in case the user has a Terraform data directory already, and we don't
|
|
# want to modify it.
|
|
# TFlint considers this variable as well.
|
|
# Ref: https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/compatibility.md#environment-variables
|
|
local TF_DATA_DIR
|
|
TF_DATA_DIR="/tmp/.terraform-${FILE_TYPE}-${DIR_NAME}"
|
|
export TF_DATA_DIR
|
|
# Let the cache know we've seen this before
|
|
# Set the value to an arbitrary non-empty string.
|
|
|
|
# Fetch Terraform modules
|
|
debug "Fetch Terraform modules for ${DIR_NAME} in ${TF_DATA_DIR}"
|
|
local FETCH_TERRAFORM_MODULES_CMD
|
|
FETCH_TERRAFORM_MODULES_CMD="$(terraform get)"
|
|
ERROR_CODE=$?
|
|
debug "Fetch Terraform modules. Exit code: ${ERROR_CODE}. Command output: ${FETCH_TERRAFORM_MODULES_CMD}"
|
|
if [ ${ERROR_CODE} -ne 0 ]; then
|
|
fatal "Error when fetching Terraform modules while linting ${FILE}"
|
|
fi
|
|
TFLINT_SEEN_DIRS[${DIR_NAME}]="false"
|
|
fi
|
|
|
|
# Because it needs to change the directory to where the file to lint is
|
|
LINT_CMD=$(
|
|
cd "${DIR_NAME}" || exit
|
|
${LINTER_COMMAND} --filter="${FILE_NAME}" 2>&1
|
|
)
|
|
else
|
|
LINT_CMD=$(
|
|
cd "${WORKSPACE_PATH}" || exit
|
|
${LINTER_COMMAND} "${FILE}" 2>&1
|
|
)
|
|
fi
|
|
|
|
ERROR_CODE=$?
|
|
|
|
local FILE_STATUS
|
|
# Assume that the file should pass linting checks
|
|
FILE_STATUS="good"
|
|
|
|
if [[ "${TEST_CASE_RUN}" == "true" ]] && [[ ${FILE} == *"bad"* ]]; then
|
|
FILE_STATUS="bad"
|
|
debug "We are running in test mode. Updating the expected FILE_STATUS for ${FILE} to: ${FILE_STATUS}"
|
|
fi
|
|
|
|
debug "Results for ${FILE}. Exit code: ${ERROR_CODE}. Command output:\n------\n${LINT_CMD}\n------"
|
|
|
|
########################################
|
|
# File status = good, this should pass #
|
|
########################################
|
|
if [[ ${FILE_STATUS} == "good" ]]; then
|
|
(("GOOD_TEST_CASES_COUNT++"))
|
|
|
|
if [ ${ERROR_CODE} -ne 0 ]; then
|
|
error "Found errors when linting ${FILE_NAME}. Exit code: ${ERROR_CODE}. Command output:\n------\n${LINT_CMD}\n------"
|
|
(("ERRORS_FOUND_${FILE_TYPE}++"))
|
|
else
|
|
notice "${FILE} was linted successfully"
|
|
if [ -n "${LINT_CMD}" ]; then
|
|
info "Command output for ${FILE_NAME}:\n------\n${LINT_CMD}\n------"
|
|
fi
|
|
fi
|
|
#######################################
|
|
# File status = bad, this should fail #
|
|
#######################################
|
|
else
|
|
if [[ "${TEST_CASE_RUN}" == "false" ]]; then
|
|
fatal "All files are supposed to pass linting checks when not running in test mode."
|
|
fi
|
|
|
|
(("BAD_TEST_CASES_COUNT++"))
|
|
|
|
if [ ${ERROR_CODE} -eq 0 ]; then
|
|
error "${FILE} should have failed test case."
|
|
(("ERRORS_FOUND_${FILE_TYPE}++"))
|
|
else
|
|
notice "${FILE} failed the test case as expected"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ "${TEST_CASE_RUN}" = "true" ]; then
|
|
|
|
debug "${LINTER_NAME} test suite has ${INDEX} test(s), of which ${BAD_TEST_CASES_COUNT} 'bad' (expected to fail), ${GOOD_TEST_CASES_COUNT} 'good' (expected to pass)."
|
|
|
|
# Check if we ran at least one test
|
|
if [ "${INDEX}" -eq 0 ]; then
|
|
fatal "Failed to find any tests ran for: ${LINTER_NAME}. Check that tests exist for linter: ${LINTER_NAME}"
|
|
fi
|
|
|
|
# Check if we ran at least one 'bad' test
|
|
if [ "${BAD_TEST_CASES_COUNT}" -eq 0 ]; then
|
|
fatal "Failed to find any tests that are expected to fail for: ${LINTER_NAME}. Check that tests that are expected to fail exist for linter: ${LINTER_NAME}"
|
|
fi
|
|
|
|
# Check if we ran at least one 'good' test
|
|
if [ "${GOOD_TEST_CASES_COUNT}" -eq 0 ]; then
|
|
fatal "Failed to find any tests that are expected to pass for: ${LINTER_NAME}. Check that tests that are expected to pass exist for linter: ${LINTER_NAME}"
|
|
fi
|
|
fi
|
|
}
|