#!/bin/bash # Formatting Validation Script # Checks code formatting and linting compliance set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # Function to check if a file is Python code is_python_file() { local file="$1" [[ "$file" == *.py ]] } # Function to check code formatting with black check_black_formatting() { echo -e "${BLUE}🎨 Checking code formatting with black...${NC}" if command -v black >/dev/null 2>&1; then if cd "$PROJECT_ROOT" && python -m black --check --diff src/ tests/ 2>/dev/null; then echo -e " ${GREEN}✅ Code formatting OK${NC}" return 0 else echo -e " ${RED}❌ Code formatting issues detected${NC}" echo -e " ${YELLOW} Run: uv run black src/ tests/ to fix${NC}" return 1 fi else echo -e " ${YELLOW}⚠️ black not available - skipping formatting check${NC}" echo -e " ${YELLOW} Install with: uv pip install black${NC}" return 0 # Not a failure, just unavailable fi } # Function to check code linting with ruff check_ruff_linting() { echo -e "${BLUE}🔍 Checking code linting with ruff...${NC}" if command -v ruff >/dev/null 2>&1; then if cd "$PROJECT_ROOT" && python -m ruff check src/ tests/ 2>/dev/null; then echo -e " ${GREEN}✅ Linting OK${NC}" return 0 else echo -e " ${RED}❌ Linting issues detected${NC}" echo -e " ${YELLOW} Run: uv run ruff check --fix src/ tests/ to fix${NC}" return 1 fi else echo -e " ${YELLOW}⚠️ ruff not available - skipping linting check${NC}" echo -e " ${YELLOW} Install with: uv pip install ruff${NC}" return 0 # Not a failure, just unavailable fi } # Function to check import organization check_import_organization() { echo -e "${BLUE}📦 Checking import organization...${NC}" local import_issues=0 while IFS= read -r -d '' file; do if is_python_file "$file"; then # Check for multiple import statements that could be combined local import_lines=$(grep -c "^import\|^from " "$file" 2>/dev/null || echo 0) local from_lines=$(grep -c "^from " "$file" 2>/dev/null || echo 0) if [[ $import_lines -gt 5 ]]; then echo -e " ${YELLOW}⚠️ Many import statements in $file ($import_lines) - consider organizing${NC}" import_issues=$((import_issues + 1)) fi # Check for unused imports (basic check) if [[ $from_lines -gt 0 ]]; then local unused_imports=0 while IFS= read -r import_line; do local module=$(echo "$import_line" | sed 's/^from \([^ ]*\) import.*/\1/') if [[ -n "$module" ]] && ! grep -q "$module\." "$file" 2>/dev/null; then if [[ $unused_imports -eq 0 ]]; then echo -e " ${YELLOW}⚠️ Potential unused imports in $file${NC}" fi unused_imports=$((unused_imports + 1)) import_issues=$((import_issues + 1)) fi done < <(grep "^from " "$file" 2>/dev/null) fi fi done < <(find "$PROJECT_ROOT/src" -name "*.py" -print0) if [[ $import_issues -eq 0 ]]; then echo -e " ${GREEN}✅ Import organization looks good${NC}" return 0 else echo -e " ${YELLOW}⚠️ $import_issues import organization issues found${NC}" return 0 # Warning, not error fi } # Function to check line length compliance check_line_length() { echo -e "${BLUE}📏 Checking line length compliance...${NC}" local long_lines=0 local max_length=100 # Black default while IFS= read -r -d '' file; do if is_python_file "$file"; then local file_long_lines=$(awk "length(\$0) > $max_length" "$file" 2>/dev/null | wc -l) if [[ $file_long_lines -gt 0 ]]; then echo -e " ${YELLOW}⚠️ $file_long_lines long lines in $file (max: $max_length chars)${NC}" long_lines=$((long_lines + file_long_lines)) fi fi done < <(find "$PROJECT_ROOT/src" -name "*.py" -print0) if [[ $long_lines -eq 0 ]]; then echo -e " ${GREEN}✅ All lines within length limits${NC}" return 0 else echo -e " ${YELLOW}⚠️ $long_lines long lines found - consider breaking them up${NC}" return 0 # Warning, not error fi } # Function to provide formatting improvement recommendations suggest_formatting_improvements() { echo -e "${BLUE}💡 Formatting Improvement Recommendations:${NC}" echo -e " ${YELLOW}• Use black for consistent code formatting${NC}" echo -e " ${YELLOW}• Use ruff for fast Python linting${NC}" echo -e " ${YELLOW}• Organize imports: standard library, third-party, local${NC}" echo -e " ${YELLOW}• Keep lines under 100 characters${NC}" echo -e " ${YELLOW}• Use consistent indentation (4 spaces)${NC}" echo -e " ${YELLOW}• Remove trailing whitespace${NC}" echo -e " ${YELLOW}• Use meaningful variable and function names${NC}" } # Main function main() { local exit_code=0 local formatting_issues=0 local linting_issues=0 echo -e "${BLUE}🎨 Formatting Validation for Project${NC}" echo -e "${BLUE}Focus: Code formatting, linting, and style compliance${NC}" echo "" # Check black formatting if ! check_black_formatting; then formatting_issues=$((formatting_issues + 1)) exit_code=1 fi echo "" # Check ruff linting if ! check_ruff_linting; then linting_issues=$((linting_issues + 1)) exit_code=1 fi echo "" # Check import organization check_import_organization echo "" # Check line length check_line_length echo "" # Provide improvement recommendations suggest_formatting_improvements echo "" # Summary echo -e "${BLUE}📋 Formatting Validation Summary:${NC}" if [[ $formatting_issues -eq 0 ]]; then echo -e " ${GREEN}✅ Code formatting: PASSED${NC}" else echo -e " ${RED}❌ Code formatting: FAILED${NC}" fi if [[ $linting_issues -eq 0 ]]; then echo -e " ${GREEN}✅ Code linting: PASSED${NC}" else echo -e " ${RED}❌ Code linting: FAILED${NC}" fi if [[ $exit_code -eq 0 ]]; then echo "" echo -e "${GREEN}🎉 All formatting checks passed!${NC}" echo -e "${GREEN}✅ Code meets formatting and style standards${NC}" else echo "" echo -e "${RED}🚫 Formatting validation failed - must be resolved before task completion${NC}" echo -e "${YELLOW} Fix all formatting issues before proceeding${NC}" fi echo "" echo -e "${BLUE}🔧 Quick Fix Commands:${NC}" echo -e " ${BLUE}• Format code:${NC} uv run black src/ tests/" echo -e " ${BLUE}• Fix linting:${NC} uv run ruff check --fix src/ tests/" echo -e " ${BLUE}• Re-validate:${NC} $0" exit $exit_code } # Run main function main "$@"