name: sysrepo CI
on:
  push:
    branches:
      - master
      - devel
  pull_request:
    branches:
      - master
      - devel

jobs:
  git-branch:
    name: Get git branch
    runs-on: ubuntu-latest
    outputs:
      branch-name: ${{ steps.get-git-branch.outputs.branch-name }}
    steps:
      - id: get-git-branch
        run: |
          if ${{ github.event_name == 'push' }}
            then export GIT_BRANCH=`echo ${{ github.ref }} | cut -d'/' -f 3`
          else
            export GIT_BRANCH=${{ github.base_ref }}
          fi
          echo "branch-name=$GIT_BRANCH" >> $GITHUB_OUTPUT

  build:
    name: ${{ matrix.config.name }}
    runs-on: ${{ matrix.config.os }} # mac-OS does not implement robust mutexes so it is not supported
    needs: git-branch
    strategy:
      fail-fast: false
      matrix:
        config:
          - {
            name: "Release, gcc",
            os: "ubuntu-latest",
            build-type: "Release",
            dep-build-type: "Release",
            cc: "gcc",
            options: "-DENABLE_TESTS=ON",
            packages: "libcmocka-dev",
            snaps: "",
            make-target: ""
          }
          - {
            name: "Release, clang",
            os: "ubuntu-latest",
            build-type: "Release",
            dep-build-type: "Release",
            cc: "clang",
            options: "-DENABLE_TESTS=ON",
            packages: "libcmocka-dev",
            snaps: "",
            make-target: ""
          }
          - {
            name: "Debug, gcc",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "Debug, clang",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "clang",
            options: "",
            # no valgrind because it does not support DWARF5 yet generated by clang 14
            packages: "libcmocka-dev",
            snaps: "",
            make-target: ""
          }
          - {
            name: "ASAN and UBSAN",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "clang",
            options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_TESTS=ON -DENABLE_VALGRIND_TESTS=OFF",
            packages: "libcmocka-dev",
            snaps: "",
            make-target: "",
            ubsan-options: "print_stacktrace=1:halt_on_error=1",
          }
          - {
            name: "Printed context OFF",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "-DPRINTED_CONTEXT_ADDRESS=0",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "MONGO DS plugin",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "-DENABLE_DS_MONGO=ON -DDEFAULT_STARTUP_DS_PLG=\"MONGO DS\" -DDEFAULT_RUNNING_DS_PLG=\"MONGO DS\" -DDEFAULT_CANDIDATE_DS_PLG=\"MONGO DS\" -DDEFAULT_OPERATIONAL_DS_PLG=\"MONGO DS\" -DDEFAULT_FACTORY_DEFAULT_DS_PLG=\"MONGO DS\"",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "MONGO DS plugin latest",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "-DENABLE_DS_MONGO=ON -DDEFAULT_STARTUP_DS_PLG=\"MONGO DS\" -DDEFAULT_RUNNING_DS_PLG=\"MONGO DS\" -DDEFAULT_CANDIDATE_DS_PLG=\"MONGO DS\" -DDEFAULT_OPERATIONAL_DS_PLG=\"MONGO DS\" -DDEFAULT_FACTORY_DEFAULT_DS_PLG=\"MONGO DS\"",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "REDIS DS plugin",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "-DENABLE_DS_REDIS=ON -DDEFAULT_STARTUP_DS_PLG=\"REDIS DS\" -DDEFAULT_RUNNING_DS_PLG=\"REDIS DS\" -DDEFAULT_CANDIDATE_DS_PLG=\"REDIS DS\" -DDEFAULT_OPERATIONAL_DS_PLG=\"REDIS DS\" -DDEFAULT_FACTORY_DEFAULT_DS_PLG=\"REDIS DS\"",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "REDIS DS plugin latest",
            os: "ubuntu-latest",
            build-type: "Debug",
            dep-build-type: "Debug",
            cc: "gcc",
            options: "-DENABLE_DS_REDIS=ON -DDEFAULT_STARTUP_DS_PLG=\"REDIS DS\" -DDEFAULT_RUNNING_DS_PLG=\"REDIS DS\" -DDEFAULT_CANDIDATE_DS_PLG=\"REDIS DS\" -DDEFAULT_OPERATIONAL_DS_PLG=\"REDIS DS\" -DDEFAULT_FACTORY_DEFAULT_DS_PLG=\"REDIS DS\"",
            packages: "libcmocka-dev valgrind",
            snaps: "",
            make-target: ""
          }
          - {
            name: "DEB Package",
            os: "ubuntu-latest",
            build-type: "Release",
            dep-build-type: "Release",
            cc: "gcc",
            options: "",
            packages: "cmake debhelper libsystemd-dev libcmocka-dev valgrind python3-pip",
            snaps: "",
            make-target: ""
          }
    env:
      UBSAN_OPTIONS: ${{ matrix.config.ubsan-options }}

    steps:
      - uses: actions/checkout@main
        with:
          fetch-depth: 100

      - name: Deps-packages
        shell: bash
        run: |
          sudo apt-get update
          if ${{ matrix.config.packages != '' }}
            then sudo apt-get install ${{ matrix.config.packages }}
          fi
          if ${{ matrix.config.snaps != '' }}
            then sudo snap install ${{ matrix.config.snaps }}
          fi
          if ${{ matrix.config.name == 'DEB Package' }}; then
            pip install apkg
            apkg system-setup
          fi

      - name: Deps-uncrustify
        shell: bash
        working-directory: ${{ github.workspace }}
        run: |
          git clone --branch uncrustify-0.77.1 https://github.com/uncrustify/uncrustify
          cd uncrustify
          mkdir build
          cd build
          CC=${{ matrix.config.cc }} cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ..
          make
          sudo make install
        if: ${{ matrix.config.name == 'Debug, gcc' }}

      - name: Deps-libyang
        shell: bash
        run: |
          git clone -b ${{ needs.git-branch.outputs.branch-name }} https://github.com/CESNET/libyang.git
          cd libyang
          if ${{ matrix.config.name == 'DEB Package' }}; then
            apkg build
            apkg install
          else
            mkdir build
            cd build
            CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_TESTS=OFF ..
            make -j2
            sudo make install
          fi

      - name: Build-and-install-package
        shell: bash
        working-directory: ${{ github.workspace }}
        run: |
          apkg build
          apkg install
        if: ${{ matrix.config.name == 'DEB Package' }}

      - name: Deps-MongoDB
        shell: bash
        run: |
          curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
          echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
          sudo apt-get update
          sudo apt-get install -y mongodb-org
          sudo service mongod start
        if: ${{ matrix.config.name == 'MONGO DS plugin' ||  matrix.config.name == 'MONGO DS plugin latest' }}

      - name: Deps-libmongoc
        shell: bash
        run: |
          wget https://github.com/mongodb/mongo-c-driver/releases/download/1.24.0/mongo-c-driver-1.24.0.tar.gz
          tar xzf mongo-c-driver-1.24.0.tar.gz
          cd mongo-c-driver-1.24.0
          mkdir cmake-build
          cd cmake-build
          cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF ..
          cmake --build .
          sudo cmake --build . --target install
        if: ${{ matrix.config.name == 'MONGO DS plugin' }}

      - name: Deps-libmongoc-latest
        shell: bash
        run: |
          git clone https://github.com/mongodb/mongo-c-driver.git
          cd mongo-c-driver
          cmake -S . -B ./_build -DENABLE_EXTRA_ALIGNMENT=OFF -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_MONGOC=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5
          cmake --build ./_build --config RelWithDebInfo --parallel
          sudo cmake --install "./_build" --prefix "/usr/local"
        if: ${{ matrix.config.name == 'MONGO DS plugin latest' }}

      - name: Deps-RedisDB
        shell: bash
        # use jammy (22.04) since redis-stack-server is not available on noble (24.04) yet!
        run: |
          curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
          sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
          echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb jammy main" | sudo tee /etc/apt/sources.list.d/redis.list
          sudo apt-get update
          sudo apt-get install redis-stack-server
          sudo service redis-stack-server start
        if: ${{ matrix.config.name == 'REDIS DS plugin' || matrix.config.name == 'REDIS DS plugin latest' }}

      - name: Deps-libhiredis
        shell: bash
        run: |
          wget https://github.com/redis/hiredis/archive/refs/tags/v1.1.0.tar.gz
          tar xzf v1.1.0.tar.gz
          cd hiredis-1.1.0
          make
          sudo make install
        if: ${{ matrix.config.name == 'REDIS DS plugin' }}

      - name: Deps-libhiredis-latest
        shell: bash
        run: |
          git clone https://github.com/redis/hiredis.git
          cd hiredis
          make
          sudo make install
        if: ${{ matrix.config.name == 'REDIS DS plugin latest' }}

      - name: Configure
        shell: bash
        working-directory: ${{ github.workspace }}
        run: |
          mkdir build
          cd build
          CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
        if: ${{ matrix.config.name != 'DEB Package' }}

      - name: Build
        shell: bash
        working-directory: ${{ github.workspace }}/build
        run: |
          export LC_ALL=C.UTF-8
          export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH
          make ${{ matrix.config.make-target }}
        if: ${{ matrix.config.name != 'DEB Package' }}

      - name: Test
        shell: bash
        working-directory: ${{ github.workspace }}/build
        run: ctest --output-on-failure
        if: ${{ matrix.config.name != 'DEB Package' }}

  build-linux-32bit:
    name: Release, Linux 32-bit, gcc
    runs-on: ubuntu-latest
    needs: git-branch
    steps:
      - uses: actions/checkout@main

      - name: Build in 32-bit container
        run: |
          docker run --rm \
            -v ${{ github.workspace }}:${{ github.workspace }} \
            -w ${{ github.workspace }} \
            i386/ubuntu \
            /bin/bash -c " \
              apt-get update -q && \
              apt-get install -y -q git cmake gcc g++ libcmocka-dev valgrind libxxhash-dev libpcre2-dev && \

              git clone -b ${{ needs.git-branch.outputs.branch-name }} https://github.com/CESNET/libyang.git && \
              cd libyang && mkdir build && cd build && \
              cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=OFF .. && \
              make -j2 && \
              make install && \
              cd ../.. && \

              mkdir build && cd build && \
              cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=ON .. && \
              make && \
              ctest --output-on-failure \
            "

  build-big-endian:
    name: Release, Big-endian, s390x
    runs-on: ubuntu-latest
    needs: git-branch
    steps:
      - uses: actions/checkout@main

      - name: Build and test
        # use QEMU user-static emulation to run non-x86 Linux
        uses: uraimo/run-on-arch-action@master
        with:
          arch: s390x
          distro: ubuntu22.04

          # speeds up build by caching Docker images in GitHub Packages
          githubToken: ${{ github.token }}

          # map the build directory to the container
          dockerRunArgs: |
            --volume "${PWD}:/workspace"

          # install dependencies inside the emulated container
          install: |
            apt-get update -q -y
            apt-get install -q -y git cmake gcc g++ libcmocka-dev valgrind libxxhash-dev libpcre2-dev

          # run the build
          run: |
            set -e

            git clone -b ${{ needs.git-branch.outputs.branch-name }} https://github.com/CESNET/libyang.git
            cd libyang && mkdir build && cd build
            cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=OFF ..
            make -j2
            make install
            cd ../..

            mkdir build
            cd build
            cmake -DPRINTED_CONTEXT_ADDRESS=0 -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=ON ..
            make
            ctest --output-on-failure
