diff --git a/scripts/validate_tabs.sh b/scripts/validate_tabs.sh index d137398..2707330 100644 --- a/scripts/validate_tabs.sh +++ b/scripts/validate_tabs.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# +# ============================================================================ # Copyright (C) 2025 Moko Consulting # # This file is part of a Moko Consulting project. @@ -21,45 +21,68 @@ # # FILE INFORMATION # DEFGROUP: MokoStandards -# INGROUP: Scripts.Validation +# INGROUP: GitHub.Actions.CI # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /scripts/validate_tabs.sh -# VERSION: 03.06.00 -# BRIEF: Detect tab characters in repository files for CI enforcement. -# +# VERSION: 01.00.00 +# BRIEF: CI validator that blocks tab characters in YAML files and enforces two-space indentation policy. +# NOTE: YAML is indentation sensitive; tabs are noncompliant. This validator fails the job when any tab is detected. +# ============================================================================ set -euo pipefail -ROOT_DIR="$(git rev-parse --show-toplevel)" -EXIT_CODE=0 +log() { + printf '%s\n' "$*" +} -echo "Scanning repository for tab characters" +fail=0 -# Exclude common binary and vendor paths -EXCLUDES=( - ".git" - "node_modules" - "vendor" - "dist" - "build" -) +log "[validate_tabs] Scope: *.yml, *.yaml" +log "[validate_tabs] Policy: tab characters are noncompliant; replace with two spaces" -EXCLUDE_ARGS=() -for path in "${EXCLUDES[@]}"; do - EXCLUDE_ARGS+=("--exclude-dir=${path}") -done - -# Search for literal tab characters -MATCHES=$(grep -RIn $'\t' "${ROOT_DIR}" "${EXCLUDE_ARGS[@]}" || true) - -if [ -n "${MATCHES}" ]; then - echo "Tab characters detected in the following files:" - echo "${MATCHES}" - echo "" - echo "CI policy violation: tabs are not permitted" - EXIT_CODE=1 +# Find YAML files tracked in git first. If not in a git repo, fall back to filesystem search. +yaml_files="" +if command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + yaml_files="$(git ls-files '*.yml' '*.yaml' 2>/dev/null || true)" else - echo "No tab characters found" + yaml_files="$(find . -type f \( -name '*.yml' -o -name '*.yaml' \) -print 2>/dev/null || true)" fi -exit "${EXIT_CODE}" +if [ -z "${yaml_files}" ]; then + log "[validate_tabs] No YAML files found. Status: PASS" + exit 0 +fi + +log "[validate_tabs] YAML files discovered: $(printf '%s\n' "${yaml_files}" | wc -l | tr -d ' ')" + +while IFS= read -r f; do + [ -n "$f" ] || continue + + # Skip deleted paths in edge cases + [ -f "$f" ] || continue + + # Detect literal tab characters and report with line numbers. + if LC_ALL=C grep -n $'\t' -- "$f" >/dev/null 2>&1; then + log "[validate_tabs] FAIL: tab detected in: $f" + + # Emit an actionable audit trail: line number plus the exact line content. + # Use sed to avoid grep prefix repetition and keep the output deterministic. + LC_ALL=C grep -n $'\t' -- "$f" | while IFS= read -r hit; do + log " ${hit}" + done + + log "[validate_tabs] Remediation: replace each tab with exactly two spaces" + log "[validate_tabs] Example: sed -i 's/\\t/ /g' \"$f\"" + + fail=1 + else + log "[validate_tabs] PASS: $f" + fi +done <<< "${yaml_files}" + +if [ "$fail" -ne 0 ]; then + log "[validate_tabs] Status: FAIL" + exit 1 +fi + +log "[validate_tabs] Status: PASS"