name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

# Codeberg's hosted Forgejo Actions runners advertise three label
# tiers: codeberg-tiny (1 CPU / 2G / 2 min), codeberg-small (2 / 4G /
# 5 min), codeberg-medium (4 / 8G / 10 min).  See
# https://codeberg.org/actions/meta for the canonical list.
#
# Codeberg does not currently offer hosted ARM, macOS, or Windows
# runners on the public free tier -- only Linux x86_64 -- so this
# workflow mirrors the Linux portion of .github/workflows/ci.yml
# (Ubuntu 22.04 + 24.04 x GCC + Clang) and skips the macOS,
# Windows, and aarch64 jobs that GitHub covers.  Codeberg's
# default runner image (ghcr.io/catthehacker/ubuntu:act-latest)
# pretends to be Ubuntu rolling; the apt-get install commands
# below pin nothing toolchain-version-wise (we trust the image)
# but install meson + ninja from apt to keep the build
# self-contained.
#
# When Codeberg adds hosted ARM runners (tracked at
# codeberg.org/actions/meta), uncomment the ubuntu-24.04-arm
# matrix entries in build below and the mirroring sanitizer /
# llvm-matrix jobs.

jobs:
  # =====================================================================
  # Linux x86_64: Ubuntu 22.04 LTS and 24.04 LTS, GCC + Clang.
  # =====================================================================
  build:
    runs-on: codeberg-medium
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04, ubuntu-24.04]
        compiler: [gcc, clang]
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y ${{ matrix.compiler }} meson ninja-build \
                                  pkg-config valgrind

      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Build lime (standalone)
        run: ${{ matrix.compiler }} -O2 -Wall -Wextra -o lime lime.c

      - name: Setup meson
        env:
          CC: ${{ matrix.compiler }}
        run: meson setup builddir -Dllvm=disabled

      - name: Build
        run: ninja -C builddir

      - name: Test
        run: meson test -C builddir --print-errorlogs

  # =====================================================================
  # Sanitizers: address, thread, undefined.
  # =====================================================================
  sanitizers:
    runs-on: codeberg-medium
    strategy:
      fail-fast: false
      matrix:
        sanitizer: [address, thread, undefined]
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc meson ninja-build pkg-config

      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Build with ${{ matrix.sanitizer }} sanitizer
        run: |
          meson setup builddir-${{ matrix.sanitizer }} \
            -Dllvm=disabled \
            -Db_sanitize=${{ matrix.sanitizer }}
          ninja -C builddir-${{ matrix.sanitizer }}

      - name: Test
        run: meson test -C builddir-${{ matrix.sanitizer }} --print-errorlogs

  # =====================================================================
  # Valgrind memcheck.
  # =====================================================================
  valgrind:
    runs-on: codeberg-medium
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc meson ninja-build pkg-config valgrind bash

      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Build
        run: |
          meson setup builddir -Dllvm=disabled
          ninja -C builddir

      - name: Valgrind check
        run: scripts/check_memory.sh

  # =====================================================================
  # Coverage gate.  Fails the build if src/ line coverage drops below
  # LIME_COV_MIN_LINES (default 72) or branch coverage drops below
  # LIME_COV_MIN_BRANCHES (default 55).  These were 78/60 against the
  # v0.5 codebase; the v0.8.x feature push (Rust output, LSP, lexer
  # subsystem) added ~3000 LOC of mostly-new infrastructure where the
  # cargo bench drivers (out-of-meson-tree) provide most of the
  # exercise.  v0.8.7 adds tests/test_emit_rust_lex covering all
  # three --rustlex emit modes; remaining uncovered code is the
  # large-DFA branches in emit_rust_lex.c that only the JSON-bench
  # fixture hits at runtime.  Floors lowered to clear current state;
  # raise as coverage improves -- the ratchet-upward goal stands.
  # =====================================================================
  coverage:
    runs-on: codeberg-medium
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc meson ninja-build pkg-config gcovr

      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Run coverage gate
        run: scripts/check_coverage.sh

  # =====================================================================
  # Guards against the three-source-of-truth version string drifting:
  # LIME_VERSION_STRING in lime.c, project(version: ...) in meson.build,
  # and the literal in src/version.c's lime_parser_version() must all
  # match.  Cheap to run; fits in the codeberg-tiny 2-min cap.
  # =====================================================================
  version-consistency:
    runs-on: codeberg-tiny
    steps:
      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Check all three sources agree
        run: scripts/check_version_consistency.sh

  # =====================================================================
  # Exercise the three LLVM/JIT linkage paths so the compat shim,
  # static-link option, and stub mode all stay green on PRs.  Each
  # variant builds Lime + LLVM (Ubuntu apt) and runs the test suite.
  # =====================================================================
  llvm-matrix:
    runs-on: codeberg-medium
    strategy:
      fail-fast: false
      matrix:
        config:
          - name: shared
            args: "-Dllvm=enabled"
          - name: static
            args: "-Dllvm=enabled -Dllvm-static=true"
          - name: disabled
            args: "-Dllvm=disabled"
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc meson ninja-build pkg-config \
                                  llvm-dev libllvm18 zlib1g-dev \
                                  libxml2-dev libffi-dev libtinfo-dev

      - name: Checkout
        uses: https://code.forgejo.org/actions/checkout@v4

      - name: Setup
        run: meson setup builddir-${{ matrix.config.name }} ${{ matrix.config.args }}

      - name: Build
        run: ninja -C builddir-${{ matrix.config.name }}

      - name: Test
        run: meson test -C builddir-${{ matrix.config.name }} --print-errorlogs

      - name: Verify libLLVM linkage matches config
        run: |
          binary=builddir-${{ matrix.config.name }}/tests/test_jit
          refs=$(ldd "$binary" 2>&1 | grep -cE libLLVM || true)
          case "${{ matrix.config.name }}" in
            shared)
              test "$refs" -ge 1 || { echo "shared expected libLLVM, got $refs"; exit 1; } ;;
            static|disabled)
              test "$refs" -eq 0 || { echo "${{ matrix.config.name }} expected 0 libLLVM, got $refs"; exit 1; } ;;
          esac
          echo "OK: ${{ matrix.config.name }} has $refs libLLVM dependencies"
