From 8e4277bf414a2a222c7a72dfef36e3a6be4a0fc5 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 12:43:59 -0700 Subject: [PATCH 01/13] Add multi-platform and multi-compiler CI testing Docker script (scripts/test-in-docker.sh): - Add distro parameter: alpine, debian, ubuntu, fedora, rocky - Add compiler parameter: gcc, clang - Add --help and --list options - Generate appropriate Dockerfile per distro/package manager GitHub Actions CI (.github/workflows/ci.yml): - Convert test job to matrix strategy with 10 combinations - Test across 5 distros: Alpine (musl), Debian, Ubuntu, Fedora, Rocky (glibc) - Test both GCC and Clang compilers on all distros - Add ARM64 testing via QEMU emulation - Add timeout-minutes to prevent hung jobs - Use fail-fast: false to run all jobs even if one fails - Keep coverage job separate (unchanged) --- .github/workflows/ci.yml | 97 ++++++++++++++++- scripts/test-in-docker.sh | 217 +++++++++++++++++++++++++++++++++++--- 2 files changed, 297 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ab57d4..0857ed0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,12 +9,81 @@ on: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 15 + + strategy: + fail-fast: false + matrix: + include: + # Alpine - musl libc + - distro: alpine + image: alpine:3.22 + compiler: gcc + pkg_install: apk add --no-cache build-base cmake bash + + - distro: alpine + image: alpine:3.22 + compiler: clang + pkg_install: apk add --no-cache build-base cmake bash clang compiler-rt + + # Debian - glibc + - distro: debian + image: debian:bookworm + compiler: gcc + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake + + - distro: debian + image: debian:bookworm + compiler: clang + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang + + # Ubuntu - glibc + - distro: ubuntu + image: ubuntu:24.04 + compiler: gcc + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake + + - distro: ubuntu + image: ubuntu:24.04 + compiler: clang + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang + + # Fedora - glibc (latest compiler versions) + - distro: fedora + image: fedora:41 + compiler: gcc + pkg_install: dnf install -y gcc gcc-c++ cmake make + + - distro: fedora + image: fedora:41 + compiler: clang + pkg_install: dnf install -y gcc gcc-c++ cmake make clang + + # Rocky Linux - RHEL compatible + - distro: rocky + image: rockylinux:9 + compiler: gcc + pkg_install: dnf install -y gcc gcc-c++ cmake make + + - distro: rocky + image: rockylinux:9 + compiler: clang + pkg_install: dnf install -y gcc gcc-c++ cmake make clang + + container: + image: ${{ matrix.image }} + + name: ${{ matrix.distro }} / ${{ matrix.compiler }} + + env: + CC: ${{ matrix.compiler == 'clang' && 'clang' || 'gcc' }} + CXX: ${{ matrix.compiler == 'clang' && 'clang++' || 'g++' }} steps: - uses: actions/checkout@v5 - name: Install dependencies - run: sudo apt-get update && sudo apt-get install -y cmake + run: ${{ matrix.pkg_install }} - name: Build and test (with sanitizers) run: | @@ -22,8 +91,34 @@ jobs: cmake --build build --parallel ctest --test-dir build --output-on-failure + test-arm64: + runs-on: ubuntu-latest + timeout-minutes: 30 + name: arm64 / gcc (QEMU) + + steps: + - uses: actions/checkout@v5 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + + - name: Build and test on ARM64 + run: | + docker run --rm --platform linux/arm64 \ + -v ${{ github.workspace }}:/src:ro \ + -w /build \ + arm64v8/alpine:3.22 sh -c " + apk add --no-cache build-base cmake bash && + cmake /src -DCMAKE_BUILD_TYPE=Debug && + cmake --build . --parallel && + ctest --output-on-failure + " + coverage: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v5 diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index 8e43b72..f5b33f8 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -2,34 +2,217 @@ # # Run pmtr tests in a Docker container (for macOS/Windows development) # -# Usage: ./scripts/test-in-docker.sh [build_type] -# build_type: Coverage (default), Debug, Release, or Sanitize +# Usage: ./scripts/test-in-docker.sh [options] [distro] [compiler] [build_type] +# +# distro: alpine (default), debian, ubuntu, fedora, rocky +# compiler: gcc (default), clang +# build_type: Coverage (default), Debug, Release, Sanitize +# +# Examples: +# ./scripts/test-in-docker.sh # alpine + gcc + Coverage +# ./scripts/test-in-docker.sh debian clang # debian + clang + Coverage +# ./scripts/test-in-docker.sh ubuntu gcc Debug # ubuntu + gcc + Debug +# ./scripts/test-in-docker.sh --list # show supported platforms # set -e -BUILD_TYPE="${1:-Coverage}" -IMAGE_NAME="pmtr-test" +show_help() { + cat << 'EOF' +Usage: ./scripts/test-in-docker.sh [options] [distro] [compiler] [build_type] + +Options: + --help, -h Show this help message + --list List all supported distro/compiler combinations + +Arguments: + distro Linux distribution (default: alpine) + Supported: alpine, debian, ubuntu, fedora, rocky + + compiler Compiler to use (default: gcc) + Supported: gcc, clang + + build_type CMake build type (default: Coverage) + Supported: Coverage, Debug, Release, Sanitize + +Examples: + ./scripts/test-in-docker.sh # alpine + gcc + Coverage + ./scripts/test-in-docker.sh debian clang # debian + clang + Coverage + ./scripts/test-in-docker.sh ubuntu gcc Debug # ubuntu + gcc + Debug + ./scripts/test-in-docker.sh fedora clang Sanitize +EOF +} + +show_list() { + cat << 'EOF' +Supported platform/compiler combinations: + + Distro libc Compilers Base Image + ────────────────────────────────────────────────────────── + alpine musl gcc, clang alpine:3.22 + debian glibc gcc, clang debian:bookworm + ubuntu glibc gcc, clang ubuntu:24.04 + fedora glibc gcc, clang fedora:41 + rocky glibc gcc, clang rockylinux:9 + +Notes: + - Coverage build uses lcov/gcov (GCC-based, may not work with clang) + - Sanitize build works best with recent GCC or clang +EOF +} + +# Parse options +case "${1:-}" in + --help|-h) + show_help + exit 0 + ;; + --list) + show_list + exit 0 + ;; +esac + +DISTRO="${1:-alpine}" +COMPILER="${2:-gcc}" +BUILD_TYPE="${3:-Coverage}" + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -echo "Building test container..." -docker build -t "$IMAGE_NAME" -f - "$PROJECT_DIR" << 'DOCKERFILE' +# Validate distro +case "$DISTRO" in + alpine|debian|ubuntu|fedora|rocky) ;; + *) + echo "Error: Unknown distro '$DISTRO'" + echo "Supported: alpine, debian, ubuntu, fedora, rocky" + exit 1 + ;; +esac + +# Validate compiler +case "$COMPILER" in + gcc|clang) ;; + *) + echo "Error: Unknown compiler '$COMPILER'" + echo "Supported: gcc, clang" + exit 1 + ;; +esac + + +# Validate build type +case "$BUILD_TYPE" in + Coverage|Debug|Release|Sanitize) ;; + *) + echo "Error: Unknown build type '$BUILD_TYPE'" + echo "Supported: Coverage, Debug, Release, Sanitize" + exit 1 + ;; +esac + +# Coverage with clang requires different tooling +if [ "$BUILD_TYPE" = "Coverage" ] && [ "$COMPILER" = "clang" ]; then + echo "Warning: Coverage build uses gcov/lcov which is GCC-based" + echo " Results may be incomplete with clang" +fi + +IMAGE_NAME="pmtr-test-${DISTRO}-${COMPILER}" + +# Generate Dockerfile based on distro +generate_dockerfile() { + case "$DISTRO" in + alpine) + cat << EOF FROM alpine:3.22 +RUN apk add --no-cache \\ + build-base \\ + cmake \\ + lcov \\ + bash \\ + gzip \\ + $( [ "$COMPILER" = "clang" ] && echo "clang compiler-rt" ) +EOF + ;; + debian) + cat << EOF +FROM debian:bookworm +RUN apt-get update && apt-get install -y --no-install-recommends \\ + build-essential \\ + cmake \\ + lcov \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + && rm -rf /var/lib/apt/lists/* +EOF + ;; + ubuntu) + cat << EOF +FROM ubuntu:24.04 +RUN apt-get update && apt-get install -y --no-install-recommends \\ + build-essential \\ + cmake \\ + lcov \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + && rm -rf /var/lib/apt/lists/* +EOF + ;; + fedora) + cat << EOF +FROM fedora:41 +RUN dnf install -y \\ + gcc \\ + g++ \\ + cmake \\ + make \\ + lcov \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + && dnf clean all +EOF + ;; + rocky) + cat << EOF +FROM rockylinux:9 +RUN dnf install -y \\ + gcc \\ + gcc-c++ \\ + cmake \\ + make \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + && dnf install -y epel-release \\ + && dnf install -y lcov \\ + && dnf clean all +EOF + ;; + esac + echo "WORKDIR /src" +} + +# Set compiler environment variables for cmake +get_compiler_env() { + if [ "$COMPILER" = "clang" ]; then + echo "CC=clang CXX=clang++" + else + echo "CC=gcc CXX=g++" + fi +} + +echo "========================================" +echo "Platform: $DISTRO" +echo "Compiler: $COMPILER" +echo "Build: $BUILD_TYPE" +echo "========================================" +echo "" -RUN apk add --no-cache \ - build-base \ - cmake \ - lcov \ - bash \ - gzip +echo "Building test container ($IMAGE_NAME)..." +generate_dockerfile | docker build -t "$IMAGE_NAME" -f - "$PROJECT_DIR" -WORKDIR /src -DOCKERFILE +echo "" +echo "Running tests..." -echo "Running tests with BUILD_TYPE=$BUILD_TYPE..." +COMPILER_ENV=$(get_compiler_env) if [ "$BUILD_TYPE" = "Coverage" ]; then docker run --rm -v "$PROJECT_DIR:/src:ro" -w /build "$IMAGE_NAME" bash -c " + export $COMPILER_ENV && \ cmake /src -DCMAKE_BUILD_TYPE=Coverage && \ cmake --build . --parallel && \ ctest --output-on-failure && \ @@ -41,10 +224,12 @@ if [ "$BUILD_TYPE" = "Coverage" ]; then " else docker run --rm -v "$PROJECT_DIR:/src:ro" -w /build "$IMAGE_NAME" bash -c " + export $COMPILER_ENV && \ cmake /src -DCMAKE_BUILD_TYPE=$BUILD_TYPE && \ cmake --build . --parallel && \ ctest --output-on-failure " fi -echo "Done!" +echo "" +echo "Done! ($DISTRO + $COMPILER + $BUILD_TYPE)" From 11c19314ac4fc2210e7655c01b408138a398d957 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 12:56:39 -0700 Subject: [PATCH 02/13] Add sanitizer runtime packages for CI matrix Fix build failures by adding missing sanitizer libraries: - Alpine gcc: gcc-sanitizer - Debian/Ubuntu clang: libclang-rt-dev - Fedora gcc: libasan libubsan - Fedora clang: compiler-rt - Rocky gcc: libasan libubsan --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0857ed0..3c9c090 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - distro: alpine image: alpine:3.22 compiler: gcc - pkg_install: apk add --no-cache build-base cmake bash + pkg_install: apk add --no-cache build-base cmake bash gcc-sanitizer - distro: alpine image: alpine:3.22 @@ -35,7 +35,7 @@ jobs: - distro: debian image: debian:bookworm compiler: clang - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev # Ubuntu - glibc - distro: ubuntu @@ -46,24 +46,24 @@ jobs: - distro: ubuntu image: ubuntu:24.04 compiler: clang - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev # Fedora - glibc (latest compiler versions) - distro: fedora image: fedora:41 compiler: gcc - pkg_install: dnf install -y gcc gcc-c++ cmake make + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan - distro: fedora image: fedora:41 compiler: clang - pkg_install: dnf install -y gcc gcc-c++ cmake make clang + pkg_install: dnf install -y gcc gcc-c++ cmake make clang compiler-rt # Rocky Linux - RHEL compatible - distro: rocky image: rockylinux:9 compiler: gcc - pkg_install: dnf install -y gcc gcc-c++ cmake make + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan - distro: rocky image: rockylinux:9 From 32f8a261be2d696bd9f0b20753ef2dd68e9b1db8 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 12:59:25 -0700 Subject: [PATCH 03/13] Fix CI: Alpine sanitizers and missing pgrep - Alpine gcc: Use Debug build (no sanitizer support on musl) - Add procps/procps-ng for pgrep command used by e2e tests - Use matrix.build_type to allow per-job build type configuration --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9c090..d39eabc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,60 +15,70 @@ jobs: fail-fast: false matrix: include: - # Alpine - musl libc + # Alpine - musl libc (no sanitizer support for gcc on musl) - distro: alpine image: alpine:3.22 compiler: gcc - pkg_install: apk add --no-cache build-base cmake bash gcc-sanitizer + build_type: Debug + pkg_install: apk add --no-cache build-base cmake bash - distro: alpine image: alpine:3.22 compiler: clang + build_type: Sanitize pkg_install: apk add --no-cache build-base cmake bash clang compiler-rt # Debian - glibc - distro: debian image: debian:bookworm compiler: gcc - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake + build_type: Sanitize + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake procps - distro: debian image: debian:bookworm compiler: clang - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev + build_type: Sanitize + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev procps # Ubuntu - glibc - distro: ubuntu image: ubuntu:24.04 compiler: gcc - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake + build_type: Sanitize + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake procps - distro: ubuntu image: ubuntu:24.04 compiler: clang - pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev + build_type: Sanitize + pkg_install: apt-get update && apt-get install -y --no-install-recommends build-essential cmake clang libclang-rt-dev procps # Fedora - glibc (latest compiler versions) - distro: fedora image: fedora:41 compiler: gcc - pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng - distro: fedora image: fedora:41 compiler: clang - pkg_install: dnf install -y gcc gcc-c++ cmake make clang compiler-rt + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make clang compiler-rt procps-ng # Rocky Linux - RHEL compatible - distro: rocky image: rockylinux:9 compiler: gcc - pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng - distro: rocky image: rockylinux:9 compiler: clang - pkg_install: dnf install -y gcc gcc-c++ cmake make clang + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make clang procps-ng container: image: ${{ matrix.image }} @@ -85,9 +95,9 @@ jobs: - name: Install dependencies run: ${{ matrix.pkg_install }} - - name: Build and test (with sanitizers) + - name: Build and test run: | - cmake -B build -DCMAKE_BUILD_TYPE=Sanitize + cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} cmake --build build --parallel ctest --test-dir build --output-on-failure From 1d6184c6153e53f52376e5614ebfb09b3743f8ea Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:01:24 -0700 Subject: [PATCH 04/13] Sync Docker test script with CI configuration - Add procps/procps-ng for pgrep (needed by e2e tests) - Add sanitizer packages: libclang-rt-dev, libasan, libubsan, compiler-rt - Auto-switch Alpine + gcc + Sanitize to Debug (musl limitation) - Update help notes --- scripts/test-in-docker.sh | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index f5b33f8..7bbc41e 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -55,8 +55,8 @@ Supported platform/compiler combinations: rocky glibc gcc, clang rockylinux:9 Notes: + - Alpine + gcc: Sanitize build not supported (musl), auto-switches to Debug - Coverage build uses lcov/gcov (GCC-based, may not work with clang) - - Sanitize build works best with recent GCC or clang EOF } @@ -116,6 +116,13 @@ if [ "$BUILD_TYPE" = "Coverage" ] && [ "$COMPILER" = "clang" ]; then echo " Results may be incomplete with clang" fi +# Alpine gcc doesn't support sanitizers (musl libc limitation) +if [ "$DISTRO" = "alpine" ] && [ "$COMPILER" = "gcc" ] && [ "$BUILD_TYPE" = "Sanitize" ]; then + echo "Warning: Alpine + gcc does not support sanitizers (musl libc limitation)" + echo " Switching to Debug build" + BUILD_TYPE="Debug" +fi + IMAGE_NAME="pmtr-test-${DISTRO}-${COMPILER}" # Generate Dockerfile based on distro @@ -140,7 +147,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \\ build-essential \\ cmake \\ lcov \\ - $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + procps \\ + $( [ "$COMPILER" = "clang" ] && echo "clang libclang-rt-dev" ) \\ && rm -rf /var/lib/apt/lists/* EOF ;; @@ -151,7 +159,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \\ build-essential \\ cmake \\ lcov \\ - $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + procps \\ + $( [ "$COMPILER" = "clang" ] && echo "clang libclang-rt-dev" ) \\ && rm -rf /var/lib/apt/lists/* EOF ;; @@ -160,11 +169,12 @@ EOF FROM fedora:41 RUN dnf install -y \\ gcc \\ - g++ \\ + gcc-c++ \\ cmake \\ make \\ lcov \\ - $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + procps-ng \\ + $( [ "$COMPILER" = "clang" ] && echo "clang compiler-rt" || echo "libasan libubsan" ) \\ && dnf clean all EOF ;; @@ -176,7 +186,8 @@ RUN dnf install -y \\ gcc-c++ \\ cmake \\ make \\ - $( [ "$COMPILER" = "clang" ] && echo "clang" ) \\ + procps-ng \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" || echo "libasan libubsan" ) \\ && dnf install -y epel-release \\ && dnf install -y lcov \\ && dnf clean all From d035e7b7bb6c9ddd2ad04bdd1748ae6e74630f34 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:11:05 -0700 Subject: [PATCH 05/13] Add Amazon Linux, Arch Linux, and Gentoo to CI matrix CI additions: - Amazon Linux 2023: gcc + Sanitize (AWS environment) - Arch Linux: gcc + clang + Sanitize (rolling release, latest compilers) - Gentoo: gcc + Debug (source-based, slower build) Docker script additions: - Support for amazonlinux, arch, gentoo distros - Warning for Gentoo + clang (requires manual setup) - Updated help text and platform list --- .github/workflows/ci.yml | 29 ++++++++++++++++++++++- scripts/test-in-docker.sh | 50 +++++++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d39eabc..968eb94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: jobs: test: runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 30 strategy: fail-fast: false @@ -80,6 +80,33 @@ jobs: build_type: Sanitize pkg_install: dnf install -y gcc gcc-c++ cmake make clang procps-ng + # Amazon Linux 2023 - AWS + - distro: amazonlinux + image: amazonlinux:2023 + compiler: gcc + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng + + # Arch Linux - rolling release, latest compilers + - distro: arch + image: archlinux:base + compiler: gcc + build_type: Sanitize + pkg_install: pacman -Syu --noconfirm base-devel cmake procps-ng + + - distro: arch + image: archlinux:base + compiler: clang + build_type: Sanitize + pkg_install: pacman -Syu --noconfirm base-devel cmake clang procps-ng + + # Gentoo - source-based, uses stage3 with prebuilt gcc + - distro: gentoo + image: gentoo/stage3 + compiler: gcc + build_type: Debug + pkg_install: emerge --sync --quiet && emerge -q dev-build/cmake sys-process/procps + container: image: ${{ matrix.image }} diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index 7bbc41e..1ae339f 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -4,7 +4,7 @@ # # Usage: ./scripts/test-in-docker.sh [options] [distro] [compiler] [build_type] # -# distro: alpine (default), debian, ubuntu, fedora, rocky +# distro: alpine (default), debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo # compiler: gcc (default), clang # build_type: Coverage (default), Debug, Release, Sanitize # @@ -26,7 +26,7 @@ Options: Arguments: distro Linux distribution (default: alpine) - Supported: alpine, debian, ubuntu, fedora, rocky + Supported: alpine, debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo compiler Compiler to use (default: gcc) Supported: gcc, clang @@ -53,9 +53,13 @@ Supported platform/compiler combinations: ubuntu glibc gcc, clang ubuntu:24.04 fedora glibc gcc, clang fedora:41 rocky glibc gcc, clang rockylinux:9 + amazonlinux glibc gcc, clang amazonlinux:2023 + arch glibc gcc, clang archlinux:base + gentoo glibc gcc gentoo/stage3 Notes: - Alpine + gcc: Sanitize build not supported (musl), auto-switches to Debug + - Gentoo: Only gcc tested (clang requires manual setup) - Coverage build uses lcov/gcov (GCC-based, may not work with clang) EOF } @@ -81,10 +85,10 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # Validate distro case "$DISTRO" in - alpine|debian|ubuntu|fedora|rocky) ;; + alpine|debian|ubuntu|fedora|rocky|amazonlinux|arch|gentoo) ;; *) echo "Error: Unknown distro '$DISTRO'" - echo "Supported: alpine, debian, ubuntu, fedora, rocky" + echo "Supported: alpine, debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo" exit 1 ;; esac @@ -116,6 +120,12 @@ if [ "$BUILD_TYPE" = "Coverage" ] && [ "$COMPILER" = "clang" ]; then echo " Results may be incomplete with clang" fi +# Gentoo with clang requires manual setup +if [ "$DISTRO" = "gentoo" ] && [ "$COMPILER" = "clang" ]; then + echo "Warning: Gentoo + clang requires manual clang installation" + echo " This combination is not tested in CI" +fi + # Alpine gcc doesn't support sanitizers (musl libc limitation) if [ "$DISTRO" = "alpine" ] && [ "$COMPILER" = "gcc" ] && [ "$BUILD_TYPE" = "Sanitize" ]; then echo "Warning: Alpine + gcc does not support sanitizers (musl libc limitation)" @@ -191,6 +201,38 @@ RUN dnf install -y \\ && dnf install -y epel-release \\ && dnf install -y lcov \\ && dnf clean all +EOF + ;; + amazonlinux) + cat << EOF +FROM amazonlinux:2023 +RUN dnf install -y \\ + gcc \\ + gcc-c++ \\ + cmake \\ + make \\ + procps-ng \\ + tar gzip \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" || echo "libasan libubsan" ) \\ + && dnf clean all +EOF + ;; + arch) + cat << EOF +FROM archlinux:base +RUN pacman -Syu --noconfirm \\ + base-devel \\ + cmake \\ + lcov \\ + procps-ng \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" ) +EOF + ;; + gentoo) + cat << EOF +FROM gentoo/stage3 +RUN emerge --sync --quiet && \\ + emerge -q dev-build/cmake sys-process/procps EOF ;; esac From 8065c3c797db4ffd60dd17e30d2b2df4e902fbd0 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:15:19 -0700 Subject: [PATCH 06/13] Fix Amazon Linux CI (add tar) and use Gentoo binary packages --- .github/workflows/ci.yml | 6 +++--- scripts/test-in-docker.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 968eb94..4da8c29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: image: amazonlinux:2023 compiler: gcc build_type: Sanitize - pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng tar gzip # Arch Linux - rolling release, latest compilers - distro: arch @@ -100,12 +100,12 @@ jobs: build_type: Sanitize pkg_install: pacman -Syu --noconfirm base-devel cmake clang procps-ng - # Gentoo - source-based, uses stage3 with prebuilt gcc + # Gentoo - uses binary packages for faster CI - distro: gentoo image: gentoo/stage3 compiler: gcc build_type: Debug - pkg_install: emerge --sync --quiet && emerge -q dev-build/cmake sys-process/procps + pkg_install: emerge-webrsync && emerge --getbinpkg -q dev-build/cmake sys-process/procps container: image: ${{ matrix.image }} diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index 1ae339f..4986f8b 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -231,8 +231,8 @@ EOF gentoo) cat << EOF FROM gentoo/stage3 -RUN emerge --sync --quiet && \\ - emerge -q dev-build/cmake sys-process/procps +RUN emerge-webrsync && \\ + emerge --getbinpkg -q dev-build/cmake sys-process/procps EOF ;; esac From 52fa817e38edfa3d8791ef1590ee583733928cdb Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:17:38 -0700 Subject: [PATCH 07/13] Fix Amazon Linux: install tar before checkout step --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4da8c29..27a9302 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: image: amazonlinux:2023 compiler: gcc build_type: Sanitize - pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng tar gzip + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng # Arch Linux - rolling release, latest compilers - distro: arch @@ -117,6 +117,10 @@ jobs: CXX: ${{ matrix.compiler == 'clang' && 'clang++' || 'g++' }} steps: + - name: Install tar (Amazon Linux) + if: matrix.distro == 'amazonlinux' + run: dnf install -y tar gzip + - uses: actions/checkout@v5 - name: Install dependencies From fe5efdcbd4049bd4cb58e787b509cad391f0262e Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:18:09 -0700 Subject: [PATCH 08/13] Fix Gentoo: use source compilation (binary packages need GPG setup) --- .github/workflows/ci.yml | 4 ++-- scripts/test-in-docker.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27a9302..4875ad2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,12 +100,12 @@ jobs: build_type: Sanitize pkg_install: pacman -Syu --noconfirm base-devel cmake clang procps-ng - # Gentoo - uses binary packages for faster CI + # Gentoo - source-based (binary packages need GPG setup) - distro: gentoo image: gentoo/stage3 compiler: gcc build_type: Debug - pkg_install: emerge-webrsync && emerge --getbinpkg -q dev-build/cmake sys-process/procps + pkg_install: emerge-webrsync && emerge -q dev-build/cmake sys-process/procps container: image: ${{ matrix.image }} diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index 4986f8b..b5b0a3c 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -232,7 +232,7 @@ EOF cat << EOF FROM gentoo/stage3 RUN emerge-webrsync && \\ - emerge --getbinpkg -q dev-build/cmake sys-process/procps + emerge -q dev-build/cmake sys-process/procps EOF ;; esac From 0fff22e85823de39c90fcaa3233e2333ffe2082d Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:18:51 -0700 Subject: [PATCH 09/13] Add arm64/clang test (QEMU) --- .github/workflows/ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4875ad2..c454e50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,7 +135,19 @@ jobs: test-arm64: runs-on: ubuntu-latest timeout-minutes: 30 - name: arm64 / gcc (QEMU) + + strategy: + fail-fast: false + matrix: + include: + - compiler: gcc + pkg_extra: "" + cc: gcc + - compiler: clang + pkg_extra: "clang compiler-rt" + cc: clang + + name: arm64 / ${{ matrix.compiler }} (QEMU) steps: - uses: actions/checkout@v5 @@ -151,8 +163,8 @@ jobs: -v ${{ github.workspace }}:/src:ro \ -w /build \ arm64v8/alpine:3.22 sh -c " - apk add --no-cache build-base cmake bash && - cmake /src -DCMAKE_BUILD_TYPE=Debug && + apk add --no-cache build-base cmake bash ${{ matrix.pkg_extra }} && + CC=${{ matrix.cc }} cmake /src -DCMAKE_BUILD_TYPE=Debug && cmake --build . --parallel && ctest --output-on-failure " From 8616e5f1945ceab12b0d347f6158cc3b3e12b3fd Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:22:22 -0700 Subject: [PATCH 10/13] Add Oracle Linux 10 to CI matrix --- .github/workflows/ci.yml | 7 +++++++ scripts/test-in-docker.sh | 24 ++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c454e50..bdfec16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,6 +80,13 @@ jobs: build_type: Sanitize pkg_install: dnf install -y gcc gcc-c++ cmake make clang procps-ng + # Oracle Linux 10 - Oracle Cloud + - distro: oraclelinux + image: oraclelinux:10 + compiler: gcc + build_type: Sanitize + pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng + # Amazon Linux 2023 - AWS - distro: amazonlinux image: amazonlinux:2023 diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index b5b0a3c..40d51ad 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -4,7 +4,7 @@ # # Usage: ./scripts/test-in-docker.sh [options] [distro] [compiler] [build_type] # -# distro: alpine (default), debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo +# distro: alpine (default), debian, ubuntu, fedora, rocky, oraclelinux, amazonlinux, arch, gentoo # compiler: gcc (default), clang # build_type: Coverage (default), Debug, Release, Sanitize # @@ -26,7 +26,7 @@ Options: Arguments: distro Linux distribution (default: alpine) - Supported: alpine, debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo + Supported: alpine, debian, ubuntu, fedora, rocky, oraclelinux, amazonlinux, arch, gentoo compiler Compiler to use (default: gcc) Supported: gcc, clang @@ -53,6 +53,7 @@ Supported platform/compiler combinations: ubuntu glibc gcc, clang ubuntu:24.04 fedora glibc gcc, clang fedora:41 rocky glibc gcc, clang rockylinux:9 + oraclelinux glibc gcc, clang oraclelinux:10 amazonlinux glibc gcc, clang amazonlinux:2023 arch glibc gcc, clang archlinux:base gentoo glibc gcc gentoo/stage3 @@ -85,10 +86,10 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # Validate distro case "$DISTRO" in - alpine|debian|ubuntu|fedora|rocky|amazonlinux|arch|gentoo) ;; + alpine|debian|ubuntu|fedora|rocky|oraclelinux|amazonlinux|arch|gentoo) ;; *) echo "Error: Unknown distro '$DISTRO'" - echo "Supported: alpine, debian, ubuntu, fedora, rocky, amazonlinux, arch, gentoo" + echo "Supported: alpine, debian, ubuntu, fedora, rocky, oraclelinux, amazonlinux, arch, gentoo" exit 1 ;; esac @@ -201,6 +202,21 @@ RUN dnf install -y \\ && dnf install -y epel-release \\ && dnf install -y lcov \\ && dnf clean all +EOF + ;; + oraclelinux) + cat << EOF +FROM oraclelinux:10 +RUN dnf install -y \\ + gcc \\ + gcc-c++ \\ + cmake \\ + make \\ + procps-ng \\ + $( [ "$COMPILER" = "clang" ] && echo "clang" || echo "libasan libubsan" ) \\ + && dnf install -y oracle-epel-release-el10 \\ + && dnf install -y lcov \\ + && dnf clean all EOF ;; amazonlinux) From 24cc2e36288adbf74a49d726b20652320446c47a Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:29:43 -0700 Subject: [PATCH 11/13] Fix Gentoo: use getuto for GPG keys, enable binary packages --- .github/workflows/ci.yml | 4 ++-- scripts/test-in-docker.sh | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdfec16..cc21cc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,12 +107,12 @@ jobs: build_type: Sanitize pkg_install: pacman -Syu --noconfirm base-devel cmake clang procps-ng - # Gentoo - source-based (binary packages need GPG setup) + # Gentoo - binary packages (getuto sets up GPG keys) - distro: gentoo image: gentoo/stage3 compiler: gcc build_type: Debug - pkg_install: emerge-webrsync && emerge -q dev-build/cmake sys-process/procps + pkg_install: export MAKEOPTS="-j$(nproc)" && getuto && emerge-webrsync && emerge --getbinpkg -q dev-build/cmake sys-process/procps container: image: ${{ matrix.image }} diff --git a/scripts/test-in-docker.sh b/scripts/test-in-docker.sh index 40d51ad..a9a4c47 100755 --- a/scripts/test-in-docker.sh +++ b/scripts/test-in-docker.sh @@ -247,8 +247,10 @@ EOF gentoo) cat << EOF FROM gentoo/stage3 -RUN emerge-webrsync && \\ - emerge -q dev-build/cmake sys-process/procps +ENV MAKEOPTS="-j\$(nproc)" +RUN getuto && \\ + emerge-webrsync && \\ + emerge --getbinpkg -q dev-build/cmake sys-process/procps EOF ;; esac From 3ab2b7572fcce1980e30fb9e8ae398efff5be4d4 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:32:21 -0700 Subject: [PATCH 12/13] Refactor: use matrix prereqs variable for checkout dependencies --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc21cc2..6313f43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,11 +87,12 @@ jobs: build_type: Sanitize pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng - # Amazon Linux 2023 - AWS + # Amazon Linux 2023 - AWS (needs tar for checkout) - distro: amazonlinux image: amazonlinux:2023 compiler: gcc build_type: Sanitize + prereqs: dnf install -y tar gzip pkg_install: dnf install -y gcc gcc-c++ cmake make libasan libubsan procps-ng # Arch Linux - rolling release, latest compilers @@ -124,9 +125,9 @@ jobs: CXX: ${{ matrix.compiler == 'clang' && 'clang++' || 'g++' }} steps: - - name: Install tar (Amazon Linux) - if: matrix.distro == 'amazonlinux' - run: dnf install -y tar gzip + - name: Install checkout prerequisites + if: matrix.prereqs + run: ${{ matrix.prereqs }} - uses: actions/checkout@v5 From c6b8f148789917317457467c97d71b15b5e4fd25 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 13:36:51 -0700 Subject: [PATCH 13/13] ci: add weekly scheduled run with per-platform failure issues - Runs every Sunday at 00:00 UTC - Creates GitHub issue on failure (only for scheduled runs) - Uses unique label per distro/compiler to prevent duplicate issues - Only creates issue if no open issue with same label exists --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6313f43..73b2e39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: branches: [ master, main ] pull_request: branches: [ master, main ] + schedule: + # Run weekly on Sundays at 00:00 UTC + - cron: '0 0 * * 0' jobs: test: @@ -140,6 +143,25 @@ jobs: cmake --build build --parallel ctest --test-dir build --output-on-failure + - name: Create issue on scheduled failure + if: failure() && github.event_name == 'schedule' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + LABEL="ci:${{ matrix.distro }}-${{ matrix.compiler }}" + EXISTING=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number') + if [ -z "$EXISTING" ]; then + gh label create "$LABEL" --color D93F0B --description "CI failure for ${{ matrix.distro }}/${{ matrix.compiler }}" 2>/dev/null || true + gh issue create \ + --title "CI: ${{ matrix.distro }}/${{ matrix.compiler }} scheduled build failure" \ + --label "$LABEL" \ + --body "The scheduled CI run failed for **${{ matrix.distro }}** with **${{ matrix.compiler }}**. + + **Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + + This may be due to upstream distro/package changes. Close this issue once fixed." + fi + test-arm64: runs-on: ubuntu-latest timeout-minutes: 30 @@ -177,6 +199,25 @@ jobs: ctest --output-on-failure " + - name: Create issue on scheduled failure + if: failure() && github.event_name == 'schedule' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + LABEL="ci:arm64-${{ matrix.compiler }}" + EXISTING=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number') + if [ -z "$EXISTING" ]; then + gh label create "$LABEL" --color D93F0B --description "CI failure for arm64/${{ matrix.compiler }}" 2>/dev/null || true + gh issue create \ + --title "CI: arm64/${{ matrix.compiler }} scheduled build failure" \ + --label "$LABEL" \ + --body "The scheduled CI run failed for **arm64** with **${{ matrix.compiler }}**. + + **Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + + This may be due to upstream distro/package changes. Close this issue once fixed." + fi + coverage: runs-on: ubuntu-latest timeout-minutes: 15 @@ -196,3 +237,4 @@ jobs: run: | ctest --test-dir build --output-on-failure make -C build coverage +