Files
yaze/scripts/pre-push-test.sh
2025-11-21 21:35:50 -05:00

400 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Pre-Push Test Script for YAZE
# Runs fast validation checks before pushing to remote
# Catches 90% of CI failures in < 2 minutes
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# Configuration
BUILD_DIR="${BUILD_DIR:-$PROJECT_ROOT/build}"
PRESET="${PRESET:-}"
CONFIG_ONLY="${CONFIG_ONLY:-0}"
SMOKE_ONLY="${SMOKE_ONLY:-0}"
SKIP_SYMBOLS="${SKIP_SYMBOLS:-0}"
SKIP_TESTS="${SKIP_TESTS:-0}"
VERBOSE="${VERBOSE:-0}"
# Statistics
TOTAL_CHECKS=0
PASSED_CHECKS=0
FAILED_CHECKS=0
START_TIME=$(date +%s)
# Helper functions
print_header() {
echo -e "\n${BLUE}===${NC} $1 ${BLUE}===${NC}"
}
print_step() {
echo -e "${YELLOW}${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
((PASSED_CHECKS++))
}
print_error() {
echo -e "${RED}${NC} $1"
((FAILED_CHECKS++))
}
print_info() {
echo -e "${BLUE}${NC} $1"
}
check_command() {
if ! command -v "$1" &> /dev/null; then
print_error "$1 not found. Please install it."
return 1
fi
return 0
}
elapsed_time() {
local END_TIME=$(date +%s)
local ELAPSED=$((END_TIME - START_TIME))
echo "${ELAPSED}s"
}
# Parse arguments
usage() {
cat << EOF
Usage: $0 [OPTIONS]
Pre-push validation script that runs fast checks to catch CI failures early.
OPTIONS:
--preset NAME Use specific CMake preset (auto-detect if not specified)
--build-dir PATH Build directory (default: build)
--config-only Only validate CMake configuration
--smoke-only Only run smoke compilation test
--skip-symbols Skip symbol conflict checking
--skip-tests Skip running unit tests
--verbose Show detailed output
-h, --help Show this help message
EXAMPLES:
$0 # Run all checks with auto-detected preset
$0 --preset mac-dbg # Run all checks with specific preset
$0 --config-only # Only validate CMake configuration
$0 --smoke-only # Only compile representative files
$0 --skip-tests # Skip unit tests (faster)
TIME BUDGET:
Config validation: ~10 seconds
Smoke compilation: ~90 seconds
Symbol checking: ~30 seconds
Unit tests: ~30 seconds
─────────────────────────────
Total (all checks): ~2 minutes
WHAT THIS CATCHES:
✓ CMake configuration errors
✓ Missing include paths
✓ Header-only compilation issues
✓ Symbol conflicts (ODR violations)
✓ Unit test failures
✓ Platform-specific issues
EOF
exit 0
}
while [[ $# -gt 0 ]]; do
case $1 in
--preset)
PRESET="$2"
shift 2
;;
--build-dir)
BUILD_DIR="$2"
shift 2
;;
--config-only)
CONFIG_ONLY=1
shift
;;
--smoke-only)
SMOKE_ONLY=1
shift
;;
--skip-symbols)
SKIP_SYMBOLS=1
shift
;;
--skip-tests)
SKIP_TESTS=1
shift
;;
--verbose)
VERBOSE=1
shift
;;
-h|--help)
usage
;;
*)
print_error "Unknown option: $1"
usage
;;
esac
done
# Auto-detect preset if not specified
if [[ -z "$PRESET" ]]; then
if [[ "$OSTYPE" == "darwin"* ]]; then
PRESET="mac-dbg"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
PRESET="lin-dbg"
else
print_error "Unsupported platform: $OSTYPE"
print_info "Please specify --preset manually"
exit 1
fi
print_info "Auto-detected preset: $PRESET"
fi
cd "$PROJECT_ROOT"
print_header "YAZE Pre-Push Validation"
print_info "Preset: $PRESET"
print_info "Build directory: $BUILD_DIR"
print_info "Time budget: ~2 minutes"
echo ""
# ============================================================================
# LEVEL 0: Static Analysis
# ============================================================================
print_header "Level 0: Static Analysis"
((TOTAL_CHECKS++))
print_step "Checking code formatting..."
if [[ $VERBOSE -eq 1 ]]; then
if cmake --build "$BUILD_DIR" --target yaze-format-check 2>&1; then
print_success "Code formatting is correct"
else
print_error "Code formatting check failed"
print_info "Run: cmake --build $BUILD_DIR --target yaze-format"
exit 1
fi
else
if cmake --build "$BUILD_DIR" --target yaze-format-check > /dev/null 2>&1; then
print_success "Code formatting is correct"
else
print_error "Code formatting check failed"
print_info "Run: cmake --build $BUILD_DIR --target yaze-format"
exit 1
fi
fi
# Skip remaining checks if config-only
if [[ $CONFIG_ONLY -eq 1 ]]; then
print_header "Summary (Config Only)"
print_info "Time elapsed: $(elapsed_time)"
print_info "Total checks: $TOTAL_CHECKS"
print_info "Passed: ${GREEN}$PASSED_CHECKS${NC}"
print_info "Failed: ${RED}$FAILED_CHECKS${NC}"
exit 0
fi
# ============================================================================
# LEVEL 1: Configuration Validation
# ============================================================================
print_header "Level 1: Configuration Validation"
((TOTAL_CHECKS++))
print_step "Validating CMake preset: $PRESET"
if cmake --preset "$PRESET" -DCMAKE_VERBOSE_MAKEFILE=OFF > /dev/null 2>&1; then
print_success "CMake configuration successful"
else
print_error "CMake configuration failed"
print_info "Run: cmake --preset $PRESET (with verbose output)"
exit 1
fi
# Check for include path issues
((TOTAL_CHECKS++))
print_step "Checking include path propagation..."
if [[ $VERBOSE -eq 1 ]]; then
if grep -q "INCLUDE_DIRECTORIES" "$BUILD_DIR/CMakeCache.txt"; then
print_success "Include paths configured"
else
print_error "Include paths not properly configured"
exit 1
fi
else
if grep -q "INCLUDE_DIRECTORIES" "$BUILD_DIR/CMakeCache.txt" 2>/dev/null; then
print_success "Include paths configured"
else
print_error "Include paths not properly configured"
exit 1
fi
fi
# ============================================================================
# LEVEL 2: Smoke Compilation
# ============================================================================
if [[ $SMOKE_ONLY -eq 0 ]]; then
print_header "Level 2: Smoke Compilation"
((TOTAL_CHECKS++))
print_step "Compiling representative files..."
print_info "This validates headers, includes, and preprocessor directives"
# List of representative files (one per major library)
SMOKE_FILES=(
"src/app/rom.cc"
"src/app/gfx/bitmap.cc"
"src/zelda3/overworld/overworld.cc"
"src/cli/service/resources/resource_catalog.cc"
)
SMOKE_FAILED=0
for file in "${SMOKE_FILES[@]}"; do
if [[ ! -f "$PROJECT_ROOT/$file" ]]; then
print_info "Skipping $file (not found)"
continue
fi
# Get object file path
OBJ_FILE="$BUILD_DIR/$(echo "$file" | sed 's/src\///' | sed 's/\.cc$/.cc.o/')"
if [[ $VERBOSE -eq 1 ]]; then
print_step " Compiling $file"
if cmake --build "$BUILD_DIR" --target "$(basename "$OBJ_FILE")" 2>&1; then
print_success "$file"
else
print_error "$file"
SMOKE_FAILED=1
fi
else
if cmake --build "$BUILD_DIR" --target "$(basename "$OBJ_FILE")" > /dev/null 2>&1; then
print_success "$file"
else
print_error "$file (run with --verbose for details)"
SMOKE_FAILED=1
fi
fi
done
if [[ $SMOKE_FAILED -eq 0 ]]; then
print_success "Smoke compilation successful"
else
print_error "Smoke compilation failed"
print_info "Run: cmake --build $BUILD_DIR -v (for verbose output)"
exit 1
fi
fi
# ============================================================================
# LEVEL 3: Symbol Validation
# ============================================================================
if [[ $SKIP_SYMBOLS -eq 0 ]]; then
print_header "Level 3: Symbol Validation"
((TOTAL_CHECKS++))
print_step "Checking for symbol conflicts..."
print_info "This detects ODR violations and duplicate symbols"
if [[ -x "$SCRIPT_DIR/verify-symbols.sh" ]]; then
if [[ $VERBOSE -eq 1 ]]; then
if "$SCRIPT_DIR/verify-symbols.sh" --build-dir "$BUILD_DIR"; then
print_success "No symbol conflicts detected"
else
print_error "Symbol conflicts detected"
exit 1
fi
else
if "$SCRIPT_DIR/verify-symbols.sh" --build-dir "$BUILD_DIR" > /dev/null 2>&1; then
print_success "No symbol conflicts detected"
else
print_error "Symbol conflicts detected"
print_info "Run: ./scripts/verify-symbols.sh --build-dir $BUILD_DIR"
exit 1
fi
fi
else
print_info "Symbol checker not found (skipping)"
print_info "Create: scripts/verify-symbols.sh"
fi
fi
# ============================================================================
# LEVEL 4: Unit Tests
# ============================================================================
if [[ $SKIP_TESTS -eq 0 ]]; then
print_header "Level 4: Unit Tests"
((TOTAL_CHECKS++))
print_step "Running unit tests..."
print_info "This validates component logic"
TEST_BINARY="$BUILD_DIR/bin/yaze_test"
if [[ ! -x "$TEST_BINARY" ]]; then
print_info "Test binary not found, building..."
if cmake --build "$BUILD_DIR" --target yaze_test > /dev/null 2>&1; then
print_success "Test binary built"
else
print_error "Failed to build test binary"
exit 1
fi
fi
if [[ $VERBOSE -eq 1 ]]; then
if "$TEST_BINARY" --unit 2>&1; then
print_success "All unit tests passed"
else
print_error "Unit tests failed"
exit 1
fi
else
if "$TEST_BINARY" --unit > /dev/null 2>&1; then
print_success "All unit tests passed"
else
print_error "Unit tests failed"
print_info "Run: $TEST_BINARY --unit (for detailed output)"
exit 1
fi
fi
fi
# ============================================================================
# Summary
# ============================================================================
print_header "Summary"
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
print_info "Time elapsed: ${ELAPSED}s"
print_info "Total checks: $TOTAL_CHECKS"
print_info "Passed: ${GREEN}$PASSED_CHECKS${NC}"
print_info "Failed: ${RED}$FAILED_CHECKS${NC}"
if [[ $FAILED_CHECKS -eq 0 ]]; then
echo ""
print_success "All checks passed! Safe to push."
exit 0
else
echo ""
print_error "Some checks failed. Please fix before pushing."
exit 1
fi