diff --git a/.github/workflows/gauntlet.yml b/.github/workflows/gauntlet.yml index 6cddd7f6..fc025b7a 100644 --- a/.github/workflows/gauntlet.yml +++ b/.github/workflows/gauntlet.yml @@ -1,4 +1,6 @@ name: GNU CRY GAUNTLET +permissions: + contents: read on: push: @@ -7,36 +9,56 @@ on: branches: [ main ] jobs: - gauntlet: + gating: runs-on: ubuntu-latest - name: C23 Compiler GAUNTLET + name: C23 Gating Compilers strategy: matrix: - compiler: [gcc-12, gcc-13, clang-18, clang-19, clang-20] + compiler: [gcc-14, clang-20] fail-fast: false - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build ${{ matrix.compiler }} Docker image - run: | - echo "🔥 Building ${{ matrix.compiler }} Docker image..." - docker build --target ${{ matrix.compiler }} -t gauntlet-${{ matrix.compiler }}:latest -f tools/gauntlet/Dockerfile.gauntlet . - - - name: Run ${{ matrix.compiler }} GAUNTLET - run: | - echo "🔫 Running ${{ matrix.compiler }} GAUNTLET..." - docker run --rm -v "$PWD":/workspace -w /workspace gauntlet-${{ matrix.compiler }}:latest - - - name: Upload build logs on failure - if: failure() - uses: actions/upload-artifact@v4 - with: - name: gauntlet-logs-${{ matrix.compiler }} - path: | - build/ - retention-days: 7 \ No newline at end of file + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Build ${{ matrix.compiler }} Docker image + run: | + echo "🔥 Building ${{ matrix.compiler }} Docker image (gating)..." + docker build --target ${{ matrix.compiler }} -t gauntlet-${{ matrix.compiler }}:latest -f tools/gauntlet/Dockerfile.gauntlet . + - name: Run ${{ matrix.compiler }} GAUNTLET + run: | + echo "🔫 Running ${{ matrix.compiler }} GAUNTLET (gating)..." + docker run --rm -v "$PWD":/workspace -w /workspace gauntlet-${{ matrix.compiler }}:latest + - name: Upload build logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: gauntlet-logs-${{ matrix.compiler }} + path: build/ + retention-days: 7 + + canary: + runs-on: ubuntu-latest + name: Compat Canaries (non-blocking) + continue-on-error: true + needs: [gating] + strategy: + matrix: + compiler: [gcc-12, gcc-13, clang-18, clang-19] + fail-fast: false + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Build ${{ matrix.compiler }} Docker image + run: | + echo "🐤 Building ${{ matrix.compiler }} Docker image (canary)..." + docker build --target ${{ matrix.compiler }} -t gauntlet-${{ matrix.compiler }}:latest -f tools/gauntlet/Dockerfile.gauntlet . + - name: Run ${{ matrix.compiler }} GAUNTLET + run: | + echo "🐤 Running ${{ matrix.compiler }} GAUNTLET (canary)..." + docker run --rm -v "$PWD":/workspace -w /workspace gauntlet-${{ matrix.compiler }}:latest + - name: Upload build logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: gauntlet-logs-${{ matrix.compiler }} + path: build/ + retention-days: 7 diff --git a/docs/CI_STRATEGY.md b/docs/CI_STRATEGY.md new file mode 100644 index 00000000..cbf61609 --- /dev/null +++ b/docs/CI_STRATEGY.md @@ -0,0 +1,62 @@ +# CI/CD Strategy + +## Overview +This repository enforces high correctness and portability while centering on modern C23. CI is split into: +- Gating jobs that must pass for merges +- Canary jobs that provide early portability signals but do not block +- Static analysis (clang-tidy) with a strict baseline +- Deterministic Docker builds to ensure local=CI parity + +## Compiler Matrix + +### Gating (C23 focus) + +- `gcc-14` — first broadly usable GCC with C23 support +- `clang-20` — latest LLVM with strong C23 + clang-tidy 20 + +Rationale: These represent the C23 target surface we care about. They block the PR when they fail. + +### Canaries (non‑blocking) + +- `gcc-12`, `gcc-13` — older GCCs common on LTS distros +- `clang-18`, `clang-19` — earlier LLVMs + +Rationale: Useful signals for downstream consumers. They run with `continue-on-error: true` so they never block merges. + +```mermaid +flowchart LR + A[Gating: gcc-14] --> M[Merge] + B[Gating: clang-20] --> M + C[Canary: gcc-13] -->|non-blocking| M + D[Canary: clang-19] -->|non-blocking| M + E[Canary: gcc-12] -->|non-blocking| M + F[Canary: clang-18] -->|non-blocking| M +``` + +## Static Analysis + +- `clang-tidy` 20 with `quality/.clang-tidy`; warnings-as-errors. +- Baseline file `tools/baseline_count.txt` enforces no regressions. +- CI builds a deterministic LLVM 20 environment in Docker. +- CRoaring is installed from apt when available, or built from source in CI to stabilize aarch64 and older runners. + +## Builds & Tests + +- Meson + Ninja builds and runs unit tests. +- Cache artifacts are not pushed; they are derived and may be uploaded only for debugging. + +## Docker Hygiene + +- Images are namespaced and labeled for safe cleanup: `gitmind/ci:clang-20`, `gitmind/gauntlet:`; label `com.gitmind.project=git-mind`. +- Local helper: `make docker-clean` removes only project images/containers and builder cache. + +## Time & Cost + +- Gating jobs run in parallel and should complete under a few minutes. +- Canaries may be slower; they are non‑blocking and primarily diagnostic. + +## Future Enhancements + +- Add cohesion-report to CI to summarize semantic (advice) changes across merges. +- Nightly long‑matrix (more compilers/OSes) as a separate scheduled workflow. +- Cache Docker layers to reduce cold start times. diff --git a/tools/gauntlet/Dockerfile.gauntlet b/tools/gauntlet/Dockerfile.gauntlet index ee9c3356..c9b6e0b3 100644 --- a/tools/gauntlet/Dockerfile.gauntlet +++ b/tools/gauntlet/Dockerfile.gauntlet @@ -1,5 +1,5 @@ # Base image with common dependencies -FROM ubuntu:22.04 as base +FROM ubuntu:22.04 AS base LABEL com.gitmind.project="git-mind" \ org.opencontainers.image.title="git-mind-gauntlet" @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive ENV TZ=UTC # Install base dependencies -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ ninja-build \ python3 \ @@ -15,108 +15,137 @@ RUN apt-get update && apt-get install -y \ pkg-config \ libsodium-dev \ libgit2-dev \ + libroaring-dev \ git \ curl \ - meson + meson && rm -rf /var/lib/apt/lists/* +HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD sh -lc "$CC --version >/dev/null 2>&1 || exit 1" + +# Provide test runner in base so all targets inherit it +RUN echo '#!/bin/bash' > /test-compiler.sh && \ + echo 'set -e' >> /test-compiler.sh && \ + echo 'echo "🔫 Testing $CC..."' >> /test-compiler.sh && \ + echo 'echo "Compiler: $CC"' >> /test-compiler.sh && \ + echo 'echo "C++ Compiler: $CXX"' >> /test-compiler.sh && \ + echo '' >> /test-compiler.sh && \ + echo '# Clean previous build' >> /test-compiler.sh && \ + echo 'rm -rf build' >> /test-compiler.sh && \ + echo '' >> /test-compiler.sh && \ + echo '# Setup build with current compiler' >> /test-compiler.sh && \ + echo 'if meson setup build --warnlevel=3; then' >> /test-compiler.sh && \ + echo ' echo "✅ Meson setup successful"' >> /test-compiler.sh && \ + echo ' if ninja -C build; then' >> /test-compiler.sh && \ + echo ' echo "✅ Build successful"' >> /test-compiler.sh && \ + echo ' if ninja -C build test; then' >> /test-compiler.sh && \ + echo ' echo "✅ Tests passed"' >> /test-compiler.sh && \ + echo ' echo "PASS"' >> /test-compiler.sh && \ + echo ' else echo "❌ Tests failed"; echo "FAIL_TEST"; fi' >> /test-compiler.sh && \ + echo ' else echo "❌ Build failed"; echo "FAIL_BUILD"; fi' >> /test-compiler.sh && \ + echo 'else echo "❌ Meson setup failed"; echo "FAIL_SETUP"; fi' >> /test-compiler.sh && \ + chmod +x /test-compiler.sh +WORKDIR /workspace +CMD ["/test-compiler.sh"] # GCC 12 (THE DEVIL) - Pre-C23 image -FROM base as gcc-12 -RUN apt-get update && apt-get install -y \ +FROM base AS gcc-12 +RUN apt-get update && apt-get install -y --no-install-recommends \ software-properties-common \ wget \ gnupg && \ add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ apt-get update && \ - apt-get install -y gcc-12 g++-12 + apt-get install -y --no-install-recommends gcc-12 g++-12 && \ + rm -rf /var/lib/apt/lists/* ENV CC=gcc-12 ENV CXX=g++-12 # GCC 13 - C23 support image -FROM base as gcc-13 -RUN apt-get update && apt-get install -y \ +FROM base AS gcc-13 +RUN apt-get update && apt-get install -y --no-install-recommends \ software-properties-common \ wget \ gnupg && \ add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ apt-get update && \ - apt-get install -y gcc-13 g++-13 + apt-get install -y --no-install-recommends gcc-13 g++-13 && \ + rm -rf /var/lib/apt/lists/* ENV CC=gcc-13 ENV CXX=g++-13 # Clang 18 - C23 support image -FROM base as clang-18 -RUN apt-get update && apt-get install -y \ +FROM base AS clang-18 +RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ gnupg \ lsb-release \ software-properties-common && \ wget -O - https://apt.llvm.org/llvm.sh | bash -s -- 18 all && \ - apt-get install -y clang-18 clang++-18 clang-tidy-18 + apt-get install -y --no-install-recommends clang-18 clang++-18 clang-tidy-18 && \ + rm -rf /var/lib/apt/lists/* ENV CC=clang-18 ENV CXX=clang++-18 # Clang 19 - C23 support image -FROM base as clang-19 -RUN apt-get update && apt-get install -y \ +FROM base AS clang-19 +RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ gnupg \ lsb-release \ software-properties-common && \ wget -O - https://apt.llvm.org/llvm.sh | bash -s -- 19 all && \ - apt-get install -y clang-19 clang++-19 clang-tidy-19 + apt-get install -y --no-install-recommends clang-19 clang++-19 clang-tidy-19 && \ + rm -rf /var/lib/apt/lists/* ENV CC=clang-19 ENV CXX=clang++-19 # Clang 20 - Latest C23 support image -FROM base as clang-20 -RUN apt-get update && apt-get install -y \ +FROM base AS clang-20 +RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ gnupg \ lsb-release \ software-properties-common && \ wget -O - https://apt.llvm.org/llvm.sh | bash -s -- 20 all && \ - apt-get install -y clang-20 clang++-20 clang-tidy-20 + apt-get install -y --no-install-recommends clang-20 clang++-20 clang-tidy-20 && \ + rm -rf /var/lib/apt/lists/* ENV CC=clang-20 ENV CXX=clang++-20 -# Default to clang-20 for standalone usage -FROM clang-20 - -# Simple test script that works with any compiler +# Ubuntu 24.04 base (for gcc-14) +FROM ubuntu:24.04 AS base-noble +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + ninja-build \ + python3 \ + python3-pip \ + pkg-config \ + libsodium-dev \ + libgit2-dev \ + libroaring-dev \ + git \ + curl \ + meson && rm -rf /var/lib/apt/lists/* +HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD sh -lc "$CC --version >/dev/null 2>&1 || exit 1" +# Provide test runner in base-noble too RUN echo '#!/bin/bash' > /test-compiler.sh && \ echo 'set -e' >> /test-compiler.sh && \ echo 'echo "🔫 Testing $CC..."' >> /test-compiler.sh && \ echo 'echo "Compiler: $CC"' >> /test-compiler.sh && \ echo 'echo "C++ Compiler: $CXX"' >> /test-compiler.sh && \ - echo '' >> /test-compiler.sh && \ - echo '# Clean previous build' >> /test-compiler.sh && \ echo 'rm -rf build' >> /test-compiler.sh && \ - echo '' >> /test-compiler.sh && \ - echo '# Setup build with current compiler' >> /test-compiler.sh && \ echo 'if meson setup build --warnlevel=3; then' >> /test-compiler.sh && \ - echo ' echo "✅ Meson setup successful"' >> /test-compiler.sh && \ - echo ' ' >> /test-compiler.sh && \ - echo ' # Build' >> /test-compiler.sh && \ - echo ' if ninja -C build; then' >> /test-compiler.sh && \ - echo ' echo "✅ Build successful"' >> /test-compiler.sh && \ - echo ' ' >> /test-compiler.sh && \ - echo ' # Run tests' >> /test-compiler.sh && \ - echo ' if ninja -C build test; then' >> /test-compiler.sh && \ - echo ' echo "✅ Tests passed"' >> /test-compiler.sh && \ - echo ' echo "PASS"' >> /test-compiler.sh && \ - echo ' else' >> /test-compiler.sh && \ - echo ' echo "❌ Tests failed"' >> /test-compiler.sh && \ - echo ' echo "FAIL_TEST"' >> /test-compiler.sh && \ - echo ' fi' >> /test-compiler.sh && \ - echo ' else' >> /test-compiler.sh && \ - echo ' echo "❌ Build failed"' >> /test-compiler.sh && \ - echo ' echo "FAIL_BUILD"' >> /test-compiler.sh && \ - echo ' fi' >> /test-compiler.sh && \ - echo 'else' >> /test-compiler.sh && \ - echo ' echo "❌ Meson setup failed"' >> /test-compiler.sh && \ - echo ' echo "FAIL_SETUP"' >> /test-compiler.sh && \ - echo 'fi' >> /test-compiler.sh && \ + echo ' if ninja -C build; then' >> /test-compiler.sh && \ + echo ' if ninja -C build test; then echo "PASS"; else echo "FAIL_TEST"; fi' >> /test-compiler.sh && \ + echo ' else echo "FAIL_BUILD"; fi' >> /test-compiler.sh && \ + echo 'else echo "FAIL_SETUP"; fi' >> /test-compiler.sh && \ chmod +x /test-compiler.sh - WORKDIR /workspace CMD ["/test-compiler.sh"] + +# GCC 14 target (gating) +FROM base-noble AS gcc-14 +RUN apt-get update && apt-get install -y --no-install-recommends gcc-14 g++-14 && rm -rf /var/lib/apt/lists/* +ENV CC=gcc-14 +ENV CXX=g++-14