Add: CI: update gcovr for code coverage; #148
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| build-and-test: | |
| name: Build & Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-22.04, macos-15-intel] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies (Ubuntu) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential cmake libpcap-dev libyaml-cpp-dev nlohmann-json3-dev \ | |
| libssl-dev libsqlite3-dev libgtest-dev pkg-config clang-format uuid-dev | |
| cd /tmp | |
| git clone https://github.com/yhirose/cpp-httplib.git | |
| cd cpp-httplib | |
| sudo cp httplib.h /usr/local/include/ | |
| - name: Install dependencies (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| export HOMEBREW_NO_AUTO_UPDATE=1 | |
| brew install --formula cmake libpcap yaml-cpp nlohmann-json cpp-httplib openssl sqlite3 googletest libxcrypt | |
| - name: Set libxcrypt environment variables (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| echo "CPPFLAGS=-I/usr/local/opt/libxcrypt/include" >> $GITHUB_ENV | |
| echo "LDFLAGS=-L/usr/local/opt/libxcrypt/lib" >> $GITHUB_ENV | |
| - name: Configure CMake | |
| run: | | |
| mkdir -p build | |
| cd build | |
| if [ "${{ runner.os }}" = "macOS" ]; then | |
| cmake .. -DCMAKE_BUILD_TYPE=Release -DOPENSSL_ROOT_DIR=$(brew --prefix openssl) | |
| else | |
| cmake .. -DCMAKE_BUILD_TYPE=Release | |
| fi | |
| - name: Build project | |
| run: | | |
| cd build | |
| make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu) | |
| - name: Copy test fixtures | |
| run: | | |
| mkdir -p build/tests | |
| cp -r tests/fixtures build/tests/ | |
| - name: Run C++ tests | |
| run: | | |
| cd build | |
| if [ "${{ runner.os }}" = "Linux" ]; then | |
| ctest --output-on-failure --parallel $(nproc) --timeout 300 || (echo "Tests failed! Checking for core dumps..." && ls -la /cores/ && exit 1) | |
| else | |
| ctest --output-on-failure --parallel $(sysctl -n hw.ncpu) --timeout 300 | |
| fi | |
| - name: Kill stale daemon processes | |
| run: | | |
| sudo pkill -9 netnet-daemon || true | |
| sleep 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pytest requests pyyaml bcrypt | |
| - name: Set interface and privilege env variable | |
| run: | | |
| if [ "${{ runner.os }}" = "macOS" ]; then | |
| echo "NETNET_IFACE=lo0" >> $GITHUB_ENV | |
| echo "NETNET_USER=nobody" >> $GITHUB_ENV | |
| echo "NETNET_GROUP=nobody" >> $GITHUB_ENV | |
| else | |
| echo "NETNET_IFACE=lo" >> $GITHUB_ENV | |
| echo "NETNET_USER=nobody" >> $GITHUB_ENV | |
| echo "NETNET_GROUP=nogroup" >> $GITHUB_ENV | |
| fi | |
| - name: Patch config for interface | |
| run: | | |
| envsubst < examples/sample-config.yaml > examples/sample-config.ci.yaml | |
| - name: Print daemon logs | |
| run: | | |
| cat /tmp/netnet-daemon.log || true | |
| - name: Wait for /login endpoint | |
| run: | | |
| for i in {1..30}; do | |
| status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8082/login || echo 000) | |
| if [ "$status" = "200" ] || [ "$status" = "404" ]; then | |
| echo "Daemon is up! (status: $status)" | |
| exit 0 | |
| fi | |
| echo "Waiting for daemon..." | |
| sleep 2 | |
| done | |
| echo "Daemon did not start in time." >&2 | |
| exit 1 | |
| - name: Print daemon log failure | |
| if: failure() | |
| run: | | |
| echo "==== netnet-daemon-log ====" | |
| cat /tmp/netnet-daemon.log || echo "No log found" | |
| - name: Run Python integration tests | |
| run: | | |
| pytest tests/integration/test_authentication.py -v | |
| pytest tests/integration/test_api.py -v | |
| - name: Stop daemon | |
| run: | | |
| sudo pkill netnet-daemon || true | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: netnet-${{ matrix.os }}-binaries | |
| path: | | |
| build/netnet | |
| build/netnet-daemon | |
| retention-days: 7 | |
| lint: | |
| name: Code Quality | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install clang-format and flake8 | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang-format | |
| pip install flake8 | |
| - name: Check C++ formatting | |
| run: | | |
| find src/ include/ tests/ -name "*.cpp" -o -name "*.h" | \ | |
| xargs clang-format --dry-run --Werror | |
| continue-on-error: true | |
| - name: Check for TODO/FIXME comments | |
| run: | | |
| echo "### TODO/FIXME Comments Found:" | |
| grep -rn "TODO\|FIXME" src/ tests/ || echo "None found" | |
| continue-on-error: true | |
| - name: Check Python formatting (flake8) | |
| run: | | |
| flake8 tests/integration/ --max-line-length=120 | |
| continue-on-error: true | |
| coverage: | |
| name: Code Coverage | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| cmake \ | |
| g++ \ | |
| libpcap-dev \ | |
| libssl-dev \ | |
| libyaml-cpp-dev \ | |
| nlohmann-json3-dev \ | |
| libgtest-dev \ | |
| libsqlite3-dev \ | |
| gettext-base | |
| cd /tmp | |
| git clone --depth 1 https://github.com/yhirose/cpp-httplib.git | |
| cd cpp-httplib | |
| cmake -S . -B build -DCMAKE_BUILD_TYPE=Release | |
| sudo cmake --build build --target install | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.13' | |
| - name: Install gcovr | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install gcovr | |
| - name: Configure CMake with coverage | |
| run: | | |
| cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \ | |
| -DCMAKE_CXX_FLAGS="--coverage -g -O0" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="--coverage" | |
| - name: Build with coverage | |
| run: cmake --build build | |
| - name: Copy test fixtures | |
| run: | | |
| mkdir -p build/tests/fixtures | |
| cp -r tests/fixtures/* build/tests/fixtures/ | |
| - name: Run C++ tests with coverage | |
| run: | | |
| cd build | |
| ctest --output-on-failure --verbose | |
| cd .. | |
| - name: Remove vendor coverage files | |
| run: | | |
| find build -path "*/vendor/*" -name "*.gcda" -delete 2>/dev/null || true | |
| find include -path "*/vendor/*" -name "*.gcda" -delete 2>/dev/null || true | |
| find . -path "*/vendor/*" -name "*.gcno" -delete 2>/dev/null || true | |
| - name: Generate C++ coverage report | |
| run: | | |
| cd build | |
| gcovr --root .. \ | |
| --exclude '.*tests/.*' \ | |
| --exclude '.*vendor/.*' \ | |
| --exclude '.*googletest/.*' \ | |
| --exclude '.*examples/.*' \ | |
| --exclude '.*build/.*' \ | |
| --exclude '.*CMakeFiles/.*' \ | |
| --exclude '.*/src/main\.cpp$$' \ | |
| --exclude '.*/src/daemon/Main\.cpp$$' \ | |
| --xml-pretty --xml coverage.xml \ | |
| --print-summary \ | |
| --sort-uncovered | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| - name: Set interface env for CI | |
| run: | | |
| echo "NETNET_IFACE=lo" >> $GITHUB_ENV | |
| echo "NETNET_USER=nobody" >> $GITHUB_ENV | |
| echo "NETNET_GROUP=nogroup" >> $GITHUB_ENV | |
| - name: Patch config for interface | |
| run: | | |
| envsubst < examples/sample-config.yaml > examples/sample-config.ci.yaml | |
| - name: Clean stale session database | |
| run: | | |
| rm -f examples/sample-config.ci.yaml.sessions 2>/dev/null || true | |
| rm -f /tmp/*.db* 2>/dev/null || true | |
| - name: Start netnet-daemon | |
| run: | | |
| sudo ./build/netnet-daemon --config examples/sample-config.ci.yaml & | |
| echo $! > /tmp/netnet-daemon.pid | |
| sleep 3 | |
| - name: Wait for daemon | |
| run: | | |
| for i in {1..10}; do | |
| curl -s http://localhost:8082/ && break || sleep 1 | |
| done | |
| - name: Run Python integration tests | |
| run: | | |
| pytest tests/integration/test_api.py -v | |
| - name: Stop daemon | |
| run: | | |
| sudo kill $(cat /tmp/netnet-daemon.pid) || true | |
| sleep 1 | |
| - name: Upload C++ coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: ./build/coverage.xml | |
| flags: cpp | |
| name: cpp-coverage | |
| token: ${{ secrets.CODECOV_TOKEN }} |