Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions check-tofu/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,34 @@ inputs:
description: Enable syntax validation with tofu validate
required: false
default: 'true'
scalr-token:
description: Token for authenticating with Scalr (required for remote modules)
required: false
scalr-hostname:
description: Scalr hostname
required: false
default: 'mbta.scalr.io'
tf-plugin-cache-dir:
description: Directory for Tofu plugin cache
required: false
default: '/tmp/.terraform-cache'

runs:
using: composite
steps:
- name: Run Tofu checks
shell: bash
env:
# Pass inputs to environment variables for the script
CHECK_SYNTAX: ${{ inputs.check-syntax }}
SCALR_TOKEN: ${{ inputs.scalr-token }}
SCALR_HOSTNAME: ${{ inputs.scalr-hostname }}
TF_PLUGIN_CACHE_DIR: ${{ inputs.tf-plugin-cache-dir }}
run: |
if [ -n "${{ inputs.directories }}" ]; then
# Split comma-separated string into array
IFS=',' read -ra DIRS <<< "${{ inputs.directories }}"
${{ github.action_path }}/check-tofu.sh "${DIRS[@]}"
"${{ github.action_path }}/check-tofu.sh" "${DIRS[@]}"
else
${{ github.action_path }}/check-tofu.sh
"${{ github.action_path }}/check-tofu.sh"
fi
109 changes: 76 additions & 33 deletions check-tofu/check-tofu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,68 @@

# Confirm that Tofu configuration is valid and properly formatted.
# If arguments are passed, they are assumed to be paths to modules to be
# checked. Otherwise all root and child modules are checked. In the latter
# checked. Otherwise all root modules are checked. In the latter
# case it is assumed that this script is being run from the root of the repo.
# Validation checks can be skipped by setting CHECK_SYNTAX=false.
# This script handles environment setup (Scalr credentials, Cache dirs)
# before running validation checks.

# global var to enable/disable syntax checks with `tofu validate`
# Global Defaults
CHECK_SYNTAX="${CHECK_SYNTAX:-true}"
TF_PLUGIN_CACHE_DIR="${TF_PLUGIN_CACHE_DIR:-/tmp/.terraform-cache}"
SCALR_HOSTNAME="${SCALR_HOSTNAME:-mbta.scalr.io}"

# tofu must be installed
echo -n "Checking for tofu binary... "
if ! which tofu; then
>&2 echo "No tofu binary could be found"
exit 1
fi
function setup_environment() {
echo "Configuring Environment..."

# Setup Scalr Credentials
if [[ -n "$SCALR_TOKEN" ]]; then
echo "Configuring Scalr credentials for $SCALR_HOSTNAME..."
cat <<EOF > "$HOME/.terraformrc"
credentials "$SCALR_HOSTNAME" {
token = "$SCALR_TOKEN"
}
EOF
else
echo "WARNING: SCALR_TOKEN not set. Remote module downloads may fail."
fi

# Setup Cache Directory
echo "Creating Tofu plugin cache directory at $TF_PLUGIN_CACHE_DIR"
mkdir -p "$TF_PLUGIN_CACHE_DIR"
export TF_PLUGIN_CACHE_DIR="$TF_PLUGIN_CACHE_DIR"
}

function check_binary() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: can you say more about the situation where this is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagined this as a replacement for the asdf cache step in the checks workflow. Instead of hitting the cache, it'll just check if a version of tofu is installed and, if not, use asdf to install

echo -n "Checking for tofu binary... "
if ! command -v tofu &> /dev/null; then
echo "No tofu binary found."
# Attempt to use ASDF if present (replaces explicit ASDF steps if run locally/CI)
if [ -f ".tool-versions" ] && command -v asdf &> /dev/null; then
echo "Attempting to install via asdf..."
asdf install tofu
asdf reshim
else
>&2 echo "Error: Tofu not found and cannot be installed automatically."
exit 1
fi
else
echo "Found $(tofu --version)"
fi
}

function check_syntax() {
# initialize the module, run `tofu validate`, and exit nonzero if errors are discovered
echo "Checking syntax..."
tofu init -backend=false
# initialize the module, run `tofu validate`
# We use -backend=false to avoid remote state locking during checks
tofu init -backend=false > /dev/null
if ! tofu validate; then
>&2 echo "tofu configuration is not valid."
exit 1
fi
}

function check_format() {
# run `tofu fmt` and exit nonzero if errors are discovered
echo "Checking formatting..."
if ! tofu fmt -check; then
>&2 echo "Tofu format is unclean. Run 'tofu fmt' and push the changes."
Expand All @@ -37,13 +73,10 @@ function check_format() {
}

function get_terraform_root_modules() {
# generate a list of all root modules in this repo
# this function assumes the script is being run at the root of the repo
if [ ! -d "terraform" ]; then
>&2 echo "Error: This script must be run from the root of the repo when run with no arguments."
>&2 echo "Error: This script must be run from the root of the repo."
exit 1
fi
# list all root modules (omitting 'modules' directory)
for dir in terraform/*/; do
if [ "$dir" != "terraform/modules/" ]; then
echo "$dir"
Expand All @@ -52,44 +85,54 @@ function get_terraform_root_modules() {
}

function run_module_checks() {
# given a directory, descend into that directory and run format and (optionally) syntax checks
local dir="$1"
local start_time
start_time=$(date +%s)

echo ""
echo "=========================================================="
echo "=== Checking ${1} ==="
echo "=== Checking ${dir} ==="
echo "=========================================================="
pushd "${1}" >/dev/null || return

pushd "${dir}" >/dev/null || return

if [ "${CHECK_SYNTAX}" == true ]; then
echo "Running syntax check for ${1}"
echo "Running syntax check for ${dir}"
check_syntax
echo "Finished syntax check for ${1}"
echo "Finished syntax check for ${dir}"
fi
echo "Running format check for ${1}"

echo "Running format check for ${dir}"
check_format
echo "Finished format check for ${1}"
echo "Finished format check for ${dir}"

echo ""
local end_time
end_time=$(date +%s)
total_time=$((end_time - start_time))
echo "Module check on ${1} took: $total_time seconds"
local total_time=$((end_time - start_time))
echo "Module check on ${dir} took: $total_time seconds"

popd >/dev/null || return
}

# get paths from arguments if passed, otherwise check all root and child modules
# --- Main Execution ---

setup_environment
check_binary

start_time=$(date +%s)

# Check if arguments provided (directories), otherwise check all
if [ "$#" -gt 0 ]; then
for tf_dir in "$@"; do
run_module_checks "${tf_dir}"
done
else
start_time=$(date +%s)
echo "Begin run_module_checks"

echo "No specific directories provided, scanning all root modules..."
while IFS='' read -r tf_dir; do
run_module_checks "${tf_dir}";
done < <(get_terraform_root_modules)

end_time=$(date +%s)
total_time=$((end_time - start_time))
echo "Module validation took: $total_time seconds"
fi

end_time=$(date +%s)
total_time=$((end_time - start_time))
echo "Total validation time: $total_time seconds"