Skip to content

Commit f85942b

Browse files
author
Bastien Abadie
committed
bot: Build then upload all reports
1 parent fd33bc9 commit f85942b

File tree

4 files changed

+80
-44
lines changed

4 files changed

+80
-44
lines changed

bot/code_coverage_bot/artifacts.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ def get_chunks(self, platform):
4444
)
4545

4646
def get_suites(self):
47+
# Add the full report
48+
out = collections.defaultdict(list)
49+
out[("all", "all")] = [artifact.path for artifact in self.artifacts]
50+
4751
# Group by suite first
4852
suites = itertools.groupby(
4953
sorted(self.artifacts, key=lambda a: a.suite), lambda a: a.suite
5054
)
51-
52-
out = collections.defaultdict(list)
5355
for suite, artifacts in suites:
5456
artifacts = list(artifacts)
5557

bot/code_coverage_bot/codecov.py

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def __init__(self, repository, revision, task_name_filter, cache_root):
4242

4343
temp_dir = tempfile.mkdtemp()
4444
self.artifacts_dir = os.path.join(temp_dir, "ccov-artifacts")
45+
self.reports_dir = os.path.join(temp_dir, "ccov-reports")
4546

4647
self.index_service = taskcluster_config.get_service("index")
4748

@@ -118,23 +119,18 @@ def retrieve_source_and_artifacts(self):
118119
# Thread 2 - Clone repository.
119120
executor.submit(self.clone_repository, self.repository, self.revision)
120121

121-
def generate_covdir(self):
122+
def build_reports(self, only=None):
122123
"""
123-
Build the full covdir report using current artifacts
124+
Build all the possible covdir reports using current artifacts
124125
"""
125-
output = grcov.report(
126-
self.artifactsHandler.get(), source_dir=self.repo_dir, out_format="covdir"
127-
)
128-
logger.info("Covdir report generated successfully")
129-
return json.loads(output)
126+
os.makedirs(self.reports_dir, exist_ok=True)
130127

131-
def build_suites(self):
132-
"""
133-
Build all the detailed covdir reports using current artifacts
134-
and upload them directly on GCP
135-
"""
128+
reports = {}
136129
for (platform, suite), artifacts in self.artifactsHandler.get_suites().items():
137130

131+
if only is not None and (platform, suite) not in only:
132+
continue
133+
138134
# Generate covdir report for that suite & platform
139135
logger.info(
140136
"Building covdir suite report",
@@ -146,27 +142,33 @@ def build_suites(self):
146142
artifacts, source_dir=self.repo_dir, out_format="covdir"
147143
)
148144

149-
# Then upload on GCP
150-
report = json.loads(output)
145+
# Write output on FS
146+
path = os.path.join(self.reports_dir, f"{platform}.{suite}.json")
147+
with open(path, "wb") as f:
148+
f.write(output)
149+
150+
reports[(platform, suite)] = path
151+
152+
return reports
153+
154+
def upload_reports(self, reports):
155+
"""
156+
Upload all provided covdir reports on GCP
157+
"""
158+
for (platform, suite), path in reports.items():
159+
report = json.load(open(path))
151160
uploader.gcp(
152161
self.branch, self.revision, report, suite=suite, platform=platform
153162
)
154163

155-
# This function is executed when the bot is triggered at the end of a mozilla-central build.
156-
def go_from_trigger_mozilla_central(self):
157-
# Check the covdir report does not already exists
158-
if uploader.gcp_covdir_exists(self.branch, self.revision, "full"):
159-
logger.warn("Covdir report already on GCP")
160-
return
161-
162-
self.retrieve_source_and_artifacts()
163-
164-
# Check that all JavaScript files present in the coverage artifacts actually exist.
165-
# If they don't, there might be a bug in the LCOV rewriter.
164+
def check_javascript_files(self):
165+
"""
166+
Check that all JavaScript files present in the coverage artifacts actually exist.
167+
If they don't, there might be a bug in the LCOV rewriter.
168+
"""
166169
for artifact in self.artifactsHandler.get():
167170
if "jsvm" not in artifact:
168171
continue
169-
170172
with zipfile.ZipFile(artifact, "r") as zf:
171173
for file_name in zf.namelist():
172174
with zf.open(file_name, "r") as fl:
@@ -185,7 +187,25 @@ def go_from_trigger_mozilla_central(self):
185187
f"{missing_files} are present in coverage reports, but missing from the repository"
186188
)
187189

188-
report = self.generate_covdir()
190+
# This function is executed when the bot is triggered at the end of a mozilla-central build.
191+
def go_from_trigger_mozilla_central(self):
192+
# Check the covdir report does not already exists
193+
if uploader.gcp_covdir_exists(self.branch, self.revision, "all", "all"):
194+
logger.warn("Full covdir report already on GCP")
195+
return
196+
197+
self.retrieve_source_and_artifacts()
198+
199+
# TODO: restore that check
200+
# self.check_javascript_files()
201+
202+
reports = self.build_reports()
203+
logger.info("Built all covdir reports", nb=len(reports))
204+
205+
# Retrieve the full report
206+
full_path = reports.get(("all", "all"))
207+
assert full_path is not None, "Missing full report (all:all)"
208+
report = json.load(open(full_path))
189209

190210
paths = uploader.covdir_paths(report)
191211
expected_extensions = [".js", ".cpp"]
@@ -194,6 +214,9 @@ def go_from_trigger_mozilla_central(self):
194214
path.endswith(extension) for path in paths
195215
), "No {} file in the generated report".format(extension)
196216

217+
self.upload_reports(reports)
218+
logger.info("Uploaded all covdir reports", nb=len(reports))
219+
197220
# Get pushlog and ask the backend to generate the coverage by changeset
198221
# data, which will be cached.
199222
with hgmo.HGMO(self.repo_dir) as hgmo_server:
@@ -203,10 +226,6 @@ def go_from_trigger_mozilla_central(self):
203226
phabricatorUploader = PhabricatorUploader(self.repo_dir, self.revision)
204227
changesets_coverage = phabricatorUploader.upload(report, changesets)
205228

206-
uploader.gcp(self.branch, self.revision, report)
207-
logger.info("Main Build uploaded on GCP")
208-
209-
self.build_suites()
210229
notify_email(self.revision, changesets, changesets_coverage)
211230

212231
# This function is executed when the bot is triggered at the end of a try build.
@@ -226,7 +245,10 @@ def go_from_trigger_try(self):
226245

227246
self.retrieve_source_and_artifacts()
228247

229-
report = self.generate_covdir()
248+
reports = self.build_reports(only=("all", "all"))
249+
full_path = reports.get(("all", "all"))
250+
assert full_path is not None, "Missing full report (all:all)"
251+
report = json.load(open(full_path))
230252

231253
logger.info("Upload changeset coverage data to Phabricator")
232254
phabricatorUploader.upload(report, changesets)

bot/code_coverage_bot/uploader.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,29 @@
1212
from code_coverage_tools.gcp import get_bucket
1313

1414
logger = structlog.get_logger(__name__)
15-
GCP_COVDIR_PATH = "{repository}/{revision}/{name}.json.zstd"
15+
GCP_COVDIR_PATH = "{repository}/{revision}/{platform}:{suite}.json.zstd"
1616

1717

18-
def gcp(repository, revision, report, platform=None, suite=None):
18+
def gcp(repository, revision, report, platform, suite):
1919
"""
2020
Upload a grcov raw report on Google Cloud Storage
2121
* Compress with zstandard
2222
* Upload on bucket using revision in name
2323
* Trigger ingestion on channel's backend
2424
"""
2525
assert isinstance(report, dict)
26+
assert isinstance(platform, str)
27+
assert isinstance(suite, str)
2628
bucket = get_bucket(secrets[secrets.GOOGLE_CLOUD_STORAGE])
2729

2830
# Compress report
2931
compressor = zstd.ZstdCompressor()
3032
archive = compressor.compress(json.dumps(report).encode("utf-8"))
3133

3234
# Upload archive
33-
if platform and suite:
34-
name = f"{platform}:{suite}"
35-
else:
36-
name = "full"
37-
38-
path = GCP_COVDIR_PATH.format(repository=repository, revision=revision, name=name)
35+
path = GCP_COVDIR_PATH.format(
36+
repository=repository, revision=revision, platform=platform, suite=suite
37+
)
3938
blob = bucket.blob(path)
4039
blob.upload_from_string(archive)
4140

@@ -56,12 +55,14 @@ def gcp(repository, revision, report, platform=None, suite=None):
5655
return blob
5756

5857

59-
def gcp_covdir_exists(repository, revision, name):
58+
def gcp_covdir_exists(repository, revision, platform, suite):
6059
"""
6160
Check if a covdir report exists on the Google Cloud Storage bucket
6261
"""
6362
bucket = get_bucket(secrets[secrets.GOOGLE_CLOUD_STORAGE])
64-
path = GCP_COVDIR_PATH.format(repository=repository, revision=revision, name=name)
63+
path = GCP_COVDIR_PATH.format(
64+
repository=repository, revision=revision, platform=platform, suite=suite
65+
)
6566
blob = bucket.blob(path)
6667
return blob.exists()
6768

bot/tests/test_artifacts.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@ def add_dir(files):
7373
a = ArtifactsHandler([])
7474
a.artifacts = fake_artifacts
7575
assert dict(a.get_suites()) == {
76+
("all", "all"): add_dir(
77+
[
78+
"windows_mochitest-1_code-coverage-jsvm.info",
79+
"linux_mochitest-2_code-coverage-grcov.zip",
80+
"windows_xpcshell-7_code-coverage-jsvm.info",
81+
"linux_xpcshell-7_code-coverage-grcov.zip",
82+
"linux_xpcshell-3_code-coverage-grcov.zip",
83+
"windows_cppunit_code-coverage-grcov.zip",
84+
"linux_firefox-ui-functional-remote_code-coverage-jsvm.info",
85+
]
86+
),
7687
("linux", "all"): add_dir(
7788
[
7889
"linux_firefox-ui-functional-remote_code-coverage-jsvm.info",

0 commit comments

Comments
 (0)