[Tracker-discuss] [issue446] Break down 'open' into 'enhancements' vs 'bugs' in roundup-summary

R David Murray metatracker at psf.upfronthosting.co.za
Sun Apr 1 05:06:26 CEST 2012


New submission from R David Murray <rdmurray at bitdance.com>:

I propose to alter the weekly roundup-summary email by breaking down the 'open' category in the header issue summary into the subcategories 'enhancements' and 'bugs'.  The idea is that you get what you measure, and if we see how many bugs we are fixing versus enhancements we are committing, we might get a few more bugs fixed.

The attached patch treats 'enhancment' and 'performance' as enhancements (yes, I know performance issues can be bugs, but ones that really are bugs tend to get fixed quickly), and everything else (including uncategorized) as bugs.

I'm sure we can make some progress on our bug count just by categorizing uncategorized issues, but that will give us a better idea of how many unfixed bugs we really have, which I think is useful info.

----------
files: bugs.patch
messages: 2419
nosy: ezio.melotti, r.david.murray
priority: feature
status: unread
title: Break down 'open' into 'enhancements' vs 'bugs' in roundup-summary

_______________________________________________________
PSF Meta Tracker <metatracker at psf.upfronthosting.co.za>
<http://psf.upfronthosting.co.za/roundup/meta/issue446>
_______________________________________________________
-------------- next part --------------
--- /home/roundup/bin/roundup-summary	2010-11-02 16:58:22.000000000 +0100
+++ roundup-summary	2012-04-01 04:50:09.000000000 +0200
@@ -24,6 +24,10 @@
     -r RESOLVED, --resolved=RESOLVED
                         Comma-delimited list of statuses that corresponds to
                         resolved (default: resolved,done,done-cbb,closed,faq).
+    -n ENHANCEMENT, --not-bug=ENHANCEMENT
+                        Comma-delimited list of types that correspond to
+                        issues that are enhancemnts, not bugs (default:
+                        enhancement)
     -o FILENAME, --output=FILENAME
                         File name for output; default is stdout.
     -e FILENAME, --errors=FILENAME
@@ -60,9 +64,11 @@
 Do NOT respond to this message.
 
 Issues counts and deltas:
-  open   %(open)5d (%(open_delta)+3d)
-  closed %(closed)5d (%(closed_delta)+3d)
-  total  %(total)5d (%(total_delta)+3d)
+  open            %(open)5d (%(open_delta)+3d)
+    enhancements  %(enhancements)5d (%(enhancements_delta)+3d)
+    bugs          %(bugs)5d (%(bugs_delta)+3d)
+  closed          %(closed)5d (%(closed_delta)+3d)
+  total           %(total)5d (%(total_delta)+3d)
 
 Open issues with patches: %(patches)-5d"""
 
@@ -79,6 +85,8 @@
 <p>Issues stats:</p>
 <table border="1">
   <tr><th>open</th><td>%(open)5d (%(open_new)+3d)</td></tr>
+  <tr><th>&nbsp;&nbsp;enhancements</th></td>%s(enhancements)5d (%s(enhancements_delta)+3d)</td></tr>
+  <tr><th>&nbsp&nbsp;;bugs</th></td>%s(bugs)5d (%s(bugs_delta)+3d)</td></tr>
   <tr><th>closed</th><td>%(closed)5d (%(closed_new)+3d)</td></tr>
   <tr><th>total</th><td>%(total)5d (%(total_new)+3d)</td></tr>
 </table>
@@ -93,6 +101,8 @@
     """
     # list of statuses to treat as closed -- these don't have to all exist.
     resolved_status_def = 'resolved,done,done-cbb,closed,faq'
+    # similar list of types to treat as enhancements, not bugs.
+    enhancement_type_def = 'enhancement,performance'
     # period of time for report. Uses roundup syntax for ranges.
     default_dates = '-1w;' # last week
     # email address of recipient of report, if any.
@@ -120,6 +130,10 @@
         help='Comma-delimited list of statuses that corresponds to resolved '
              '(default: %default).')
     advanced.add_option(
+        '-n', '--not-bug', dest='enhancements', default=enhancement_type_def,
+        help='Comma-delmited list of types that correspond to issues that '
+             'are enhancements, not bugs (default: %default).')
+    advanced.add_option(
         '-o', '--output', dest='output', metavar='FILENAME', default='',
         help='File name for output; default is stdout.')
     advanced.add_option(
@@ -144,6 +158,7 @@
                      'you must supply the path to a tracker home.')
     options.dates = get_dates(options.dates)
     options.resolved = [s.strip() for s in options.resolved.split(',')]
+    options.enhancements = [s.strip() for s in options.enhancements.split(',')]
     instance_home = args[0]
     return options, instance_home
 
@@ -208,9 +223,9 @@
         start_str = start_date.pretty(format='%F') # %F -> yyyy-mm-dd
         end_str = end_date.pretty(format='%F')
         # counters for current values
-        open_tot = closed_tot = all_tot = 0
+        open_tot = enhance_tot = closed_tot = all_tot = 0
         # counters for previous values
-        open_old = closed_old = all_old = 0
+        open_old = enhance_old = closed_old = all_old = 0
         with_patch = 0
         patch_id = DB.keyword.lookup('patch')
         for id, issue in self.issues.iteritems():
@@ -218,6 +233,8 @@
             if issue['creation'] > end_date:
                 continue
             all_tot += 1
+            was_enhance = issue['last_period_type'] in OPTIONS.enhancements
+            is_enhance = issue['type'] in OPTIONS.enhancements
             if issue['creation'] < start_date:
                 all_old += 1
                 # check if the issue was closed at the end of the previous
@@ -226,6 +243,9 @@
                     closed_old += 1
                 else:
                     open_old += 1
+                    if was_enhance:
+                        enhance_old += 1
+                
             # check if the issue is closed now
             if issue['closed']:
                 closed_tot += 1
@@ -233,10 +253,16 @@
                 open_tot += 1
                 if patch_id in issue['keyword_ids']:
                     with_patch += 1
+                if is_enhance:
+                    enhance_tot += 1
         all_delta = all_tot - all_old
         open_delta = open_tot - open_old
         closed_delta = closed_tot - closed_old
         assert all_delta == open_delta + closed_delta
+        enhance_delta = enhance_tot - enhance_old
+        bugs_tot = open_tot - enhance_tot
+        bugs_old = open_old - enhance_old
+        bugs_delta = bugs_tot - bugs_old
         # save the values in an attribute to avoid calculating it twice
         # when both the txt and the HTML header are needed (i.e. when sending
         # HTML mails)
@@ -246,6 +272,8 @@
             tracker_name=DB.config.TRACKER_NAME,
             open=open_tot, open_delta=open_delta,
             closed=closed_tot, closed_delta=closed_delta,
+            bugs=bugs_tot, bugs_delta=bugs_delta,
+            enhancements=enhance_tot, enhancements_delta=enhance_delta,
             total=all_tot, total_delta=all_delta,
             patches=with_patch,
         )
@@ -505,6 +533,9 @@
         status = None,
         real_status = sid2name(attrs['status']), # Avoid a bug in get_issue_attrs
         last_period_status = None, # the status of the issue before start_date
+        type = '',
+        real_type = tid2name(attrs['type']),
+        last_period_type = None, # the type of the issue before start_date
         actor = None,
         activity = None,
         keyword_ids = kwds,
@@ -524,6 +555,8 @@
         status1 = sid2name(attrs['status']),
         actor2 = attrs['actor'],
         activity2 = attrs['activity'],
+        type2 = tid2name(attrs['type']),
+        type1 = tid2name(attrs['type']),
         journal = journal
     )
     return issue, helper
@@ -545,13 +578,14 @@
         return dates.to_value > issue['creation'] <= dates.from_value
 
     def update(issue, helper):
-        for key in ('status', 'actor', 'activity'):
+        for key in ('status', 'actor', 'activity', 'type'):
             issue[key] = issue[key] or helper[key + '2']
     # I'm not sure all this stuff is necessary, but it seems to work...
     # this trick catches the first time we are in the interval of interest
     if helper['activity2'] < dates.to_value:
         update(issue, helper)
     status_changes = []
+    type_changes = []
     old_time = issue['creation']
     for _, time, userid, act, data in helper['journal']:
         in_period =  dates.to_value > time >= dates.from_value
@@ -585,7 +619,12 @@
                     issue['real_status'] in OPTIONS.resolved):
                     issue['closer'] = userid
                     issue['closed_date'] = time
+            if 'type' in data:
+                helper['type1'] = tid2name(data['type'])
+                type_changes.append((old_time, helper['type1']))
+                old_time = time
     status_changes.append((old_time, issue['real_status']))
+    type_changes.append((old_time, issue['real_type']))
     # if the status didn't change and this is still None set it to 'open',
     # leave it to None for new issues
     if issue['creation'] < dates.from_value:
@@ -594,6 +633,11 @@
                 issue['last_period_status'] = status
         if issue['last_period_status'] is None:
             issue['last_period_status'] = 'open'
+        for time, type in type_changes:
+            if time < dates.from_value:
+                issue['last_period_type'] = type
+        if issue['last_period_type'] is None:
+            issue['last_period_type'] = issue['type']
     # get these set if not done before
     update(issue, helper)
     last_opened = issue['reopened_date'] or issue['creation']
@@ -657,6 +701,13 @@
     cache[status_id] = name
     return name
 
+def tid2name(issue_type_id, cache={None:'none'}):
+    if issue_type_id in cache:
+        return cache[issue_type_id]
+    name = DB.issue_type.get(issue_type_id, 'name')
+    cache[issue_type_id] = name
+    return name
+
 def uid2name(user_id, cache={None:'none'}):
     if user_id in cache:
         return cache[user_id]


More information about the Tracker-discuss mailing list