Skip to content

Commit c053542

Browse files
committed
bot: Generate a mapping file from commit to its coverage statistics
1 parent bca685a commit c053542

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# -*- coding: utf-8 -*-
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this
4+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
6+
import io
7+
import json
8+
import os
9+
10+
import requests
11+
import structlog
12+
import zstandard
13+
14+
from code_coverage_bot import hgmo
15+
from code_coverage_bot import utils
16+
from code_coverage_bot.phabricator import PhabricatorUploader
17+
from code_coverage_bot.secrets import secrets
18+
from code_coverage_tools.gcp import DEFAULT_FILTER
19+
from code_coverage_tools.gcp import download_report
20+
from code_coverage_tools.gcp import get_bucket
21+
from code_coverage_tools.gcp import get_name
22+
from code_coverage_tools.gcp import list_reports
23+
24+
logger = structlog.get_logger(__name__)
25+
26+
27+
def generate(repo_dir: str) -> None:
28+
commit_coverage_path = "commit_coverage.json"
29+
30+
url = f"https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.relman.code-coverage.{secrets[secrets.APP_CHANNEL]}.cron.latest/artifacts/public/{commit_coverage_path}.zst" # noqa
31+
r = requests.head(url, allow_redirects=True)
32+
if r.status_code != 404:
33+
utils.download_file(url, f"{commit_coverage_path}.zst")
34+
35+
try:
36+
dctx = zstandard.ZstdDecompressor()
37+
with open(f"{commit_coverage_path}.zst", "rb") as zf:
38+
with dctx.stream_reader(zf) as reader:
39+
commit_coverage = json.load(reader)
40+
except FileNotFoundError:
41+
commit_coverage = {}
42+
43+
assert (
44+
secrets[secrets.GOOGLE_CLOUD_STORAGE] is not None
45+
), "Missing GOOGLE_CLOUD_STORAGE secret"
46+
bucket = get_bucket(secrets[secrets.GOOGLE_CLOUD_STORAGE])
47+
48+
for changeset, platform, suite in list_reports(bucket, "mozilla-central"):
49+
# We are only interested in "overall" coverage, not platform or suite specific.
50+
if platform != DEFAULT_FILTER or suite != DEFAULT_FILTER:
51+
continue
52+
53+
# We already have data for this commit.
54+
if changeset in commit_coverage:
55+
continue
56+
57+
report_name = get_name("mozilla-central", changeset, platform, suite)
58+
assert download_report("ccov-reports", bucket, report_name)
59+
60+
with open(os.path.join("ccov-reports", f"{report_name}.json"), "r") as f:
61+
report = json.load(f)
62+
63+
phabricatorUploader = PhabricatorUploader(repo_dir, changeset)
64+
65+
with hgmo.HGMO(repo_dir=repo_dir) as hgmo_server:
66+
changesets = hgmo_server.get_automation_relevance_changesets(changeset)
67+
68+
results = phabricatorUploader.generate(report, changesets)
69+
for changeset in changesets:
70+
desc = changeset["desc"].split("\n")[0]
71+
72+
if any(text in desc for text in ["r=merge", "a=merge"]):
73+
continue
74+
75+
# Lookup changeset coverage from phabricator uploader
76+
coverage = results.get(changeset["node"])
77+
if coverage is None:
78+
logger.warn("No coverage found", changeset=changeset)
79+
continue
80+
81+
commit_coverage[changeset["node"]] = {
82+
"added": sum(c["lines_added"] for c in coverage["paths"].values()),
83+
"covered": sum(c["lines_covered"] for c in coverage["paths"].values()),
84+
"unknown": sum(c["lines_unknown"] for c in coverage["paths"].values()),
85+
}
86+
87+
cctx = zstandard.ZstdCompressor(threads=-1)
88+
with open(f"{commit_coverage_path}.zst", "wb") as zf:
89+
with cctx.stream_writer(zf) as compressor:
90+
with io.TextIOWrapper(compressor, encoding="utf-8") as f:
91+
json.dump(commit_coverage, f)

bot/code_coverage_bot/hooks/cron.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import structlog
88

99
from code_coverage_bot import chunk_mapping
10+
from code_coverage_bot import commit_coverage
1011
from code_coverage_bot import config
1112
from code_coverage_bot import uploader
1213
from code_coverage_bot.cli import setup_cli
@@ -33,9 +34,11 @@ def __init__(self, *args, **kwargs):
3334

3435
super().__init__(config.MOZILLA_CENTRAL_REPOSITORY, revision, *args, **kwargs)
3536

36-
def run(self):
37+
def run(self) -> None:
3738
self.retrieve_source_and_artifacts()
3839

40+
commit_coverage.generate(self.repo_dir)
41+
3942
logger.info("Generating zero coverage reports")
4043
zc = ZeroCov(self.repo_dir)
4144
zc.generate(self.artifactsHandler.get(), self.revision)
@@ -58,7 +61,7 @@ def run(self):
5861
)
5962

6063

61-
def main():
64+
def main() -> None:
6265
logger.info("Starting code coverage bot for cron")
6366
args = setup_cli(ask_revision=False, ask_repository=False)
6467
hook = CronHook(args.task_name_filter, args.cache_root, args.working_dir)

bot/taskcluster-hook-cron.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
"public/zero_coverage_report.json": {
4040
"path": "/zero_coverage_report.json",
4141
"type": "file"
42+
},
43+
"public/commit_coverage.json.zst": {
44+
"path": "/commit_coverage.json.zst",
45+
"type": "file"
4246
}
4347
},
4448
"cache": {

0 commit comments

Comments
 (0)