forked from mozilla/code-coverage
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzero_coverage.py
More file actions
146 lines (118 loc) · 4.87 KB
/
Copy pathzero_coverage.py
File metadata and controls
146 lines (118 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# -*- coding: utf-8 -*-
import json
import os
from datetime import datetime
import pytz
import structlog
from code_coverage_bot import grcov
from code_coverage_bot import hgmo
logger = structlog.get_logger(__name__)
class ZeroCov(object):
DATE_FORMAT = "%Y-%m-%d"
def __init__(self, repo_dir):
assert os.path.isdir(repo_dir), "{} is not a directory".format(repo_dir)
self.repo_dir = repo_dir
def get_file_size(self, filename):
if self.repo_dir:
filename = os.path.join(self.repo_dir, filename)
if os.path.isfile(filename):
return os.path.getsize(filename)
return 0
def get_utc_from_timestamp(self, ts):
d = datetime.utcfromtimestamp(ts)
return d.replace(tzinfo=pytz.utc)
def get_date_str(self, d):
return d.strftime(ZeroCov.DATE_FORMAT)
def get_pushlog(self):
with hgmo.HGMO(self.repo_dir) as hgmo_server:
pushlog = hgmo_server.get_pushes(startID=0)
logger.info("Pushlog retrieved")
return pushlog
def get_fileinfo(self, filenames):
pushlog = self.get_pushlog()
if not pushlog:
return {}
res = {}
filenames = set(filenames)
for push in pushlog["pushes"].values():
pushdate = self.get_utc_from_timestamp(push["date"])
for chgset in push["changesets"]:
for f in chgset["files"]:
if f not in filenames:
continue
if f not in res:
res[f] = {
"size": self.get_file_size(f),
"first_push_date": pushdate,
"last_push_date": pushdate,
"commits": 1,
}
else:
r = res[f]
if pushdate < r["first_push_date"]:
r["first_push_date"] = pushdate
elif pushdate > r["last_push_date"]:
r["last_push_date"] = pushdate
r["commits"] += 1
# stringify the pushdates
for v in res.values():
v["first_push_date"] = self.get_date_str(v["first_push_date"])
v["last_push_date"] = self.get_date_str(v["last_push_date"])
# add default data for files which are not in res
for f in filenames:
if f in res:
continue
res[f] = {
"size": 0,
"first_push_date": "",
"last_push_date": "",
"commits": 0,
}
return res
def generate(self, artifacts, hgrev, out_dir="."):
report = grcov.report(
artifacts, out_format="coveralls+", source_dir=self.repo_dir
)
report = json.loads(report)
zero_coverage_files = set()
zero_coverage_functions = {}
for sf in report["source_files"]:
name = sf["name"]
# For C/C++ source files, we can consider a file as being uncovered
# when all its source lines are uncovered.
all_lines_uncovered = all(c is None or c == 0 for c in sf["coverage"])
# For JavaScript files, we can't do the same, as the top-level is always
# executed, even if it just contains declarations. So, we need to check if
# all its functions, except the top-level, are uncovered.
all_functions_uncovered = True
for f in sf["functions"]:
f_name = f["name"]
if f_name == "top-level":
continue
if not f["exec"]:
if name in zero_coverage_functions:
zero_coverage_functions[name].append(f["name"])
else:
zero_coverage_functions[name] = [f["name"]]
else:
all_functions_uncovered = False
if all_lines_uncovered or (
len(sf["functions"]) > 1 and all_functions_uncovered
):
zero_coverage_files.add(name)
os.makedirs(os.path.join(out_dir, "zero_coverage_functions"), exist_ok=True)
filesinfo = self.get_fileinfo(zero_coverage_functions.keys())
zero_coverage_info = []
for fname, functions in zero_coverage_functions.items():
info = filesinfo[fname]
info.update(
{
"name": fname,
"funcs": len(functions),
"uncovered": fname in zero_coverage_files,
}
)
zero_coverage_info.append(info)
zero_coverage_report = {"hg_revision": hgrev, "files": zero_coverage_info}
with open(os.path.join(out_dir, "zero_coverage_report.json"), "w") as f:
json.dump(zero_coverage_report, f)