From ce981f3d4f40cafd75cd0014e91e5a0653793fe0 Mon Sep 17 00:00:00 2001 From: cdecker Date: Tue, 8 Sep 2026 19:04:30 +0200 Subject: [PATCH 1/4] gitignore: anchor the coverage entry to the repository root The entry is unanchored, so it matches contrib/coverage/ as well as the coverage/ build output directory it was meant for. That is how 4b9cffe183 came to add the coverage documentation, the Makefile targets, the pyln-testing plumbing and the nightly workflow while silently leaving the scripts they all call out of the commit. Changelog-None Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HGKo3ccLpkH2xFeEXUzEBK --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5a7f6ebca5be..2a860dd6aaeb 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ gen_*.c gen_*.h wire/gen_*_csv cli/lightning-cli -coverage +/coverage # Coverage profiling data files *.profraw *.profdata From eca681c232f53c8c1ca95205c532a7485e3f70ca Mon Sep 17 00:00:00 2001 From: cdecker Date: Tue, 8 Sep 2026 19:06:02 +0200 Subject: [PATCH 2/4] coverage: restore the scripts every caller already references None of these are new: 4b9cffe183 wrote the documentation and the callers for them, but .gitignore swallowed the directory itself, so master ships a coverage feature whose every entry point is a missing file. - Makefile's coverage-clang-collect and coverage-clang-report call collect-coverage.sh and generate-coverage-report.sh - .github/workflows/coverage-nightly.yaml calls the same two, and has failed at "Merge coverage data" every night since - doc/COVERAGE.md documents those two plus per-test-coverage.sh, per-test-coverage-html.sh and cleanup-corrupt-profraw.sh - doc/contribute-to-core-lightning/contributor-workflow.md points at clang-coverage-report.sh, which the same commit deleted from contrib/ after re-pointing the doc at contrib/coverage/ The files are restored unmodified; clang-coverage-report.sh is byte-identical to the one removed from contrib/. Changelog-None Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HGKo3ccLpkH2xFeEXUzEBK --- contrib/coverage/clang-coverage-report.sh | 27 +++++ contrib/coverage/cleanup-corrupt-profraw.sh | 55 +++++++++ contrib/coverage/collect-coverage.sh | 116 +++++++++++++++++++ contrib/coverage/generate-coverage-report.sh | 58 ++++++++++ contrib/coverage/per-test-coverage-html.sh | 86 ++++++++++++++ contrib/coverage/per-test-coverage.sh | 108 +++++++++++++++++ 6 files changed, 450 insertions(+) create mode 100755 contrib/coverage/clang-coverage-report.sh create mode 100755 contrib/coverage/cleanup-corrupt-profraw.sh create mode 100755 contrib/coverage/collect-coverage.sh create mode 100755 contrib/coverage/generate-coverage-report.sh create mode 100755 contrib/coverage/per-test-coverage-html.sh create mode 100755 contrib/coverage/per-test-coverage.sh diff --git a/contrib/coverage/clang-coverage-report.sh b/contrib/coverage/clang-coverage-report.sh new file mode 100755 index 000000000000..246163ce55cb --- /dev/null +++ b/contrib/coverage/clang-coverage-report.sh @@ -0,0 +1,27 @@ +#!/bin/bash -eu +# +# Generates an HTML coverage report from a raw Clang coverage profile. See +# https://clang.llvm.org/docs/SourceBasedCodeCoverage.html for more details. +# +# Example usage to create full_channel.html from full_channel.profraw for the +# run-full_channel unit test: +# ./contrib/clang-coverage-report.sh channeld/test/run-full_channel \ +# full_channel.profraw full_channel.html + +if [[ "$#" -ne 3 ]]; then + echo "Usage: $0 BINARY RAW_PROFILE_FILE TARGET_HTML_FILE" + exit 1 +fi + +readonly BINARY="$1" +readonly RAW_PROFILE_FILE="$2" +readonly TARGET_HTML_FILE="$3" + +MERGED_PROFILE_FILE=$(mktemp) +readonly MERGED_PROFILE_FILE + +llvm-profdata merge -sparse "${RAW_PROFILE_FILE}" -o "${MERGED_PROFILE_FILE}" +llvm-cov show "${BINARY}" -instr-profile="${MERGED_PROFILE_FILE}" -format=html \ + > "${TARGET_HTML_FILE}" + +rm "${MERGED_PROFILE_FILE}" diff --git a/contrib/coverage/cleanup-corrupt-profraw.sh b/contrib/coverage/cleanup-corrupt-profraw.sh new file mode 100755 index 000000000000..13b104bdabbd --- /dev/null +++ b/contrib/coverage/cleanup-corrupt-profraw.sh @@ -0,0 +1,55 @@ +#!/bin/bash -eu +# Remove corrupt .profraw files from the coverage directory +# Usage: ./cleanup-corrupt-profraw.sh [COVERAGE_DIR] + +COVERAGE_DIR="${1:-${CLN_COVERAGE_DIR:-/tmp/cln-coverage}}" + +if [ ! -d "$COVERAGE_DIR" ]; then + echo "Coverage directory not found: $COVERAGE_DIR" + exit 1 +fi + +echo "Scanning for corrupt profraw files in: $COVERAGE_DIR" + +# Find all profraw files +mapfile -t PROFRAW_FILES < <(find "$COVERAGE_DIR" -name "*.profraw" 2>/dev/null || true) + +if [ ${#PROFRAW_FILES[@]} -eq 0 ]; then + echo "No .profraw files found" + exit 0 +fi + +echo "Found ${#PROFRAW_FILES[@]} profile files" + +CORRUPT_FILES=() +for profraw in "${PROFRAW_FILES[@]}"; do + # Try to validate the file + if ! llvm-profdata show "$profraw" >/dev/null 2>&1; then + CORRUPT_FILES+=("$profraw") + fi +done + +if [ ${#CORRUPT_FILES[@]} -eq 0 ]; then + echo "✓ No corrupt files found" + exit 0 +fi + +echo "" +echo "Found ${#CORRUPT_FILES[@]} corrupt file(s):" +for corrupt in "${CORRUPT_FILES[@]}"; do + echo " - $corrupt" +done + +echo "" +read -p "Delete these corrupt files? [y/N] " -n 1 -r +echo + +if [[ $REPLY =~ ^[Yy]$ ]]; then + for corrupt in "${CORRUPT_FILES[@]}"; do + rm -f "$corrupt" + echo " Deleted: $corrupt" + done + echo "✓ Removed ${#CORRUPT_FILES[@]} corrupt file(s)" +else + echo "No files were deleted" +fi diff --git a/contrib/coverage/collect-coverage.sh b/contrib/coverage/collect-coverage.sh new file mode 100755 index 000000000000..df66b1cbbb38 --- /dev/null +++ b/contrib/coverage/collect-coverage.sh @@ -0,0 +1,116 @@ +#!/bin/bash -eu +# Merge all .profraw files into a single .profdata file +# Usage: ./collect-coverage.sh [COVERAGE_DIR] [OUTPUT_FILE] + +COVERAGE_DIR="${1:-${CLN_COVERAGE_DIR:-/tmp/cln-coverage}}" +OUTPUT="${2:-coverage/merged.profdata}" + +echo "Collecting coverage from: $COVERAGE_DIR" + +# Find all profraw files +mapfile -t PROFRAW_FILES < <(find "$COVERAGE_DIR" -name "*.profraw" 2>/dev/null || true) + +if [ ${#PROFRAW_FILES[@]} -eq 0 ]; then + echo "ERROR: No .profraw files found in $COVERAGE_DIR" + exit 1 +fi + +echo "Found ${#PROFRAW_FILES[@]} profile files" + +# Validate each profraw file and filter out corrupt/incomplete ones +# Define validation function for parallel execution +validate_file() { + local profraw="$1" + + # Check if file is empty + if [ ! -s "$profraw" ]; then + return 1 # Empty + fi + + # Check if file is suspiciously small (likely incomplete write) + # Valid profraw files are typically > 1KB + filesize=$(stat -c%s "$profraw" 2>/dev/null || stat -f%z "$profraw" 2>/dev/null) + if [ "$filesize" -lt 1024 ]; then + return 2 # Too small + fi + + # Try to validate the file by checking if llvm-profdata can read it + if llvm-profdata show "$profraw" >/dev/null 2>&1; then + echo "$profraw" # Valid - output to stdout + return 0 + else + return 3 # Corrupt + fi +} + +# Export function for parallel execution +export -f validate_file + +TOTAL=${#PROFRAW_FILES[@]} +NPROC=$(nproc 2>/dev/null || echo 4) +echo "Validating ${TOTAL} files in parallel (using ${NPROC} cores)..." + +# Run validation in parallel and collect valid files +mapfile -t VALID_FILES < <( + printf '%s\n' "${PROFRAW_FILES[@]}" | \ + xargs -P "$NPROC" -I {} bash -c 'validate_file "$@"' _ {} +) + +# Calculate error counts +CORRUPT_COUNT=$((TOTAL - ${#VALID_FILES[@]})) + +if [ ${#VALID_FILES[@]} -eq 0 ]; then + echo "ERROR: No valid .profraw files found (all $CORRUPT_COUNT files were corrupt/incomplete)" + exit 1 +fi + +echo "Valid files: ${#VALID_FILES[@]}" +if [ $CORRUPT_COUNT -gt 0 ]; then + echo "Filtered out: $CORRUPT_COUNT files (empty/small/corrupt)" +fi +mkdir -p "$(dirname "$OUTPUT")" + +# Merge with -sparse flag for efficiency +# Use batched merging to avoid "Argument list too long" errors +BATCH_SIZE=500 +TOTAL_FILES=${#VALID_FILES[@]} + +if [ "$TOTAL_FILES" -le "$BATCH_SIZE" ]; then + # Small enough to merge in one go + echo "Merging ${TOTAL_FILES} files..." + llvm-profdata merge -sparse "${VALID_FILES[@]}" -o "$OUTPUT" +else + # Need to merge in batches + echo "Merging ${TOTAL_FILES} files in batches of ${BATCH_SIZE}..." + + # Create temp directory for intermediate files + TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/profdata-merge.XXXXXX") + trap 'rm -rf "$TEMP_DIR"' EXIT + + BATCH_NUM=0 + INTERMEDIATE_FILES=() + + # Merge files in batches + for ((i=0; i/dev/null | awk '/^ALL_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') +mapfile -t TEST_BINARIES < <(make -qp 2>/dev/null | awk '/^ALL_TEST_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') + +# Combine all binaries +ALL_BINARIES=("${BINARIES[@]}" "${TEST_BINARIES[@]}") + +# Build llvm-cov arguments +ARGS=() +for bin in "${ALL_BINARIES[@]}"; do + if [ -f "$bin" ]; then + if [ ${#ARGS[@]} -eq 0 ]; then + ARGS+=("$bin") # First binary is primary + else + ARGS+=("-object=$bin") # Others use -object= + fi + fi +done + +if [ ${#ARGS[@]} -eq 0 ]; then + echo "ERROR: No instrumented binaries found" + echo "Make sure you've built with --enable-coverage" + exit 1 +fi + +echo "Generating coverage report for ${#ARGS[@]} binaries..." + +# Generate HTML report +llvm-cov show "${ARGS[@]}" \ + -instr-profile="$PROFDATA" \ + -format=html \ + -output-dir="$OUTPUT_DIR" \ + -show-line-counts-or-regions \ + -show-instantiations=false + +echo "✓ HTML report: $OUTPUT_DIR/index.html" + +# Generate text summary +mkdir -p coverage +llvm-cov report "${ARGS[@]}" \ + -instr-profile="$PROFDATA" \ + | tee coverage/summary.txt + +echo "✓ Summary: coverage/summary.txt" diff --git a/contrib/coverage/per-test-coverage-html.sh b/contrib/coverage/per-test-coverage-html.sh new file mode 100755 index 000000000000..a4deb2320f41 --- /dev/null +++ b/contrib/coverage/per-test-coverage-html.sh @@ -0,0 +1,86 @@ +#!/bin/bash -eu +# Generate HTML coverage reports for each test +# Usage: ./per-test-coverage-html.sh [PROFDATA_DIR] [OUTPUT_DIR] + +PROFDATA_DIR="${1:-coverage/per-test}" +OUTPUT_DIR="${2:-coverage/per-test-html}" + +if [ ! -d "$PROFDATA_DIR" ]; then + echo "ERROR: Profdata directory not found: $PROFDATA_DIR" + echo "Run ./contrib/coverage/per-test-coverage.sh first" + exit 1 +fi + +# Get all binaries from Makefile (includes plugins, tools, test binaries) +echo "Discovering instrumented binaries from Makefile..." +mapfile -t BINARIES < <(make -qp 2>/dev/null | awk '/^ALL_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') +mapfile -t TEST_BINARIES < <(make -qp 2>/dev/null | awk '/^ALL_TEST_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') + +# Combine all binaries +ALL_BINARIES=("${BINARIES[@]}" "${TEST_BINARIES[@]}") + +# Build llvm-cov arguments +ARGS=() +for bin in "${ALL_BINARIES[@]}"; do + if [ -f "$bin" ]; then + if [ ${#ARGS[@]} -eq 0 ]; then + ARGS+=("$bin") # First binary is primary + else + ARGS+=("-object=$bin") # Others use -object= + fi + fi +done + +if [ ${#ARGS[@]} -eq 0 ]; then + echo "ERROR: No instrumented binaries found" + echo "Make sure you've built with --enable-coverage" + exit 1 +fi + +# Find all profdata files +mapfile -t PROFDATA_FILES < <(find "$PROFDATA_DIR" -name "*.profdata" 2>/dev/null | sort) + +if [ ${#PROFDATA_FILES[@]} -eq 0 ]; then + echo "ERROR: No .profdata files found in $PROFDATA_DIR" + echo "Run ./contrib/coverage/per-test-coverage.sh first" + exit 1 +fi + +mkdir -p "$OUTPUT_DIR" + +echo "Generating HTML reports for ${#PROFDATA_FILES[@]} tests..." +echo "Using ${#ARGS[@]} instrumented binaries" +echo "" + +# Generate HTML for each test +for profdata in "${PROFDATA_FILES[@]}"; do + test_name=$(basename "$profdata" .profdata) + html_dir="$OUTPUT_DIR/$test_name" + + echo -n " $test_name... " + + # Generate HTML report + if llvm-cov show "${ARGS[@]}" \ + -instr-profile="$profdata" \ + -format=html \ + -output-dir="$html_dir" \ + -show-line-counts-or-regions \ + -show-instantiations=false 2>/dev/null; then + echo "✓" + else + echo "✗ (failed)" + rm -rf "$html_dir" + fi +done + +echo "" +echo "HTML reports generated in: $OUTPUT_DIR" +echo "" +echo "Open reports:" +for profdata in "${PROFDATA_FILES[@]}"; do + test_name=$(basename "$profdata" .profdata) + html_dir="$OUTPUT_DIR/$test_name" + if [ -f "$html_dir/index.html" ]; then + echo " $test_name: $html_dir/index.html" + fi +done diff --git a/contrib/coverage/per-test-coverage.sh b/contrib/coverage/per-test-coverage.sh new file mode 100755 index 000000000000..29cb27ecb222 --- /dev/null +++ b/contrib/coverage/per-test-coverage.sh @@ -0,0 +1,108 @@ +#!/bin/bash -eu +# Generate per-test coverage reports +# Usage: ./per-test-coverage.sh [COVERAGE_DIR] [OUTPUT_DIR] + +COVERAGE_DIR="${1:-${CLN_COVERAGE_DIR:-/tmp/cln-coverage}}" +OUTPUT_DIR="${2:-coverage/per-test}" + +if [ ! -d "$COVERAGE_DIR" ]; then + echo "ERROR: Coverage directory not found: $COVERAGE_DIR" + exit 1 +fi + +# Get all binaries from Makefile (includes plugins, tools, test binaries) +echo "Discovering instrumented binaries from Makefile..." +mapfile -t BINARIES < <(make -qp 2>/dev/null | awk '/^ALL_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') +mapfile -t TEST_BINARIES < <(make -qp 2>/dev/null | awk '/^ALL_TEST_PROGRAMS :=/ {$1=$2=""; print}' | tr ' ' '\n' | grep -v '^$') + +# Combine all binaries +ALL_BINARIES=("${BINARIES[@]}" "${TEST_BINARIES[@]}") + +# Build llvm-cov arguments +BINARY_ARGS=() +for bin in "${ALL_BINARIES[@]}"; do + if [ -f "$bin" ]; then + if [ ${#BINARY_ARGS[@]} -eq 0 ]; then + BINARY_ARGS+=("$bin") # First binary is primary + else + BINARY_ARGS+=("-object=$bin") # Others use -object= + fi + fi +done + +if [ ${#BINARY_ARGS[@]} -eq 0 ]; then + echo "ERROR: No instrumented binaries found" + echo "Make sure you've built with --enable-coverage" + exit 1 +fi + +mkdir -p "$OUTPUT_DIR" + +# Find all test subdirectories +mapfile -t TEST_DIRS < <(find "$COVERAGE_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort) + +if [ ${#TEST_DIRS[@]} -eq 0 ]; then + echo "ERROR: No test subdirectories found in $COVERAGE_DIR" + echo "Note: Test organization requires CLN_TEST_NAME to be set" + exit 1 +fi + +echo "Generating coverage for ${#TEST_DIRS[@]} tests..." + +# Process each test +for test_dir in "${TEST_DIRS[@]}"; do + test_name=$(basename "$test_dir") + echo -n " $test_name... " + + # Find profraw files for this test + mapfile -t PROFRAW_FILES < <(find "$test_dir" -name "*.profraw" 2>/dev/null || true) + + if [ ${#PROFRAW_FILES[@]} -eq 0 ]; then + echo "no profraw files" + continue + fi + + # Validate and filter profraw files + VALID_FILES=() + for profraw in "${PROFRAW_FILES[@]}"; do + if [ -s "$profraw" ]; then + filesize=$(stat -c%s "$profraw" 2>/dev/null || stat -f%z "$profraw" 2>/dev/null) + if [ "$filesize" -ge 1024 ]; then + if llvm-profdata show "$profraw" >/dev/null 2>&1; then + VALID_FILES+=("$profraw") + fi + fi + fi + done + + if [ ${#VALID_FILES[@]} -eq 0 ]; then + echo "no valid files" + continue + fi + + # Merge profraw files for this test + test_profdata="$OUTPUT_DIR/$test_name.profdata" + if ! llvm-profdata merge -sparse "${VALID_FILES[@]}" -o "$test_profdata" 2>/dev/null; then + echo "merge failed" + continue + fi + + # Generate text summary for this test + llvm-cov report "${BINARY_ARGS[@]}" \ + -instr-profile="$test_profdata" \ + > "$OUTPUT_DIR/$test_name.txt" 2>/dev/null || { + echo "report failed" + rm -f "$test_profdata" + continue + } + + echo "✓ (${#VALID_FILES[@]} files)" +done + +echo "" +echo "Per-test coverage reports in: $OUTPUT_DIR" +echo " - *.profdata - Merged profile data per test" +echo " - *.txt - Text coverage summary per test" +echo "" +echo "To generate HTML reports for all tests:" +echo " ./contrib/coverage/per-test-coverage-html.sh" From f7fda8c4ca7ec7b969974094e365b59310b73e79 Mon Sep 17 00:00:00 2001 From: cdecker Date: Tue, 8 Sep 2026 19:06:49 +0200 Subject: [PATCH 3/4] coverage: export lcov beside the HTML report llvm-cov can emit lcov from the profile and binary list the script has already assembled, so this costs one more invocation and gives the report a machine-readable form. The nightly needs it: it currently hands Codecov coverage/merged.profdata, which Codecov cannot parse. It is also what GitLab's coverage visualization wants, via lcov_cobertura. Paths are rewritten relative to the repository root, since both consumers match the report against the repository tree. Changelog-None Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HGKo3ccLpkH2xFeEXUzEBK --- contrib/coverage/generate-coverage-report.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contrib/coverage/generate-coverage-report.sh b/contrib/coverage/generate-coverage-report.sh index ba099100587f..e17b361b6644 100755 --- a/contrib/coverage/generate-coverage-report.sh +++ b/contrib/coverage/generate-coverage-report.sh @@ -56,3 +56,15 @@ llvm-cov report "${ARGS[@]}" \ | tee coverage/summary.txt echo "✓ Summary: coverage/summary.txt" + +# Machine-readable export for tools that ingest lcov: Codecov, and +# lcov_cobertura for GitLab's coverage visualization. Both match the paths in +# the report against the repository tree, so strip the build directory off. +llvm-cov export "${ARGS[@]}" \ + -instr-profile="$PROFDATA" \ + -format=lcov > coverage/coverage.lcov.tmp + +sed "s|^SF:$PWD/|SF:|" coverage/coverage.lcov.tmp > coverage/coverage.lcov +rm -f coverage/coverage.lcov.tmp + +echo "✓ LCOV: coverage/coverage.lcov" From a4b5738cdceced6bc5367e2b765e388d904ac270 Mon Sep 17 00:00:00 2001 From: cdecker Date: Tue, 8 Sep 2026 19:06:59 +0200 Subject: [PATCH 4/4] ci: fix the coverage nightly's profile handling Three things stand between the restored scripts and a nightly that finishes: pyln-testing sets CLN_TEST_NAME for every test, so the profiles land in $CLN_COVERAGE_DIR// and never directly in $CLN_COVERAGE_DIR. The coverage-raw/*.profraw upload glob therefore matches nothing, under if-no-files-found: error. A local three-test run produced 515 profiles, all of them in subdirectories. Both jobs now hand the directory to collect-coverage.sh, which walks it and drops what crashed tests left half-written; that also retires the flattening cp, which could collide on -.profraw between matrix cells. The build uses the runner's default clang while the report job installed LLVM 18 and symlinked llvm-profdata to it. There are no compatibility guarantees for the raw profile format across LLVM releases, so the two have to come from the same one. Codecov cannot read a .profdata; it gets the lcov export instead. Changelog-None Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HGKo3ccLpkH2xFeEXUzEBK --- .github/workflows/coverage-nightly.yaml | 33 +++++++++---------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/.github/workflows/coverage-nightly.yaml b/.github/workflows/coverage-nightly.yaml index 08f99161a2c3..7473fdaca915 100644 --- a/.github/workflows/coverage-nightly.yaml +++ b/.github/workflows/coverage-nightly.yaml @@ -101,7 +101,8 @@ jobs: if: always() with: name: coverage-raw-${{ matrix.name }} - path: coverage-raw/*.profraw + # pyln-testing puts the profiles in per-test subdirectories + path: coverage-raw/ if-no-files-found: error report: @@ -114,13 +115,13 @@ jobs: - name: Checkout uses: actions/checkout@v6 + # The raw profile format has no compatibility guarantees across LLVM + # releases, so llvm-profdata has to come from the same release as the + # clang that produced the profiles: the distro default in both cases. - name: Install LLVM tools run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 18 - sudo ln -sf /usr/bin/llvm-profdata-18 /usr/bin/llvm-profdata - sudo ln -sf /usr/bin/llvm-cov-18 /usr/bin/llvm-cov + sudo apt-get update + sudo apt-get install -y llvm - name: Download build artifact uses: actions/download-artifact@v8 @@ -136,28 +137,18 @@ jobs: pattern: coverage-raw-* path: coverage-artifacts + # collect-coverage.sh walks the tree itself and rejects the profiles + # that crashed tests left half-written, so it gets the whole download. - name: Merge coverage data - run: | - mkdir -p coverage-raw coverage - find coverage-artifacts -name "*.profraw" -exec cp {} coverage-raw/ \; - PROFRAW_COUNT=$(ls -1 coverage-raw/*.profraw 2>/dev/null | wc -l) - echo "Found $PROFRAW_COUNT profile files" - if [ "$PROFRAW_COUNT" -eq 0 ]; then - echo "ERROR: No coverage data found" - exit 1 - fi - chmod +x contrib/coverage/collect-coverage.sh - CLN_COVERAGE_DIR=coverage-raw ./contrib/coverage/collect-coverage.sh + run: ./contrib/coverage/collect-coverage.sh coverage-artifacts - name: Generate HTML report - run: | - chmod +x contrib/coverage/generate-coverage-report.sh - ./contrib/coverage/generate-coverage-report.sh + run: ./contrib/coverage/generate-coverage-report.sh - name: Upload to Codecov uses: codecov/codecov-action@v6 with: - files: coverage/merged.profdata + files: coverage/coverage.lcov flags: integration-tests name: cln-nightly-coverage token: ${{ secrets.CODECOV_TOKEN }}