fix: simplify worker and linterVersions (#5123)

- 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.
This commit is contained in:
Marco Ferrari 2024-01-15 19:37:45 +01:00 committed by GitHub
parent 915e018216
commit 5219feefab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 203 additions and 424 deletions

View file

@ -1,14 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
################################################################################
################################################################################
########### Super-Linter linting Functions @admiralawkbar ######################
################################################################################
################################################################################
########################## FUNCTION CALLS BELOW ################################
################################################################################
################################################################################
#### Function LinterRulesLocation ##############################################
LinterRulesLocation() { LinterRulesLocation() {
# We need to see if the user has set the rules location to the root # We need to see if the user has set the rules location to the root
# directory, or to some nested folder # directory, or to some nested folder

View file

@ -1,22 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
################################################################################
################################################################################
########### Super-Linter linting Functions @admiralawkbar ######################
################################################################################
################################################################################
#### Function GetLinterVersions ################################################
GetLinterVersions() { GetLinterVersions() {
#########################
# Print version headers #
#########################
debug "---------------------------------------------"
debug "WRITE_LINTER_VERSIONS_FILE: ${WRITE_LINTER_VERSIONS_FILE}" debug "WRITE_LINTER_VERSIONS_FILE: ${WRITE_LINTER_VERSIONS_FILE}"
debug "VERSION_FILE: ${VERSION_FILE}"
debug "Linter Version Info:"
if [ "${WRITE_LINTER_VERSIONS_FILE}" = "true" ]; then if [ "${WRITE_LINTER_VERSIONS_FILE}" = "true" ]; then
debug "Building linter version file..." debug "Building linter version file: ${VERSION_FILE}"
if BuildLinterVersions "${VERSION_FILE}" "${LINTER_NAMES_ARRAY[@]}"; then if BuildLinterVersions "${VERSION_FILE}" "${LINTER_NAMES_ARRAY[@]}"; then
info "Linter version file built correctly." info "Linter version file built correctly."
exit exit
@ -27,31 +15,9 @@ GetLinterVersions() {
debug "Skipping versions file build..." debug "Skipping versions file build..."
fi fi
################################ if ! cat "${VERSION_FILE}"; then
# Cat the linter versions file # fatal "Failed to view version file: ${VERSION_FILE}."
################################
CAT_CMD=$(cat "${VERSION_FILE}" 2>&1)
#######################
# Load the error code #
#######################
ERROR_CODE=$?
##############################
# Check the shell for errors #
##############################
if [ ${ERROR_CODE} -ne 0 ]; then
# Failure
fatal "Failed to view version file:[${VERSION_FILE}]"
else
# Success
debug "${CAT_CMD}"
fi fi
#########################
# Print version footers #
#########################
debug "---------------------------------------------"
} }
################################################################################ ################################################################################
#### Function BuildLinterVersions ############################################## #### Function BuildLinterVersions ##############################################
@ -59,6 +25,10 @@ BuildLinterVersions() {
VERSION_FILE="${1}" && shift VERSION_FILE="${1}" && shift
LINTER_ARRAY=("$@") LINTER_ARRAY=("$@")
# Start with an empty file. We might have built this file in a previous build
# stage, so we start fresh here.
rm -rfv "${VERSION_FILE}"
debug "Building linter version file ${VERSION_FILE} for the following linters: ${LINTER_ARRAY[*]}..." debug "Building linter version file ${VERSION_FILE} for the following linters: ${LINTER_ARRAY[*]}..."
########################################################## ##########################################################
@ -66,15 +36,14 @@ BuildLinterVersions() {
########################################################## ##########################################################
for LINTER in "${LINTER_ARRAY[@]}"; do for LINTER in "${LINTER_ARRAY[@]}"; do
if [ -n "${LINTER}" ]; then if [ -n "${LINTER}" ]; then
####################
# Get the versions # # Some linters need to account for special commands to get their version
####################
if [[ ${LINTER} == "arm-ttk" ]]; then if [[ ${LINTER} == "arm-ttk" ]]; then
# Need specific command for ARM
GET_VERSION_CMD="$(grep -iE 'version' "/usr/bin/arm-ttk" | xargs 2>&1)" GET_VERSION_CMD="$(grep -iE 'version' "/usr/bin/arm-ttk" | xargs 2>&1)"
elif [[ ${LINTER} == "bash-exec" ]] || [[ ${LINTER} == "gherkin-lint" ]] || [[ ${LINTER} == "asl-validator" ]]; then # Some linters don't support a "get version" command
# Need specific command for Protolint and editorconfig-checker elif [[ ${LINTER} == "bash-exec" ]] || [[ ${LINTER} == "gherkin-lint" ]]; then
GET_VERSION_CMD="$(echo "--version not supported")" GET_VERSION_CMD="Version command not supported"
elif [[ ${LINTER} == "checkstyle" ]] || [[ ${LINTER} == "google-java-format" ]]; then elif [[ ${LINTER} == "checkstyle" ]] || [[ ${LINTER} == "google-java-format" ]]; then
GET_VERSION_CMD="$(java -jar "/usr/bin/${LINTER}" --version 2>&1)" GET_VERSION_CMD="$(java -jar "/usr/bin/${LINTER}" --version 2>&1)"
elif [[ ${LINTER} == "clippy" ]]; then elif [[ ${LINTER} == "clippy" ]]; then
@ -91,63 +60,32 @@ BuildLinterVersions() {
elif [[ ${LINTER} == "protolint" ]] || [[ ${LINTER} == "gitleaks" ]]; then elif [[ ${LINTER} == "protolint" ]] || [[ ${LINTER} == "gitleaks" ]]; then
GET_VERSION_CMD="$(${LINTER} version)" GET_VERSION_CMD="$(${LINTER} version)"
elif [[ ${LINTER} == "lua" ]]; then elif [[ ${LINTER} == "lua" ]]; then
# Semi standardversion command
GET_VERSION_CMD="$("${LINTER}" -v 2>&1)" GET_VERSION_CMD="$("${LINTER}" -v 2>&1)"
elif [[ ${LINTER} == "renovate-config-validator" ]]; then elif [[ ${LINTER} == "renovate-config-validator" ]]; then
GET_VERSION_CMD="$(renovate --version 2>&1)" GET_VERSION_CMD="$(renovate --version 2>&1)"
elif [[ ${LINTER} == "terrascan" ]]; then elif [[ ${LINTER} == "terrascan" ]]; then
GET_VERSION_CMD="$("${LINTER}" version 2>&1)" GET_VERSION_CMD="$("${LINTER}" version 2>&1)"
else else
# Standard version command # Unset TF_LOG_LEVEL so that the version file doesn't contain debug log when running
GET_VERSION_CMD="$("${LINTER}" --version 2>&1)" # commands that read TF_LOG_LEVEL or TFLINT_LOG, which are likely set to DEBUG when
# building the versions file
GET_VERSION_CMD="$(
unset TF_LOG_LEVEL
unset TFLINT_LOG
"${LINTER}" --version 2>&1
)"
fi fi
#######################
# Load the error code #
#######################
ERROR_CODE=$? ERROR_CODE=$?
##############################
# Check the shell for errors #
##############################
debug "Linter version for ${LINTER}: ${GET_VERSION_CMD}. Error code: ${ERROR_CODE}"
if [ ${ERROR_CODE} -ne 0 ]; then if [ ${ERROR_CODE} -ne 0 ]; then
fatal "[${LINTER}]: Failed to get version info: ${GET_VERSION_CMD}" fatal "[${LINTER}]: Failed to get version info. Exit code: ${ERROR_CODE}. Output: ${GET_VERSION_CMD}"
else else
########################## info "Successfully found version for ${LINTER}: ${GET_VERSION_CMD}"
# Print the version info # if ! echo "${LINTER}: ${GET_VERSION_CMD}" >>"${VERSION_FILE}" 2>&1; then
########################## fatal "Failed to write data to file!"
info "Successfully found version for ${F[W]}[${LINTER}]${F[B]}: ${F[W]}${GET_VERSION_CMD}" fi
WriteFile "${LINTER}" "${GET_VERSION_CMD}" "${VERSION_FILE}"
fi fi
fi fi
done done
} }
################################################################################
#### Function WriteFile ########################################################
WriteFile() {
##############
# Read Input #
##############
LINTER="$1" # Name of the linter
VERSION="$2" # Version returned from check
VERSION_FILE=$3 # Version file path
#################################
# Write the data to output file #
#################################
echo "${LINTER}: ${VERSION}" >>"${VERSION_FILE}" 2>&1
#######################
# Load the error code #
#######################
# shellcheck disable=SC2320
ERROR_CODE=$?
##############################
# Check the shell for errors #
##############################
if [ $ERROR_CODE -ne 0 ]; then
fatal "Failed to write data to file!"
fi
}

View file

@ -1,363 +1,213 @@
#!/usr/bin/env bash #!/usr/bin/env bash
################################################################################
################################################################################
########### Super-Linter linting Functions @admiralawkbar ######################
################################################################################
################################################################################
########################## FUNCTION CALLS BELOW ################################
################################################################################
################################################################################
#### Function LintCodebase #####################################################
function LintCodebase() { function LintCodebase() {
# Call comes through as: FILE_TYPE="${1}" && shift
# LintCodebase "${LANGUAGE}" "${LINTER_NAME}" "${LINTER_COMMAND}" "${FILTER_REGEX_INCLUDE}" "${FILTER_REGEX_EXCLUDE}" "${TEST_CASE_RUN}" "${!LANGUAGE_FILE_ARRAY}" LINTER_NAME="${1}" && shift
#################### LINTER_COMMAND="${1}" && shift
# Pull in the vars # FILTER_REGEX_INCLUDE="${1}" && shift
#################### FILTER_REGEX_EXCLUDE="${1}" && shift
FILE_TYPE="${1}" && shift # Pull the variable and remove from array path (Example: JSON) TEST_CASE_RUN="${1}" && shift
LINTER_NAME="${1}" && shift # Pull the variable and remove from array path (Example: jsonlint) FILE_ARRAY=("$@")
LINTER_COMMAND="${1}" && shift # Pull the variable and remove from array path (Example: jsonlint -c ConfigFile /path/to/file)
FILTER_REGEX_INCLUDE="${1}" && shift # Pull the variable and remove from array path (Example: */src/*,*/test/*)
FILTER_REGEX_EXCLUDE="${1}" && shift # Pull the variable and remove from array path (Example: */examples/*,*/test/*.test)
TEST_CASE_RUN="${1}" && shift # Flag for if running in test cases
FILE_ARRAY=("$@") # Array of files to validate (Example: ${FILE_ARRAY_JSON})
########################## # Array to track directories where tflint was run
# Initialize empty Array #
##########################
LIST_FILES=()
###################################################
# Array to track directories where tflint was run #
###################################################
declare -A TFLINT_SEEN_DIRS declare -A TFLINT_SEEN_DIRS
################ # To count how many files were checked for a given FILE_TYPE
# Set the flag #
################
SKIP_FLAG=0
INDEX=0 INDEX=0
# We use these flags to check how many "bad" and "good" test cases we ran # To check how many "bad" and "good" test cases we ran
BAD_TEST_CASES_COUNT=0 BAD_TEST_CASES_COUNT=0
GOOD_TEST_CASES_COUNT=0 GOOD_TEST_CASES_COUNT=0
############################################################ WORKSPACE_PATH="${GITHUB_WORKSPACE}"
# Check to see if we need to go through array or all files # if [ "${TEST_CASE_RUN}" == "true" ]; then
############################################################ WORKSPACE_PATH="${GITHUB_WORKSPACE}/${TEST_CASE_FOLDER}"
if [ ${#FILE_ARRAY[@]} -eq 0 ]; then
SKIP_FLAG=1
debug " - No files found in changeset to lint for language:[${FILE_TYPE}]"
else
# We have files added to array of files to check
LIST_FILES=("${FILE_ARRAY[@]}") # Copy the array into list
fi fi
debug "Workspace path: ${WORKSPACE_PATH}"
debug "SKIP_FLAG: ${SKIP_FLAG}, list of files to lint: ${LIST_FILES[*]}" 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
# Check if any data was found # info "Checking file: ${FILE}"
###############################
if [ ${SKIP_FLAG} -eq 0 ]; then
WORKSPACE_PATH="${GITHUB_WORKSPACE}"
if [ "${TEST_CASE_RUN}" == "true" ]; then
debug "TEST_CASE_FOLDER: ${TEST_CASE_FOLDER}"
WORKSPACE_PATH="${GITHUB_WORKSPACE}/${TEST_CASE_FOLDER}"
fi
debug "Workspace path: ${WORKSPACE_PATH}"
################
# print header #
################
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[*]}"
if [ "${TEST_CASE_RUN}" = "true" ]; then
info "Testing Codebase [${FILE_TYPE}] files..."
else
info "Linting [${FILE_TYPE}] files..."
fi
info "----------------------------------------------"
info "----------------------------------------------"
##################
# Lint the files #
##################
for FILE in "${LIST_FILES[@]}"; do
debug "Linting FILE: ${FILE}"
# We want a lowercase value
local -l INDIVIDUAL_TEST_FOLDER
# Folder for specific tests. By convention, it's the lowercased FILE_TYPE
INDIVIDUAL_TEST_FOLDER="${FILE_TYPE}"
debug "INDIVIDUAL_TEST_FOLDER for ${FILE}: ${INDIVIDUAL_TEST_FOLDER}"
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 local TEST_CASE_DIRECTORY
TEST_CASE_DIRECTORY="${TEST_CASE_FOLDER}/${INDIVIDUAL_TEST_FOLDER}" TEST_CASE_DIRECTORY="${TEST_CASE_FOLDER}/${FILE_TYPE,,}/"
debug "TEST_CASE_DIRECTORY for ${FILE}: ${TEST_CASE_DIRECTORY}" debug "TEST_CASE_DIRECTORY for ${FILE}: ${TEST_CASE_DIRECTORY}"
if [[ "${TEST_CASE_RUN}" == "true" ]]; then if [[ ${FILE} != *"${TEST_CASE_DIRECTORY}"* ]]; then
if [[ ${FILE_TYPE} != "ANSIBLE" ]]; then debug "Skipping ${FILE} because it's not in the test case directory for ${FILE_TYPE}..."
# These linters expect files inside a directory, not a directory. So we add a trailing slash continue
TEST_CASE_DIRECTORY="${TEST_CASE_DIRECTORY}/"
debug "Updated TEST_CASE_DIRECTORY for ${FILE_TYPE} to: ${TEST_CASE_DIRECTORY}"
fi
if [[ ${FILE} != *"${TEST_CASE_DIRECTORY}"* ]]; then
debug "Skipping ${FILE} because it's not in the test case directory for ${FILE_TYPE}..."
continue
fi
fi fi
fi
local FILE_NAME local FILE_NAME
FILE_NAME=$(basename "${FILE}" 2>&1) FILE_NAME=$(basename "${FILE}" 2>&1)
debug "FILE_NAME for ${FILE}: ${FILE_NAME}" debug "FILE_NAME for ${FILE}: ${FILE_NAME}"
local DIR_NAME local DIR_NAME
DIR_NAME=$(dirname "${FILE}" 2>&1) DIR_NAME=$(dirname "${FILE}" 2>&1)
debug "DIR_NAME for ${FILE}: ${DIR_NAME}" debug "DIR_NAME for ${FILE}: ${DIR_NAME}"
(("INDEX++")) (("INDEX++"))
info "File: ${FILE}" LINTED_LANGUAGES_ARRAY+=("${FILE_TYPE}")
local LINT_CMD
LINT_CMD=''
################################# if [[ ${FILE_TYPE} == "POWERSHELL" ]] || [[ ${FILE_TYPE} == "ARM" ]]; then
# Add the language to the array # # Need to run PowerShell commands using pwsh -c, also exit with exit code from inner subshell
################################# LINT_CMD=$(
LINTED_LANGUAGES_ARRAY+=("${FILE_TYPE}") cd "${WORKSPACE_PATH}" || exit
pwsh -NoProfile -NoLogo -Command "${LINTER_COMMAND} \"${FILE}\"; if (\${Error}.Count) { exit 1 }"
#################### exit $? 2>&1
# Set the base Var # )
#################### elif [[ ${FILE_TYPE} == "R" ]]; then
LINT_CMD='' local r_dir
if [ ! -f "${DIR_NAME}/.lintr" ]; then
##################### r_dir="${WORKSPACE_PATH}"
# Check for ansible #
#####################
if [[ ${FILE_TYPE} == "ANSIBLE" ]]; then
LINT_CMD=$(
cd "${FILE}" || exit
# Don't pass the file to lint to enable ansible-lint autodetection mode.
# See https://ansible-lint.readthedocs.io/usage for details
${LINTER_COMMAND} 2>&1
)
####################################
# Corner case for pwsh subshell #
# - PowerShell (PSScriptAnalyzer) #
# - ARM (arm-ttk) #
####################################
elif [[ ${FILE_TYPE} == "POWERSHELL" ]] || [[ ${FILE_TYPE} == "ARM" ]]; then
################################
# Lint the file with the rules #
################################
# 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
)
###############################################################################
# Corner case for R as we have to pass it to R #
###############################################################################
elif [[ ${FILE_TYPE} == "R" ]]; then
#######################################
# Lint the file with the updated path #
#######################################
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
)
#########################################################
# Corner case for C# as it writes to tty and not stdout #
#########################################################
elif [[ ${FILE_TYPE} == "CSHARP" ]]; then
LINT_CMD=$(
cd "${DIR_NAME}" || exit
${LINTER_COMMAND} "${FILE_NAME}" | tee /dev/tty2 2>&1
exit "${PIPESTATUS[0]}"
)
###########################################################################################
# Corner case for GO_MODULES because it expects that the working directory is a Go module #
###########################################################################################
elif [[ ${FILE_TYPE} == "GO_MODULES" ]]; then
debug "Linting a Go module. Changing the working directory to ${FILE} before running the linter."
LINT_CMD=$(
cd "${FILE}" || exit 1
${LINTER_COMMAND} 2>&1
)
#######################################################
# Corner case for KTLINT as it cant use the full path #
#######################################################
elif [[ ${FILE_TYPE} == "KOTLIN" ]]; then
LINT_CMD=$(
cd "${DIR_NAME}" || exit
${LINTER_COMMAND} "${FILE_NAME}" 2>&1
)
######################
# Check for Renovate #
######################
elif [[ ${FILE_TYPE} == "RENOVATE" ]]; then
LINT_CMD=$(
cd "${WORKSPACE_PATH}" || exit
RENOVATE_CONFIG_FILE="${FILE}" ${LINTER_COMMAND} 2>&1
)
#############################################################################################
# Corner case for TERRAFORM_TFLINT as it can't use the full path and needs to fetch modules #
#############################################################################################
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 " Setting up TERRAFORM_TFLINT cache for ${DIR_NAME}"
TF_DOT_DIR="${DIR_NAME}/.terraform"
if [ -d "${TF_DOT_DIR}" ]; then
# Just in case there's something in the .terraform folder, keep a copy of it
TF_BACKUP_DIR="/tmp/.terraform-tflint-backup${DIR_NAME}"
debug " Backing up ${TF_DOT_DIR} to ${TF_BACKUP_DIR}"
mkdir -p "${TF_BACKUP_DIR}"
cp -r "${TF_DOT_DIR}" "${TF_BACKUP_DIR}"
# Store the destination directory so we can restore from our copy later
TFLINT_SEEN_DIRS[${DIR_NAME}]="${TF_BACKUP_DIR}"
else
# Just let the cache know we've seen this before
TFLINT_SEEN_DIRS[${DIR_NAME}]='false'
fi
(
cd "${DIR_NAME}" || exit
terraform get >/dev/null
)
fi
LINT_CMD=$(
cd "${DIR_NAME}" || exit
${LINTER_COMMAND} --filter="${FILE_NAME}" 2>&1
)
else else
################################ r_dir="${DIR_NAME}"
# Lint the file with the rules #
################################
LINT_CMD=$(
cd "${WORKSPACE_PATH}" || exit
${LINTER_COMMAND} "${FILE}" 2>&1
)
fi fi
####################### LINT_CMD=$(
# Load the error code # 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
ERROR_CODE=$? )
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
# Check for if it was supposed to pass # # (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.
local FILE_STATUS # TFlint considers this variable as well.
# Assume that the file should pass linting checks # Ref: https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/compatibility.md#environment-variables
FILE_STATUS="good" local TF_DATA_DIR
TF_DATA_DIR="/tmp/.terraform-${FILE_TYPE}-${DIR_NAME}"
if [[ "${TEST_CASE_RUN}" == "true" ]]; then export TF_DATA_DIR
if [[ ${FILE} == *"bad"* ]]; then # Let the cache know we've seen this before
FILE_STATUS="bad" # Set the value to an arbitrary non-empty string.
debug "We are running in test mode. Updating the expected FILE_STATUS for ${FILE} to: ${FILE_STATUS}"
fi
fi
########################################
# File status = good, this should pass #
########################################
if [[ ${FILE_STATUS} == "good" ]]; then
# Increase the good test cases count
(("GOOD_TEST_CASES_COUNT++"))
# 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 if [ ${ERROR_CODE} -ne 0 ]; then
error "Found errors when running ${LINTER_NAME} on ${FILE}. Error code: ${ERROR_CODE}. File type: ${FILE_TYPE}. Command output:${NC}\n------\n${LINT_CMD}\n------" fatal "Error when fetching Terraform modules while linting ${FILE}"
# Increment the error count
(("ERRORS_FOUND_${FILE_TYPE}++"))
else
info " - File:${F[W]}[${FILE_NAME}]${F[B]} was linted with ${F[W]}[${LINTER_NAME}]${F[B]} successfully"
if [ -n "${LINT_CMD}" ]; then
info " - Command output:${NC}\n------\n${LINT_CMD}\n------"
fi
fi 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 else
####################################### notice "${FILE} was linted successfully"
# File status = bad, this should fail # if [ -n "${LINT_CMD}" ]; then
####################################### info "Command output for ${FILE_NAME}:\n------\n${LINT_CMD}\n------"
if [[ "${TEST_CASE_RUN}" == "false" ]]; then
fatal "All files are supposed to pass linting checks when not running in test mode. TEST_CASE_RUN: ${TEST_CASE_RUN}"
fi
(("BAD_TEST_CASES_COUNT++"))
if [ ${ERROR_CODE} -eq 0 ]; then
#########
# Error #
#########
error "Found errors in [${LINTER_NAME}] linter!"
error "This file should have failed test case!"
error "Error code: ${ERROR_CODE}. Command output:${NC}\n------\n${LINT_CMD}\n------"
# Increment the error count
(("ERRORS_FOUND_${FILE_TYPE}++"))
else
info " - File:${F[W]}[${FILE_NAME}]${F[B]} failed test case (Error code: ${ERROR_CODE}) with ${F[W]}[${LINTER_NAME}]${F[B]} as expected"
fi fi
fi fi
debug "Error code: ${ERROR_CODE}. Command output:${NC}\n------\n${LINT_CMD}\n------" #######################################
done # File status = bad, this should fail #
fi #######################################
else
# Clean up after TFLINT if [[ "${TEST_CASE_RUN}" == "false" ]]; then
for TF_DIR in "${!TFLINT_SEEN_DIRS[@]}"; do fatal "All files are supposed to pass linting checks when not running in test mode."
(
cd "${TF_DIR}" || exit
rm -rf .terraform
# Check to see if there was a .terraform folder there before we got started, restore it if so
POTENTIAL_BACKUP_DIR="${TFLINT_SEEN_DIRS[${TF_DIR}]}"
if [[ "${POTENTIAL_BACKUP_DIR}" != 'false' ]]; then
# Put the copy back in place
debug " Restoring ${TF_DIR}/.terraform from ${POTENTIAL_BACKUP_DIR}"
mv "${POTENTIAL_BACKUP_DIR}/.terraform" .terraform
fi 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 done
if [ "${TEST_CASE_RUN}" = "true" ]; then if [ "${TEST_CASE_RUN}" = "true" ]; then
debug "The ${LINTER_NAME} (linter: ${LINTER_NAME}) test suite has ${INDEX} test, of which ${BAD_TEST_CASES_COUNT} 'bad' (supposed to fail), ${GOOD_TEST_CASES_COUNT} 'good' (supposed to pass)." 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 # Check if we ran at least one test
if [ "${INDEX}" -eq 0 ]; then if [ "${INDEX}" -eq 0 ]; then
error "Failed to find any tests ran for the Linter:[${LINTER_NAME}]!" fatal "Failed to find any tests ran for: ${LINTER_NAME}. Check that tests exist for linter: ${LINTER_NAME}"
fatal "Validate logic and that tests exist for linter: ${LINTER_NAME}"
fi fi
# Check if we ran 'bad' tests # Check if we ran at least one 'bad' test
if [ "${BAD_TEST_CASES_COUNT}" -eq 0 ]; then if [ "${BAD_TEST_CASES_COUNT}" -eq 0 ]; then
if [ "${FILE_TYPE}" = "ANSIBLE" ]; 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}"
debug "There are no 'bad' tests for ${FILE_TYPE}, but it's a corner case that we allow because ${LINTER_NAME} is supposed to lint entire directories and the test suite doesn't support this corner case for 'bad' tests yet."
else
error "Failed to find any tests that are expected to fail for the Linter:[${LINTER_NAME}]!"
fatal "Validate logic and that tests that are expected to fail exist for linter: ${LINTER_NAME}"
fi
fi fi
# Check if we ran 'good' tests # Check if we ran at least one 'good' test
if [ "${GOOD_TEST_CASES_COUNT}" -eq 0 ]; then if [ "${GOOD_TEST_CASES_COUNT}" -eq 0 ]; then
error "Failed to find any tests that are expected to pass for the Linter:[${LINTER_NAME}]!" 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}"
fatal "Validate logic and that tests that are expected to pass exist for linter: ${LINTER_NAME}"
fi fi
fi fi
} }

View file

@ -512,14 +512,14 @@ GetGitHubVars() {
if [ -z "${GITHUB_EVENT_PATH}" ]; then if [ -z "${GITHUB_EVENT_PATH}" ]; then
fatal "Failed to get GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}]" fatal "Failed to get GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}]"
else else
info "Successfully found:${F[W]}[GITHUB_EVENT_PATH]${F[B]}, value:${F[W]}[${GITHUB_EVENT_PATH}]${F[B]}" info "Successfully found GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}]"
debug "${GITHUB_EVENT_PATH} contents: $(cat "${GITHUB_EVENT_PATH}")" debug "${GITHUB_EVENT_PATH} contents: $(cat "${GITHUB_EVENT_PATH}")"
fi fi
if [ -z "${GITHUB_SHA}" ]; then if [ -z "${GITHUB_SHA}" ]; then
fatal "Failed to get GITHUB_SHA: ${GITHUB_SHA}" fatal "Failed to get GITHUB_SHA: ${GITHUB_SHA}"
else else
info "Successfully found:${F[W]}[GITHUB_SHA]${F[B]}, value:${F[W]}[${GITHUB_SHA}]" info "Successfully found GITHUB_SHA: ${GITHUB_SHA}"
fi fi
################################################## ##################################################
@ -547,7 +547,7 @@ GetGitHubVars() {
if [ -z "${GITHUB_PUSH_COMMIT_COUNT}" ]; then if [ -z "${GITHUB_PUSH_COMMIT_COUNT}" ]; then
fatal "Failed to get GITHUB_PUSH_COMMIT_COUNT" fatal "Failed to get GITHUB_PUSH_COMMIT_COUNT"
fi fi
info "Successfully found:${F[W]}[GITHUB_PUSH_COMMIT_COUNT]${F[B]}, value:${F[W]}[${GITHUB_PUSH_COMMIT_COUNT}]" info "Successfully found GITHUB_PUSH_COMMIT_COUNT: ${GITHUB_PUSH_COMMIT_COUNT}"
# Ref: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context # Ref: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
debug "Get the hash of the commit to start the diff from from Git because the GitHub push event payload may not contain references to base_ref or previous commit." debug "Get the hash of the commit to start the diff from from Git because the GitHub push event payload may not contain references to base_ref or previous commit."
@ -560,7 +560,7 @@ GetGitHubVars() {
fi fi
ValidateGitBeforeShaReference ValidateGitBeforeShaReference
info "Successfully found:${F[W]}[GITHUB_BEFORE_SHA]${F[B]}, value:${F[W]}[${GITHUB_BEFORE_SHA}]" info "Successfully found GITHUB_BEFORE_SHA: ${GITHUB_BEFORE_SHA}"
fi fi
############################ ############################
@ -570,7 +570,7 @@ GetGitHubVars() {
error "Failed to get [GITHUB_ORG]!" error "Failed to get [GITHUB_ORG]!"
fatal "[${GITHUB_ORG}]" fatal "[${GITHUB_ORG}]"
else else
info "Successfully found:${F[W]}[GITHUB_ORG]${F[B]}, value:${F[W]}[${GITHUB_ORG}]" info "Successfully found GITHUB_ORG: ${GITHUB_ORG}"
fi fi
####################### #######################
@ -585,7 +585,7 @@ GetGitHubVars() {
error "Failed to get [GITHUB_REPO]!" error "Failed to get [GITHUB_REPO]!"
fatal "[${GITHUB_REPO}]" fatal "[${GITHUB_REPO}]"
else else
info "Successfully found:${F[W]}[GITHUB_REPO]${F[B]}, value:${F[W]}[${GITHUB_REPO}]" info "Successfully found GITHUB_REPO: ${GITHUB_REPO}"
fi fi
fi fi
@ -600,21 +600,21 @@ GetGitHubVars() {
if [ -z "${GITHUB_TOKEN}" ]; then if [ -z "${GITHUB_TOKEN}" ]; then
fatal "Failed to get [GITHUB_TOKEN]. Terminating because status reports were explicitly enabled, but GITHUB_TOKEN was not provided." fatal "Failed to get [GITHUB_TOKEN]. Terminating because status reports were explicitly enabled, but GITHUB_TOKEN was not provided."
else else
info "Successfully found:${F[W]}[GITHUB_TOKEN]." info "Successfully found GITHUB_TOKEN."
fi fi
if [ -z "${GITHUB_REPOSITORY}" ]; then if [ -z "${GITHUB_REPOSITORY}" ]; then
error "Failed to get [GITHUB_REPOSITORY]!" error "Failed to get [GITHUB_REPOSITORY]!"
fatal "[${GITHUB_REPOSITORY}]" fatal "[${GITHUB_REPOSITORY}]"
else else
info "Successfully found:${F[W]}[GITHUB_REPOSITORY]${F[B]}, value:${F[W]}[${GITHUB_REPOSITORY}]" info "Successfully found GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}"
fi fi
if [ -z "${GITHUB_RUN_ID}" ]; then if [ -z "${GITHUB_RUN_ID}" ]; then
error "Failed to get [GITHUB_RUN_ID]!" error "Failed to get [GITHUB_RUN_ID]!"
fatal "[${GITHUB_RUN_ID}]" fatal "[${GITHUB_RUN_ID}]"
else else
info "Successfully found:${F[W]}[GITHUB_RUN_ID]${F[B]}, value:${F[W]}[${GITHUB_RUN_ID}]" info "Successfully found GITHUB_RUN_ID ${GITHUB_RUN_ID}"
fi fi
else else
debug "Skip GITHUB_TOKEN, GITHUB_REPOSITORY, and GITHUB_RUN_ID validation because we don't need these variables for GitHub Actions status reports. MULTI_STATUS: ${MULTI_STATUS}" debug "Skip GITHUB_TOKEN, GITHUB_REPOSITORY, and GITHUB_RUN_ID validation because we don't need these variables for GitHub Actions status reports. MULTI_STATUS: ${MULTI_STATUS}"
@ -719,7 +719,7 @@ Footer() {
################### ###################
# Print the goods # # Print the goods #
################### ###################
error "ERRORS FOUND${NC} in ${LANGUAGE}:[${!ERROR_COUNTER}]" error "ERRORS FOUND in ${LANGUAGE}:[${!ERROR_COUNTER}]"
######################################### #########################################
# Create status API for Failed language # # Create status API for Failed language #
@ -780,22 +780,22 @@ UpdateLoopsForImage() {
"RUST_2021" "RUST_CLIPPY") "RUST_2021" "RUST_CLIPPY")
# Remove from LANGUAGE_ARRAY # Remove from LANGUAGE_ARRAY
echo "Removing Languages from LANGUAGE_ARRAY for slim image..." debug "Removing Languages from LANGUAGE_ARRAY for slim image..."
for REMOVE_LANGUAGE in "${REMOVE_ARRAY[@]}"; do for REMOVE_LANGUAGE in "${REMOVE_ARRAY[@]}"; do
for INDEX in "${!LANGUAGE_ARRAY[@]}"; do for INDEX in "${!LANGUAGE_ARRAY[@]}"; do
if [[ ${LANGUAGE_ARRAY[INDEX]} = "${REMOVE_LANGUAGE}" ]]; then if [[ ${LANGUAGE_ARRAY[INDEX]} = "${REMOVE_LANGUAGE}" ]]; then
echo "found item:[${REMOVE_LANGUAGE}], removing Language..." debug "found item:[${REMOVE_LANGUAGE}], removing Language..."
unset 'LANGUAGE_ARRAY[INDEX]' unset 'LANGUAGE_ARRAY[INDEX]'
fi fi
done done
done done
# Remove from LINTER_NAMES_ARRAY # Remove from LINTER_NAMES_ARRAY
echo "Removing Linters from LINTER_NAMES_ARRAY for slim image..." debug "Removing Linters from LINTER_NAMES_ARRAY for slim image..."
for REMOVE_LINTER in "${REMOVE_ARRAY[@]}"; do for REMOVE_LINTER in "${REMOVE_ARRAY[@]}"; do
for INDEX in "${!LINTER_NAMES_ARRAY[@]}"; do for INDEX in "${!LINTER_NAMES_ARRAY[@]}"; do
if [[ ${INDEX} = "${REMOVE_LINTER}" ]]; then if [[ ${INDEX} = "${REMOVE_LINTER}" ]]; then
echo "found item:[${REMOVE_LINTER}], removing linter..." debug "found item:[${REMOVE_LINTER}], removing linter..."
unset 'LINTER_NAMES_ARRAY[$INDEX]' unset 'LINTER_NAMES_ARRAY[$INDEX]'
fi fi
done done