diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e48b4b6..0768265 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,14 +3,57 @@ name: Tests on: push: branches: [ "*" ] + paths: + - 'install.sh' + - 'src/**' + - 'tests/**' + - '.github/workflows/**' + - '*.txt' # requirements files + - '*.toml' # pyproject.toml + - '*.cfg' # setup.cfg + - '*.py' # any Python file in root pull_request: branches: [ "*" ] + paths: + - 'install.sh' + - 'src/**' + - 'tests/**' + - '.github/workflows/**' + - '*.txt' # requirements files + - '*.toml' # pyproject.toml + - '*.cfg' # setup.cfg + - '*.py' # any Python file in root jobs: + # Detect which files changed to run only relevant tests + detect-changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + python: ${{ steps.filter.outputs.python }} + installer: ${{ steps.filter.outputs.installer }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + python: + - 'src/**/*.py' + - 'tests/test_*.py' + - '*.txt' + - '*.toml' + - '*.cfg' + installer: + - 'install.sh' + - 'tests/test_installer.sh' + - '.github/workflows/test.yml' + unit-tests: name: Unit Tests runs-on: ubuntu-latest - if: false # Temporarily disabled to save CI minutes while troubleshooting installer tests + needs: detect-changes + if: needs.detect-changes.outputs.python == 'true' strategy: matrix: @@ -62,7 +105,8 @@ jobs: integration-tests: name: Integration Tests runs-on: ubuntu-latest - if: false # Temporarily disabled to save CI minutes while troubleshooting installer tests + needs: detect-changes + if: needs.detect-changes.outputs.python == 'true' strategy: matrix: @@ -123,6 +167,8 @@ jobs: installer-test: name: Installer Test (Fresh System) runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.installer == 'true' strategy: fail-fast: false @@ -164,3 +210,68 @@ jobs: echo "✓ Pip packages: bleak, bluezero" >> $GITHUB_STEP_SUMMARY echo "✓ Install method: System packages (no compilation)" >> $GITHUB_STEP_SUMMARY echo "✓ Installation time: < 1 minute" >> $GITHUB_STEP_SUMMARY + + installer-test-arm: + name: Installer Test (Raspberry Pi OS - ARM) + runs-on: ubuntu-latest + # Only run on pull requests to main branch + if: github.event_name == 'pull_request' && github.base_ref == 'main' + timeout-minutes: 20 # ARM emulation is slower, allow extra time + + strategy: + fail-fast: false + matrix: + include: + # Raspberry Pi OS 32-bit (armhf/armv7) + # Based on Debian Bookworm - matches Raspberry Pi OS Lite 32-bit + - os-image: "arm32v7/debian:bookworm" + platform: "linux/arm/v7" + arch-name: "Raspberry Pi OS 32-bit (armhf)" + + # Raspberry Pi OS 64-bit (arm64/aarch64) + # Based on Debian Bookworm - matches Raspberry Pi OS Lite 64-bit + - os-image: "arm64v8/debian:bookworm" + platform: "linux/arm64" + arch-name: "Raspberry Pi OS 64-bit (arm64)" + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm,arm64 + + - name: Run installer test on ${{ matrix.arch-name }} + run: | + docker run --rm \ + --platform ${{ matrix.platform }} \ + -v $PWD:/workspace \ + -w /workspace \ + -e DEBIAN_FRONTEND=noninteractive \ + -e DEBCONF_NONINTERACTIVE_SEEN=true \ + -e TZ=UTC \ + ${{ matrix.os-image }} \ + bash tests/test_installer.sh + continue-on-error: false + + - name: Installation summary + if: always() + run: | + echo "## ARM Installer Test Results" >> $GITHUB_STEP_SUMMARY + echo "**Architecture:** ${{ matrix.arch-name }}" >> $GITHUB_STEP_SUMMARY + echo "**Platform:** ${{ matrix.platform }}" >> $GITHUB_STEP_SUMMARY + echo "**Base Image:** ${{ matrix.os-image }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ matrix.platform }}" == "linux/arm/v7" ]]; then + echo "✓ System packages: python3-gi, python3-dbus, python3-cairo, bluez, libffi-dev" >> $GITHUB_STEP_SUMMARY + echo "✓ libffi-dev included for 32-bit ARM cffi compilation" >> $GITHUB_STEP_SUMMARY + else + echo "✓ System packages: python3-gi, python3-dbus, python3-cairo, bluez" >> $GITHUB_STEP_SUMMARY + fi + echo "✓ Pip packages: bleak==1.1.1, bluezero" >> $GITHUB_STEP_SUMMARY + echo "✓ BLE interface files copied" >> $GITHUB_STEP_SUMMARY + echo "✓ BlueZ experimental mode configured" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "_Note: Tests run via QEMU emulation (2-5x slower than native)_" >> $GITHUB_STEP_SUMMARY diff --git a/install.sh b/install.sh index 73f94b6..f9cdbca 100755 --- a/install.sh +++ b/install.sh @@ -158,7 +158,67 @@ fi echo -# Step 1: Check for Reticulum installation +# Step 1: Install system dependencies +print_header "Installing System Dependencies" + +if command -v apt-get &> /dev/null; then + # Debian/Ubuntu/Raspberry Pi OS + print_info "Detected Debian/Ubuntu-based system" + + # Detect architecture for platform-specific dependencies + ARCH=$(dpkg --print-architecture 2>/dev/null || echo "unknown") + print_info "Detected architecture: $ARCH" + + PACKAGES="python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin" + + # Add libffi-dev only for 32-bit ARM (armhf) - needed for cffi compilation + # x86_64 and arm64 have pre-built cffi wheels available + if [[ "$ARCH" == "armhf" ]]; then + PACKAGES="$PACKAGES libffi-dev" + print_info "32-bit ARM detected - adding libffi-dev for cffi compilation" + fi + + echo "Installing: $PACKAGES" + + # Use sudo only if not running as root + if [ "$EUID" -eq 0 ]; then + apt-get update + apt-get install -y $PACKAGES + else + sudo apt-get update + sudo apt-get install -y $PACKAGES + fi + print_success "System dependencies installed (using pre-compiled system packages)" +elif command -v pacman &> /dev/null; then + # Arch Linux + print_info "Detected Arch Linux" + echo "Installing: base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap" + print_warning "Note: PyGObject will be compiled from pip due to version requirements (bluezero needs <3.52.0, Arch has 3.54.5)" + # Use sudo only if not running as root + if [ "$EUID" -eq 0 ]; then + # Sync package database first (may have been synced in basic prereqs, but ensure it's current) + pacman -Sy --noconfirm + # Skip python-gobject to avoid version conflict - pip will compile PyGObject + # gobject-introspection provides dev files needed for PyGObject compilation + pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap + else + sudo pacman -Sy --noconfirm + sudo pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap + fi + print_success "System dependencies installed (PyGObject will be compiled from pip)" +else + print_warning "Could not detect package manager" + print_info "Please manually install: BlueZ 5.x, python3-dbus" + read -p "Continue anyway? (y/N) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi +fi + +echo + +# Step 2: Check for Reticulum installation print_header "Checking for Reticulum" RNS_VENV="" @@ -260,51 +320,6 @@ fi echo -# Step 2: Install system dependencies -print_header "Installing System Dependencies" - -if command -v apt-get &> /dev/null; then - # Debian/Ubuntu/Raspberry Pi OS - print_info "Detected Debian/Ubuntu-based system" - echo "Installing: python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin" - # Use sudo only if not running as root - if [ "$EUID" -eq 0 ]; then - apt-get update - apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin - else - sudo apt-get update - sudo apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin - fi - print_success "System dependencies installed (using pre-compiled system packages)" -elif command -v pacman &> /dev/null; then - # Arch Linux - print_info "Detected Arch Linux" - echo "Installing: base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap" - print_warning "Note: PyGObject will be compiled from pip due to version requirements (bluezero needs <3.52.0, Arch has 3.54.5)" - # Use sudo only if not running as root - if [ "$EUID" -eq 0 ]; then - # Sync package database first (may have been synced in basic prereqs, but ensure it's current) - pacman -Sy --noconfirm - # Skip python-gobject to avoid version conflict - pip will compile PyGObject - # gobject-introspection provides dev files needed for PyGObject compilation - pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap - else - sudo pacman -Sy --noconfirm - sudo pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap - fi - print_success "System dependencies installed (PyGObject will be compiled from pip)" -else - print_warning "Could not detect package manager" - print_info "Please manually install: BlueZ 5.x, python3-dbus" - read -p "Continue anyway? (y/N) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi -fi - -echo - # Step 3: Install Python dependencies print_header "Installing Python Dependencies" diff --git a/tests/test_installer.sh b/tests/test_installer.sh index a361145..5e5916e 100755 --- a/tests/test_installer.sh +++ b/tests/test_installer.sh @@ -205,7 +205,14 @@ echo "Installation summary:" echo " • install.sh is fully self-contained (handles all prerequisites)" echo " • Reticulum Network Stack: installed via pip" if [ "$OS_TYPE" = "debian" ]; then - echo " • System packages: python3, python3-pip, git, python3-gi, python3-dbus, python3-cairo, bluez" + # Detect architecture for platform-specific package list + ARCH=$(dpkg --print-architecture 2>/dev/null || echo "unknown") + if [[ "$ARCH" == "armhf" ]]; then + echo " • System packages: python3, python3-pip, git, python3-gi, python3-dbus, python3-cairo, bluez, libffi-dev" + echo " • Note: libffi-dev included for 32-bit ARM cffi compilation" + else + echo " • System packages: python3, python3-pip, git, python3-gi, python3-dbus, python3-cairo, bluez" + fi echo " • Pip packages: rns, bleak, bluezero" echo " • Install method: System packages (no compilation)" echo " • Installation time: < 1 minute"