#!/bin/bash # CI-specific validation script for Foxhunt # This script mimics the CI environment validation for local testing set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" print_header() { echo -e "${PURPLE}╔═══════════════════════════════════════════════╗${NC}" echo -e "${PURPLE}║ 🦊 Foxhunt CI Validation Simulation ║${NC}" echo -e "${PURPLE}║ Test CI Pipeline Locally ║${NC}" echo -e "${PURPLE}╚═══════════════════════════════════════════════╝${NC}" echo } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_info() { echo -e "${BLUE}ℹ️ $1${NC}" } print_section() { echo echo -e "${PURPLE}📋 $1${NC}" echo -e "${PURPLE}$(echo "$1" | sed 's/./─/g')${NC}" } # Simulate CI environment setup setup_ci_environment() { print_section "Setting Up CI-like Environment" cd "$PROJECT_ROOT" # Set CI environment variables export CARGO_TERM_COLOR=always export RUST_BACKTRACE=1 export CARGO_INCREMENTAL=0 export CARGO_NET_RETRY=10 export RUSTUP_MAX_RETRIES=10 print_info "Environment variables set for CI simulation" # Clean everything first (like CI does) print_info "Cleaning workspace (simulating fresh CI environment)..." cargo clean # Check Rust toolchain local rust_version=$(rustc --version) print_info "Rust toolchain: $rust_version" # Check system dependencies check_system_dependencies print_success "CI environment setup complete" } # Check system dependencies like CI does check_system_dependencies() { print_info "Checking system dependencies..." local missing_deps=() # Check for required tools if ! command -v pkg-config &> /dev/null; then missing_deps+=("pkg-config") fi if ! command -v protoc &> /dev/null; then missing_deps+=("protobuf-compiler") fi # Check for required libraries if ! pkg-config --exists openssl; then missing_deps+=("libssl-dev") fi if ! pkg-config --exists libpq; then missing_deps+=("libpq-dev") fi if [[ ${#missing_deps[@]} -gt 0 ]]; then print_warning "Missing system dependencies: ${missing_deps[*]}" print_info "Install with: sudo apt-get install ${missing_deps[*]}" return 1 fi print_success "All system dependencies available" return 0 } # Run the full validation suite like CI run_ci_validation() { print_section "Running Full CI Validation" cd "$PROJECT_ROOT" local start_time=$(date +%s) local validation_modes=("libs" "bins" "tests" "examples") local failed_modes=() # Add Docker if available if command -v docker &> /dev/null && docker info &> /dev/null; then validation_modes+=("docker") print_info "Docker available - including Docker validation" else print_warning "Docker not available - skipping Docker validation" fi # Run each validation mode separately (like CI matrix) for mode in "${validation_modes[@]}"; do print_section "Validating: $mode" local mode_start=$(date +%s) if ./scripts/validate-local.sh "$mode" --format json --output "reports/ci-${mode}-report.json"; then local mode_end=$(date +%s) local mode_duration=$((mode_end - mode_start)) print_success "Mode '$mode' completed successfully in ${mode_duration}s" else local mode_end=$(date +%s) local mode_duration=$((mode_end - mode_start)) print_error "Mode '$mode' failed after ${mode_duration}s" failed_modes+=("$mode") fi done local end_time=$(date +%s) local total_duration=$((end_time - start_time)) # Generate summary report generate_ci_summary_report "${failed_modes[@]}" "$total_duration" if [[ ${#failed_modes[@]} -eq 0 ]]; then print_success "All CI validation modes passed in ${total_duration}s" return 0 else print_error "CI validation failed. Failed modes: ${failed_modes[*]}" return 1 fi } # Generate a summary report like CI does generate_ci_summary_report() { local failed_modes=("$@") local total_duration="${!#}" # Last argument local failed_count=$((${#failed_modes[@]})) if [[ $failed_count -gt 0 ]]; then # Remove last argument (duration) from failed_modes array unset failed_modes[$((${#failed_modes[@]}-1))] fi print_section "CI Validation Summary" echo "📊 **Overall Results**" echo "- Total Duration: ${total_duration}s" echo "- Validation Modes: libs, bins, tests, examples, docker" if [[ $failed_count -eq 0 ]]; then echo "- Status: ✅ ALL PASSED" echo "- Success Rate: 100%" else echo "- Status: ❌ FAILURES DETECTED" echo "- Failed Modes: ${failed_modes[*]}" echo "- Success Rate: $(( (5 - failed_count) * 100 / 5 ))%" fi echo echo "📁 **Reports Generated**" ls -la reports/ci-*-report.json 2>/dev/null || echo "No report files found" echo echo "🔍 **Next Steps**" if [[ $failed_count -eq 0 ]]; then echo "- All validations passed - ready for CI!" echo "- Consider running the actual GitHub Actions workflow" else echo "- Fix issues in failed modes: ${failed_modes[*]}" echo "- Check individual reports for detailed error information" echo "- Re-run validation after fixes" fi } # Test specific scenarios that might fail in CI test_ci_scenarios() { print_section "Testing CI-specific Scenarios" cd "$PROJECT_ROOT" # Test with different feature combinations print_info "Testing workspace with all features enabled..." if ! cargo check --workspace --all-features --quiet; then print_error "Workspace check with all features failed" return 1 fi # Test with minimal features print_info "Testing workspace with no default features..." if ! cargo check --workspace --no-default-features --quiet; then print_warning "Some crates may require default features" fi # Test documentation builds (common CI failure) print_info "Testing documentation builds..." if ! cargo doc --workspace --no-deps --quiet; then print_error "Documentation build failed" return 1 fi # Test with different optimization levels print_info "Testing release builds..." if ! cargo build --workspace --release --quiet; then print_error "Release build failed" return 1 fi print_success "CI scenario testing completed" return 0 } # Usage information show_usage() { echo "Usage: $0 [OPTIONS]" echo echo "Options:" echo " -h, --help Show this help message" echo " --skip-deps-check Skip system dependencies check" echo " --skip-scenarios Skip CI scenario testing" echo " --quick Run quick validation only" echo echo "This script simulates the CI environment and validation process" echo "to help identify issues before they occur in the actual CI pipeline." } # Main execution main() { local skip_deps_check=false local skip_scenarios=false local quick_mode=false # Parse arguments while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_usage exit 0 ;; --skip-deps-check) skip_deps_check=true shift ;; --skip-scenarios) skip_scenarios=true shift ;; --quick) quick_mode=true shift ;; *) print_error "Unknown option: $1" show_usage exit 1 ;; esac done print_header # Create reports directory mkdir -p "$PROJECT_ROOT/reports" # Setup CI environment setup_ci_environment # Check dependencies unless skipped if [[ "$skip_deps_check" == "false" ]] && ! check_system_dependencies; then print_error "System dependencies check failed" exit 1 fi # Run appropriate validation if [[ "$quick_mode" == "true" ]]; then print_section "Quick CI Validation" if ./scripts/validate-local.sh all --jobs 4 --timeout 180; then print_success "Quick CI validation passed" else print_error "Quick CI validation failed" exit 1 fi else if ! run_ci_validation; then exit 1 fi # Run CI scenario tests unless skipped if [[ "$skip_scenarios" == "false" ]] && ! test_ci_scenarios; then print_error "CI scenario testing failed" exit 1 fi fi print_success "CI validation simulation completed successfully!" print_info "Your code should pass the actual CI pipeline" } main "$@"