Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,31 @@ jobs:
exit 1
fi

- name: Generate Python coverage report
id: report_python
if: ${{ steps.report_gcc.outcome != 'skipped' || steps.report_clang.outcome != 'skipped' }}
shell: bash
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/phlex-build"

echo "➡️ Generating Python coverage report..."
echo "::group::Running coverage-python target"

# Check if pytest-cov is available
if python3 -c "import pytest_cov" 2>/dev/null; then
if cmake --build . --target coverage-python -v; then
echo "::endgroup::"
echo "✅ Python coverage report generation succeeded."
else
echo "::endgroup::"
echo "::warning::Python coverage report generation failed (non-fatal)."
fi
else
echo "::endgroup::"
echo "::notice::pytest-cov not available; skipping Python coverage report."
fi

- name: Capture coverage artifact availability
id: coverage_outputs
if: ${{ steps.report_gcc.outcome != 'skipped' || steps.report_clang.outcome != 'skipped' }}
Expand All @@ -229,6 +254,11 @@ jobs:
else
echo "has_coverage_llvm_info=false" >> "$GITHUB_OUTPUT"
fi
if [ -f coverage-python.xml ]; then
echo "has_coverage_python_xml=true" >> "$GITHUB_OUTPUT"
else
echo "has_coverage_python_xml=false" >> "$GITHUB_OUTPUT"
fi

- name: Unknown Coverage Report Error
if: ${{ steps.report_gcc.outcome == 'skipped' && steps.report_clang.outcome == 'skipped' }}
Expand All @@ -251,12 +281,14 @@ jobs:
coverage.profdata \
coverage.xml \
coverage.info \
coverage.info.final; do
coverage.info.final \
coverage-python.xml; do
if [ -f "$file" ]; then
cp "$file" "$ARTIFACT_DIR/"
fi
done
if [ -d coverage-html ]; then cp -R coverage-html "$ARTIFACT_DIR/"; fi
if [ -d coverage-python-html ]; then cp -R coverage-python-html "$ARTIFACT_DIR/"; fi

- name: Detect artifact upload availability
id: artifact_runtime
Expand Down Expand Up @@ -318,6 +350,9 @@ jobs:
if [ -f coverage-artifacts/coverage-llvm.info ]; then
files+=("coverage-artifacts/coverage-llvm.info")
fi
if [ -f coverage-artifacts/coverage-python.xml ]; then
files+=("coverage-artifacts/coverage-python.xml")
fi

ls -al coverage-artifacts || true

Expand Down
44 changes: 41 additions & 3 deletions Modules/private/CreateCoverageTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# * coverage: Generates coverage reports from existing coverage data
# * coverage-html: Generates HTML coverage report using lcov/genhtml
# * coverage-xml: Generates XML coverage report using gcovr
# * coverage-clean: Cleans coverage data files
# * coverage-python: Generates Python coverage report using pytest-cov
# * coverage-clean: Cleans coverage data files (C++ and Python)
#
# ~~~
# Usage:
Expand All @@ -14,6 +15,7 @@
# Options:
# ENABLE_COVERAGE must be ON
# Requires: CMake >= 3.22
# Python coverage requires pytest and pytest-cov installed
# ~~~

include_guard()
Expand All @@ -28,7 +30,7 @@ find_program(GENHTML_EXECUTABLE genhtml)
find_program(GCOVR_EXECUTABLE gcovr)

# Find Python and normalization scripts
find_package(Python COMPONENTS Interpreter)
find_package(Python 3.12 COMPONENTS Interpreter QUIET)

# Find CTest coverage tool
find_program(LLVM_COV_EXECUTABLE NAMES llvm-cov-21 llvm-cov DOC "LLVM coverage tool")
Expand Down Expand Up @@ -542,11 +544,47 @@ function(_create_coverage_targets_impl)
COMMAND find ${CMAKE_BINARY_DIR} -name "*.gcno" -delete
COMMAND rm -f ${CMAKE_BINARY_DIR}/coverage.info*
COMMAND rm -f ${CMAKE_BINARY_DIR}/coverage.xml
COMMAND rm -f ${CMAKE_BINARY_DIR}/coverage-python.xml
COMMAND rm -rf ${CMAKE_BINARY_DIR}/coverage-html
COMMAND rm -rf ${CMAKE_BINARY_DIR}/coverage-python-html
COMMAND rm -rf ${CMAKE_BINARY_DIR}/.coverage
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Cleaning coverage data files"
COMMENT "Cleaning coverage data files (C++ and Python)"
)

# Add Python coverage target if pytest-cov is available
if(Python_FOUND)
execute_process(
COMMAND ${Python_EXECUTABLE} -c "import pytest_cov"
RESULT_VARIABLE PYTEST_COV_CHECK
OUTPUT_QUIET
ERROR_QUIET
)
if(PYTEST_COV_CHECK EQUAL 0)
add_custom_target(
coverage-python
COMMAND
${CMAKE_COMMAND} -E echo
"[Coverage] Generating Python coverage report using pytest-cov..."
COMMAND
${CMAKE_COMMAND} -E env PYTHONPATH=${PROJECT_SOURCE_DIR}/test/python
PHLEX_INSTALL=${PROJECT_SOURCE_DIR} ${Python_EXECUTABLE} -m pytest
${PROJECT_SOURCE_DIR}/test/python/test_phlex.py --cov=${PROJECT_SOURCE_DIR}/test/python
--cov-report=term-missing --cov-report=xml:${CMAKE_BINARY_DIR}/coverage-python.xml
--cov-report=html:${CMAKE_BINARY_DIR}/coverage-python-html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Generating Python coverage report"
VERBATIM
)
message(STATUS "Added 'coverage-python' target for Python test coverage (pytest-cov)")
else()
message(
STATUS
"pytest-cov not found; Python coverage target not available. Install with: pip install pytest-cov"
)
endif()
endif()

message(
STATUS
"Coverage targets added: coverage, coverage-gcov, coverage-xml, coverage-html, coverage-clean"
Expand Down
21 changes: 19 additions & 2 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,12 @@ Provides convenient commands for managing code coverage analysis.
| Command | Description |
|---------|-------------|
| `setup` | Configure and build with coverage instrumentation |
| `clean` | Remove coverage data files |
| `test` | Run tests with coverage collection |
| `clean` | Remove coverage data files (C++ and Python) |
| `test` | Run tests with coverage collection (C++ and Python) |
| `report` | Generate both XML and HTML coverage reports |
| `xml` | Generate XML coverage report only |
| `html` | Generate HTML coverage report only |
| `python` | Generate Python coverage report using pytest-cov |
| `view` | Open HTML coverage report in browser |
| `summary` | Show coverage summary in terminal |
| `upload` | Upload coverage to Codecov |
Expand All @@ -186,6 +187,16 @@ The `coverage.sh` script automatically sources `setup-env.sh` if found:
2. Then tries repository-level: `$PROJECT_SOURCE/scripts/setup-env.sh`
3. If neither found, assumes environment is already configured

#### Python Coverage Requirements

Python coverage requires the following packages to be installed:

```bash
pip install pytest pytest-cov
```

When `ENABLE_COVERAGE=ON` and pytest-cov is available, Python tests will automatically generate coverage reports alongside C++ coverage.

#### Coverage Examples

**Complete coverage workflow**:
Expand All @@ -204,6 +215,12 @@ The `coverage.sh` script automatically sources `setup-env.sh` if found:
./scripts/coverage.sh view # View in browser
```

**Python coverage only**:

```bash
./scripts/coverage.sh setup test python
```

**Generate and upload to Codecov**:

```bash
Expand Down
Loading
Loading