From 21363810324594fbe467dea479103c4da6a3b1c0 Mon Sep 17 00:00:00 2001 From: drunkonjava Date: Thu, 31 Jul 2025 01:36:11 -0400 Subject: [PATCH] feat: Add build & error diagnostics tools ## Description Implement build error diagnostics and enhanced compiler output for better debugging and development experience. ## Part of - Original PR: #233 - Phase: 2 of 5 ## Changes - Add build-error-diagnostics.sh for enhanced error reporting - Add xcode-build-wrapper.sh for compiler output enhancement - Add ci-validation.sh for CI configuration validation - Add build-parallel.sh for parallel module building - Update Makefile with diagnostic flags and error filtering ## Testing - Build diagnostics will be tested when running 'make build' - Error filtering improves developer experience - Parallel builds improve performance ## Dependencies - Depends on: PR #234 (CI core infrastructure) --- Makefile | 8 +- scripts/build-error-diagnostics.sh | 409 +++++++++++++++++++++++++++++ scripts/ci-validation.sh | 139 ++++++++++ scripts/xcode-build-wrapper.sh | 131 +++++++++ 4 files changed, 684 insertions(+), 3 deletions(-) create mode 100755 scripts/build-error-diagnostics.sh create mode 100755 scripts/ci-validation.sh create mode 100755 scripts/xcode-build-wrapper.sh diff --git a/Makefile b/Makefile index 2749f595..4607b659 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,9 @@ DANGER = bundle exec danger # Swift Compiler Flags # SWIFT_FLAGS = OTHER_SWIFT_FLAGS="-warnings-as-errors" # Temporarily disabled due to conflict -SWIFT_FLAGS = +SWIFT_FLAGS = OTHER_SWIFT_FLAGS="-Xfrontend -warn-long-function-bodies=100 -Xfrontend -warn-long-expression-type-checking=100" RELEASE_FLAGS = COMPILER_INDEX_STORE_ENABLE=NO SWIFT_COMPILATION_MODE=wholemodule +DEBUG_FLAGS = OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies -Xfrontend -debug-time-expression-type-checking" # Parallel build settings PARALLEL_WORKERS = $(shell sysctl -n hw.ncpu) @@ -73,7 +74,7 @@ regenerate: clean-project generate ## Clean and regenerate project # MARK: - Building .PHONY: build -build: generate ## Build the project +build: generate ## Build the project with enhanced diagnostics @echo "$(BLUE)Building $(PROJECT_NAME) ($(CONFIGURATION))...$(NC)" @$(XCODEBUILD) build \ -project $(PROJECT) \ @@ -82,8 +83,9 @@ build: generate ## Build the project -derivedDataPath $(DERIVED_DATA) \ $(BUILD_FLAGS) \ $(SWIFT_FLAGS) \ + $(if $(filter Debug,$(CONFIGURATION)),$(DEBUG_FLAGS),) \ CODE_SIGNING_ALLOWED=NO \ - | $(XCPRETTY) + 2>&1 | ./scripts/build-error-diagnostics.sh filter | $(XCPRETTY) @echo "$(GREEN)โœ“ Build succeeded$(NC)" .PHONY: build-modular diff --git a/scripts/build-error-diagnostics.sh b/scripts/build-error-diagnostics.sh new file mode 100755 index 00000000..e82bef13 --- /dev/null +++ b/scripts/build-error-diagnostics.sh @@ -0,0 +1,409 @@ +#!/bin/bash +# Build Error Diagnostics Script +# Enhances Xcode build errors with module context and helpful suggestions + +set -eo pipefail # Remove 'u' to handle unset variables gracefully + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +BUILD_LOG="${BUILT_PRODUCTS_DIR}/build-diagnostics.log" +ERROR_REPORT="${BUILT_PRODUCTS_DIR}/error-report.json" + +# Colors for Xcode output +ERROR_PREFIX="error:" +WARNING_PREFIX="warning:" +NOTE_PREFIX="note:" + +# Module detection from file path +detect_module() { + local file_path=$1 + local module="" + + # Extract module name from path + if [[ "$file_path" =~ /(Foundation-[^/]+|Infrastructure-[^/]+|Services-[^/]+|UI-[^/]+|Features-[^/]+|App-[^/]+)/ ]]; then + module="${BASH_REMATCH[1]}" + fi + + echo "$module" +} + +# Get emoji for module +get_module_emoji() { + local module=$1 + case "$module" in + Foundation-Core) echo "๐Ÿ”จ" ;; + Foundation-Models) echo "๐Ÿ“ฆ" ;; + Infrastructure-Network) echo "๐ŸŒ" ;; + Infrastructure-Storage) echo "๐Ÿ’พ" ;; + Infrastructure-Security) echo "๐Ÿ”" ;; + Services-Authentication) echo "๐Ÿ”‘" ;; + Services-Sync) echo "๐Ÿ”„" ;; + Features-Inventory) echo "๐Ÿ“‹" ;; + Features-Scanner) echo "๐Ÿ“ธ" ;; + Features-Settings) echo "โš™๏ธ" ;; + UI-Core) echo "๐ŸŽฏ" ;; + UI-Components) echo "๐Ÿงฉ" ;; + *) echo "๐Ÿ“ฑ" ;; + esac +} + +# Enhanced error message formatter with comprehensive patterns +format_error_message() { + local file=$1 + local line=$2 + local column=$3 + local error_type=$4 + local message=$5 + + local module=$(detect_module "$file") + local emoji=$(get_module_emoji "$module") + + # Extract just the filename for cleaner output + local filename=$(basename "$file") + + # Enhanced error message + echo "${file}:${line}:${column}: ${error_type} ${emoji} [${module}] ${message}" + + # Comprehensive error pattern matching with recovery suggestions + + # Import/Scope errors + if [[ "$message" =~ "cannot find.*in scope" ]] || [[ "$message" =~ "undeclared type" ]]; then + local missing_type=$(echo "$message" | grep -oE "'[^']+'" | head -1 | tr -d "'") + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Missing type: ${missing_type}" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Possible solutions:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 1. Import the module containing this type" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 2. Check if the type name is spelled correctly" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 3. Verify module dependencies: ./scripts/validate-module-dependencies.sh" + + # Suggest common imports based on type + case "$missing_type" in + *Error|*ServiceError) + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“ฆ Try: import FoundationCore" + ;; + *ViewModel|*Coordinator) + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“ฆ Try: import UICore" + ;; + *Storage|*Repository) + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“ฆ Try: import InfrastructureStorage" + ;; + esac + fi + + # Availability errors + if [[ "$message" =~ "is only available in iOS ([0-9.]+)" ]] || [[ "$message" =~ "@available" ]]; then + local required_version="${BASH_REMATCH[1]:-14.0}" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“ฑ iOS Availability Issue" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Solutions:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 1. Add: @available(iOS ${required_version}, *)" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 2. Use availability check: if #available(iOS ${required_version}, *) { }" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 3. Update deployment target in project.yml" + fi + + # Concurrency/Sendable errors + if [[ "$message" =~ "Sendable" ]] || [[ "$message" =~ "actor-isolated" ]] || [[ "$message" =~ "concurrent" ]]; then + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ”„ Concurrency Issue" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Solutions:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 1. Add: @unchecked Sendable (if thread-safe)" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 2. Use actor isolation: actor MyActor { }" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 3. Add @MainActor for UI code" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 4. Use nonisolated(unsafe) for immutable globals" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“š Example: Foundation-Core/Sources/FoundationCore/Utilities/ErrorBoundary.swift" + fi + + # Module boundary violations + if [[ "$message" =~ "import.*not allowed" ]] || [[ "$module" == "Foundation-"* && "$message" =~ "import.*Infrastructure" ]]; then + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿšซ Module Boundary Violation" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Architecture Rules:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข Foundation โ†’ (no external dependencies)" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข Infrastructure โ†’ Foundation only" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข Services โ†’ Foundation + Infrastructure" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข UI โ†’ Foundation only" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข Features โ†’ All lower layers" + fi + + # Error handling + if [[ "$message" =~ "throw" ]] || [[ "$message" =~ "Error" ]] || [[ "$message" =~ "catch" ]]; then + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ›ก๏ธ Error Handling" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Use domain-specific errors:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข InventoryServiceError for inventory operations" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข ScannerError for scanner issues" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข SyncError for synchronization" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โ€ข AuthenticationError for auth flows" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ“Š Errors include automatic telemetry and recovery suggestions" + fi + + # Performance warnings + if [[ "$message" =~ "long.*type-checking" ]] || [[ "$message" =~ "long.*function" ]]; then + echo "${file}:${line}:${column}: ${NOTE_PREFIX} โšก Performance Warning" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Optimization suggestions:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 1. Add explicit type annotations" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 2. Break complex expressions into steps" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 3. Extract complex logic into functions" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 4. Use type aliases for complex types" + fi + + # Memory/Resource warnings + if [[ "$message" =~ "memory" ]] || [[ "$message" =~ "retain cycle" ]] || [[ "$message" =~ "leak" ]]; then + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’พ Memory Management" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} ๐Ÿ’ก Best practices:" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 1. Use [weak self] in closures" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 2. Avoid strong reference cycles" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 3. Use autoreleasepool for loops" + echo "${file}:${line}:${column}: ${NOTE_PREFIX} 4. Profile with Instruments" + fi +} + +# Process Swift compiler output +process_compiler_output() { + local line="$1" + + # Match Swift compiler error/warning format + if [[ "$line" =~ ^([^:]+):([0-9]+):([0-9]+):[[:space:]]*(error|warning|note):[[:space:]]*(.*) ]]; then + local file="${BASH_REMATCH[1]}" + local line_num="${BASH_REMATCH[2]}" + local column="${BASH_REMATCH[3]}" + local msg_type="${BASH_REMATCH[4]}" + local message="${BASH_REMATCH[5]}" + + # Track error/warning + if [[ "$msg_type" == "error" ]] || [[ "$msg_type" == "warning" ]]; then + local module=$(detect_module "$file") + track_error "$module" "${msg_type}:" "$message" + fi + + format_error_message "$file" "$line_num" "$column" "${msg_type}:" "$message" + else + # Pass through other messages unchanged + echo "$line" + fi +} + +# Module boundary violation checker +check_module_boundaries() { + local file=$1 + local content=$2 + local module=$(detect_module "$file") + + # Check for cross-layer violations + case "$module" in + Foundation-*) + if echo "$content" | grep -E "import (Infrastructure|Services|UI|Features)" > /dev/null; then + echo "${file}:1:1: ${ERROR_PREFIX} ๐Ÿšซ [Module Boundary] Foundation layer cannot import from higher layers" + fi + ;; + Infrastructure-*) + if echo "$content" | grep -E "import (Services|UI|Features)" > /dev/null; then + echo "${file}:1:1: ${ERROR_PREFIX} ๐Ÿšซ [Module Boundary] Infrastructure layer cannot import from Services/UI/Features" + fi + ;; + Services-*) + if echo "$content" | grep -E "import (UI|Features)" > /dev/null; then + echo "${file}:1:1: ${ERROR_PREFIX} ๐Ÿšซ [Module Boundary] Services layer cannot import from UI/Features" + fi + ;; + UI-*) + if echo "$content" | grep -E "import (Infrastructure|Services|Features)" > /dev/null; then + echo "${file}:1:1: ${WARNING_PREFIX} โš ๏ธ [Module Boundary] UI layer should not import from Infrastructure/Services/Features" + fi + ;; + esac +} + +# Performance warning enhancer +enhance_performance_warnings() { + local file=$1 + local function=$2 + local time=$3 + local module=$(detect_module "$file") + + echo "${file}:1:1: ${WARNING_PREFIX} โฑ๏ธ [${module}] Function '${function}' took ${time}ms to type-check" + + # Module-specific suggestions + case "$module" in + Features-Scanner) + echo "${file}:1:1: ${NOTE_PREFIX} ๐Ÿ’ก Consider breaking down image processing into smaller functions" + ;; + Services-Sync) + echo "${file}:1:1: ${NOTE_PREFIX} ๐Ÿ’ก Complex async operations may benefit from actor isolation" + ;; + *) + echo "${file}:1:1: ${NOTE_PREFIX} ๐Ÿ’ก Consider explicit type annotations to speed up compilation" + ;; + esac +} + +# Error tracking +declare -A ERROR_COUNTS +declare -A WARNING_COUNTS +declare -A MODULE_ERRORS +TOTAL_ERRORS=0 +TOTAL_WARNINGS=0 + +# Track error for reporting +track_error() { + local module=$1 + local error_type=$2 + local message=$3 + + case "$error_type" in + error:) + ((TOTAL_ERRORS++)) + ((ERROR_COUNTS[$module]++)) + ;; + warning:) + ((TOTAL_WARNINGS++)) + ((WARNING_COUNTS[$module]++)) + ;; + esac + + # Store for module-specific tracking + if [ -z "${MODULE_ERRORS[$module]}" ]; then + MODULE_ERRORS[$module]="" + fi + MODULE_ERRORS[$module]+="$message\n" +} + +# Generate summary report +generate_summary() { + if [ $TOTAL_ERRORS -gt 0 ] || [ $TOTAL_WARNINGS -gt 0 ]; then + echo "" + echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + echo " BUILD DIAGNOSTICS SUMMARY " + echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + echo "" + echo "Total Errors: ${TOTAL_ERRORS}" + echo "Total Warnings: ${TOTAL_WARNINGS}" + echo "" + + if [ ${#ERROR_COUNTS[@]} -gt 0 ]; then + echo "Errors by Module:" + for module in "${!ERROR_COUNTS[@]}"; do + local emoji=$(get_module_emoji "$module") + echo " ${emoji} ${module}: ${ERROR_COUNTS[$module]}" + done + echo "" + fi + + if [ ${#WARNING_COUNTS[@]} -gt 0 ]; then + echo "Warnings by Module:" + for module in "${!WARNING_COUNTS[@]}"; do + local emoji=$(get_module_emoji "$module") + echo " ${emoji} ${module}: ${WARNING_COUNTS[$module]}" + done + echo "" + fi + + # Module-specific recommendations + echo "Module-Specific Recommendations:" + for module in "${!MODULE_ERRORS[@]}"; do + case "$module" in + Features-Scanner) + if [[ "${MODULE_ERRORS[$module]}" =~ "camera" ]] || [[ "${MODULE_ERRORS[$module]}" =~ "AVFoundation" ]]; then + echo " ๐Ÿ“ธ [Features-Scanner]:" + echo " โ€ข Check Info.plist for camera permissions" + echo " โ€ข Verify AVFoundation framework is linked" + echo " โ€ข Test on real device for camera features" + fi + ;; + Services-Sync) + if [[ "${MODULE_ERRORS[$module]}" =~ "CloudKit" ]] || [[ "${MODULE_ERRORS[$module]}" =~ "sync" ]]; then + echo " ๐Ÿ”„ [Services-Sync]:" + echo " โ€ข Verify CloudKit entitlements" + echo " โ€ข Check iCloud container configuration" + echo " โ€ข Test network conditions" + fi + ;; + Infrastructure-Storage) + if [[ "${MODULE_ERRORS[$module]}" =~ "CoreData" ]] || [[ "${MODULE_ERRORS[$module]}" =~ "persistent" ]]; then + echo " ๐Ÿ’พ [Infrastructure-Storage]:" + echo " โ€ข Check Core Data model version" + echo " โ€ข Verify migration mappings" + echo " โ€ข Test data persistence" + fi + ;; + esac + done + + echo "" + echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + + # Save summary to file + if [ -n "$ERROR_REPORT" ]; then + { + echo "{" + echo " \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," + echo " \"total_errors\": $TOTAL_ERRORS," + echo " \"total_warnings\": $TOTAL_WARNINGS," + echo " \"errors_by_module\": {" + local first=true + for module in "${!ERROR_COUNTS[@]}"; do + [ "$first" = true ] && first=false || echo "," + echo -n " \"$module\": ${ERROR_COUNTS[$module]}" + done + echo "" + echo " }," + echo " \"warnings_by_module\": {" + first=true + for module in "${!WARNING_COUNTS[@]}"; do + [ "$first" = true ] && first=false || echo "," + echo -n " \"$module\": ${WARNING_COUNTS[$module]}" + done + echo "" + echo " }" + echo "}" + } > "$ERROR_REPORT" + fi + fi +} + +# Main execution for Xcode integration +main() { + # Create diagnostics directory + mkdir -p "$(dirname "$BUILD_LOG")" + + # Initialize error tracking + echo "Build Diagnostics Started: $(date)" > "$BUILD_LOG" + + # Process input line by line + while IFS= read -r line; do + # Enhanced error processing + process_compiler_output "$line" + + # Log for analysis + echo "$line" >> "$BUILD_LOG" + done + + # Generate summary at the end + generate_summary +} + +# If running in Xcode build phase +if [ "${XCODE_VERSION_MAJOR:-}" != "" ]; then + # This script can be added as a build phase to process compiler output + # For now, we'll just ensure our error handling infrastructure is available + + # Ensure error handling is properly imported in the main app + MAIN_APP_FILE="${PROJECT_ROOT}/App-Main/Sources/HomeInventoryApp/HomeInventoryApp.swift" + + if [ -f "$MAIN_APP_FILE" ]; then + # Check if error handling is imported + if ! grep -q "import FoundationCore" "$MAIN_APP_FILE"; then + echo "${MAIN_APP_FILE}:1:1: ${WARNING_PREFIX} ๐Ÿ’ก Import FoundationCore to access enhanced error handling" + fi + fi + + # Run module dependency validation (non-blocking) + "${SCRIPT_DIR}/validate-module-dependencies.sh" 2>&1 | while IFS= read -r line; do + if [[ "$line" =~ "ERROR:" ]]; then + echo "ModuleDependencies:1:1: ${ERROR_PREFIX} $line" + elif [[ "$line" =~ "WARNING:" ]]; then + echo "ModuleDependencies:1:1: ${WARNING_PREFIX} $line" + fi + done || true +fi + +# Allow script to be used as a filter +if [ "${1:-}" = "filter" ]; then + main +fi \ No newline at end of file diff --git a/scripts/ci-validation.sh b/scripts/ci-validation.sh new file mode 100755 index 00000000..4fde9013 --- /dev/null +++ b/scripts/ci-validation.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# CI Validation Helper Script +# Description: Validates CI configuration and runs basic checks + +set -e + +echo "๐Ÿ” CI Validation Helper" +echo "======================" + +# Check if we're in the right directory +if [ ! -f "project.yml" ]; then + echo "โŒ Error: project.yml not found. Please run from project root." + exit 1 +fi + +# Check GitHub workflows +echo "๐Ÿ“‹ Checking GitHub Workflows..." +if [ ! -d ".github/workflows" ]; then + echo "โŒ No GitHub workflows directory found" + exit 1 +fi + +workflows=(".github/workflows/pr-validation.yml" ".github/workflows/tests.yml") +for workflow in "${workflows[@]}"; do + if [ -f "$workflow" ]; then + echo "โœ… Found: $workflow" + else + echo "โŒ Missing: $workflow" + fi +done + +# Check for required tools +echo "๐Ÿ› ๏ธ Checking Required Tools..." +tools=("xcodegen" "swiftlint" "xcpretty") +for tool in "${tools[@]}"; do + if command -v "$tool" &> /dev/null; then + echo "โœ… $tool is installed" + else + echo "โš ๏ธ $tool is not installed (will be installed in CI)" + fi +done + +# Validate XcodeGen project +echo "๐Ÿ—๏ธ Validating XcodeGen Configuration..." +if command -v xcodegen &> /dev/null; then + if xcodegen generate --spec project.yml --project HomeInventoryModular.xcodeproj; then + echo "โœ… XcodeGen project generation successful" + else + echo "โŒ XcodeGen project generation failed" + exit 1 + fi +else + echo "โš ๏ธ XcodeGen not available, skipping project generation test" +fi + +# Check SwiftLint configuration +echo "๐Ÿ“ Validating SwiftLint Configuration..." +if [ -f ".swiftlint.yml" ]; then + echo "โœ… SwiftLint configuration found" + if command -v swiftlint &> /dev/null; then + # Run SwiftLint in quiet mode to check configuration + if swiftlint version &> /dev/null; then + echo "โœ… SwiftLint configuration is valid" + else + echo "โŒ SwiftLint configuration has issues" + fi + fi +else + echo "โŒ No SwiftLint configuration found" +fi + +# Check test targets +echo "๐Ÿงช Checking Test Targets..." +if [ -f "HomeInventoryModular.xcodeproj/project.pbxproj" ]; then + if grep -q "HomeInventoryModularUITests" HomeInventoryModular.xcodeproj/project.pbxproj; then + echo "โœ… UI Tests target found" + else + echo "โš ๏ธ UI Tests target not found" + fi + + if grep -q "UIScreenshots" HomeInventoryModular.xcodeproj/project.pbxproj; then + echo "โœ… Unit Tests target found" + else + echo "โš ๏ธ Unit Tests target not found" + fi +else + echo "โš ๏ธ Xcode project not found, cannot check test targets" +fi + +# Check module structure +echo "๐Ÿ“ฆ Checking Module Structure..." +expected_modules=("Foundation-Core" "Foundation-Models" "Infrastructure-Network" "Infrastructure-Storage" "UI-Components" "Features-Inventory" "App-Main") +missing_modules=() + +for module in "${expected_modules[@]}"; do + if [ -d "$module" ]; then + echo "โœ… $module" + else + echo "โš ๏ธ $module (missing)" + missing_modules+=("$module") + fi +done + +if [ ${#missing_modules[@]} -gt 0 ]; then + echo "โš ๏ธ Some modules are missing. CI may fail for missing dependencies." +fi + +# Security checks +echo "๐Ÿ”’ Running Basic Security Checks..." +security_issues=0 + +# Check for hardcoded secrets +if grep -r "password\s*=\s*\"" --include="*.swift" . | grep -v "placeholder\|example\|test" | head -5; then + echo "โš ๏ธ Potential hardcoded passwords found" + ((security_issues++)) +fi + +if grep -r "api[_-]?key\s*=\s*\"" --include="*.swift" . | grep -v "placeholder\|example\|test" | head -5; then + echo "โš ๏ธ Potential hardcoded API keys found" + ((security_issues++)) +fi + +if [ $security_issues -eq 0 ]; then + echo "โœ… No obvious security issues found" +fi + +echo "" +echo "๐Ÿ“Š Summary" +echo "==========" +echo "โœ… CI validation complete" +echo "๐Ÿ“ Review any warnings above before pushing to CI" +echo "" + +if [ ${#missing_modules[@]} -gt 0 ] || [ $security_issues -gt 0 ]; then + echo "โš ๏ธ Some issues found - CI may have warnings but should still run" + exit 0 +else + echo "๐ŸŽ‰ All checks passed - CI should run successfully" +fi \ No newline at end of file diff --git a/scripts/xcode-build-wrapper.sh b/scripts/xcode-build-wrapper.sh new file mode 100755 index 00000000..c9e0a86c --- /dev/null +++ b/scripts/xcode-build-wrapper.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# Xcode Build Wrapper Script +# Enhances compiler output with module context and helpful error messages + +# This script wraps the Swift compiler to provide enhanced error messages +# To use: Set as a custom build rule or use with xcodebuild + +# Capture the original compiler command +COMPILER="$1" +shift + +# Colors and formatting +RED='\033[0;31m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +GREEN='\033[0;32m' +BOLD='\033[1m' +NC='\033[0m' + +# Module detection from file path +detect_module() { + local file=$1 + if [[ "$file" =~ /(Foundation-[^/]+|Infrastructure-[^/]+|Services-[^/]+|UI-[^/]+|Features-[^/]+|App-[^/]+)/ ]]; then + echo "${BASH_REMATCH[1]}" + else + echo "Unknown" + fi +} + +# Error enhancement function +enhance_error() { + local line="$1" + + # Parse Swift error format + if [[ "$line" =~ ^([^:]+):([0-9]+):([0-9]+):[[:space:]]*(error|warning|note):[[:space:]]*(.*) ]]; then + local file="${BASH_REMATCH[1]}" + local line_num="${BASH_REMATCH[2]}" + local column="${BASH_REMATCH[3]}" + local type="${BASH_REMATCH[4]}" + local message="${BASH_REMATCH[5]}" + + local module=$(detect_module "$file") + local emoji="" + + # Module-specific emojis + case "$module" in + Foundation-Core) emoji="๐Ÿ”จ" ;; + Features-Scanner) emoji="๐Ÿ“ธ" ;; + Services-Sync) emoji="๐Ÿ”„" ;; + Features-Inventory) emoji="๐Ÿ“‹" ;; + *) emoji="๐Ÿ“ฑ" ;; + esac + + # Enhanced output + echo -e "${file}:${line_num}:${column}: ${type}: ${emoji} [${module}] ${message}" + + # Add helpful context based on error patterns + case "$message" in + *"ServiceError"*) + echo -e "${file}:${line_num}:${column}: note: ๐Ÿ’ก Use domain-specific errors from ServiceError.swift for better diagnostics" + ;; + *"Sendable"*) + echo -e "${file}:${line_num}:${column}: note: ๐Ÿ’ก Consider @unchecked Sendable or actor isolation" + ;; + *"import"*"not found"*) + echo -e "${file}:${line_num}:${column}: note: ๐Ÿ’ก Check module dependencies with ./scripts/validate-module-dependencies.sh" + ;; + *"available in iOS"*) + echo -e "${file}:${line_num}:${column}: note: ๐Ÿ’ก Add @available(iOS 14.0, *) or check deployment target" + ;; + esac + else + # Pass through unchanged + echo "$line" + fi +} + +# Create a temporary file for compiler output +TEMP_OUTPUT=$(mktemp) + +# Run the actual compiler command and capture output +"$COMPILER" "$@" 2>&1 | tee "$TEMP_OUTPUT" | while IFS= read -r line; do + enhance_error "$line" +done + +# Get the compiler exit code +COMPILER_EXIT_CODE=${PIPESTATUS[0]} + +# Additional diagnostics in case of failure +if [ $COMPILER_EXIT_CODE -ne 0 ]; then + # Extract the file being compiled + for arg in "$@"; do + if [[ "$arg" == *.swift ]]; then + MODULE=$(detect_module "$arg") + echo -e "\n${YELLOW}โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}" + echo -e "${YELLOW}Module Build Failed: ${MODULE}${NC}" + echo -e "${YELLOW}โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}" + + # Module-specific hints + case "$MODULE" in + Features-Scanner) + echo -e "${BLUE}๐Ÿ’ก Scanner module hints:${NC}" + echo " - Check camera permissions in Info.plist" + echo " - Verify AVFoundation framework is linked" + echo " - Use ScannerError for scanner-specific failures" + ;; + Services-Sync) + echo -e "${BLUE}๐Ÿ’ก Sync module hints:${NC}" + echo " - Verify CloudKit entitlements" + echo " - Check for actor isolation in async code" + echo " - Use SyncError for sync-specific failures" + ;; + Infrastructure-Storage) + echo -e "${BLUE}๐Ÿ’ก Storage module hints:${NC}" + echo " - Check Core Data model configuration" + echo " - Verify managed object context setup" + echo " - Use proper concurrency for Core Data" + ;; + esac + + echo -e "${YELLOW}โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}\n" + break + fi + done +fi + +# Clean up +rm -f "$TEMP_OUTPUT" + +# Exit with the same code as the compiler +exit $COMPILER_EXIT_CODE \ No newline at end of file