@@ -15,161 +15,144 @@ def get_full_path(command):
1515 sys .exit (1 )
1616 return cmd
1717
18-
1918build_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
11596def 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
168143if __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 )
0 commit comments