Source code for memote.suite.reporting.history
# -*- coding: utf-8 -*-
# Copyright 2017 Novo Nordisk Foundation Center for Biosustainability,
# Technical University of Denmark.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Render results into pretty HTML."""
from __future__ import absolute_import
import logging
from memote.suite.reporting.report import Report
[docs]LOGGER = logging.getLogger(__name__)
[docs]class HistoryReport(Report):
"""
Render a rich report using the git repository history.
Attributes
----------
configuration : memote.MemoteConfiguration
A memote configuration structure.
"""
def __init__(self, history, configuration, **kwargs):
"""
Initialize the git history report.
Parameters
----------
history : memote.HistoryManager
An instance that manages access to test results.
configuration : memote.MemoteConfiguration
A memote configuration structure.
"""
super(HistoryReport, self).__init__(
result=None, configuration=configuration, **kwargs
)
self._report_type = "history"
self._history = history
self.config = configuration
self.result = self.collect_history()
self.result.update(self.config)
[docs] def collect_history(self):
"""Build the structure of results in terms of a commit history."""
def format_data(data):
"""Format result data according to the user-defined type."""
# TODO Remove this failsafe once proper error handling is in place.
if type == "percent" or data is None:
# Return an empty list here to reduce the output file size.
# The angular report will ignore the `data` and instead display
# the `metric`.
return []
if type == "count":
return len(data)
return data
base = dict()
tests = base.setdefault("tests", dict())
score = base.setdefault("score", dict())
score_collection = score.setdefault("total_score", dict())
for branch, commits in self._history.iter_branches():
for commit in reversed(commits):
result = self.result = self._history.get_result(commit)
# Calculate the score for each result and store all the total
# scores for each commit in the base dictionary.
self.compute_score()
total_score = self.result["score"]["total_score"]
score_collection.setdefault("history", list())
score_collection["format_type"] = "score"
score_collection["history"].append(
{"branch": branch, "commit": commit, "metric": total_score}
)
# Now arrange the results for each test into the appropriate
# format. Specifically such that the Accordion and the Vega
# Plot components can easily read them.
for test in result.cases:
tests.setdefault(test, dict())
if "title" not in tests[test]:
tests[test]["title"] = result.cases[test]["title"]
if "summary" not in tests[test]:
tests[test]["summary"] = result.cases[test]["summary"]
if "type" not in tests[test]:
tests[test]["format_type"] = result.cases[test]["format_type"]
type = tests[test]["format_type"]
metric = result.cases[test].get("metric")
data = result.cases[test].get("data")
res = result.cases[test].get("result")
if isinstance(metric, dict):
tests[test].setdefault("history", dict())
for param in metric:
tests[test]["history"].setdefault(param, list()).append(
{
"branch": branch,
"commit": commit,
"metric": metric.get(param),
"data": format_data(data.get(param)),
"result": res.get(param),
}
)
else:
tests[test].setdefault("history", list()).append(
{
"branch": branch,
"commit": commit,
"metric": metric,
"data": format_data(data),
"result": res,
}
)
return base