This is an automated email from the ASF dual-hosted git repository.
hgruszecki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/master by this push:
new 6f01169b8 fix(ci): use cargo-llvm-cov for Python SDK coverage (#2817)
6f01169b8 is described below
commit 6f01169b8cf7a8c574405556f23355ccfa0a0821
Author: Atharva Lade <[email protected]>
AuthorDate: Thu Feb 26 14:58:09 2026 -0600
fix(ci): use cargo-llvm-cov for Python SDK coverage (#2817)
Co-authored-by: Maciej Modzelewski <[email protected]>
---
.../actions/python-maturin/pre-merge/action.yml | 74 +++++++++++++++++-----
.github/workflows/_test.yml | 2 +-
.github/workflows/post-merge.yml | 50 +++++++++++++--
3 files changed, 102 insertions(+), 24 deletions(-)
diff --git a/.github/actions/python-maturin/pre-merge/action.yml
b/.github/actions/python-maturin/pre-merge/action.yml
index 062ef8a6a..b6134e4b3 100644
--- a/.github/actions/python-maturin/pre-merge/action.yml
+++ b/.github/actions/python-maturin/pre-merge/action.yml
@@ -34,6 +34,11 @@ runs:
- name: Setup Rust with cache
uses: ./.github/actions/utils/setup-rust-with-cache
+ - name: Install llvm-tools for coverage
+ if: inputs.task == 'test'
+ run: rustup component add llvm-tools-preview
+ shell: bash
+
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -83,8 +88,23 @@ runs:
echo "mypy version: $(uv run mypy --version)"
shell: bash
- - name: Build Python wheel for testing
- if: inputs.task == 'test' || inputs.task == 'build'
+ - name: Build Python wheel with coverage instrumentation
+ if: inputs.task == 'test'
+ run: |
+ cd foreign/python
+ mkdir -p target/coverage
+
+ # Instrument Rust code with coverage and set profraw output path
+ export RUSTFLAGS="-C instrument-coverage"
+ export LLVM_PROFILE_FILE="$(pwd)/target/coverage/%p-%4m.profraw"
+ echo "LLVM_PROFILE_FILE=${LLVM_PROFILE_FILE}" >> $GITHUB_ENV
+
+ echo "Building Python wheel with coverage instrumentation..."
+ uv run maturin develop --release
+ shell: bash
+
+ - name: Build Python wheel
+ if: inputs.task == 'build'
run: |
cd foreign/python
@@ -92,18 +112,10 @@ runs:
echo "Building Python wheel..."
uv run maturin build -o dist
- if [ "${{ inputs.task }}" = "test" ]; then
- # Install the built wheel for testing
- echo "Installing built wheel..."
- uv pip install dist/*.whl --force-reinstall
- fi
-
- if [ "${{ inputs.task }}" = "build" ]; then
- # List built artifacts
- echo ""
- echo "Build artifacts:"
- ls -la dist/
- fi
+ # List built artifacts
+ echo ""
+ echo "Build artifacts:"
+ ls -la dist/
shell: bash
- name: Start Iggy server
@@ -123,7 +135,6 @@ runs:
IGGY_SERVER_HOST=127.0.0.1 \
IGGY_SERVER_TCP_PORT=8090 \
uv run pytest tests/ -v \
- --cov --cov-report=xml:../../reports/python-coverage.xml \
--junitxml=../../reports/python-junit.xml \
--tb=short \
--capture=no || TEST_EXIT_CODE=$?
@@ -142,7 +153,6 @@ runs:
# Run unit tests only (exclude integration tests)
uv run pytest tests/ -v \
-m "not integration" \
- --cov --cov-report=xml:../../reports/python-coverage.xml \
--junitxml=../../reports/python-junit.xml \
--tb=short || TEST_EXIT_CODE=$?
@@ -157,6 +167,36 @@ runs:
pid-file: ${{ steps.iggy.outputs.pid_file }}
log-file: ${{ steps.iggy.outputs.log_file }}
+ - name: Generate coverage report
+ if: inputs.task == 'test'
+ run: |
+ mkdir -p reports
+ cd foreign/python
+
+ PROFRAW_COUNT=$(find target/coverage -name '*.profraw' 2>/dev/null |
wc -l)
+ echo "Found ${PROFRAW_COUNT} profraw file(s)"
+
+ if [ "${PROFRAW_COUNT}" -eq 0 ]; then
+ echo "No profraw files found, skipping coverage report"
+ exit 0
+ fi
+
+ LLVM_PROFDATA=$(find "$(rustc --print sysroot)" -name 'llvm-profdata'
-type f | head -1)
+ LLVM_COV=$(find "$(rustc --print sysroot)" -name 'llvm-cov' -type f |
head -1)
+ SHARED_LIB=$(find target/release -name 'libapache_iggy*.so'
2>/dev/null | head -1)
+
+ "${LLVM_PROFDATA}" merge -sparse target/coverage/*.profraw -o
target/coverage/merged.profdata
+
+ "${LLVM_COV}" export \
+ --format=lcov \
+ --instr-profile=target/coverage/merged.profdata \
+ --ignore-filename-regex='(/.cargo/registry|/rustc/)' \
+ "${SHARED_LIB}" \
+ > ../../reports/python-coverage.lcov
+
+ echo "Coverage report generated: $(wc -l <
../../reports/python-coverage.lcov) lines"
+ shell: bash
+
- name: Upload test artifacts
if: always() && inputs.task == 'test'
uses: actions/upload-artifact@v4
@@ -164,7 +204,7 @@ runs:
name: python-test-results-${{ github.run_id }}-${{ github.run_attempt
}}
path: |
reports/python-junit.xml
- reports/python-coverage.xml
+ reports/python-coverage.lcov
foreign/python/dist/*.whl
retention-days: 7
if-no-files-found: ignore
diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml
index a9726361a..1a10e89ac 100644
--- a/.github/workflows/_test.yml
+++ b/.github/workflows/_test.yml
@@ -88,7 +88,7 @@ jobs:
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
- files: reports/python-coverage.xml
+ files: reports/python-coverage.lcov
disable_search: true
flags: python
fail_ci_if_error: false
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml
index 86db7b1ce..fb32e86f9 100644
--- a/.github/workflows/post-merge.yml
+++ b/.github/workflows/post-merge.yml
@@ -360,6 +360,9 @@ jobs:
with:
save-cache: "false"
+ - name: Install llvm-tools for coverage
+ run: rustup component add llvm-tools-preview
+
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -368,23 +371,30 @@ jobs:
cd foreign/python
uv sync --frozen --extra dev --extra testing --extra testing-docker
- - name: Build Python wheel
+ - name: Build Python wheel with coverage instrumentation
run: |
cd foreign/python
- uv run maturin build -o dist
- uv pip install dist/*.whl --force-reinstall
+ mkdir -p target/coverage
+
+ # Instrument Rust code with coverage and set profraw output path
+ export RUSTFLAGS="-C instrument-coverage"
+ export LLVM_PROFILE_FILE="$(pwd)/target/coverage/%p-%4m.profraw"
+ echo "LLVM_PROFILE_FILE=${LLVM_PROFILE_FILE}" >> $GITHUB_ENV
+
+ echo "Building Python wheel with coverage instrumentation..."
+ uv run maturin develop --release
- name: Start Iggy server
id: iggy
uses: ./.github/actions/utils/server-start
- - name: Run tests with coverage
+ - name: Run tests
run: |
cd foreign/python
IGGY_SERVER_HOST=127.0.0.1 \
IGGY_SERVER_TCP_PORT=8090 \
uv run pytest tests/ -v \
- --cov --cov-report=xml:../../reports/python-coverage.xml \
+ --junitxml=../../reports/python-junit.xml \
--tb=short \
--capture=no
@@ -395,11 +405,39 @@ jobs:
pid-file: ${{ steps.iggy.outputs.pid_file }}
log-file: ${{ steps.iggy.outputs.log_file }}
+ - name: Generate coverage report
+ run: |
+ mkdir -p reports
+ cd foreign/python
+
+ PROFRAW_COUNT=$(find target/coverage -name '*.profraw' 2>/dev/null |
wc -l)
+ echo "Found ${PROFRAW_COUNT} profraw file(s)"
+
+ if [ "${PROFRAW_COUNT}" -eq 0 ]; then
+ echo "No profraw files found, skipping coverage report"
+ exit 0
+ fi
+
+ LLVM_PROFDATA=$(find "$(rustc --print sysroot)" -name
'llvm-profdata' -type f | head -1)
+ LLVM_COV=$(find "$(rustc --print sysroot)" -name 'llvm-cov' -type f
| head -1)
+ SHARED_LIB=$(find target/release -name 'libapache_iggy*.so'
2>/dev/null | head -1)
+
+ "${LLVM_PROFDATA}" merge -sparse target/coverage/*.profraw -o
target/coverage/merged.profdata
+
+ "${LLVM_COV}" export \
+ --format=lcov \
+ --instr-profile=target/coverage/merged.profdata \
+ --ignore-filename-regex='(/.cargo/registry|/rustc/)' \
+ "${SHARED_LIB}" \
+ > ../../reports/python-coverage.lcov
+
+ echo "Coverage report generated: $(wc -l <
../../reports/python-coverage.lcov) lines"
+
- name: Upload to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
- files: reports/python-coverage.xml
+ files: reports/python-coverage.lcov
disable_search: true
flags: python
fail_ci_if_error: false