name: Matrix Smoke on: pull_request: push: branches: - main - master permissions: contents: read jobs: linux-smoke: runs-on: ubuntu-latest defaults: run: working-directory: ods steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: AMD Path Smoke run: bash tests/smoke/linux-amd.sh - name: NVIDIA Path Smoke run: bash tests/smoke/linux-nvidia.sh - name: WSL Logic Smoke run: bash tests/smoke/wsl-logic.sh - name: Mobile Dispatch Smoke run: bash tests/smoke/mobile-dispatch.sh # Multi-distro installer detection tests (dry-run, no GPU required) distro-matrix: strategy: fail-fast: false matrix: include: - distro: ubuntu-24.04 container: ubuntu:24.04 expected_pkg: apt - distro: ubuntu-22.04 container: ubuntu:22.04 expected_pkg: apt - distro: debian-12 container: debian:12 expected_pkg: apt - distro: linux-mint-21.3 container: linuxmintd/mint21.3-amd64:latest expected_pkg: apt - distro: fedora-41 container: fedora:41 expected_pkg: dnf - distro: rocky-9 container: rockylinux:9 expected_pkg: dnf - distro: archlinux container: archlinux:latest expected_pkg: pacman - distro: manjaro container: manjarolinux/base:latest expected_pkg: pacman - distro: cachyos container: cachyos/cachyos:latest expected_pkg: pacman - distro: opensuse-tw container: opensuse/tumbleweed:latest expected_pkg: zypper runs-on: ubuntu-latest timeout-minutes: 20 container: ${{ matrix.container }} defaults: run: working-directory: ods name: "distro: ${{ matrix.distro }}" steps: - name: Install checkout prerequisites (distro-aware) working-directory: / run: | retry() { attempt=1 max=3 delay=15 until "$@"; do status=$? if [ "$attempt" -ge "$max" ]; then return "$status" fi echo "Command failed (attempt ${attempt}/${max}): $*" echo "Retrying in ${delay}s..." sleep "$delay" attempt=$((attempt + 1)) done } bounded() { seconds="$1" shift if command -v timeout >/dev/null 2>&1; then timeout "$seconds" "$@" else "$@" fi } prepare_pacman_keyrings() { command -v pacman-key >/dev/null 2>&1 || return 0 pacman-key --init || true for ring in archlinux manjaro cachyos; do if [ -f "/usr/share/pacman/keyrings/${ring}.gpg" ]; then pacman-key --populate "$ring" || true fi done } configure_zypper_ci_network() { mkdir -p /etc/zypp/zypp.conf.d { printf '%s\n' '[main]' printf '%s\n' 'download.transfer_timeout = 180' printf '%s\n' 'download.connect_timeout = 30' printf '%s\n' 'download.min_download_speed = 0' printf '%s\n' 'download.max_silent_tries = 3' printf '%s\n' 'download.max_concurrent_connections = 2' } >/etc/zypp/zypp.conf.d/99-ods-ci-network.conf } if command -v apt-get &>/dev/null; then apt-get update -qq && apt-get install -y -qq ca-certificates git curl elif command -v dnf &>/dev/null; then dnf install -y -q ca-certificates git curl-minimal elif command -v pacman &>/dev/null; then prepare_pacman_keyrings retry pacman -Syyu --noconfirm --needed ca-certificates git curl elif command -v zypper &>/dev/null; then configure_zypper_ci_network echo "Skipping zypper checkout prerequisites; packaging.sh install behavior is tested after checkout." fi - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Verify /etc/os-release working-directory: / shell: bash run: | echo "=== /etc/os-release ===" cat /etc/os-release . /etc/os-release echo "ID=$ID" echo "ID_LIKE=${ID_LIKE:-none}" - name: Test packaging.sh detection shell: bash run: | # Source the packaging library and verify detection export LOG_FILE=/dev/null log() { echo "[INFO] $1"; } warn() { echo "[WARN] $1"; } error() { echo "[ERROR] $1"; exit 1; } source installers/lib/packaging.sh detect_pkg_manager echo "Detected: PKG_MANAGER=$PKG_MANAGER" echo "Expected: ${{ matrix.expected_pkg }}" if [[ "$PKG_MANAGER" != "${{ matrix.expected_pkg }}" ]]; then echo "FAIL: expected ${{ matrix.expected_pkg }}, got $PKG_MANAGER" exit 1 fi echo "PASS: package manager detection correct" - name: Test pkg_install (install jq + rsync) shell: bash run: | export LOG_FILE=/dev/null log() { echo "[INFO] $1"; } warn() { echo "[WARN] $1"; } error() { echo "[ERROR] $1"; exit 1; } source installers/lib/packaging.sh detect_pkg_manager pkg_update pkg_install curl jq rsync || echo "WARN: jq/rsync install failed (may not be in repos)" # Verify the core tools used by installer phases. if command -v curl &>/dev/null; then echo "PASS: curl available" else echo "FAIL: curl not available after pkg_install" exit 1 fi if command -v rsync &>/dev/null; then echo "PASS: rsync available" else echo "FAIL: rsync not available after pkg_install" exit 1 fi - name: Test installer bash syntax run: | bash -n install-core.sh bash -n installers/lib/packaging.sh for f in installers/phases/*.sh; do bash -n "$f" && echo " OK: $f" || echo " FAIL: $f" done macos-smoke: runs-on: macos-latest defaults: run: working-directory: ods steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: macOS Dispatch Smoke run: bash tests/smoke/macos-dispatch.sh - name: Bash 3.2 syntax check (catches declare -g, associative arrays, etc.) run: | echo "=== Checking installer scripts for Bash 3.2 compatibility ===" FAIL=0 for f in install-core.sh installers/phases/*.sh installers/lib/*.sh; do if [[ -f "$f" ]]; then # macOS ships Bash 3.2 at /bin/bash — use it for syntax check if /bin/bash -n "$f" 2>/dev/null; then echo " OK: $f" else echo " FAIL: $f" FAIL=1 fi fi done # Also check macOS-specific scripts for f in installers/macos/**/*.sh; do if [[ -f "$f" ]]; then if /bin/bash -n "$f" 2>/dev/null; then echo " OK: $f" else echo " FAIL: $f" FAIL=1 fi fi done if [[ $FAIL -eq 1 ]]; then echo "" echo "FAIL: Some scripts have Bash 3.2 syntax errors." echo "Common issues: declare -g, associative arrays (declare -A)," echo " &>> redirection, |& pipes, [[ with regex =~" exit 1 fi echo "PASS: All installer scripts parse under Bash 3.2"