name: Linux

on: [push, pull_request]

jobs:
  build-linux:
    defaults:
      run:
        shell: bash
    name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
    runs-on: ubuntu-22.04
    permissions:
      actions: read
      contents: read
      security-events: write
    strategy:
      fail-fast: true
      matrix:
        build_type: [Release, Debug]
        lib: [shared, static]
        std: [14, 17, 20, 23]

    steps:
      - uses: actions/checkout@v4

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: cpp

      - name: Setup Dependencies
        run: |
          sudo apt-get update
          DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
            build-essential \
            cmake \
            gcovr \
            libgflags-dev \
            libunwind-dev \
            ninja-build

      - name: Cache GTest
        id: cache-gtest
        uses: actions/cache@v4
        with:
          path: gtest/
          key: ${{runner.os}}-gtest-1.11

      - name: Download GTest
        if: steps.cache-gtest.outputs.cache-hit != 'true'
        run: |
          wget https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz
          tar xvf release-1.11.0.tar.gz

      - name: Build GTest
        if: steps.cache-gtest.outputs.cache-hit != 'true'
        run: |
          cmake -S googletest-release-1.11.0 -B build-googletest \
            -DBUILD_SHARED_LIBS=${{matrix.shared}} \
            -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest \
            -G Ninja
          cmake --build build-googletest --target install

      - name: Setup Environment
        if: matrix.build_type == 'Debug'
        run: |
          echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
          echo 'GTest_ROOT=${{github.workspace}}/gtest' >> $GITHUB_ENV

      - name: Configure
        env:
          CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
        run: |
          cmake -S . -B build_${{matrix.build_type}} \
            -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
            -DCMAKE_CXX_STANDARD=${{matrix.std}} \
            -DCMAKE_CXX_STANDARD_REQUIRED=ON \
            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
            -G Ninja \
            -Werror

      - name: Build
        run: |
          cmake --build build_${{matrix.build_type}} \
                --config ${{matrix.build_type}}

      - name: Install
        run: |
          cmake --build build_${{matrix.build_type}} \
                --config ${{matrix.build_type}} \
                --target install

          cmake build_${{matrix.build_type}} \
                -DCMAKE_INSTALL_INCLUDEDIR=${{runner.workspace}}/foo/include \
                -DCMAKE_INSTALL_LIBDIR=${{runner.workspace}}/foo/lib \
                -DCMAKE_INSTALL_DATAROOTDIR=${{runner.workspace}}/foo/share
          cmake --build build_${{matrix.build_type}} \
                --config ${{matrix.build_type}} \
                --target install

      - name: Test CMake Package (relative GNUInstallDirs)
        run: |
          cmake -S src/package_config_unittest/working_config \
                -B build_${{matrix.build_type}}_package \
                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
                -DCMAKE_PREFIX_PATH=${{github.workspace}}/install \
                -G Ninja
          cmake --build build_${{matrix.build_type}}_package \
                --config ${{matrix.build_type}}

      - name: Test CMake Package (absolute GNUInstallDirs)
        run: |
          cmake -S src/package_config_unittest/working_config \
                -B build_${{matrix.build_type}}_package_foo \
                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
                -DCMAKE_PREFIX_PATH=${{runner.workspace}}/foo \
                -G Ninja
          cmake --build build_${{matrix.build_type}}_package_foo \
                --config ${{matrix.build_type}}

      - name: Test
        run: |
          ctest --test-dir build_${{matrix.build_type}} -j$(nproc) --output-on-failure

      - name: Generate Coverage
        if: matrix.build_type == 'Debug'
        run: |
          cd build_${{matrix.build_type}}
          gcovr -r .. . -s --xml coverage.xml

      - name: Upload Coverage to Codecov
        if: matrix.build_type == 'Debug'
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: build_${{matrix.build_type}}/coverage.xml
          fail_ci_if_error: true
          verbose: true

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
