Source code for hammurabi.reporters.base

# pylint: disable=too-few-public-methods

"""
This module contains the definition of Reporters which is responsible for
exposing the execution results in several formats.
"""
from abc import ABC, abstractmethod
from datetime import datetime
import logging
from pathlib import Path
from typing import Any, Iterable, List

from pydantic import BaseModel  # pylint: disable=no-name-in-module

from hammurabi.config import config
from hammurabi.law import Law
from hammurabi.rules.base import Rule


[docs]class LawItem(BaseModel): """ LawItem represents the basic summary of a low attached to a rule. """ name: str description: str
[docs]class RuleItem(BaseModel): """ RuleItem represents the registered rule and its status. The rule (as normally) has the status of the execution which can be passed, failed or skipped. """ name: str law: LawItem
[docs]class AdditionalData(BaseModel): """ Additional data which may not be set for every execution. """ # Add the execution start and finish datetime # to the report for statistic purposes started: str = datetime.min.isoformat() finished: str = datetime.min.isoformat() # When PR is not created, still do the reporting pull_request_url: str = ""
[docs]class Report(BaseModel): """ The report object which contains all the necessary and optional data for the report will be generated. """ passed: List[RuleItem] = list() failed: List[RuleItem] = list() skipped: List[RuleItem] = list() additional_data: AdditionalData = AdditionalData()
[docs]class Reporter(ABC): """ Abstract class which describes the bare minimum and helper functions for Reporters. A reporter can generate different outputs from the results of the execution. Also, reporters can be extended by additional data which may not contain data for every execution like GitHub pull request url. The report file's name set by ``report_name`` config parameter. .. note:: Reporters measures the execution time for the complete execution from checking out the git branch until the pull request creation finished. Although the completion time is measured, it is not detailed for the rules. At this moment measuring execution time of rules is not planned. Example usage: .. code-block:: python >>> from hammurabi.reporters.base import Reporter >>> >>> >>> class JsonReporter(Reporter): >>> def report(self) -> str: >>> return self._get_report().json() :param laws: Iterable Law objects which will be included to the report :type laws: Iterable[Law] """ def __init__(self, laws: List[Law]) -> None: self.laws = laws self.additional_data: AdditionalData = AdditionalData() self.report_path: Path = config.settings.report_name @staticmethod def __get_rule_item_from_rule(law: Law, rule: Rule, **kwargs) -> RuleItem: """ Get a rule item from a combination of a Rule and a Law. :param law: The parent law of the rule :type law: ``hammurabi.law.Law`` :param rule: The rule which should be transformed :type rule: ``hammurabi.rules.base.Rule`` :return: Return the transformed RuleItem from the given law and rule :rtype: RuleItem """ logging.info('Collecting report data for "%s"', str(rule)) return RuleItem( name=rule.name, law=LawItem(name=law.name, description=law.description), **kwargs, ) def __get_rule_items( self, law: Law, rules: Iterable[Rule], **kwargs ) -> List[RuleItem]: """ Get all the passed rule items for a law. :param law: The parent law of the rule :type law: ``hammurabi.law.Law`` :return: Return all the passed rules transformed to ``RuleItem``s :rtype: List[RuleItem] """ logging.info('Collecting report data for "%s"', str(law)) items: List[RuleItem] = list() for rule in rules: items += (self.__get_rule_item_from_rule(law, rule, **kwargs),) return items def _get_report(self) -> Report: """ Get and prepare the report for actual reporting. :return: Return the assembled report object :rtype: ``hammurabi.reporters.base.Report`` """ logging.info("Generating execution report") report = Report(additional_data=self.additional_data) for law in self.laws: report.passed += self.__get_rule_items(law, law.passed_rules) report.failed += self.__get_rule_items(law, law.failed_rules) report.skipped += self.__get_rule_items(law, law.skipped_rules) logging.info("Execution report generated") return report
[docs] @abstractmethod def report(self) -> Any: """ Do the actual reporting based on the report assembled. """