bot/code_review_bot/tasks/coverage.py (50 lines of code) (raw):
import os
import structlog
from code_review_bot import Issue, Level
from code_review_bot.config import settings
from code_review_bot.tasks.base import AnalysisTask
logger = structlog.get_logger(__name__)
ISSUE_MARKDOWN = """
## coverage problem
- **Path**: {path}
- **Publishable**: {publishable}
```
{message}
```
"""
class CoverageIssue(Issue):
def __init__(self, analyzer, path, lineno, message, revision):
super().__init__(
analyzer,
revision,
path,
line=lineno and int(lineno) or None,
nb_lines=1,
check="no-coverage",
level=Level.Warning,
message=message,
)
def is_publishable(self):
"""
Coverage issues are always publishable, unless they are in header files
"""
return self.validates()
def validates(self):
"""
Coverage issues are always publishable, unless they are in header files
"""
_, ext = os.path.splitext(self.path)
return ext.lower() in settings.cpp_extensions.union(settings.js_extensions)
def as_text(self):
"""
Build the text content for reporters
"""
return self.message
def as_markdown(self):
"""
Build the Markdown content for the debug email
"""
return ISSUE_MARKDOWN.format(
path=self.path,
message=self.message,
publishable=self.is_publishable() and "yes" or "no",
)
class ZeroCoverageTask(AnalysisTask):
"""
List all issues found by coverage analysis on specified files
Uses the most recent data from the code coverage bot
"""
route = "project.relman.code-coverage.production.cron.latest"
artifacts = ["public/zero_coverage_report.json"]
@property
def display_name(self):
return "code coverage analysis"
def parse_issues(self, artifacts, revision):
zero_coverage_files = {
file_info["name"]
for artifact in artifacts.values()
for file_info in artifact["files"]
if file_info["uncovered"]
}
return [
CoverageIssue(self, path, 0, "This file is uncovered", revision)
for path in revision.files
if path in zero_coverage_files
]