The metrics module now supports multiple repositories (See issue #24).

This commit is contained in:
Adam Waldenberg 2015-11-01 03:36:40 +01:00
parent 7acf871ab1
commit 802f18e7e5
3 changed files with 52 additions and 40 deletions

View File

@ -26,6 +26,7 @@ import sys
from .blame import Blame from .blame import Blame
from .changes import Changes from .changes import Changes
from .config import GitConfig from .config import GitConfig
from .metrics import MetricsLogic
from . import (basedir, clone, extensions, filtering, format, help, interval, from . import (basedir, clone, extensions, filtering, format, help, interval,
localization, optval, terminal, version) localization, optval, terminal, version)
from .output import outputable from .output import outputable
@ -59,8 +60,10 @@ class Runner(object):
terminal.skip_escapes(not sys.stdout.isatty()) terminal.skip_escapes(not sys.stdout.isatty())
terminal.set_stdout_encoding() terminal.set_stdout_encoding()
previous_directory = os.getcwd() previous_directory = os.getcwd()
summed_blames = None summed_blames = None
summed_changes = None summed_changes = None
summed_metrics = None
for repo in repos: for repo in repos:
os.chdir(previous_directory) os.chdir(previous_directory)
@ -70,6 +73,9 @@ class Runner(object):
summed_blames = Blame(self.hard, self.useweeks, changes) + summed_blames summed_blames = Blame(self.hard, self.useweeks, changes) + summed_blames
summed_changes = changes + summed_changes summed_changes = changes + summed_changes
if self.include_metrics:
summed_metrics = MetricsLogic() + summed_metrics
if sys.stdout.isatty() and format.is_interactive_format(): if sys.stdout.isatty() and format.is_interactive_format():
terminal.clear_row() terminal.clear_row()
@ -85,7 +91,7 @@ class Runner(object):
outputable.output(TimelineOutput(summed_changes, self.useweeks)) outputable.output(TimelineOutput(summed_changes, self.useweeks))
if self.include_metrics: if self.include_metrics:
outputable.output(MetricsOutput()) outputable.output(MetricsOutput(summed_metrics))
if self.responsibilities: if self.responsibilities:
outputable.output(ResponsibilitiesOutput(summed_changes, summed_blames)) outputable.output(ResponsibilitiesOutput(summed_changes, summed_blames))

View File

@ -69,6 +69,15 @@ class MetricsLogic(object):
if lines > 0 and METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD < cycc / float(lines): if lines > 0 and METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD < cycc / float(lines):
self.cyclomatic_complexity_density[i.strip()] = cycc / float(lines) self.cyclomatic_complexity_density[i.strip()] = cycc / float(lines)
def __add__(self, other):
if other == None:
return self
self.eloc.update(other.eloc)
self.cyclomatic_complexity.update(other.cyclomatic_complexity)
self.cyclomatic_complexity_density.update(other.cyclomatic_complexity_density)
return self
@staticmethod @staticmethod
def get_cyclomatic_complexity(file_r, extension): def get_cyclomatic_complexity(file_r, extension):
is_inside_comment = False is_inside_comment = False

View File

@ -21,7 +21,7 @@ from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
from ..changes import FileDiff from ..changes import FileDiff
from ..localization import N_ from ..localization import N_
from .. import metrics from ..metrics import (__metric_eloc__, METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD, METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD)
from .outputable import Outputable from .outputable import Outputable
ELOC_INFO_TEXT = N_("The following files are suspiciously big (in order of severity)") ELOC_INFO_TEXT = N_("The following files are suspiciously big (in order of severity)")
@ -38,54 +38,55 @@ def __get_metrics_score__(ceiling, value):
return i[1] return i[1]
class MetricsOutput(Outputable): class MetricsOutput(Outputable):
def output_text(self): def __init__(self, metrics):
metrics_logic = metrics.MetricsLogic() self.metrics = metrics
Outputable.__init__(self)
if not metrics_logic.eloc and not metrics_logic.cyclomatic_complexity and not metrics_logic.cyclomatic_complexity_density: def output_text(self):
if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
print("\n" + _(METRICS_MISSING_INFO_TEXT) + ".") print("\n" + _(METRICS_MISSING_INFO_TEXT) + ".")
if metrics_logic.eloc: if self.metrics.eloc:
print("\n" + _(ELOC_INFO_TEXT) + ":") print("\n" + _(ELOC_INFO_TEXT) + ":")
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
print(_("{0} ({1} estimated lines of code)").format(i[1], str(i[0]))) print(_("{0} ({1} estimated lines of code)").format(i[1], str(i[0])))
if metrics_logic.cyclomatic_complexity: if self.metrics.cyclomatic_complexity:
print("\n" + _(CYCLOMATIC_COMPLEXITY_TEXT) + ":") print("\n" + _(CYCLOMATIC_COMPLEXITY_TEXT) + ":")
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
print(_("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0]))) print(_("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0])))
if metrics_logic.cyclomatic_complexity_density: if self.metrics.cyclomatic_complexity_density:
print("\n" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + ":") print("\n" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + ":")
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity_density.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
print(_("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0])) print(_("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0]))
def output_html(self): def output_html(self):
metrics_logic = metrics.MetricsLogic()
metrics_xml = "<div><div class=\"box\" id=\"metrics\">" metrics_xml = "<div><div class=\"box\" id=\"metrics\">"
if not metrics_logic.eloc and not metrics_logic.cyclomatic_complexity and not metrics_logic.cyclomatic_complexity_density: if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
metrics_xml += "<p>" + _(METRICS_MISSING_INFO_TEXT) + ".</p>" metrics_xml += "<p>" + _(METRICS_MISSING_INFO_TEXT) + ".</p>"
if metrics_logic.eloc: if self.metrics.eloc:
metrics_xml += "<div><h4>" + _(ELOC_INFO_TEXT) + ".</h4>" metrics_xml += "<div><h4>" + _(ELOC_INFO_TEXT) + ".</h4>"
for num, i in enumerate(sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse=True)): for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True)):
metrics_xml += "<div class=\"" + __get_metrics_score__(metrics.__metric_eloc__[FileDiff.get_extension(i[1])], i[0]) + \ metrics_xml += "<div class=\"" + __get_metrics_score__(__metric_eloc__[FileDiff.get_extension(i[1])], i[0]) + \
(" odd\">" if num % 2 == 1 else "\">") + \ (" odd\">" if num % 2 == 1 else "\">") + \
_("{0} ({1} estimated lines of code)").format(i[1], str(i[0])) + "</div>" _("{0} ({1} estimated lines of code)").format(i[1], str(i[0])) + "</div>"
metrics_xml += "</div>" metrics_xml += "</div>"
if metrics_logic.cyclomatic_complexity: if self.metrics.cyclomatic_complexity:
metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_TEXT) + "</h4>" metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_TEXT) + "</h4>"
for num, i in enumerate(sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity.items()]), reverse=True)): for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True)):
metrics_xml += "<div class=\"" + __get_metrics_score__(metrics.METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD, i[0]) + \ metrics_xml += "<div class=\"" + __get_metrics_score__(METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD, i[0]) + \
(" odd\">" if num % 2 == 1 else "\">") + \ (" odd\">" if num % 2 == 1 else "\">") + \
_("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0])) + "</div>" _("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0])) + "</div>"
metrics_xml += "</div>" metrics_xml += "</div>"
if metrics_logic.cyclomatic_complexity_density: if self.metrics.cyclomatic_complexity_density:
metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + "</h4>" metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + "</h4>"
for num, i in enumerate(sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity_density.items()]), reverse=True)): for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True)):
metrics_xml += "<div class=\"" + __get_metrics_score__(metrics.METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD, i[0]) + \ metrics_xml += "<div class=\"" + __get_metrics_score__(METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD, i[0]) + \
(" odd\">" if num % 2 == 1 else "\">") + \ (" odd\">" if num % 2 == 1 else "\">") + \
_("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0]) + "</div>" _("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0]) + "</div>"
metrics_xml += "</div>" metrics_xml += "</div>"
@ -94,15 +95,13 @@ class MetricsOutput(Outputable):
print(metrics_xml) print(metrics_xml)
def output_json(self): def output_json(self):
metrics_logic = metrics.MetricsLogic() if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
if not metrics_logic.eloc and not metrics_logic.cyclomatic_complexity and not metrics_logic.cyclomatic_complexity_density:
print(",\n\t\t\"metrics\": {\n\t\t\t\"message\": \"" + _(METRICS_MISSING_INFO_TEXT) + "\"\n\t\t}", end="") print(",\n\t\t\"metrics\": {\n\t\t\t\"message\": \"" + _(METRICS_MISSING_INFO_TEXT) + "\"\n\t\t}", end="")
else: else:
eloc_xml = "" eloc_xml = ""
if metrics_logic.eloc: if self.metrics.eloc:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
eloc_xml += "{\n\t\t\t\t\"type\": \"estimated-lines-of-code\",\n" eloc_xml += "{\n\t\t\t\t\"type\": \"estimated-lines-of-code\",\n"
eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n" eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n"
eloc_xml += "\t\t\t\t\"value\": " + str(i[0]) + "\n" eloc_xml += "\t\t\t\t\"value\": " + str(i[0]) + "\n"
@ -110,8 +109,8 @@ class MetricsOutput(Outputable):
else: else:
eloc_xml = eloc_xml[:-1] eloc_xml = eloc_xml[:-1]
if metrics_logic.cyclomatic_complexity: if self.metrics.cyclomatic_complexity:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
eloc_xml += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity\",\n" eloc_xml += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity\",\n"
eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n" eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n"
eloc_xml += "\t\t\t\t\"value\": " + str(i[0]) + "\n" eloc_xml += "\t\t\t\t\"value\": " + str(i[0]) + "\n"
@ -119,8 +118,8 @@ class MetricsOutput(Outputable):
else: else:
eloc_xml = eloc_xml[:-1] eloc_xml = eloc_xml[:-1]
if metrics_logic.cyclomatic_complexity_density: if self.metrics.cyclomatic_complexity_density:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity_density.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
eloc_xml += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity-density\",\n" eloc_xml += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity-density\",\n"
eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n" eloc_xml += "\t\t\t\t\"file-name\": \"" + i[1] + "\",\n"
eloc_xml += "\t\t\t\t\"value\": {0:.3f} \"\n".format(i[0]) eloc_xml += "\t\t\t\t\"value\": {0:.3f} \"\n".format(i[0])
@ -130,29 +129,27 @@ class MetricsOutput(Outputable):
print(",\n\t\t\"metrics\": {\n\t\t\t\"violations\": [\n\t\t\t" + eloc_xml + "]\n\t\t}", end="") print(",\n\t\t\"metrics\": {\n\t\t\t\"violations\": [\n\t\t\t" + eloc_xml + "]\n\t\t}", end="")
def output_xml(self): def output_xml(self):
metrics_logic = metrics.MetricsLogic() if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
if not metrics_logic.eloc and not metrics_logic.cyclomatic_complexity and not metrics_logic.cyclomatic_complexity_density:
print("\t<metrics>\n\t\t<message>" + _(METRICS_MISSING_INFO_TEXT) + "</message>\n\t</metrics>") print("\t<metrics>\n\t\t<message>" + _(METRICS_MISSING_INFO_TEXT) + "</message>\n\t</metrics>")
else: else:
eloc_xml = "" eloc_xml = ""
if metrics_logic.eloc: if self.metrics.eloc:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
eloc_xml += "\t\t\t<estimated-lines-of-code>\n" eloc_xml += "\t\t\t<estimated-lines-of-code>\n"
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n" eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n" eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n"
eloc_xml += "\t\t\t</estimated-lines-of-code>\n" eloc_xml += "\t\t\t</estimated-lines-of-code>\n"
if metrics_logic.cyclomatic_complexity: if self.metrics.cyclomatic_complexity:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
eloc_xml += "\t\t\t<cyclomatic-complexity>\n" eloc_xml += "\t\t\t<cyclomatic-complexity>\n"
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n" eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n" eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n"
eloc_xml += "\t\t\t</cyclomatic-complexity>\n" eloc_xml += "\t\t\t</cyclomatic-complexity>\n"
if metrics_logic.cyclomatic_complexity_density: if self.metrics.cyclomatic_complexity_density:
for i in sorted(set([(j, i) for (i, j) in metrics_logic.cyclomatic_complexity_density.items()]), reverse=True): for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
eloc_xml += "\t\t\t<cyclomatic-complexity-density>\n" eloc_xml += "\t\t\t<cyclomatic-complexity-density>\n"
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n" eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
eloc_xml += "\t\t\t\t<value>{0:.3f}</value>\n".format(i[0]) eloc_xml += "\t\t\t\t<value>{0:.3f}</value>\n".format(i[0])