--- /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:

+ %s(enhancements)5d (%s(enhancements_delta)+3d) + %s(bugs)5d (%s(bugs_delta)+3d)
open%(open)5d (%(open_new)+3d)
  enhancements
  ;bugs
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]