diff --git a/hooks/_common.sh b/hooks/_common.sh index 386f3ae07..0e9454458 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -51,7 +51,22 @@ function common::parse_cmdline { case $argv in -a | --args) shift - ARGS+=("$1") + # `argv` is an string from array with content like: + # ('provider aws' '--version "> 0.14"' '--ignore-path "some/path"') + # where each element is the value of each `--args` from hook config. + # `echo` prints contents of `argv` as an expanded string + # `xargs` passes expanded string to `printf` + # `printf` which splits it into NUL-separated elements, + # NUL-separated elements read by `read` using empty separator + # (`-d ''` or `-d $'\0'`) + # into an `ARGS` array + + # This allows to "rebuild" initial `args` array of sort of grouped elements + # into a proper array, where each element is a standalone array slice + # with quoted elements being treated as a standalone slice of array as well. + while read -r -d '' ARG; do + ARGS+=("$ARG") + done < <(echo "$1" | xargs printf '%s\0') shift ;; -h | --hook-config) @@ -129,7 +144,7 @@ function common::parse_and_export_env_vars { ####################################################################### function common::is_hook_run_on_whole_repo { local -r hook_id="$1" - shift 1 + shift local -a -r files=("$@") # get directory containing `.pre-commit-hooks.yaml` file local -r root_config_dir="$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)")" @@ -163,21 +178,31 @@ function common::is_hook_run_on_whole_repo { # 2.1. If at least 1 check failed - change exit code to non-zero # 3. Complete hook execution and return exit code # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # hook_id (string) hook ID, see `- id` for details in .pre-commit-hooks.yaml file +# args_array_length (integer) Count of arguments in args array. +# args (array) arguments that configure wrapped tool behavior # files (array) filenames to check ####################################################################### function common::per_dir_hook { - local -r args="$1" - local -r hook_id="$2" + local -r hook_id="$1" + local -i args_array_length=$2 shift 2 + local -a args=() + # Expand args to a true array. + # Based on https://stackoverflow.com/a/10953834 + while ((args_array_length-- > 0)); do + args+=("$1") + shift + done + # assign rest of function's positional ARGS into `files` array, + # despite there's only one positional ARG left local -a -r files=("$@") # check is (optional) function defined if [ "$(type -t run_hook_on_whole_repo)" == function ] && # check is hook run via `pre-commit run --all` common::is_hook_run_on_whole_repo "$hook_id" "${files[@]}"; then - run_hook_on_whole_repo "$args" + run_hook_on_whole_repo "${args[@]}" exit 0 fi @@ -203,7 +228,7 @@ function common::per_dir_hook { dir_path="${dir_path//__REPLACED__SPACE__/ }" pushd "$dir_path" > /dev/null || continue - per_dir_hook_unique_part "$args" "$dir_path" + per_dir_hook_unique_part "$dir_path" "${args[@]}" local exit_code=$? if [ $exit_code -ne 0 ]; then diff --git a/hooks/terraform_checkov.sh b/hooks/terraform_checkov.sh index f64a2644b..fe0de0017 100755 --- a/hooks/terraform_checkov.sh +++ b/hooks/terraform_checkov.sh @@ -13,34 +13,35 @@ function main { common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars # Support for setting PATH to repo root. - # shellcheck disable=SC2178 # It's the simplest syntax for that case - ARGS=${ARGS[*]/__GIT_WORKING_DIR__/$(pwd)\/} + for i in "${!ARGS[@]}"; do + ARGS[i]=${ARGS[i]/__GIT_WORKING_DIR__/$(pwd)\/} + done + # Suppress checkov color if [ "$PRE_COMMIT_COLOR" = "never" ]; then export ANSI_COLORS_DISABLED=true fi - # shellcheck disable=SC2128 # It's the simplest syntax for that case - common::per_dir_hook "$ARGS" "$HOOK_ID" "${FILES[@]}" + + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - # common logic located in common::per_dir_hook - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - checkov -d . ${args[@]} + checkov -d . "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? @@ -51,14 +52,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - checkov -d "$(pwd)" ${args[@]} + checkov -d "$(pwd)" "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/terraform_docs.sh b/hooks/terraform_docs.sh index 2aac79551..c994208f7 100755 --- a/hooks/terraform_docs.sh +++ b/hooks/terraform_docs.sh @@ -13,11 +13,11 @@ function main { common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars # Support for setting relative PATH to .terraform-docs.yml config. - # shellcheck disable=SC2178 # It's the simplest syntax for that case - ARGS=${ARGS[*]/--config=/--config=$(pwd)\/} - # shellcheck disable=SC2128 # It's the simplest syntax for that case + for i in "${!ARGS[@]}"; do + ARGS[i]=${ARGS[i]/--config=/--config=$(pwd)\/} + done # shellcheck disable=SC2153 # False positive - terraform_docs_ "${HOOK_CONFIG[*]}" "$ARGS" "${FILES[@]}" + terraform_docs_ "${HOOK_CONFIG[*]}" "${ARGS[*]}" "${FILES[@]}" } ####################################################################### @@ -91,7 +91,7 @@ function terraform_docs { shift 3 local -a -r files=("$@") - declare -a paths + local -a paths local index=0 local file_with_path diff --git a/hooks/terraform_fmt.sh b/hooks/terraform_fmt.sh index 1011357dc..73e3a3f1e 100755 --- a/hooks/terraform_fmt.sh +++ b/hooks/terraform_fmt.sh @@ -19,27 +19,27 @@ function main { fi # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terraform fmt ${args[@]} + terraform fmt "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/terraform_providers_lock.sh b/hooks/terraform_providers_lock.sh index 3036cae23..a75a7e536 100755 --- a/hooks/terraform_providers_lock.sh +++ b/hooks/terraform_providers_lock.sh @@ -16,22 +16,23 @@ function main { # JFYI: suppress color for `terraform providers lock` is N/A` # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") local exit_code @@ -41,8 +42,7 @@ function per_dir_hook_unique_part { } # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terraform providers lock ${args[@]} + terraform providers lock "${args[@]}" # return exit code to common::per_dir_hook exit_code=$? diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index ae53ce1a2..d3e4646d4 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -14,8 +14,9 @@ function main { common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars # Support for setting PATH to repo root. - # shellcheck disable=SC2178 # It's the simplest syntax for that case - ARGS=${ARGS[*]/__GIT_WORKING_DIR__/$(pwd)\/} + for i in "${!ARGS[@]}"; do + ARGS[i]=${ARGS[i]/__GIT_WORKING_DIR__/$(pwd)\/} + done # JFYI: tflint color already suppressed via PRE_COMMIT_COLOR=never # Run `tflint --init` for check that plugins installed. @@ -30,31 +31,31 @@ function main { echo "${TFLINT_INIT}" return ${exit_code} } - # shellcheck disable=SC2128 # It's the simplest syntax for that case - common::per_dir_hook "$ARGS" "$HOOK_ID" "${FILES[@]}" + + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # Print checked PATH **only** if TFLint have any messages # shellcheck disable=SC2091,SC2068 # Suppress error output $(tflint ${args[@]} 2>&1) 2> /dev/null || { common::colorify "yellow" "TFLint in $dir_path/:" - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - tflint ${args[@]} + tflint "${args[@]}" } # return exit code to common::per_dir_hook diff --git a/hooks/terraform_tfsec.sh b/hooks/terraform_tfsec.sh index 8864b8085..535116794 100755 --- a/hooks/terraform_tfsec.sh +++ b/hooks/terraform_tfsec.sh @@ -13,37 +13,36 @@ function main { common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars # Support for setting PATH to repo root. - # shellcheck disable=SC2178 # It's the simplest syntax for that case - ARGS=${ARGS[*]/__GIT_WORKING_DIR__/$(pwd)\/} + for i in "${!ARGS[@]}"; do + ARGS[i]=${ARGS[i]/__GIT_WORKING_DIR__/$(pwd)\/} + done # Suppress tfsec color if [ "$PRE_COMMIT_COLOR" = "never" ]; then - # shellcheck disable=SC2178,SC2128 # It's the simplest syntax for that case - ARGS+=" --no-color" + ARGS+=("--no-color") fi - # shellcheck disable=SC2128 # It's the simplest syntax for that case - common::per_dir_hook "$ARGS" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - tfsec ${args[@]} + tfsec "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? @@ -54,14 +53,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - tfsec "$(pwd)" ${args[@]} + tfsec "$(pwd)" "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/terraform_validate.sh b/hooks/terraform_validate.sh index f99f32bcc..cd23a52a8 100755 --- a/hooks/terraform_validate.sh +++ b/hooks/terraform_validate.sh @@ -21,7 +21,7 @@ function main { ARGS+=("-no-color") fi # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### @@ -31,17 +31,16 @@ function main { # 2. Run `terraform validate` # 3. If at least 1 check failed - change the exit code to non-zero # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging -# ENV_VARS (array) environment variables that will be used with -# `terraform` commands +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") local exit_code local validate_output @@ -52,8 +51,7 @@ function per_dir_hook_unique_part { } # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - validate_output=$(terraform validate ${args[@]} 2>&1) + validate_output=$(terraform validate "${args[@]}" 2>&1) exit_code=$? if [ $exit_code -ne 0 ]; then diff --git a/hooks/terragrunt_fmt.sh b/hooks/terragrunt_fmt.sh index 18c9cd673..279e78d51 100755 --- a/hooks/terragrunt_fmt.sh +++ b/hooks/terragrunt_fmt.sh @@ -15,27 +15,27 @@ function main { # JFYI: terragrunt hclfmt color already suppressed via PRE_COMMIT_COLOR=never # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terragrunt hclfmt ${args[@]} + terragrunt hclfmt "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? @@ -46,14 +46,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terragrunt hclfmt "$(pwd)" ${args[@]} + terragrunt hclfmt "$(pwd)" "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/terragrunt_validate.sh b/hooks/terragrunt_validate.sh index 1588450ed..7d9e287db 100755 --- a/hooks/terragrunt_validate.sh +++ b/hooks/terragrunt_validate.sh @@ -15,27 +15,27 @@ function main { # JFYI: terragrunt validate color already suppressed via PRE_COMMIT_COLOR=never # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terragrunt validate ${args[@]} + terragrunt validate "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? @@ -46,14 +46,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terragrunt run-all validate ${args[@]} + terragrunt run-all validate "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/terrascan.sh b/hooks/terrascan.sh index d36095216..ad81aaba9 100755 --- a/hooks/terrascan.sh +++ b/hooks/terrascan.sh @@ -15,27 +15,27 @@ function main { # JFYI: terrascan color already suppressed via PRE_COMMIT_COLOR=never # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terrascan scan -i terraform ${args[@]} + terrascan scan -i terraform "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? @@ -46,14 +46,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - terrascan scan -i terraform ${args[@]} + terrascan scan -i terraform "${args[@]}" # return exit code to common::per_dir_hook local exit_code=$? diff --git a/hooks/tfupdate.sh b/hooks/tfupdate.sh index db3fc5b4e..ebfa7ce2d 100755 --- a/hooks/tfupdate.sh +++ b/hooks/tfupdate.sh @@ -14,27 +14,38 @@ function main { common::parse_and_export_env_vars # JFYI: suppress color for `tfupdate` is N/A` + # Prevent PASSED scenarios for things like: + # - --args=--version '~> 4.2.0' + # - --args=provider aws # shellcheck disable=SC2153 # False positive - common::per_dir_hook "${ARGS[*]}" "$HOOK_ID" "${FILES[@]}" + if ! [[ ${ARGS[0]} =~ ^[a-z] ]]; then + common::colorify 'red' "Check the hook args order in .pre-commit.config.yaml." + common::colorify 'red' "Current command looks like:" + common::colorify 'red' "tfupdate ${ARGS[*]}" + exit 1 + fi + + # shellcheck disable=SC2153 # False positive + common::per_dir_hook "$HOOK_ID" "${#ARGS[@]}" "${ARGS[@]}" "${FILES[@]}" } ####################################################################### # Unique part of `common::per_dir_hook`. The function is executed in loop # on each provided dir path. Run wrapped tool with specified arguments # Arguments: -# args (string with array) arguments that configure wrapped tool behavior # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { - local -r args="$1" # shellcheck disable=SC2034 # Unused var. - local -r dir_path="$2" + local -r dir_path="$1" + shift + local -a -r args=("$@") # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - tfupdate ${args[@]} . + tfupdate "${args[@]}" . # return exit code to common::per_dir_hook local exit_code=$? @@ -45,15 +56,13 @@ function per_dir_hook_unique_part { # Unique part of `common::per_dir_hook`. The function is executed one time # in the root git repo # Arguments: -# args (string with array) arguments that configure wrapped tool behavior +# args (array) arguments that configure wrapped tool behavior ####################################################################### function run_hook_on_whole_repo { - local -r args="$1" + local -a -r args=("$@") + # pass the arguments to hook - # shellcheck disable=SC2068 # hook fails when quoting is used ("$arg[@]") - # shellcheck disable=SC2048 # Use "${array[@]}" (with quotes) to prevent whitespace problems. - # shellcheck disable=SC2086 # Double quote to prevent globbing and word splitting. - tfupdate ${args[*]} --recursive . + tfupdate "${args[@]}" --recursive . # return exit code to common::per_dir_hook local exit_code=$?