From 44a773f502baaee473446f55591f0930fe2362da Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 13 Apr 2026 00:58:29 +0100 Subject: [PATCH] Port coverage workflow to cmake --- .github/workflows/coverage.yml | 45 +++++++++++++--------- test/merge-gcda.py | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 17 deletions(-) create mode 100755 test/merge-gcda.py diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8904e747..3b03a7f8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -17,12 +17,13 @@ on: jobs: coverage: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - run: | sudo apt-get update sudo apt-get install -y \ + cmake \ docbook-xsl \ lcov \ libargon2-dev \ @@ -36,6 +37,7 @@ jobs: libssl-dev \ libwrap0-dev \ microsocks \ + ninja-build \ python3-all \ python3-paho-mqtt \ python3-psutil \ @@ -44,25 +46,34 @@ jobs: - uses: actions/checkout@v6 - - run: | - make \ - WITH_COVERAGE=yes \ - CFLAGS="-O0 -Wall -ggdb -fprofile-arcs" \ - -j $(nproc) \ - binary - make \ - WITH_COVERAGE=yes \ - CFLAGS="-O0 -Wall -ggdb -fprofile-arcs" \ - -j $(nproc) \ - test-compile + - name: Configure + run: | + cmake \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Debug \ + -S . \ + -B build + env: + CFLAGS: "-coverage -O0 -Wall -ggdb -fprofile-arcs -fprofile-dir=${{github.workspace}}/coverage.%p" + CXXFLAGS: "-coverage -O0 -Wall -ggdb -fprofile-arcs -fprofile-dir=${{github.workspace}}/coverage.%p" + LDFLAGS: "-coverage" - - run: | - make -C test test + - name: Build + run: cmake --build build --parallel $(nproc) - - run: | - lcov --capture --directory . --output-file coverage.info --no-external + - name: Tests + working-directory: build/ + run: ctest -j20 --resource-spec-file ../test/resource.json --output-on-failure --repeat until-pass:5 - - uses: codecov/codecov-action@v4 + - name: Merge GCDA files + run: test/merge-gcda.py + + - name: Generate coverage data + run: | + lcov --capture --directory . --output-file coverage.info --no-external --exclude test/ --exclude deps/ --exclude include/ + + - name: Update to Codecov + uses: codecov/codecov-action@v6 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true diff --git a/test/merge-gcda.py b/test/merge-gcda.py new file mode 100755 index 00000000..0a3b05e7 --- /dev/null +++ b/test/merge-gcda.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import os +import shutil +import subprocess +import time +from pathlib import Path + +def run_merge(processes, d1, d2, output_dir): + cmd = ["gcov-tool", "merge", "-o", output_dir, d1, d2] + proc = subprocess.Popen(cmd) + proc.output_dir = output_dir + processes.append(proc) + + +final_output_dir = "cov-merged" +os.mkdir(final_output_dir) + +dirs = [] +with os.scandir('.') as scan: + for d in scan: + if "coverage." in d.name and d.is_dir(): + dirs.append(d.name) + +max_process_count = 20 +process_count = 0 +processes = [] +merge_index = 0 + +dirs_to_remove = [] + +while len(dirs) > 0 or len(processes) > 0: + for p in processes: + p.poll() + if p.returncode is not None: + processes.remove(p) + if p.output_dir != final_output_dir: + dirs.append(p.output_dir) + + if len(dirs) == 1 and len(processes) == 0: + d1 = dirs.pop() + d2 = final_output_dir + output_dir = final_output_dir + + dirs_to_remove.append(d1) + + run_merge(processes, d1, d2, output_dir) + elif len(dirs) > 1 and len(processes) < max_process_count: + d1 = dirs.pop() + d2 = dirs.pop() + + output_dir = f"tmp{merge_index}" + merge_index += 1 + + dirs_to_remove.append(d1) + dirs_to_remove.append(d2) + + run_merge(processes, d1, d2, output_dir) + else: + time.sleep(0.1) + +files = list(Path(final_output_dir).iterdir()) +for f in files: + shutil.move(f, f.name.replace("#", "/")) + +dirs_to_remove.sort() +for d in dirs_to_remove: + print(d) + shutil.rmtree(d) +os.rmdir(final_output_dir)