diff --git a/scripts/local-ci/lib/ci-env.sh b/scripts/local-ci/lib/ci-env.sh index 66e3964a..e9634a9c 100755 --- a/scripts/local-ci/lib/ci-env.sh +++ b/scripts/local-ci/lib/ci-env.sh @@ -16,6 +16,11 @@ source "$_LIB_DIR/common.sh" # Validate macOS version validate_macos_version() { + if is_linux; then + log_info "Running on Linux - skipping macOS version check" + return 0 + fi + local os_version os_version=$(sw_vers -productVersion) local major_version @@ -33,6 +38,11 @@ validate_xcode() { local required_major="${1:-16}" local required_minor="${2:-0}" + if is_linux; then + log_info "Running on Linux - skipping Xcode validation" + return 0 + fi + if [[ ! -d "$XCODE_PATH" ]]; then error_exit "Xcode not found at $XCODE_PATH" fi @@ -60,7 +70,19 @@ validate_swift() { local required_version="${1:-6.0}" if ! command_exists swift; then - error_exit "Swift not found. Install Xcode or Swift toolchain." + if is_linux; then + log_error "Swift is required but not found on Linux" + log_error "" + log_error "Please install Swift following the instructions in:" + log_error " DOCS/RULES/12_Swift_Installation_Linux.md" + log_error "" + log_error "Quick install:" + log_error " curl -L https://swiftlang.github.io/swiftly/swiftly-install.sh | bash" + log_error " swiftly install latest" + error_exit "Swift installation required" + else + error_exit "Swift not found. Install Xcode or Swift toolchain." + fi fi local swift_version @@ -69,6 +91,7 @@ validate_swift() { # Note: Version comparison would need more sophisticated parsing # For now, just report the version + return 0 } # Check Homebrew @@ -89,9 +112,67 @@ ensure_swiftlint() { if [[ "$mode" == "docker" ]]; then log_info "SwiftLint mode: Docker (no local installation needed)" + if check_docker; then + log_success "Docker is available and running" + else + log_warning "Docker not running. Ensure Docker Desktop is started." + fi + return 0 + fi + + # On Linux, prefer Docker or build from source + if is_linux; then + if ! command_exists swiftlint; then + log_warning "SwiftLint not found on Linux" + + # Try Docker first + if check_docker; then + log_info "Docker is available. Switching to Docker mode for SwiftLint" + export SWIFTLINT_MODE="docker" + return 0 + fi + + # Try building from source if Swift is available + if command_exists swift; then + log_info "Attempting to build SwiftLint from source..." + local install_dir="$HOME/.local-ci/swiftlint" + + if [[ -x "$install_dir/swiftlint" ]]; then + log_success "Using cached SwiftLint from $install_dir" + export PATH="$install_dir:$PATH" + return 0 + fi + + log_info "This may take several minutes..." + local temp_dir + temp_dir=$(create_temp_dir) + + if git clone --depth 1 --branch 0.53.0 https://github.com/realm/SwiftLint.git "$temp_dir/SwiftLint" 2>/dev/null && + (cd "$temp_dir/SwiftLint" && swift build -c release) 2>/dev/null; then + mkdir -p "$install_dir" + cp "$temp_dir/SwiftLint/.build/release/swiftlint" "$install_dir/" + export PATH="$install_dir:$PATH" + rm -rf "$temp_dir" + log_success "SwiftLint built and installed to $install_dir" + return 0 + else + rm -rf "$temp_dir" + log_warning "Failed to build SwiftLint from source" + fi + fi + + log_warning "SwiftLint not available. Use Docker mode: SWIFTLINT_MODE=docker" + log_info "Or install Swift and try building from source" + return 1 + fi + + local swiftlint_version + swiftlint_version=$(swiftlint version) + log_success "SwiftLint version: $swiftlint_version" return 0 fi + # macOS path if ! command_exists swiftlint; then log_warning "SwiftLint not found" if check_homebrew; then @@ -109,6 +190,11 @@ ensure_swiftlint() { # Ensure Tuist is installed ensure_tuist() { + if is_linux; then + log_info "Running on Linux - Tuist is macOS-only, skipping" + return 0 + fi + local tuist_version="${TUIST_VERSION:-}" local install_dir="$HOME/.local-ci/tuist" @@ -217,6 +303,11 @@ validate_python() { # Detect best available iOS simulator for testing # Returns destination specifier string with ID detect_ios_simulator() { + if is_linux; then + log_warning "iOS Simulator not available on Linux" + return 1 + fi + local device_name="${1:-iPhone 16}" local workspace="${2:-}" local scheme="${3:-}" @@ -274,11 +365,15 @@ detect_ios_simulator() { validate_ci_environment() { log_section "Validating CI Environment" + local current_os + current_os=$(detect_os) + log_info "Detected OS: $current_os" + validate_macos_version validate_xcode 16 0 validate_swift 6.0 check_homebrew || true - ensure_swiftlint + ensure_swiftlint || true validate_python || true log_success "CI environment validation complete" @@ -291,8 +386,10 @@ setup_ci_environment() { load_config validate_ci_environment - # Set up derived data path for consistent builds - export DERIVED_DATA_PATH="${DERIVED_DATA_PATH:-$HOME/Library/Developer/Xcode/DerivedData}" + # Set up derived data path for consistent builds (macOS only) + if is_macos; then + export DERIVED_DATA_PATH="${DERIVED_DATA_PATH:-$HOME/Library/Developer/Xcode/DerivedData}" + fi # Set up build cache export BUILD_CACHE_DIR="${BUILD_CACHE_DIR:-$HOME/.local-ci/build-cache}" diff --git a/scripts/local-ci/lib/common.sh b/scripts/local-ci/lib/common.sh index e7a30317..2429655f 100755 --- a/scripts/local-ci/lib/common.sh +++ b/scripts/local-ci/lib/common.sh @@ -51,6 +51,31 @@ command_exists() { command -v "$1" >/dev/null 2>&1 } +# Detect operating system +detect_os() { + case "$(uname -s)" in + Darwin*) + echo "macos" + ;; + Linux*) + echo "linux" + ;; + *) + echo "unknown" + ;; + esac +} + +# Check if running on macOS +is_macos() { + [[ "$(detect_os)" == "macos" ]] +} + +# Check if running on Linux +is_linux() { + [[ "$(detect_os)" == "linux" ]] +} + # Detect repository root detect_repo_root() { local current_dir="$PWD" @@ -218,7 +243,8 @@ parse_common_args() { # Export functions export -f log_info log_success log_warning log_error log_section -export -f error_exit command_exists detect_repo_root load_config +export -f error_exit command_exists detect_os is_macos is_linux +export -f detect_repo_root load_config export -f detect_xcode_version detect_swift_version check_xcode_version export -f check_docker timed_run create_temp_dir cleanup_temp_files export -f parse_common_args diff --git a/scripts/local-ci/run-build.sh b/scripts/local-ci/run-build.sh index ee1a208b..41dbaa93 100755 --- a/scripts/local-ci/run-build.sh +++ b/scripts/local-ci/run-build.sh @@ -154,32 +154,36 @@ fi # Tuist Workspace Generation # ============================================================================ if [[ "$SPM_ONLY" != "true" ]] && [[ "$SKIP_TUIST" != "true" ]]; then - log_section "Tuist Workspace Generation" + if is_linux; then + log_info "Running on Linux - skipping Tuist workspace generation (macOS only)" + else + log_section "Tuist Workspace Generation" - ensure_tuist + ensure_tuist - # Validate Tuist project - if timed_run "Validate Tuist project" tuist dump project; then - log_success "Tuist project validation passed" - else - log_error "Tuist project validation failed" - ((FAILURES++)) - fi + # Validate Tuist project + if timed_run "Validate Tuist project" tuist dump project; then + log_success "Tuist project validation passed" + else + log_error "Tuist project validation failed" + ((FAILURES++)) + fi - # Install dependencies - if timed_run "Install Tuist dependencies" tuist install; then - log_success "Tuist dependencies installed" - else - log_error "Tuist install failed" - ((FAILURES++)) - fi + # Install dependencies + if timed_run "Install Tuist dependencies" tuist install; then + log_success "Tuist dependencies installed" + else + log_error "Tuist install failed" + ((FAILURES++)) + fi - # Generate workspace - if timed_run "Generate Xcode workspace" tuist generate --no-open; then - log_success "Xcode workspace generated" - else - log_error "Tuist generate failed" - ((FAILURES++)) + # Generate workspace + if timed_run "Generate Xcode workspace" tuist generate --no-open; then + log_success "Xcode workspace generated" + else + log_error "Tuist generate failed" + ((FAILURES++)) + fi fi fi @@ -187,7 +191,10 @@ fi # Xcode Builds # ============================================================================ if [[ "$SPM_ONLY" != "true" ]] && [[ -f "$REPO_ROOT/ISOInspector.xcworkspace/contents.xcworkspacedata" ]]; then - log_section "Xcode Builds" + if is_linux; then + log_info "Running on Linux - skipping Xcode builds (macOS only)" + else + log_section "Xcode Builds" XCODE_BUILD_ARGS=( -workspace ISOInspector.xcworkspace @@ -275,9 +282,12 @@ if [[ "$SPM_ONLY" != "true" ]] && [[ -f "$REPO_ROOT/ISOInspector.xcworkspace/con fi fi fi + fi else if [[ "$SPM_ONLY" != "true" ]]; then - log_warning "Xcode workspace not found. Run with Tuist generation or use --spm-only" + if ! is_linux; then + log_warning "Xcode workspace not found. Run with Tuist generation or use --spm-only" + fi fi fi diff --git a/scripts/local-ci/run-lint.sh b/scripts/local-ci/run-lint.sh index e15d983a..6e7927c8 100755 --- a/scripts/local-ci/run-lint.sh +++ b/scripts/local-ci/run-lint.sh @@ -154,34 +154,50 @@ fi if [[ "$SKIP_SWIFTLINT" != "true" ]]; then log_section "SwiftLint ($SWIFTLINT_MODE mode)" - # Function to run SwiftLint on a specific config - run_swiftlint_check() { - local name="$1" - local work_dir="$2" - local config="$3" - - log_info "Running SwiftLint on $name..." - - if [[ "$SWIFTLINT_MODE" == "docker" ]]; then - if [[ "$AUTO_FIX" == "true" ]]; then - run_swiftlint_autocorrect_docker "$work_dir" "$config" - fi - run_swiftlint_docker "$work_dir" "$config" --strict + # Check if SwiftLint is available + SWIFTLINT_AVAILABLE=false + if [[ "$SWIFTLINT_MODE" == "docker" ]]; then + if check_docker; then + SWIFTLINT_AVAILABLE=true else - # Native mode - pushd "$work_dir" >/dev/null + log_warning "Docker not available - skipping SwiftLint" + fi + elif command_exists swiftlint; then + SWIFTLINT_AVAILABLE=true + else + log_warning "SwiftLint not available - skipping SwiftLint checks" + log_info "Install SwiftLint or use Docker mode: SWIFTLINT_MODE=docker" + fi - if [[ "$AUTO_FIX" == "true" ]]; then - swiftlint --fix --config "$config" || true + if [[ "$SWIFTLINT_AVAILABLE" == "true" ]]; then + # Function to run SwiftLint on a specific config + run_swiftlint_check() { + local name="$1" + local work_dir="$2" + local config="$3" + + log_info "Running SwiftLint on $name..." + + if [[ "$SWIFTLINT_MODE" == "docker" ]]; then + if [[ "$AUTO_FIX" == "true" ]]; then + run_swiftlint_autocorrect_docker "$work_dir" "$config" + fi + run_swiftlint_docker "$work_dir" "$config" --strict + else + # Native mode + pushd "$work_dir" >/dev/null + + if [[ "$AUTO_FIX" == "true" ]]; then + swiftlint --fix --config "$config" || true + fi + + swiftlint lint --strict --config "$config" + local result=$? + + popd >/dev/null + return $result fi - - swiftlint lint --strict --config "$config" - local result=$? - - popd >/dev/null - return $result - fi - } + } # Main Project if timed_run "SwiftLint (Main Project)" run_swiftlint_check "Main Project" "$REPO_ROOT" ".swiftlint.yml"; then @@ -210,6 +226,7 @@ if [[ "$SKIP_SWIFTLINT" != "true" ]]; then ((FAILURES++)) fi fi + fi fi # ============================================================================ diff --git a/scripts/local-ci/run-tests.sh b/scripts/local-ci/run-tests.sh index 018f5c9d..fa50de38 100755 --- a/scripts/local-ci/run-tests.sh +++ b/scripts/local-ci/run-tests.sh @@ -146,7 +146,10 @@ fi # Xcode Tests # ============================================================================ if [[ "$SPM_ONLY" != "true" ]] && [[ -f "$REPO_ROOT/ISOInspector.xcworkspace/contents.xcworkspacedata" ]]; then - log_section "Xcode Tests" + if is_linux; then + log_info "Running on Linux - skipping Xcode tests (macOS only)" + else + log_section "Xcode Tests" XCODE_TEST_ARGS=( -workspace ISOInspector.xcworkspace @@ -207,9 +210,12 @@ if [[ "$SPM_ONLY" != "true" ]] && [[ -f "$REPO_ROOT/ISOInspector.xcworkspace/con fi fi fi + fi else if [[ "$SPM_ONLY" != "true" ]]; then - log_warning "Xcode workspace not found. Run ./scripts/local-ci/run-build.sh first or use --spm-only" + if ! is_linux; then + log_warning "Xcode workspace not found. Run ./scripts/local-ci/run-build.sh first or use --spm-only" + fi fi fi