Skip to content

Add: CI: update gcovr for code coverage; #148

Add: CI: update gcovr for code coverage;

Add: CI: update gcovr for code coverage; #148

Workflow file for this run

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 }}