From 16154cd0ba94964a14fdc4fc4dacae6aaac330fb Mon Sep 17 00:00:00 2001 From: Adam Waldenberg Date: Mon, 27 Jan 2014 03:11:15 +0100 Subject: [PATCH] Added age value to the blame output (Fixes issue 10). This completes the "code stability" functionality. While code stability is a percentage (zero and up) that reflects the stability of the authors code, the age value is a pseudo-value describing the average age of all the authors rows. The older the code, the higher the value. Code stability can sometimes be above 100%, depending on the way git calculates insertions and blamed rows. --- gitinspector/blame.py | 29 ++++++++++++++++++++++++----- gitinspector/changes.py | 7 +++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/gitinspector/blame.py b/gitinspector/blame.py index ae4391c..583ef39 100644 --- a/gitinspector/blame.py +++ b/gitinspector/blame.py @@ -24,6 +24,7 @@ from outputable import Outputable from changes import FileDiff import comment import changes +import datetime import filtering import format import gravatar @@ -40,6 +41,7 @@ NUM_THREADS = multiprocessing.cpu_count() class BlameEntry: rows = 0 + skew = 0 # Used when calculating average code age (time-adjusted stability value). comments = 0 __thread_lock__ = threading.BoundedSemaphore(NUM_THREADS) @@ -71,6 +73,7 @@ class BlameThread(threading.Thread): email = Blame.get_author_email(j) author = self.changes.get_latest_author_by_email(email) + __blame_lock__.acquire() # Global lock used to protect calls from here... if not filtering.set_filtered(author, "author") and not filtering.set_filtered(email, "email"): @@ -80,6 +83,13 @@ class BlameThread(threading.Thread): self.blames[(author, self.filename)].comments += comments self.blames[(author, self.filename)].rows += 1 + time = Blame.get_time(j) + time = datetime.date(int(time[0:4]), int(time[5:7]), int(time[8:10])) + + if (time - self.changes.first_commit_date).days > 0: + self.blames[(author, self.filename)].skew += (float((self.changes.last_commit_date - time).days) / + (time - self.changes.first_commit_date).days) + __blame_lock__.release() # ...to here. git_blame_r.close() @@ -138,6 +148,11 @@ class Blame: content = re.search(" \d+\)(.*)", string) return content.group(1).lstrip() + @staticmethod + def get_time(string): + time = re.search(" \(.*?(\d\d\d\d-\d\d-\d\d)", string) + return time.group(1).strip() + def get_summed_blames(self): summed_blames = {} for i in self.blames.items(): @@ -145,6 +160,7 @@ class Blame: summed_blames[i[0][0]] = BlameEntry() summed_blames[i[0][0]].rows += i[1].rows + summed_blames[i[0][0]].skew += i[1].skew summed_blames[i[0][0]].comments += i[1].comments return summed_blames @@ -174,8 +190,8 @@ class BlameOutput(Outputable): def output_html(self): blame_xml = "
" blame_xml += "

" + _(BLAME_INFO_TEXT) + ".

" - blame_xml += "".format(_("Author"), - _("Rows"), _("Stability"), _("% in comments")) + blame_xml += "".format( + _("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments")) blame_xml += "" chart_data = "" blames = sorted(__blame__.get_summed_blames().items()) @@ -197,6 +213,7 @@ class BlameOutput(Outputable): blame_xml += "" blame_xml += "") + blame_xml += "" blame_xml += "" blame_xml += "" blame_xml += "" @@ -205,7 +222,7 @@ class BlameOutput(Outputable): if blames[-1] != entry: chart_data += ", " - blame_xml += "
{0} {1} {2} {3}
{0} {1} {2} {3} {4}
" + str(entry[1].rows) + "" + ("{0:.1f}".format(100.0 * entry[1].rows / self.changes.get_authorinfo_list()[entry[0]].insertions) + "" + "{0:.2f}".format(float(entry[1].skew) / entry[1].rows) + "" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "" + work_percentage + "
 
" + blame_xml += "   " blame_xml += "
" blame_xml += "