diff --git a/.claude/tasks/2025-07-07-bash-migration.md b/.claude/tasks/2025-07-07-bash-migration.md index dc2f15fa..1a3e5da6 100644 --- a/.claude/tasks/2025-07-07-bash-migration.md +++ b/.claude/tasks/2025-07-07-bash-migration.md @@ -1,17 +1,19 @@ # Bash Migration Epic -## Current Status (July 7, 2025) +## Current Status (July 11, 2025) **Task**: Migrate dotfiles installation infrastructure from custom zsh to industry-standard bash + shellcheck + bats **Approach**: Enhanced 3-phase migration with setup.bash at the center for maximum tooling leverage -**Current**: Phase 1 enhanced scope - migrating setup.bash + core scripts + shared utilities +**Current**: Phase 1 nearing completion - core utilities and 4 installation scripts migrated, setup.bash pending ## Migration Strategy ### Phase 1: Setup + Core Infrastructure Migration (IN PROGRESS - Enhanced Scope) **Goal**: Migrate setup.bash + core installation scripts + shared utilities for maximum tooling leverage -#### ✅ PR #13: GitHub Installation Testing (MERGED) +#### Completed PRs + +##### ✅ PR #13: GitHub Installation Testing (MERGED) - **Files Created**: - `lib/github-utils.bash` - GitHub SSH utilities (shellcheck clean) - `bin/install/github.bash` - Bash replacement for github.zsh @@ -22,6 +24,46 @@ - **Benefits Demonstrated**: Better error catching, industry-standard tooling, cleaner syntax - **Status**: MERGED - established complete migration pattern with 20 passing tests +##### ✅ PR #15: SSH Installation Testing (MERGED) +- **Files Created**: + - `lib/ssh-utils.bash` - SSH utilities with comprehensive functionality + - `bin/install/ssh.bash` - Bash replacement for ssh.zsh + - `test/install/test-ssh-utils.bats` - 14 utility function tests + - `test/install/test-ssh-installation.bats` - 7 integration tests +- **Test Results**: All 21 tests passing, shellcheck compliance verified +- **Improvements**: Better macOS version detection for ssh-add keychain flag +- **Status**: MERGED - SSH installation fully migrated to bash + +##### ✅ PR #17: Homebrew Utilities Migration (MERGED) +- **Files Created**: + - `lib/homebrew-utils.bash` - Homebrew shared utilities + - `bin/install/homebrew.bash` - Bash replacement for homebrew.zsh + - `test/install/test-homebrew-utils.bats` - Comprehensive utility tests +- **Status**: MERGED - Homebrew installation fully migrated with shared utilities + +##### ✅ PR #18: Core Utility Libraries Migration (MERGED) +- **Files Migrated**: + - `bin/lib/machine-detection.bash` - Dynamic hostname-based machine detection + - `bin/lib/prerequisite-validation.bash` - System prerequisites validation + - Test files for all core utilities +- **Status**: MERGED - Core utilities successfully migrated to bash + +##### ✅ PR #19: Dry-run and Error Handling Utilities (MERGED) +- **Files Created**: + - `bin/lib/dry-run-utils.bash` - Complete dry-run functionality + - `bin/lib/error-handling.bash` - Error handling and retry mechanisms + - `test/setup/test-dry-run-utils-bash.bats` - 20 tests for dry-run utilities +- **Test Results**: 20/20 tests passing, zero shellcheck warnings +- **Status**: MERGED - Dry-run and error handling utilities in bash +- **Note**: Error handling tests still needed + +##### ✅ PR #20: Symlink Utilities Extraction (MERGED) +- **Files Created**: + - `lib/symlink-utils.bash` - Symlink management utilities + - `bin/install/symlinks.bash` - Bash replacement for symlinks installation + - `test/setup/test-symlink-utils-bash.bats` - Comprehensive symlink tests +- **Status**: MERGED - Symlink functionality fully migrated to bash + ### Phase 2: Remaining Script Migration (Pending) **Goal**: Migrate remaining installation scripts using established three-tier architecture diff --git a/test/setup/test-error-handling-bash.bats b/test/setup/test-error-handling-bash.bats new file mode 100644 index 00000000..c0dce346 --- /dev/null +++ b/test/setup/test-error-handling-bash.bats @@ -0,0 +1,135 @@ +#!/usr/bin/env bats + +# Test error handling utilities (bash implementation) + +# Load the error handling utilities +load "../../bin/lib/error-handling.bash" + +# Test capture_error with no command provided +@test "capture_error returns error when no command provided" { + run capture_error + [ "$status" -eq 1 ] + [[ "$output" =~ "Error: No command provided to capture_error" ]] +} + +# Test capture_error with successful command +@test "capture_error executes successful command and returns 0" { + run capture_error "echo 'Hello World'" + [ "$status" -eq 0 ] + [[ "$output" == "Hello World" ]] +} + +# Test capture_error with failing command +@test "capture_error handles failing command and provides context" { + run capture_error "exit 42" "Test operation" + [ "$status" -eq 42 ] + [[ "$output" =~ "Error: Test operation failed (exit code: 42)" ]] + [[ "$output" =~ "Command: exit 42" ]] +} + +# Test capture_error preserves command output before showing error +@test "capture_error shows command output before error message" { + run capture_error "echo 'Output before failure' && exit 1" "Command with output" + [ "$status" -eq 1 ] + [[ "${lines[0]}" == "Output before failure" ]] + [[ "$output" =~ "Error: Command with output failed" ]] +} + +# Test retry_with_backoff with no command provided +@test "retry_with_backoff returns error when no command provided" { + run retry_with_backoff + [ "$status" -eq 1 ] + [[ "$output" =~ "Error: No command provided to retry_with_backoff" ]] +} + +# Test retry_with_backoff with successful command on first try +@test "retry_with_backoff succeeds on first attempt" { + run retry_with_backoff "exit 0" + [ "$status" -eq 0 ] +} + +# Test retry_with_backoff exhausts all attempts and fails +@test "retry_with_backoff fails after exhausting max attempts" { + run retry_with_backoff "exit 1" 2 0 + [ "$status" -eq 1 ] +} + +# Test handle_error with no command provided +@test "handle_error returns error when no command provided" { + run handle_error + [ "$status" -eq 1 ] + [[ "$output" =~ "Error: No command provided to handle_error" ]] +} + +# Test handle_error displays error message and generic suggestion +@test "handle_error displays error message and generic suggestion" { + run handle_error "test-command" "999" "Custom error message" + [ "$status" -eq 1 ] + [[ "$output" =~ "❌ Error occurred while running: test-command" ]] + [[ "$output" =~ "Error: Custom error message" ]] + [[ "$output" =~ "💡 Suggestion: Check the command syntax and try again" ]] +} + +# Test handle_error provides permission-specific suggestion +@test "handle_error provides permission-specific suggestion for EACCES" { + run handle_error "test-command" "EACCES" "Permission denied" + [ "$status" -eq 1 ] + [[ "$output" =~ "❌ Error occurred while running: test-command" ]] + [[ "$output" =~ "Error: Permission denied" ]] + [[ "$output" =~ "💡 Suggestion: Try running with sudo or check file permissions" ]] +} + +# Test handle_error provides file-not-found suggestion +@test "handle_error provides file-not-found suggestion for ENOENT" { + run handle_error "test-command" "ENOENT" "No such file or directory" + [ "$status" -eq 1 ] + [[ "$output" =~ "❌ Error occurred while running: test-command" ]] + [[ "$output" =~ "Error: No such file or directory" ]] + [[ "$output" =~ "💡 Suggestion: Check if the file or directory exists" ]] +} + +# Test handle_error provides network-specific suggestion +@test "handle_error provides network-specific suggestion for ECONNREFUSED" { + run handle_error "test-command" "ECONNREFUSED" "Connection refused" + [ "$status" -eq 1 ] + [[ "$output" =~ "❌ Error occurred while running: test-command" ]] + [[ "$output" =~ "Error: Connection refused" ]] + [[ "$output" =~ "💡 Suggestion: Check your internet connection or try again later" ]] +} + +# Test handle_error provides disk-space suggestion +@test "handle_error provides disk-space suggestion for ENOSPC" { + run handle_error "test-command" "ENOSPC" "No space left on device" + [ "$status" -eq 1 ] + [[ "$output" =~ "❌ Error occurred while running: test-command" ]] + [[ "$output" =~ "Error: No space left on device" ]] + [[ "$output" =~ "💡 Suggestion: Free up disk space and try again" ]] +} + +# Test retry_with_backoff succeeds on second attempt +@test "retry_with_backoff succeeds on second attempt after one failure" { + # Create a file that tracks attempts + local attempt_file=$(mktemp) + echo "0" > "$attempt_file" + + # Command that fails first time, succeeds second time + local test_command=" + current=\$(cat '$attempt_file') + next=\$((current + 1)) + echo \$next > '$attempt_file' + [ \$next -eq 2 ] + " + + run retry_with_backoff "$test_command" 3 0 + [ "$status" -eq 0 ] + + # Clean up + rm -f "$attempt_file" +} + +# Test capture_error with default context +@test "capture_error uses default context when none provided" { + run capture_error "exit 1" + [ "$status" -eq 1 ] + [[ "$output" =~ "Error: Command execution failed" ]] +} \ No newline at end of file