--- /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 @@
Issues stats:
| open | %(open)5d (%(open_new)+3d) |
+ | enhancements | %s(enhancements)5d (%s(enhancements_delta)+3d)
+ |   ;bugs | %s(bugs)5d (%s(bugs_delta)+3d)
| closed | %(closed)5d (%(closed_new)+3d) |
| total | %(total)5d (%(total_new)+3d) |
@@ -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]