name: CI

on: [push, pull_request]

concurrency:
  group: ci-${{ github.head_ref || github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  test-ubuntu-latest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        # Fail build if there are warnings
        # build with TLS just for compilation coverage
        run: make -j4 all-with-unit-tests SERVER_CFLAGS='-Werror' BUILD_TLS=yes USE_FAST_FLOAT=yes
      - name: install old server for compatibility testing
        run: |
          cd tests/tmp
          wget https://download.valkey.io/releases/valkey-7.2.7-noble-x86_64.tar.gz
          tar -xvf valkey-7.2.7-noble-x86_64.tar.gz
      - name: test
        run: |
          sudo apt-get install tcl8.6 tclx
          ./runtest --verbose --tags -slow --dump-logs --other-server-path tests/tmp/valkey-7.2.7-noble-x86_64/bin/valkey-server
      - name: module api test
        run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs --other-server-path tests/tmp/valkey-7.2.7-noble-x86_64/bin/valkey-server
      - name: validate commands.def up to date
        run: |
          touch src/commands/ping.json
          make commands.def
          dirty=$(git diff)
          if [[ ! -z  $dirty ]]; then echo $dirty; exit 1; fi
      - name: unit tests
        run: |
          ./src/valkey-unit-tests

  test-ubuntu-latest-cmake:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: cmake and make
        run: |
          sudo apt-get install -y cmake libssl-dev
          mkdir -p build-release
          cd build-release
          cmake -DCMAKE_BUILD_TYPE=Release .. -DBUILD_TLS=yes -DBUILD_UNIT_TESTS=yes
          make -j$(nproc)
      - name: test
        run: |
          sudo apt-get install -y tcl8.6 tclx
          ln -sf $(pwd)/build-release/bin/valkey-server $(pwd)/src/valkey-server
          ln -sf $(pwd)/build-release/bin/valkey-cli $(pwd)/src/valkey-cli
          ln -sf $(pwd)/build-release/bin/valkey-benchmark $(pwd)/src/valkey-benchmark
          ln -sf $(pwd)/build-release/bin/valkey-server $(pwd)/src/valkey-check-aof
          ln -sf $(pwd)/build-release/bin/valkey-server $(pwd)/src/valkey-check-rdb
          ln -sf $(pwd)/build-release/bin/valkey-server $(pwd)/src/valkey-sentinel
          ./runtest --verbose --tags -slow --dump-logs
      - name: unit tests
        run: |
          ./build-release/bin/valkey-unit-tests

  test-sanitizer-address:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        # build with TLS module just for compilation coverage
        run: make -j4 all-with-unit-tests SANITIZER=address SERVER_CFLAGS='-Werror' BUILD_TLS=module
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx -y
      - name: test
        run: ./runtest --verbose --tags -slow --dump-logs
      - name: module api test
        run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs
      - name: unit tests
        run: ./src/valkey-unit-tests

  test-rdma:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: prepare-development-libraries
        run: sudo apt-get install librdmacm-dev libibverbs-dev
      - name: make-rdma-module
        run: make -j4 BUILD_RDMA=module
      - name: make-rdma-builtin
        run: |
          make distclean
          make -j4 BUILD_RDMA=yes
      - name: clone-rxe-kmod
        run: |
          mkdir -p tests/rdma/rxe
          git clone https://github.com/pizhenwei/rxe.git tests/rdma/rxe
          make -C tests/rdma/rxe
      - name: clear-kernel-log
        run: sudo dmesg -c > /dev/null
      - name: test
        run: sudo ./runtest-rdma --install-rxe
      - name: show-kernel-log
        run: sudo dmesg -c

  build-debian-old:
    runs-on: ubuntu-latest
    container: debian:buster
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        run: |
          apt-get update && apt-get install -y build-essential
          make -j4 SERVER_CFLAGS='-Werror'

  build-macos-latest:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        # Build with additional upcoming features
        run: make -j3 all-with-unit-tests SERVER_CFLAGS='-Werror' USE_FAST_FLOAT=yes

  build-32bit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        # Fast float requires C++ 32-bit libraries to compile on 64-bit ubuntu
        # machine i.e. "-cross" suffixed version. Cross-compiling c++ to 32-bit
        # also requires multilib support for g++ compiler i.e. "-multilib"
        # suffixed version of g++. g++-multilib generally includes libstdc++.
        # *cross version as well, but it is also added explicitly just in case.
        run: |
          sudo apt-get update
          sudo apt-get install libc6-dev-i386 libstdc++-11-dev-i386-cross gcc-multilib g++-multilib
          make -j4 SERVER_CFLAGS='-Werror' 32bit USE_FAST_FLOAT=yes

  build-libc-malloc:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - name: make
        run: make -j4 SERVER_CFLAGS='-Werror' MALLOC=libc USE_FAST_FLOAT=yes

  build-almalinux8-jemalloc:
    runs-on: ubuntu-latest
    container: almalinux:8
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: make
        run: |
          dnf -y install epel-release gcc gcc-c++ make procps-ng which
          make -j4 SERVER_CFLAGS='-Werror' USE_FAST_FLOAT=yes

  format-yaml:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Set up Go
        uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
        with:
          go-version: "1.22.4"

      - name: Setup YAML formatter
        run: |
          go install github.com/google/yamlfmt/cmd/yamlfmt@latest

      - name: Run yamlfmt
        id: yamlfmt
        run: |
          yamlfmt -lint -conf .config/format.yml .
          # Capture the diff output
          DIFF=$(git diff)
          if [ ! -z "$DIFF" ]; then
            # Encode the diff in Base64 to ensure it's handled as a single line
            ENCODED_DIFF=$(echo "$DIFF" | base64 -w 0)
            echo "diff=$ENCODED_DIFF" >> $GITHUB_OUTPUT
          fi
        shell: bash

      - name: Check for formatting changes
        if: ${{ steps.yamlfmt.outputs.diff }}
        run: |
          echo "ERROR: YAML file is not formatted properly. Here is the diff: "
          # Decode the Base64 diff to display it
          echo "${{ steps.clang-format.outputs.diff }}" | base64 --decode
          exit 1
        shell: bash
