This is an automated email from the ASF dual-hosted git repository.

xushiyan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hudi-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 8f41bf0  chore: support generating local coverage report (#491)
8f41bf0 is described below

commit 8f41bf0f90f780275a4d1b959f3cbd70e0aa0800
Author: Shiyan Xu <[email protected]>
AuthorDate: Mon Dec 22 10:39:57 2025 -0600

    chore: support generating local coverage report (#491)
---
 .github/workflows/ci.yml |  7 +----
 .gitignore               |  1 +
 Makefile                 | 76 ++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b3a6f99..32fbca8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -70,12 +70,7 @@ jobs:
           # Reduce cache size by cleaning old artifacts
           cache-all-crates: false
       - name: Rust unit tests with coverage report
-        run: |
-          cargo tarpaulin \
-            --engine llvm --no-dead-code --no-fail-fast --all-features 
--workspace \
-            --exclude-files cpp/src/* \
-            --exclude-files crates/core/src/avro_to_arrow/* \
-            -o xml --output-dir ./cov-reports --skip-clean
+        run: make coverage-xml
       - name: Upload coverage report
         uses: actions/upload-artifact@v6
         with:
diff --git a/.gitignore b/.gitignore
index 35f0b00..51d85c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ __pycache__
 # coverage files
 *.profraw
 cobertura.xml
+/cov-reports/
diff --git a/Makefile b/Makefile
index 8c92533..217b21b 100644
--- a/Makefile
+++ b/Makefile
@@ -19,24 +19,53 @@ SHELL := /bin/bash
 
 .DEFAULT_GOAL := help
 
-# Check if uv is installed
-UV_CHECK := $(shell command -v uv 2> /dev/null)
-ifndef UV_CHECK
-$(error "uv is not installed. Please install it first: curl -LsSf 
https://astral.sh/uv/install.sh | sh")
-endif
-
 VENV := .venv
 PYTHON_DIR = python
 MATURIN_VERSION := $(shell grep 'requires =' $(PYTHON_DIR)/pyproject.toml | 
cut -d= -f2- | tr -d '[ "]')
 PACKAGE_VERSION := $(shell grep version Cargo.toml | head -n 1 | awk '{print 
$$3}' | tr -d '"' )
 
+# Check if uv is installed (only enforced for Python-related targets)
+UV_CHECK := $(shell command -v uv 2> /dev/null)
+define check_uv
+       @if [ -z "$(UV_CHECK)" ]; then \
+               echo "Error: uv is not installed. Please install it first: curl 
-LsSf https://astral.sh/uv/install.sh | sh"; \
+               exit 1; \
+       fi
+endef
+
+# Check if cargo-tarpaulin is installed (only enforced for coverage targets)
+TARPAULIN_CHECK := $(shell command -v cargo-tarpaulin 2> /dev/null)
+define check_tarpaulin
+       @if [ -z "$(TARPAULIN_CHECK)" ]; then \
+               echo "Error: cargo-tarpaulin is not installed. Run: cargo 
install cargo-tarpaulin"; \
+               exit 1; \
+       fi
+endef
+
+# =============================================================================
+# Coverage Configuration
+# =============================================================================
+COV_OUTPUT_DIR := ./cov-reports
+COV_THRESHOLD ?= 60
+COV_EXCLUDE := \
+       --exclude-files 'cpp/src/*' \
+       --exclude-files 'crates/core/src/avro_to_arrow/*'
+TARPAULIN_COMMON := --engine llvm --no-dead-code --no-fail-fast \
+       --all-features --workspace $(COV_EXCLUDE) --skip-clean
+
+.PHONY: help
+help: ## Show this help message
+       @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN 
{FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
+
 .PHONY: setup-venv
 setup-venv: ## Setup the virtualenv
+       $(call check_uv)
        $(info --- Setup virtualenv ---)
        uv venv $(VENV)
 
 .PHONY: setup
 setup: ## Setup the requirements
+       $(call check_uv)
        $(info --- Setup dependencies ---)
        uv pip install "$(MATURIN_VERSION)"
 
@@ -92,5 +121,40 @@ test-rust: ## Run tests on Rust
 
 .PHONY: test-python
 test-python: ## Run tests on Python
+       $(call check_uv)
        $(info --- Run Python tests ---)
        uv run pytest -s $(PYTHON_DIR)
+
+.PHONY: coverage
+coverage: coverage-rust ## Generate coverage report (alias for coverage-rust)
+
+.PHONY: coverage-rust
+coverage-rust: ## Generate HTML coverage report for Rust
+       $(call check_tarpaulin)
+       @mkdir -p $(COV_OUTPUT_DIR)
+       ./build-wrapper.sh cargo tarpaulin $(TARPAULIN_COMMON) \
+               -o Html --output-dir $(COV_OUTPUT_DIR)
+       @echo "Coverage report generated at 
$(COV_OUTPUT_DIR)/tarpaulin-report.html"
+
+.PHONY: coverage-xml
+coverage-xml: ## Generate XML coverage report for Rust (CI format)
+       $(call check_tarpaulin)
+       @mkdir -p $(COV_OUTPUT_DIR)
+       ./build-wrapper.sh cargo tarpaulin $(TARPAULIN_COMMON) \
+               -o xml --output-dir $(COV_OUTPUT_DIR)
+
+.PHONY: coverage-open
+coverage-open: coverage-rust ## Generate and open HTML coverage report in 
browser
+       @command -v open >/dev/null 2>&1 && open 
$(COV_OUTPUT_DIR)/tarpaulin-report.html || \
+        command -v xdg-open >/dev/null 2>&1 && xdg-open 
$(COV_OUTPUT_DIR)/tarpaulin-report.html || \
+        echo "Open $(COV_OUTPUT_DIR)/tarpaulin-report.html manually"
+
+.PHONY: coverage-check
+coverage-check: ## Fail if coverage is below threshold (COV_THRESHOLD=60)
+       $(call check_tarpaulin)
+       ./build-wrapper.sh cargo tarpaulin $(TARPAULIN_COMMON) \
+               --fail-under $(COV_THRESHOLD)
+
+.PHONY: clean-coverage
+clean-coverage: ## Remove coverage reports
+       rm -rf $(COV_OUTPUT_DIR)

Reply via email to