Skip to content

Commit a1cbf90

Browse files
committed
Check coverage in CI
Signed-off-by: Kateryna Nezdolii <kateryna.nezdolii@gmail.com>
1 parent e3dbcd7 commit a1cbf90

15 files changed

Lines changed: 963 additions & 1 deletion

File tree

.bazelrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ build:clang-common --action_env=CXX=clang++-18 --host_action_env=CXX=clang++-18
1212
build:rbe-toolchain-clang --action_env=CC=clang-18 --action_env=CXX=clang++-18
1313
build:rbe-toolchain-arm64-clang --action_env=CC=clang-18 --action_env=CXX=clang++-18
1414

15+
coverage --config=coverage
16+
17+
build:coverage --combined_report=lcov
18+
build:coverage --action_env=CC=clang-18 --host_action_env=CC=clang-18
19+
build:coverage --action_env=CXX=clang++-18 --host_action_env=CXX=clang++-18
20+
#build:coverage --test_arg="--log-path /dev/null"
21+
build:coverage --test_tag_filters=-nocoverage,-fuzz_target
22+
build:coverage --remote_download_minimal
23+
1524
# Use platforms based toolchain resolution
1625
build --incompatible_enable_cc_toolchain_resolution
1726
build --platform_mappings=bazel/platform_mappings
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: CI Check coverage
2+
on:
3+
pull_request: {}
4+
5+
permissions:
6+
# To be able to access the repository with actions/checkout
7+
contents: read
8+
pull-requests: read
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
coverage:
16+
timeout-minutes: 460
17+
name: Check coverage for pull request #${{ github.event.pull_request.number }}
18+
runs-on: ubuntu-22.04
19+
steps:
20+
- name: Clear Workspace
21+
shell: bash
22+
run: |
23+
sudo rm -r /usr/local/.ghcup
24+
sudo rm -r /usr/local/lib/android
25+
sudo rm -r /opt/hostedtoolcache
26+
- name: Check disk space
27+
shell: bash
28+
run: |
29+
df . -h
30+
- name: Check out the repository to the runner
31+
uses: actions/checkout@v4
32+
- name: Setup gcloud credentials
33+
uses: google-github-actions/auth@v2
34+
with:
35+
credentials_json: ${{ secrets.CI_CILIUM_PROXY_SA_KEY }}
36+
- name: set up google cloud sdk
37+
uses: 'google-github-actions/setup-gcloud@v2'
38+
with:
39+
version: '>= 507.0.0'
40+
- name: Install deps (for C++)
41+
shell: bash
42+
run: |
43+
sudo apt-get update && \
44+
sudo apt-get upgrade -y --no-install-recommends && \
45+
sudo apt-get install -y --no-install-recommends \
46+
ca-certificates libc6-dev autoconf automake cmake coreutils curl git libtool make ninja-build patch patchelf \
47+
python3 python-is-python3 unzip virtualenv wget zip software-properties-common && \
48+
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
49+
sudo apt-add-repository -y "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" && \
50+
sudo apt-get update && \
51+
sudo apt-get install -y --no-install-recommends \
52+
clang-18 clangd-18 clang-tidy-18 clang-tools-18 llvm-18-dev lldb-18 lld-18 clang-format-18 libc++-18-dev libc++abi-18-dev libclang-rt-18-dev lcov && \
53+
sudo apt-get purge --auto-remove && \
54+
sudo apt-get clean && \
55+
sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
56+
cp /usr/lib/llvm-18/bin/llvm-cov /usr/local/bin
57+
cp /usr/lib/llvm-18/bin/llvm-profdata /usr/local/bin
58+
- name: Install Go
59+
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
60+
with:
61+
# renovate: datasource=golang-version depName=go
62+
go-version: 1.24.6
63+
- name: Sync crate lockfile with bazel
64+
shell: bash
65+
run: |
66+
CARGO_BAZEL_ISOLATED=0 CARGO_BAZEL_REPIN=1 bazel sync --only=crate_index
67+
- name: Build proxylib
68+
shell: bash
69+
run: |
70+
go version
71+
make -C proxylib
72+
- name: Build test deps
73+
shell: bash
74+
run: |
75+
BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --remote_cache=${{ vars.GCS_ARTIFACT_BUCKET_REMOTE_CACHE }} --google_default_credentials" BAZEL_TEST_OPTS="--test_timeout=300 --local_test_jobs=1 --flaky_test_attempts=3" make envoy-test-deps
76+
- name: Generate coverage data
77+
shell: bash
78+
run: |
79+
echo "Generating bazel coverage: "
80+
./tests/run_bazel_coverage.sh
81+
ls -la /home/runner/work/cilium-proxy/cilium-proxy/generated/coverage/
82+
- name: Upload (sync) to GCS bucket
83+
if: '!cancelled()'
84+
shell: bash
85+
run: |
86+
UPLOAD_DIR="/home/runner/work/cilium-proxy/cilium-proxy/generated/coverage/"
87+
SHA=${{ github.sha }}
88+
BUCKET_PATH="${{ vars.GCS_ARTIFACT_BUCKET_COVERAGE }}/${SHA:0:7}/coverage"
89+
echo "Uploading to gs://$BUCKET_PATH ..."
90+
gsutil \
91+
-mq rsync \
92+
-dr "$UPLOAD_DIR" \
93+
"gs://$BUCKET_PATH"
94+
echo "Artifacts uploaded to: https://storage.googleapis.com/$BUCKET_PATH/html/index.html" >&2
95+
strategy:
96+
fail-fast: false
97+
matrix:
98+
include:
99+
- target: coverage
100+
name: Coverage
101+
diskspace-hack: true
102+
diskspace-hack-paths: |
103+
/opt/hostedtoolcache
104+
/usr/local/lib/android

WORKSPACE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ git_repository(
4949
# // clang-format on
5050
)
5151

52+
load("//bazel:repo.bzl", "cilium_proxy_repo")
53+
54+
cilium_proxy_repo()
55+
5256
#
5357
# Bazel does not do transitive dependencies, so we must basically
5458
# include all of Envoy's WORKSPACE file below, with the following

bazel/repo.bzl

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# `@cilium_proxy_repo` repository rule for managing the repo and querying its metadata.
2+
3+
def _cilium_proxy_repo_impl(repository_ctx):
4+
"""This provides information about the Envoy repository
5+
6+
You can access the current project and api versions and the path to the repository in
7+
.bzl/BUILD files as follows:
8+
9+
```starlark
10+
load("@cilium_proxy_repo//:version.bzl", "VERSION", "API_VERSION")
11+
```
12+
13+
`*VERSION` can be used to derive version-specific rules and can be passed
14+
to the rules.
15+
16+
The `VERSION`s and also the local `PATH` to the repo can be accessed in
17+
python libraries/binaries. By adding `@cilium_proxy_repo` to `deps` they become
18+
importable through the `cilium_proxy_repo` namespace.
19+
20+
As the `PATH` is local to the machine, it is generally only useful for
21+
jobs that will run locally.
22+
23+
This can be useful, for example, for bazel run jobs to run bazel queries that cannot be run
24+
within the constraints of a `genquery`, or that otherwise need access to the repository
25+
files.
26+
27+
Project and repo data can be accessed in JSON format using `@cilium_proxy_repo//:project`, eg:
28+
29+
```starlark
30+
load("@aspect_bazel_lib//lib:jq.bzl", "jq")
31+
32+
jq(
33+
name = "project_version",
34+
srcs = ["@cilium_proxy_repo//:data"],
35+
out = "version.txt",
36+
args = ["-r"],
37+
filter = ".version",
38+
)
39+
40+
```
41+
42+
"""
43+
repo_version_path = repository_ctx.path(repository_ctx.attr.envoy_version)
44+
api_version_path = repository_ctx.path(repository_ctx.attr.envoy_api_version)
45+
version = repository_ctx.read(repo_version_path).strip()
46+
api_version = repository_ctx.read(api_version_path).strip()
47+
repository_ctx.file("version.bzl", "VERSION = '%s'\nAPI_VERSION = '%s'" % (version, api_version))
48+
repository_ctx.file("path.bzl", "PATH = '%s'" % repo_version_path.dirname)
49+
repository_ctx.file("__init__.py", "PATH = '%s'\nVERSION = '%s'\nAPI_VERSION = '%s'" % (repo_version_path.dirname, version, api_version))
50+
repository_ctx.file("WORKSPACE", "")
51+
repository_ctx.file("BUILD", '''
52+
load("@rules_python//python:defs.bzl", "py_library")
53+
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
54+
load("//:path.bzl", "PATH")
55+
56+
py_library(
57+
name = "cilium_proxy_repo",
58+
srcs = ["__init__.py"],
59+
visibility = ["//visibility:public"],
60+
)
61+
62+
''')
63+
64+
_cilium_proxy_repo = repository_rule(
65+
implementation = _cilium_proxy_repo_impl,
66+
attrs = {
67+
#todo(nezdolik) add cilium version
68+
"envoy_version": attr.label(default = "@envoy//:VERSION.txt"),
69+
"envoy_api_version": attr.label(default = "@envoy//:API_VERSION.txt"),
70+
},
71+
)
72+
73+
def cilium_proxy_repo():
74+
if "cilium_proxy_repo" not in native.existing_rules().keys():
75+
_cilium_proxy_repo(name = "cilium_proxy_repo")

envoy.bazelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ build:coverage --linkopt=-Wl,-s,--no-relax
262262
build:coverage --test_env=ENVOY_IP_TEST_VERSIONS=v4only
263263
build:coverage --define=dynamic_link_tests=false
264264
# Use custom report generator that also generates HTML
265-
build:coverage --coverage_report_generator=@envoy//tools/coverage:report_generator
265+
build:coverage --coverage_report_generator=//tools/coverage:cilium_report_generator
266266

267267
build:test-coverage --test_arg="-l trace"
268268
build:test-coverage --test_arg="--log-path /dev/null"

tests/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@aspect_bazel_lib//lib:yq.bzl", "yq")
12
load(
23
"@envoy//bazel:envoy_build_system.bzl",
34
"envoy_cc_test",
@@ -18,6 +19,14 @@ api_cc_py_proto_library(
1819
srcs = ["bpf_metadata.proto"],
1920
)
2021

22+
yq(
23+
name = "coverage_config",
24+
srcs = [":coverage.yaml"],
25+
outs = ["cilium_coverage_config.json"],
26+
args = ["-o=json"],
27+
visibility = ["//visibility:public"],
28+
)
29+
2130
envoy_cc_test_library(
2231
name = "accesslog_server_lib",
2332
srcs = ["accesslog_server.cc"],

tests/coverage.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
thresholds:
2+
total: 95.0
3+
per_directory: 95.0
4+
5+
directories:
6+
cilium: 95.0
7+
linux: 95.0

tests/run_bazel_coverage.sh

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env bash
2+
3+
set -e -o pipefail
4+
set +x
5+
set -u
6+
7+
LLVM_VERSION=${LLVM_VERSION:-"18.1.8"}
8+
CLANG_VERSION=$(clang-18 --version | grep version | sed -e 's/\ *Ubuntu clang version \([0-9.]*\).*/\1/')
9+
LLVM_COV_VERSION=$(llvm-cov --version | grep version | sed -e 's/\ *Ubuntu LLVM version \([0-9.]*\).*/\1/')
10+
LLVM_PROFDATA_VERSION=$(llvm-profdata show --version | grep version | sed -e 's/\ *Ubuntu LLVM version \(.*\)/\1/')
11+
SRCDIR=${SRCDIR:-"${PWD}"}
12+
13+
#ERROR: clang version Ubuntu18.1.3 does not match expected 18.1.3
14+
if [[ "${CLANG_VERSION}" != "${LLVM_VERSION}" ]]; then
15+
echo "ERROR: clang version ${CLANG_VERSION} does not match expected ${LLVM_VERSION}" >&2
16+
exit 1
17+
fi
18+
19+
if [[ "${LLVM_COV_VERSION}" != "${LLVM_VERSION}" ]]; then
20+
echo "ERROR: llvm-cov version ${LLVM_COV_VERSION} does not match expected ${LLVM_VERSION}" >&2
21+
exit 1
22+
fi
23+
24+
if [[ "${LLVM_PROFDATA_VERSION}" != "${LLVM_VERSION}" ]]; then
25+
echo "ERROR: llvm-profdata version ${LLVM_PROFDATA_VERSION} does not match expected ${LLVM_VERSION}" >&2
26+
exit 1
27+
fi
28+
29+
COVERAGE_TARGET="${COVERAGE_TARGET:-}"
30+
#TBD propogate any important global build options
31+
read -ra BAZEL_BUILD_OPTIONS <<< "${BAZEL_BUILD_OPTION_LIST:-}"
32+
read -ra BAZEL_GLOBAL_OPTIONS <<< "${BAZEL_GLOBAL_OPTION_LIST:-}"
33+
34+
# This is the target that will be run to generate coverage data. It can be overridden by consumer
35+
# projects that want to run coverage on a different/combined target.
36+
# Command-line arguments take precedence over ${COVERAGE_TARGET}.
37+
if [[ $# -gt 0 ]]; then
38+
COVERAGE_TARGETS=("$@")
39+
elif [[ -n "${COVERAGE_TARGET}" ]]; then
40+
COVERAGE_TARGETS=("${COVERAGE_TARGET}")
41+
else
42+
COVERAGE_TARGETS=(//tests/...)
43+
fi
44+
45+
BAZEL_COVERAGE_OPTIONS=()
46+
BAZEL_COVERAGE_OPTIONS+=(--heap_dump_on_oom)
47+
BAZEL_COVERAGE_OPTIONS+=(--action_env=BAZEL_USE_LLVM_NATIVE_COVERAGE=1)
48+
BAZEL_COVERAGE_OPTIONS+=(--combined_report=lcov)
49+
BAZEL_COVERAGE_OPTIONS+=(--coverage_report_generator=//tools/coverage:cilium_report_generator)
50+
BAZEL_COVERAGE_OPTIONS+=(--experimental_use_llvm_covmap)
51+
BAZEL_COVERAGE_OPTIONS+=(--experimental_generate_llvm_lcov)
52+
BAZEL_COVERAGE_OPTIONS+=(--experimental_split_coverage_postprocessing)
53+
BAZEL_COVERAGE_OPTIONS+=(--experimental_fetch_all_coverage_outputs)
54+
BAZEL_COVERAGE_OPTIONS+=(--collect_code_coverage)
55+
BAZEL_COVERAGE_OPTIONS+=(--remote_download_minimal)
56+
BAZEL_COVERAGE_OPTIONS+=(--copt=-DNDEBUG)
57+
BAZEL_COVERAGE_OPTIONS+=(--build_tests_only)
58+
#from envoy
59+
BAZEL_COVERAGE_OPTIONS+=(--experimental_repository_cache_hardlinks)
60+
BAZEL_COVERAGE_OPTIONS+=(--verbose_failures)
61+
BAZEL_COVERAGE_OPTIONS+=(--experimental_generate_json_trace_profile)
62+
BAZEL_COVERAGE_OPTIONS+=(--action_env=GCOV=llvm-profdata)
63+
BAZEL_VALIDATE_OPTIONS=()
64+
65+
66+
# Output unusually long logs due to trace logging.
67+
BAZEL_COVERAGE_OPTIONS+=("--experimental_ui_max_stdouterr_bytes=80000000")
68+
BAZEL_BUILD_OPTIONS+=("--remote_cache=https://storage.googleapis.com/cilium-proxy-bazel-remote-cache")
69+
BAZEL_BUILD_OPTIONS+=("--google_default_credentials")
70+
71+
COVERAGE_DIR="${SRCDIR}/generated/coverage"
72+
73+
COVERAGE_DATA="${COVERAGE_DIR}/coverage.dat"
74+
75+
76+
run_coverage() {
77+
echo "Running bazel coverage with:"
78+
echo " Options: ${BAZEL_BUILD_OPTIONS[*]} ${BAZEL_COVERAGE_OPTIONS[*]}"
79+
echo " Targets: ${COVERAGE_TARGETS[*]}"
80+
bazel coverage "${COVERAGE_TARGETS[@]}" "${BAZEL_BUILD_OPTIONS[@]}" "${BAZEL_COVERAGE_OPTIONS[@]}" --compiler=clang-18 --verbose_failures --sandbox_writable_path=$(bazel info output_path) --test_timeout=300 --local_test_jobs=1 --flaky_test_attempts=3 --instrument_test_targets --instrumentation_filter='^//'
81+
82+
if [[ ! -e bazel-out/_coverage/_coverage_report.dat ]]; then
83+
echo "ERROR: No coverage report found (bazel-out/_coverage/_coverage_report.dat)" >&2
84+
exit 1
85+
elif [[ ! -s bazel-out/_coverage/_coverage_report.dat ]]; then
86+
echo "ERROR: Coverage report is empty (bazel-out/_coverage/_coverage_report.dat)" >&2
87+
exit 1
88+
fi
89+
}
90+
91+
unpack_coverage_results() {
92+
rm -rf "${COVERAGE_DIR}"
93+
mkdir -p "${COVERAGE_DIR}"
94+
rm -f bazel-out/_coverage/_coverage_report.tar.zst
95+
mv bazel-out/_coverage/_coverage_report.dat bazel-out/_coverage/_coverage_report.tar.zst
96+
bazel run "${BAZEL_BUILD_OPTIONS[@]}" --nobuild_tests_only @envoy//tools/zstd -- -d -c "${PWD}/bazel-out/_coverage/_coverage_report.tar.zst" \
97+
| tar -xf - -C "${COVERAGE_DIR}"
98+
COVERAGE_JSON="${COVERAGE_DIR}/coverage.json"
99+
}
100+
101+
validate_coverage() {
102+
bazel run \
103+
"${BAZEL_BUILD_OPTIONS[@]}" \
104+
"${BAZEL_VALIDATE_OPTIONS[@]}" \
105+
--nobuild_tests_only \
106+
//tools/coverage:validate \
107+
"$COVERAGE_JSON"
108+
}
109+
110+
run_coverage
111+
unpack_coverage_results
112+
validate_coverage

0 commit comments

Comments
 (0)