Skip to content

Commit 53e7de1

Browse files
Add s32k1xx coverage and merge reports
- Integrated tests-s32k1xx-debug into coverage workflow - Merged coverage reports for single badge and HTML output - Relative path to repo root - Excluded all third-party and mock files from coverage Change-Id: Ia1a8c46c4929494f64fa3613f811f38e380bfad2
1 parent 9a54b8f commit 53e7de1

File tree

2 files changed

+94
-111
lines changed

2 files changed

+94
-111
lines changed

.ci/code_coverage.py

Lines changed: 93 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -15,161 +15,144 @@ def get_full_path(command):
1515
sys.exit(1)
1616
return cmd
1717

18-
1918
build_dir_name = "code_coverage"
2019

20+
targets = [
21+
("s32k1xx", "tests-s32k1xx-debug"),
22+
("posix", "tests-posix-debug"),
23+
]
2124

22-
def build():
23-
build_dir = Path(build_dir_name)
24-
build_dir.parents
25-
if build_dir.exists():
26-
shutil.rmtree(build_dir)
25+
def build(env):
26+
for name, preset in targets:
27+
build_dir = Path(build_dir_name) / name
2728

28-
env = dict(os.environ)
29+
if build_dir.exists():
30+
shutil.rmtree(build_dir)
2931

30-
threads = os.cpu_count() - 1
31-
if threads is None:
32-
threads = 1
32+
subprocess.run([
33+
"cmake", "--preset", preset,
34+
"-B", str(build_dir),
35+
], check=True, env=env)
3336

34-
env["CTEST_PARALLEL_LEVEL"] = str(threads)
35-
env["CMAKE_BUILD_PARALLEL_LEVEL"] = str(threads)
36-
env["CC"] = get_full_path(f"gcc-{GCC_VERSION}")
37-
env["CXX"] = get_full_path(f"g++-{GCC_VERSION}")
37+
subprocess.run([
38+
"cmake", "--build", str(build_dir), "--config", "Debug"
39+
], check=True, env=env)
3840

39-
subprocess.run(
40-
[
41-
"cmake",
42-
"--preset",
43-
"tests-posix-debug",
44-
"-B",
45-
f"{build_dir_name}",
46-
],
47-
check=True,
48-
env=env,
49-
)
41+
subprocess.run([
42+
"ctest", "--test-dir", str(build_dir), "--output-on-failure"
43+
], check=True, env=env)
5044

51-
subprocess.run(
52-
["cmake", "--build", f"{build_dir_name}", "--config", "Debug", "--verbose"],
53-
check=True,
54-
env=env,
55-
)
45+
def generate_combined_coverage():
46+
tracefiles = []
5647

57-
subprocess.run(
58-
["ctest", "--test-dir", f"{build_dir_name}", "--output-on-failure"],
59-
check=True,
60-
env=env,
61-
)
48+
exclude_patterns = [
49+
"*/mock/*",
50+
"*/gmock/*",
51+
"*/gtest/*",
52+
"*/test/*",
53+
"*/3rdparty/*",
54+
]
6255

56+
for name, _ in targets:
57+
unfiltered = f"code_coverage/coverage_{name}_unfiltered.info"
58+
filtered = f"code_coverage/coverage_{name}.info"
6359

64-
def generate_coverage():
65-
# Capture coverage data
66-
subprocess.run(
67-
[
60+
subprocess.run([
6861
"lcov",
6962
"--gcov-tool", f"gcov-{GCC_VERSION}",
7063
"--capture",
71-
"--directory",
72-
f"{build_dir_name}",
64+
"--directory", f"code_coverage/{name}",
7365
"--no-external",
74-
"--base-directory",
75-
".",
76-
"--output-file",
77-
f"{build_dir_name}/coverage_unfiltered.info",
66+
"--base-directory", ".",
67+
"--output-file", unfiltered,
7868
"--ignore-errors", "mismatch",
79-
],
80-
check=True,
81-
)
69+
"--rc", "geninfo_unexecuted_blocks=1",
70+
], check=True)
71+
72+
subprocess.run([
73+
"lcov", "--remove",
74+
unfiltered,
75+
*exclude_patterns,
76+
"--output-file", filtered,
77+
"--ignore-errors", "mismatch",
78+
], check=True)
8279

83-
# Remove unwanted paths from coverage
80+
tracefiles.append(filtered)
8481

85-
subprocess.run(
86-
[
87-
"lcov",
88-
"--gcov-tool", f"gcov-{GCC_VERSION}",
89-
"--remove",
90-
f"{build_dir_name}/coverage_unfiltered.info",
91-
"*/3rdparty/*",
92-
"*/mock/*",
93-
"*/test/*",
94-
"--output-file",
95-
f"{build_dir_name}/coverage.info",
96-
"--ignore-errors", "mismatch",
97-
],
98-
check=True,
99-
)
82+
merge_args = ["lcov", "--ignore-errors", "mismatch"]
83+
for tf in tracefiles:
84+
merge_args += ["--add-tracefile", tf]
85+
merge_args += ["--output-file", f"{build_dir_name}/coverage.info"]
10086

101-
# Generate HTML report
102-
subprocess.run(
103-
[
104-
"genhtml",
105-
f"{build_dir_name}/coverage.info",
106-
"--output-directory",
107-
f"{build_dir_name}/coverage",
108-
"--prefix",
109-
"/home/jenkins/",
110-
],
111-
check=True,
112-
)
87+
subprocess.run(merge_args, check=True)
11388

89+
repo_root = Path(__file__).resolve().parents[1]
90+
subprocess.run([
91+
"genhtml", f"{build_dir_name}/coverage.info",
92+
"--prefix", str(repo_root),
93+
"--output-directory", f"{build_dir_name}/coverage"
94+
], check=True)
11495

11596
def generate_badges():
116-
# FIXME: It's questionable whether we want to have a dependency to an
117-
# external service for generating these badges. This introduces a possible
118-
# cause of instabilities in case the external service becomes unavailable,
119-
# as already happened in the CI.
120-
12197
result = subprocess.run(
12298
[
12399
"lcov",
124100
"--gcov-tool", f"gcov-{GCC_VERSION}",
125-
"--summary",
126-
f"{build_dir_name}/coverage.info",
101+
"--summary", f"{build_dir_name}/coverage.info",
127102
"--ignore-errors", "mismatch",
128103
],
129104
capture_output=True,
130105
text=True,
131106
check=True,
132107
)
108+
133109
summary = result.stdout
134110

135111
line_percentage = re.search(r"lines\.*:\s+(\d+\.\d+)%", summary)
136-
function_percentage = re.search(r"functions\.*:\s+(\d+\.\d+)%", summary)
112+
func_percentage = re.search(r"functions\.*:\s+(\d+\.\d+)%", summary)
137113

138114
coverage_badge_path = Path(build_dir_name).joinpath("coverage_badges")
139115
coverage_badge_path.mkdir(parents=True, exist_ok=True)
140116

141117
if line_percentage:
142-
line_value = line_percentage.group(1)
143-
print(f"Line Percentage: {line_value}%")
144-
subprocess.run(
145-
[
146-
"wget",
147-
f"https://img.shields.io/badge/coverage-{line_value}%25-brightgreen.svg",
148-
"-O",
149-
coverage_badge_path.joinpath("line_coverage_badge.svg").as_posix(),
150-
],
151-
check=True,
152-
)
118+
line_value = line_percentage.group(1)
119+
print(f"Line Percentage: {line_value}%")
120+
subprocess.run(
121+
[
122+
"wget",
123+
f"https://img.shields.io/badge/coverage-{line_value}%25-brightgreen.svg",
124+
"-O",
125+
coverage_badge_path.joinpath("line_coverage_badge.svg").as_posix(),
126+
],
127+
check=True,
128+
)
153129

154130
if function_percentage:
155-
function_value = function_percentage.group(1)
156-
print(f"Function Percentage: {function_value}%")
157-
subprocess.run(
158-
[
159-
"wget",
160-
f"https://img.shields.io/badge/coverage-{function_value}%25-brightgreen.svg",
161-
"-O",
162-
coverage_badge_path.joinpath("function_coverage_badge.svg").as_posix(),
163-
],
164-
check=True,
165-
)
166-
131+
function_value = function_percentage.group(1)
132+
print(f"Function Percentage: {function_value}%")
133+
subprocess.run(
134+
[
135+
"wget",
136+
f"https://img.shields.io/badge/coverage-{function_value}%25-brightgreen.svg",
137+
"-O",
138+
coverage_badge_path.joinpath("function_coverage_badge.svg").as_posix(),
139+
],
140+
check=True,
141+
)
167142

168143
if __name__ == "__main__":
169144
try:
170-
build()
171-
generate_coverage()
145+
env = dict(os.environ)
146+
threads = os.cpu_count() - 1 or 1
147+
env["CTEST_PARALLEL_LEVEL"] = str(threads)
148+
env["CMAKE_BUILD_PARALLEL_LEVEL"] = str(threads)
149+
150+
env["CC"] = get_full_path(f"gcc-{GCC_VERSION}")
151+
env["CXX"] = get_full_path(f"g++-{GCC_VERSION}")
152+
153+
build(env)
154+
generate_combined_coverage()
172155
generate_badges()
173156
except subprocess.CalledProcessError as e:
174157
print(f"Command failed with exit code {e.returncode}")
175-
sys.exit(e.returncode)
158+
sys.exit(e.returncode)

.github/workflows/code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ jobs:
5858
uses: actions/upload-artifact@v4
5959
with:
6060
name: coverage_badges
61-
path: code_coverage/coverage_badges.zip
61+
path: code_coverage/coverage_badges.zip

0 commit comments

Comments
 (0)