def add_user_transitions_to_issues(issues, user_transitions): all_from_statuses = [ user_transition.split(',')[0].lower() for user_transition in user_transitions.values() ] all_to_statuses = [ user_transition.split(',')[1].lower() for user_transition in user_transitions.values() ] for issue in issues: from_status_times = {} to_status_times = {} # Register only the first change to from status and always the last change to to status for transition in issue['__transitions']: status = '+' + transition['to_status'].lower().replace(' ', '') if not status in from_status_times and status in all_from_statuses: from_status_times[status] = transition['when'] if status in all_to_statuses: to_status_times[status] = transition['when'] if transition['from_status']: status = '-' + transition['from_status'].lower().replace(' ', '') if not status in from_status_times and status in all_from_statuses: from_status_times[status] = transition['when'] if status in all_to_statuses: to_status_times[status] = transition['when'] result = {} for user_transition_key, user_transition_value in user_transitions.items(): from_status = user_transition_value.split(',')[0].lower() to_status = user_transition_value.split(',')[1].lower() result[user_transition_key] = (parse_iso(to_status_times[to_status]) - parse_iso(from_status_times[from_status])).total_seconds() / (24 * 3600) if (from_status in from_status_times) and (to_status in to_status_times) else 'NA' from_status_field_name = 'first_time_' + ('into_' if from_status[0] == '+' else 'out_of_') + from_status[1:] to_status_field_name = 'last_time_' + ('into_' if to_status[0] == '+' else 'out_of_') + to_status[1:] result[from_status_field_name] = from_status_times[from_status] if from_status in from_status_times else 'NA' result[to_status_field_name] = to_status_times[to_status] if to_status in to_status_times else 'NA' issue['__user_transitions'] = result
def write_issue_counts(basename, dir, issues): if len(issues) == 0: return with open(os.path.join(dir, basename + '-daycounts.csv'), 'w') as csv_file: writer = util.Utf8CsvDictWriter(csv_file, ['day', 'status', 'count']) #TODO: prettify garble, probably want to create a generator for the days transitions, known_statuses = all_transitions_and_known_statuses( issues) issue_counts = {s: 0 for s in known_statuses} one_day = datetime.timedelta(days=1) day = parse_iso(transitions[0]['when']) itr = iter(transitions) line = itr.next() while day <= parse_iso(transitions[-1]['when']): while parse_iso(line['when']) < day: issue_counts[line['from_status']] -= 1 issue_counts[line['to_status']] += 1 line = itr.next() rows = [{ 'day': day.isoformat(), 'status': k, 'count': v } for k, v in issue_counts.items() if k != None] for row in rows: writer.writerow(row) day += one_day
def write_issue_counts(basename, dir, issues): if len(issues) == 0: return with open(os.path.join(dir, basename + '-daycounts.csv'), 'w') as csv_file: writer = util.Utf8CsvDictWriter(csv_file, ['day', 'status', 'count']) #TODO: prettify garble, probably want to create a generator for the days transitions, known_statuses = all_transitions_and_known_statuses(issues) issue_counts = { s : 0 for s in known_statuses } one_day = datetime.timedelta(days = 1) day = parse_iso(transitions[0]['when']) itr = iter(transitions) line = itr.next() while day <= parse_iso(transitions[-1]['when']): while parse_iso(line['when']) < day: issue_counts[line['from_status']] -= 1 issue_counts[line['to_status']] += 1 line = itr.next() rows = [ { 'day' : day.isoformat(), 'status' : k, 'count' : v } for k,v in issue_counts.items() if k != None ] for row in rows: writer.writerow(row) day += one_day
def add_transitions_to_issues(issues): for issue in issues: # filter histories for changes that involve the status field log = issue['changelog']['histories'] workflow_log = [ line for line in log if 'status' in [i['field'] for i in line['items']] ] #remove non status related items from log for line in workflow_log: line['status_item'], = filter(lambda i: i['field'] == 'status', line['items']) # Not sure if they come in sorted order workflow_log.sort(key=lambda x: x['created']) # Create a list from the from 'nothing' to Open transition and the rest of the transitions transitions = [ { 'transition': 'Non-existent to Open', 'when': retrieve_dotnotation_field(issue, 'fields.created'), 'who': retrieve_dotnotation_field(issue, 'fields.reporter.name'), 'from_status': None, 'to_status': 'Open', 'days_in_from_status': None, 'days_since_open': None } ] + [{ 'transition': '%s to %s' % (retrieve_dotnotation_field(line, 'status_item.fromString'), retrieve_dotnotation_field(line, 'status_item.toString')), 'when': retrieve_dotnotation_field(line, 'created'), 'who': retrieve_dotnotation_field(line, 'author.name'), 'from_status': retrieve_dotnotation_field(line, 'status_item.fromString'), 'to_status': retrieve_dotnotation_field(line, 'status_item.toString'), 'days_since_open': (parse_iso(retrieve_dotnotation_field(line, 'created')) - parse_iso(retrieve_dotnotation_field( issue, 'fields.created'))).total_seconds() / (24 * 3600) } for line in workflow_log] # Calculate days between transitions for idx in xrange(1, len(transitions)): transitions[idx]['days_in_from_status'] = ( parse_iso(transitions[idx]['when']) - parse_iso(transitions[idx - 1]['when'])).total_seconds() / ( 24 * 3600) issue['__transitions'] = transitions
def add_user_transitions_to_issues(issues, user_transitions): all_from_statuses = [ user_transition.split(',')[0].lower() for user_transition in user_transitions.values() ] all_to_statuses = [ user_transition.split(',')[1].lower() for user_transition in user_transitions.values() ] for issue in issues: from_status_times = {} to_status_times = {} # Register only the first change to from status and always the last change to to status for transition in issue['__transitions']: status = '+' + transition['to_status'].lower().replace(' ', '') if not status in from_status_times and status in all_from_statuses: from_status_times[status] = transition['when'] if status in all_to_statuses: to_status_times[status] = transition['when'] if transition['from_status']: status = '-' + transition['from_status'].lower().replace( ' ', '') if not status in from_status_times and status in all_from_statuses: from_status_times[status] = transition['when'] if status in all_to_statuses: to_status_times[status] = transition['when'] result = {} for user_transition_key, user_transition_value in user_transitions.items( ): from_status = user_transition_value.split(',')[0].lower() to_status = user_transition_value.split(',')[1].lower() result[user_transition_key] = ( parse_iso(to_status_times[to_status]) - parse_iso(from_status_times[from_status])).total_seconds() / ( 24 * 3600) if (from_status in from_status_times) and ( to_status in to_status_times) else 'NA' from_status_field_name = 'first_time_' + ( 'into_' if from_status[0] == '+' else 'out_of_') + from_status[1:] to_status_field_name = 'last_time_' + ( 'into_' if to_status[0] == '+' else 'out_of_') + to_status[1:] result[from_status_field_name] = from_status_times[ from_status] if from_status in from_status_times else 'NA' result[to_status_field_name] = to_status_times[ to_status] if to_status in to_status_times else 'NA' issue['__user_transitions'] = result
def add_transitions_to_issues(issues): for issue in issues: # filter histories for changes that involve the status field log = issue['changelog']['histories'] workflow_log = [ line for line in log if 'status' in [i['field'] for i in line['items']] ] #remove non status related items from log for line in workflow_log: line['status_item'], = filter(lambda i: i['field'] == 'status', line['items']) # Not sure if they come in sorted order workflow_log.sort(key = lambda x: x['created']) # Create a list from the from 'nothing' to Open transition and the rest of the transitions transitions = [{ 'transition' : 'Non-existent to Open', 'when' : retrieve_dotnotation_field(issue, 'fields.created'), 'who' : retrieve_dotnotation_field(issue, 'fields.reporter.name'), 'from_status' : None, 'to_status' : 'Open', 'days_in_from_status' : None, 'days_since_open' : None }] + [{ 'transition' : '%s to %s' % (retrieve_dotnotation_field(line, 'status_item.fromString'), retrieve_dotnotation_field(line, 'status_item.toString')), 'when' : retrieve_dotnotation_field(line, 'created'), 'who' : retrieve_dotnotation_field(line, 'author.name'), 'from_status' : retrieve_dotnotation_field(line, 'status_item.fromString'), 'to_status' : retrieve_dotnotation_field(line, 'status_item.toString'), 'days_since_open' : (parse_iso(retrieve_dotnotation_field(line, 'created')) - parse_iso(retrieve_dotnotation_field(issue, 'fields.created'))).total_seconds() / (24 * 3600) } for line in workflow_log] # Calculate days between transitions for idx in xrange(1, len(transitions)): transitions[idx]['days_in_from_status'] = (parse_iso(transitions[idx]['when']) - parse_iso(transitions[idx - 1]['when'])).total_seconds() / (24 * 3600) issue['__transitions'] = transitions
def issue_fields(issue): result = {} # Add basic fields for field_name, dotted_field in as_is_fields.items(): result[field_name] = retrieve_dotnotation_field(issue, dotted_field) # Add user transitions for field_name, field_value in issue['__user_transitions'].items(): result[field_name] = field_value # Calculate # of days in current status result['days_in_current_status'] = (datetime.datetime.now(iso8601.Utc()) - parse_iso(issue['__transitions'][-1]['when'])).total_seconds() / (24 * 3600) # Add character lenghts for some fields description_field = retrieve_dotnotation_field(issue, 'fields.description') summary_field = retrieve_dotnotation_field(issue, 'fields.summary') result['description_length'] = len(description_field) if description_field else None result['summary_length'] = len(summary_field) if summary_field else None return result
def issue_fields(issue): result = {} # Add basic fields for field_name, dotted_field in as_is_fields.items(): result[field_name] = retrieve_dotnotation_field(issue, dotted_field) # Add user transitions for field_name, field_value in issue['__user_transitions'].items(): result[field_name] = field_value # Calculate # of days in current status result['days_in_current_status'] = ( datetime.datetime.now(iso8601.Utc()) - parse_iso( issue['__transitions'][-1]['when'])).total_seconds() / (24 * 3600) # Add character lenghts for some fields description_field = retrieve_dotnotation_field(issue, 'fields.description') summary_field = retrieve_dotnotation_field(issue, 'fields.summary') result['description_length'] = len( description_field) if description_field else None result['summary_length'] = len(summary_field) if summary_field else None return result
def most_recent_update(issues): return parse_iso(max(i['fields']['updated'] for i in issues))