Skip to content

fix: ensure ansible-playbook runs with bash shell in Docker containers #81

fix: ensure ansible-playbook runs with bash shell in Docker containers

fix: ensure ansible-playbook runs with bash shell in Docker containers #81

name: Multi-Platform Bootstrap Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch: # Allow manual trigger
jobs:
# ===========================================================================
# macOS Tests
# ===========================================================================
test-macos-15:
name: macOS 15 (Sequoia) - ARM64
runs-on: macos-15 # M1/M2/M3 runner, latest
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(sw_vers -productName) $(sw_vers -productVersion)"
echo "Architecture: $(uname -m)"
echo "Hostname: $(hostname)"
uname -a
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Homebrew environment dynamically
if [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Development Tools ==="
python3 --version || echo "python3 not found"
node --version || echo "Node not in PATH yet"
go version || echo "Go not in PATH yet"
echo -e "\n=== Verifying CLI Tools ==="
fzf --version || echo "fzf not found"
rg --version 2>&1 | head -1 || echo "ripgrep not found"
bat --version || echo "bat not found"
echo -e "\n=== Verifying Package Managers ==="
brew --version || echo "brew not found"
~/.local/bin/mise --version || echo "mise not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
- name: Check Ansible RECAP
run: |
echo "Checking for Ansible failures..."
# This will be in the bootstrap output
# We can't easily grep it here, but the step will fail if bootstrap failed
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: macos-15-logs
path: |
/tmp/*.log
~/Library/Logs/Homebrew/
test-macos-14:
name: macOS 14 (Sonoma) - ARM64
runs-on: macos-14 # M1/M2 runner
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(sw_vers -productName) $(sw_vers -productVersion)"
echo "Architecture: $(uname -m)"
echo "Hostname: $(hostname)"
uname -a
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Homebrew environment dynamically
if [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Development Tools ==="
python3 --version || echo "python3 not found"
node --version || echo "Node not in PATH yet"
go version || echo "Go not in PATH yet"
echo -e "\n=== Verifying CLI Tools ==="
fzf --version || echo "fzf not found"
rg --version 2>&1 | head -1 || echo "ripgrep not found"
bat --version || echo "bat not found"
echo -e "\n=== Verifying Package Managers ==="
brew --version || echo "brew not found"
~/.local/bin/mise --version || echo "mise not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
- name: Check Ansible RECAP
run: |
echo "Checking for Ansible failures..."
# This will be in the bootstrap output
# We can't easily grep it here, but the step will fail if bootstrap failed
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: macos-14-logs
path: |
/tmp/*.log
~/Library/Logs/Homebrew/
test-macos-13:
name: macOS 13 (Ventura) - x86_64
runs-on: macos-13 # Intel runner
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(sw_vers -productName) $(sw_vers -productVersion)"
echo "Architecture: $(uname -m)"
uname -a
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
eval "$(/opt/homebrew/bin/brew shellenv)"
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: macos-13-logs
path: |
/tmp/*.log
~/Library/Logs/Homebrew/
test-macos-12:
name: macOS 12 (Monterey) - x86_64
runs-on: macos-12 # Intel runner
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(sw_vers -productName) $(sw_vers -productVersion)"
echo "Architecture: $(uname -m)"
uname -a
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
eval "$(/opt/homebrew/bin/brew shellenv)"
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: macos-12-logs
path: |
/tmp/*.log
~/Library/Logs/Homebrew/
# ===========================================================================
# Ubuntu Tests (Native Runners)
# ===========================================================================
test-ubuntu-24:
name: Ubuntu 24.04 LTS (Noble)
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(lsb_release -d | cut -f2)"
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
df -h
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
export DEBIAN_FRONTEND=noninteractive
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Development Tools ==="
python3 --version || echo "python3 not found"
node --version || echo "Node not in PATH yet"
go version || echo "Go not in PATH yet"
echo -e "\n=== Verifying CLI Tools ==="
fzf --version || echo "fzf not found"
rg --version 2>&1 | head -1 || echo "ripgrep not found"
batcat --version || bat --version || echo "bat not found"
echo -e "\n=== Verifying Databases ==="
psql --version || echo "psql not found"
sqlite3 --version || echo "sqlite3 not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
echo -e "\n=== Verifying Vim Symlinks ==="
ls -la /usr/local/bin/vim || echo "vim symlink not found"
ls -la /usr/local/bin/vi || echo "vi symlink not found"
- name: Check for zero failures
run: |
if [ -f ~/.devkit/.bootstrap_success ]; then
echo "✅ Bootstrap completed successfully!"
exit 0
else
echo "❌ ERROR: Bootstrap did not complete successfully!"
echo ""
echo "=== Bootstrap logs ==="
if [ -f ~/.devkit/logs/setup.log ]; then
tail -100 ~/.devkit/logs/setup.log || true
fi
exit 1
fi
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ubuntu-24-logs
path: |
/tmp/*.log
~/.ansible/
test-ubuntu-22:
name: Ubuntu 22.04 LTS (Jammy)
runs-on: ubuntu-22.04
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(lsb_release -d | cut -f2)"
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
export DEBIAN_FRONTEND=noninteractive
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
fi
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ubuntu-22-logs
path: |
/tmp/*.log
test-ubuntu-20:
name: Ubuntu 20.04 LTS (Focal)
runs-on: ubuntu-20.04
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
echo "OS: $(lsb_release -d | cut -f2)"
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
- name: Run bootstrap
run: |
chmod +x bootstrap.sh
export DEBIAN_FRONTEND=noninteractive
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ubuntu-20-logs
path: |
/tmp/*.log
# ===========================================================================
# Debian Tests (Docker Containers)
# ===========================================================================
test-debian-12:
name: Debian 12 (Bookworm) - Docker
runs-on: ubuntu-latest
container:
image: debian:12
options: --user root
timeout-minutes: 45
steps:
- name: Install git, bash, and curl (needed for checkout and bootstrap)
run: |
apt-get update -y
apt-get install -y git bash curl build-essential
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
cat /etc/os-release
uname -a
- name: Run bootstrap
shell: bash
run: |
chmod +x bootstrap.sh
export DEBIAN_FRONTEND=noninteractive
# Run bootstrap with verbose output and capture errors
bash -x bootstrap.sh 2>&1 | tee /tmp/bootstrap.log || {
EXIT_CODE=$?
echo "Bootstrap failed with exit code $EXIT_CODE"
echo "=== Last 50 lines of output ==="
tail -50 /tmp/bootstrap.log || true
exit $EXIT_CODE
}
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: debian-12-logs
path: /tmp/*.log
test-debian-11:
name: Debian 11 (Bullseye) - Docker
runs-on: ubuntu-latest
container:
image: debian:11
options: --user root
timeout-minutes: 45
steps:
- name: Install git, bash, and curl (needed for checkout and bootstrap)
run: |
apt-get update -y
apt-get install -y git bash curl build-essential
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
cat /etc/os-release
uname -a
- name: Run bootstrap
shell: bash
run: |
chmod +x bootstrap.sh
export DEBIAN_FRONTEND=noninteractive
# Run bootstrap with verbose output and capture errors
bash -x bootstrap.sh 2>&1 | tee /tmp/bootstrap.log || {
EXIT_CODE=$?
echo "Bootstrap failed with exit code $EXIT_CODE"
echo "=== Last 50 lines of output ==="
tail -50 /tmp/bootstrap.log || true
exit $EXIT_CODE
}
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: debian-11-logs
path: /tmp/*.log
# ===========================================================================
# Test Summary
# ===========================================================================
test-summary:
name: Test Summary
needs:
- test-macos-15
- test-macos-14
- test-macos-13
- test-macos-12
- test-ubuntu-24
- test-ubuntu-22
- test-ubuntu-20
- test-debian-12
- test-debian-11
- test-fedora-40
- test-arch-linux
runs-on: ubuntu-latest
if: always()
steps:
- name: Check test results
run: |
echo "=== Test Results Summary ==="
echo ""
echo "Native Runners (Critical):"
echo " macOS 15 (Sequoia): ${{ needs.test-macos-15.result }}"
echo " macOS 14 (Sonoma): ${{ needs.test-macos-14.result }}"
echo " macOS 13 (Ventura): ${{ needs.test-macos-13.result }}"
echo " macOS 12 (Monterey): ${{ needs.test-macos-12.result }}"
echo " Ubuntu 24.04 (Noble): ${{ needs.test-ubuntu-24.result }}"
echo " Ubuntu 22.04 (Jammy): ${{ needs.test-ubuntu-22.result }}"
echo " Ubuntu 20.04 (Focal): ${{ needs.test-ubuntu-20.result }}"
echo ""
echo "Container Tests (Informational):"
echo " Debian 12 (Bookworm): ${{ needs.test-debian-12.result }}"
echo " Debian 11 (Bullseye): ${{ needs.test-debian-11.result }}"
echo " Fedora 40: ${{ needs.test-fedora-40.result }}"
echo " Arch Linux: ${{ needs.test-arch-linux.result }}"
echo ""
# Count critical vs informational failures
critical_failures=0
info_failures=0
# Critical tests (native runners)
[[ "${{ needs.test-macos-15.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-macos-14.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-macos-13.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-macos-12.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-ubuntu-24.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-ubuntu-22.result }}" != "success" ]] && ((critical_failures++))
[[ "${{ needs.test-ubuntu-20.result }}" != "success" ]] && ((critical_failures++))
# Informational tests (containers - may have transient failures)
[[ "${{ needs.test-debian-12.result }}" != "success" ]] && ((info_failures++))
[[ "${{ needs.test-debian-11.result }}" != "success" ]] && ((info_failures++))
[[ "${{ needs.test-fedora-40.result }}" != "success" ]] && ((info_failures++))
[[ "${{ needs.test-arch-linux.result }}" != "success" ]] && ((info_failures++))
critical_total=7
info_total=4
critical_successes=$((critical_total - critical_failures))
info_successes=$((info_total - info_failures))
echo "=== Final Results ==="
echo "Critical (Native): $critical_successes/$critical_total passed"
echo "Informational (Containers): $info_successes/$info_total passed"
echo ""
if [ $critical_failures -gt 0 ]; then
echo "⚠️ Some critical tests failed. Check the logs above."
exit 1
else
echo "✓ All critical tests passed!"
if [ $info_failures -gt 0 ]; then
echo "ℹ️ Note: $info_failures informational container tests had issues (non-blocking)"
fi
fi
# ===========================================================================
# Fedora/Arch Tests (Now Fully Supported!)
# ===========================================================================
test-fedora-40:
name: Fedora 40 - Docker
runs-on: ubuntu-latest
container:
image: fedora:40
options: --user root
timeout-minutes: 45
steps:
- name: Install git, curl and build tools (needed for checkout and bootstrap)
run: |
dnf install -y git curl gcc g++ make
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
cat /etc/os-release
uname -a
- name: Run bootstrap
shell: bash
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: fedora-40-logs
path: /tmp/*.log
test-arch-linux:
name: Arch Linux - Docker
runs-on: ubuntu-latest
container:
image: archlinux:latest
options: --user root
timeout-minutes: 45
steps:
- name: Install git, curl and build tools (needed for checkout and bootstrap)
run: |
pacman -Sy --noconfirm git curl base-devel
- name: Checkout code
uses: actions/checkout@v4
- name: Show system info
run: |
cat /etc/os-release
uname -a
- name: Run bootstrap
shell: bash
run: |
chmod +x bootstrap.sh
./bootstrap.sh
env:
CI: true
- name: Verify installations
run: |
# Source Linuxbrew environment dynamically
if [ -f /home/linuxbrew/.linuxbrew/bin/brew ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -f /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
elif command -v brew &> /dev/null; then
eval "$(brew shellenv)"
fi
echo "PATH=$PATH"
echo "=== Verifying Core Tools ==="
git --version || echo "git not found"
zsh --version || echo "zsh not found"
tmux -V || echo "tmux not found"
nvim --version 2>&1 | head -1 || echo "nvim not found"
echo -e "\n=== Verifying Config Files ==="
ls -la ~/.zshrc || echo ".zshrc not found"
ls -la ~/.tmux.conf || echo ".tmux.conf not found"
ls -la ~/.config/nvim/ || echo "nvim config not found"
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: arch-linux-logs
path: /tmp/*.log