Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
bazel-*
.bazel-*

# Generated coverage reports (output from `bazel run @score_cpp_policies//coverage:generate_coverage_html`)
cpp_coverage/
*/cpp_coverage/

# IDE files
.vscode/
.idea/
Expand Down
23 changes: 23 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,26 @@ bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.2.17")
bazel_dep(name = "aspect_rules_lint", version = "2.5.0")

# ---------------------------------------------------------------------------
# Coverage tooling (//coverage/...). Hosts the merger/reporter/justify/
# effective_coverage Python binaries and the shell driver. Consumers do not
# need rules_python themselves to use //coverage:reporter — it is wired in
# here once for the whole policies module.
# ---------------------------------------------------------------------------
bazel_dep(name = "rules_python", version = "1.8.5")
bazel_dep(name = "rules_shell", version = "0.3.0")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
python_version = "3.12",
is_default = True,
)

pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "score_cpp_policies_pip",
python_version = "3.12",
requirements_lock = "//coverage:requirements_lock.txt",
)
use_repo(pip, "score_cpp_policies_pip")
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# score_cpp_policies

Centralized C++ quality tool policies for Eclipse S-CORE, providing sanitizer
configurations and clang-tidy integration reusable across all S-CORE modules
(logging, communication, baselibs, etc.).
configurations, clang-tidy integration and source-based code coverage
reusable across all S-CORE modules (logging, communication, baselibs, etc.).

Planned: clang-format, code coverage policies.
Planned: clang-format.

## What This Provides

Expand All @@ -15,6 +15,10 @@ Planned: clang-format, code coverage policies.
- **Constraint system** — `target_compatible_with` settings for sanitizer-incompatible targets
- **`clang_tidy/.clang-tidy`** — centralized default check set (conservative baseline, tailorable per module)
- **`clang_tidy/clang_tidy.bazelrc`** — `--config=clang-tidy` bazelrc config consumers can import
- **`//coverage:reporter` + `score_coverage_reporter` macro** — llvm-cov source-based
coverage with a shared baseline of ignore regexes (test/mock/fake/external), pluggable
per-module extensions and an effective-coverage justification post-processor.
See [`coverage/README.md`](coverage/README.md) for the seven-step adoption guide.

## Available Sanitizer Configurations

Expand Down Expand Up @@ -54,6 +58,10 @@ bazel_dep(name = "score_cpp_policies")

Copy [`sanitizers/sanitizers.bazelrc`](sanitizers/sanitizers.bazelrc) into your repository's `.bazelrc`.

### Configure Coverage

See [`coverage/README.md`](coverage/README.md).

### Run Tests

```bash
Expand Down
106 changes: 106 additions & 0 deletions coverage/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@rules_python//python:defs.bzl", "py_binary", "py_library")
load("@rules_shell//shell:sh_binary.bzl", "sh_binary")

package(default_visibility = ["//visibility:public"])

# Files consumers may reference directly (e.g. .bazelrc imports, custom macros).
exports_files([
"coverage.bazelrc",
"filter_regexes.txt",
"generate_coverage_html.sh",
])

# ---------------------------------------------------------------------------
# Per-test coverage merger.
# Bazel calls this as --coverage_output_generator once per test; it takes
# profraw files + the source-file manifest, merges them with llvm-profdata
# and packages everything (profdata + object-file list) into a zip that the
# reporter later aggregates.
#
# llvm-profdata is supplied by label via the score_coverage_merger wrapper
# (see defs.bzl), which passes --llvm_profdata as an absolute path.
# ---------------------------------------------------------------------------
py_library(
name = "merger_lib",
srcs = ["merger.py"],
imports = [".."],
)

py_binary(
name = "merger",
srcs = ["merger.py"],
)

# ---------------------------------------------------------------------------
# Final coverage reporter (HTML / LCOV / text).
# Invoked indirectly via the per-consumer wrapper produced by
# `score_coverage_reporter` (see defs.bzl). Reads per-test zips, merges all
# profdata, then calls llvm-cov to render the combined report.
#
# Note: this target intentionally does NOT carry the llvm-cov / llvm-profdata
# binaries in its `data` — the consumer-side wrapper supplies them by label,
# letting each consumer pick its own llvm_toolchain repository name and
# version (see score_coverage_reporter in coverage/defs.bzl).
# ---------------------------------------------------------------------------
py_library(
name = "reporter_lib",
srcs = ["reporter.py"],
imports = [".."],
deps = ["@rules_python//python/runfiles"],
)

py_binary(
name = "reporter",
srcs = ["reporter.py"],
deps = ["@rules_python//python/runfiles"],
)

# ---------------------------------------------------------------------------
# Coverage justification processor.
# Reads a YAML database of justifications + scans source for COV_JUSTIFIED
# markers and emits a manifest of (file, line) -> justification.
# ---------------------------------------------------------------------------
py_binary(
name = "justify",
srcs = ["justify.py"],
deps = [
"@score_cpp_policies_pip//pyyaml",
],
)

# ---------------------------------------------------------------------------
# Effective coverage calculator + HTML post-processor.
# Takes the llvm-cov HTML report and the resolved justification manifest;
# rewrites the HTML to highlight justified lines and emits effective
# coverage statistics.
# ---------------------------------------------------------------------------
py_binary(
name = "effective_coverage",
srcs = ["effective_coverage.py"],
)

# ---------------------------------------------------------------------------
# Generic post-`bazel coverage` driver. Consumers invoke this via
# `bazel run @score_cpp_policies//coverage:generate_coverage_html -- [flags]`.
# ---------------------------------------------------------------------------
sh_binary(
name = "generate_coverage_html",
srcs = ["generate_coverage_html.sh"],
data = [
":justify",
":effective_coverage",
],
)
Loading