Project

General

Profile

Task #1868 ยป esc-mentoring.py

Jan Iversen, 2016-04-15 06:15

 
#!/usr/bin/env python3
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

import sys
import csv
import io
import datetime
import json
import xmltodict
from xml.etree.ElementTree import XML
from urllib.request import urlopen, URLError



def get_count_needsDevEval() :
url = 'https://bugs.documentfoundation.org/buglist.cgi?' \
'bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=VERIFIED&bug_status=NEEDINFO' \
'&columnlist=Cbug_id%2Cassigned_to%2Cbug_status%2Cshort_desc%2Cchangeddate%2Creporter%2Clongdescs.count%2Copendate%2Cstatus_whiteboard' \
'&keywords=needsDevEval%2C%20' \
'&keywords_type=allwords' \
'&query_format=advanced' \
'&resolution=---' \
'&ctype=csv' \
'&human=0'
try:
resp = urlopen(url)
except URLError:
sys.stderr.write('Error fetching {}'.format(url))
sys.exit(1)
xCSV = list(csv.reader(io.TextIOWrapper(resp)))
return len(xCSV) -1



def get_easyHacks() :
url = 'https://bugs.documentfoundation.org/buglist.cgi?' \
'bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=VERIFIED&bug_status=NEEDINFO' \
'&columnlist=Cbug_id%2Cassigned_to%2Cbug_status%2Cshort_desc%2Cchangeddate%2Creporter%2Clongdescs.count%2Copendate%2Cstatus_whiteboard' \
'&keywords=easyHack%2C%20' \
'&keywords_type=allwords' \
'&query_format=advanced' \
'&resolution=---' \
'&ctype=csv' \
'&human=0'
try:
resp = urlopen(url)
except URLError:
sys.stderr.write('Error fetching {}'.format(url))
sys.exit(1)
xCSV = list(csv.reader(io.TextIOWrapper(resp)))[1:]
resp.close()
xCSV.sort()
rawList = {}
for row in xCSV:
id = int(row[0])
if row[1] == 'libreoffice-bugs' :
assign = ''
else :
assign = row[1]
status = row[2]
if status == 'REOPENED' :
status = 'NEW'
rawList[id] = {'id' : id,
'assign' : assign,
'status' : status,
'desc' : row[3],
'change' : datetime.datetime.strptime(row[4].split(' ')[0], '%Y-%m-%d').date(),
'reporter' : row[5],
'comments' : int(row[6]),
'created' : datetime.datetime.strptime(row[7].split(' ')[0], '%Y-%m-%d').date(),
'whiteboard' : row[8]
}
return rawList



def get_gerrit(doNonCom) :
url = 'https://gerrit.libreoffice.org/changes/?' \
'q=status:open'
if (doNonCom) :
url = url + '+-ownerin:committer'

# Add needed fields
url = url + '&o=DETAILED_LABELS&o=MESSAGES&o=DETAILED_ACCOUNTS'
#url = url + '&o=code_review&o=reviewers&pp=0'

try:
resp = urlopen(url)
except URLError:
sys.stderr.write('Error fetching {}'.format(url))
sys.exit(1)

data = resp.read().decode('utf8')[5:]
rawList = json.loads(data)
resp.close()
for row in rawList :
row['updated'] = datetime.datetime.strptime(row['updated'].split(' ')[0], '%Y-%m-%d').date()
return rawList



def get_bug(id) :
url = 'https://bugs.documentfoundation.org/show_bug.cgi?ctype=xml&id=' + str(id)
try:
resp = urlopen(url)
except URLError:
sys.stderr.write('Error fetching {}'.format(url))
sys.exit(1)
bug = xmltodict.parse(resp.read())
resp.close()
return bug



def optimize_bug(bug_org) :
bug = bug_org['bugzilla']['bug']
del bug['bug_file_loc']
del bug['cclist_accessible']
del bug['classification']
del bug['classification_id']
del bug['comment_sort_order']
del bug['creation_ts']
del bug['delta_ts']
del bug['reporter_accessible']
del bug['resolution']

# collect info for new comments:
if 'reporter' not in bug :
newText = 'org_reporter: MISSING'
else :
if type(bug['reporter']) is str:
newText = 'org_reporter: ' + bug['reporter'] + '\n'
else :
newText = 'org_reporter: ' + bug['reporter']['@name'] + '/' + bug['reporter']['#text'] + '\n'
del bug['reporter']

for line in bug['long_desc'] :
if 'who' not in line or type(line) is str:
newText += 'who: UNKNOWN' + '\n' + line
else :
newText += 'who: ' + line['who']['@name'] + '/' + line['who']['#text']
bug['long_desc'] = []
bug['long_desc'].append({'thetext' : newText})
addAlso = 'https://issues.apache.org/ooo/show_bug.cgi?id='+bug['bug_id']
if 'see_also' not in bug :
bug['see_also'] = addAlso
elif not type(bug['see_also']) is list :
x = bug['see_also']
bug['see_also'] = [x, addAlso]
else :
bug['see_also'].append(addAlso)
return bug



def formatEasy(easyHack) :
return 'https://bugs.documentfoundation.org/show_bug.cgi?id={} mentor:{} -> "{}"'.format(easyHack['id'], easyHack['reporter'], easyHack['desc'])



def formatGerrit(patch) :
return 'https://gerrit.libreoffice.org/#/c/{}/ author:{} -> "{}"'.format(patch['_number'], patch['owner']['name'], patch['subject'])



def checkGerrit(checkType, patch, cDate=0, eDate=0) :
if checkType == 1 or checkType == 3:
# True, if there are no -1 and patch is mergeable
# 3 also checks on start/end date
# Optional Check no open comments

# date check (3 days old)
if checkType == 3 and (patch['updated'] < cDate or patch['updated'] > eDate) :
return False

# not mergeable
if not patch['mergeable'] :
return False

# review or verify -1
if 'labels' in patch and 'Code-Review' in patch['labels'] and 'all' in patch['labels']['Code-Review'] :
for chk in patch['labels']['Code-Review']['all'] :
if 'value' in chk and chk['value'] < 0 :
return False
if 'labels' in patch and 'Verified' in patch['labels'] and 'all' in patch['labels']['Verified'] :
for chk in patch['labels']['Verified']['all'] :
if 'value' in chk and chk['value'] < 0 :
return False
return True
elif checkType == 2 :
# True if there are reviewer
if 'labels' in patch and 'Code-Review' in patch['labels'] and 'all' in patch['labels']['Code-Review'] :
for chk in patch['labels']['Code-Review']['all'] :
name = chk['name']
if not name == 'Jenkins' and not name == patch['owner'] :
return True
return False
elif checkType == 4 :
# True if merge conflict and no jani comment
return False
elif checkType == 5 :
# true if last change is older than startDate
if patch['updated'] <= cDate :
return True
return False
return False



def ESC_report(easyHacks, gerritOpen, gerritContributor, needsDevEval) :
# prepare to count easyHacks, and list special status, new hacks (7 days)
xTot = len(easyHacks)
xAssign = 0
xOpen = 0
xInfo = 0
xComm = 0
xRevi = 0
pNew = []
pInfo = []
cDate = datetime.date.today() - datetime.timedelta(days=8)
for key, row in easyHacks.items():
# Calculate type of status
status = row['status']
if status == 'ASSIGNED' :
xAssign += 1
elif status == 'NEEDINFO' :
xInfo += 1
pInfo.append(row)
elif status == 'NEW' :
xOpen += 1
if row['comments'] >= 5 :
xComm += 1
if row['whiteboard'] == 'ToBeReviewed':
xRevi += 1

if row['created'] >= cDate :
pNew.append(row)
print('* Easy Hacks (JanI)')
print(' + total {}: {} not assigned, {} Assigned to contributors, {} need info'.format(xTot, xOpen, xAssign, xInfo))
print(' + needsDevEval {} needs to be evaluated'.format(needsDevEval))
print(' + cleanup: {} has more than 4 comments, {} needs to be reviewed'.format(xComm, xRevi))
print(' + new last 8 days:')
for row in pNew :
print(' ', end='')
print(formatEasy(row))
print (' + <text>')
print('\n\n')

xTot = len(gerritOpen)
xRevi = 0
for row in gerritOpen:
# can be merged (depending comments)
if checkGerrit(1, row) :
xRevi += 1
print ('* Mentoring Update (JanI)')
print (' + total: {} open gerrit patches of which {} are mergeable'.format(xTot, xRevi))
xTot = len(gerritContributor)
xRevi = 0
for row in gerritContributor:
# can be merged (depending comments)
if checkGerrit(1, row) :
xRevi += 1
print (' + contributors: {} open gerrit patches of which {} are mergeable'.format(xTot, xRevi))
print (' + <text>')



def DAY_report(runMsg, easyHacks, gerritOpen, gerritContributor) :
# Day report looks 8 days back
cDate = datetime.date.today() - datetime.timedelta(days=8)

print("*** new easyHacks (verify who created it):")
for key, row in easyHacks.items():
if row['created'] >= cDate :
print(' ', end='')
print(formatEasy(row))

print("\n\n*** Gerrit mangler reviewer:")
for row in gerritContributor:
if not checkGerrit(2, row) :
print(' ', end='')
print(formatGerrit(row))

# Month report looks 30 days back
cDate = datetime.date.today() - datetime.timedelta(days=30)

print("\n\n*** Gerrit to abandon:")
for row in gerritContributor:
# can be merged (depending comments)
if checkGerrit(5, row, cDate=cDate) :
print(' ', end='')
print(formatGerrit(row))

print('\n\n*** assigned easyHacks, no movement')
for key, row in easyHacks.items():
if row['change'] <= cDate and row['status'] == 'ASSIGNED':
print(' ', end='')
print(formatEasy(row))

print("\n\ne*** asyHacks needing review due to whiteboard:")
bugs = []
for key, row in easyHacks.items():
if row['comments'] < 5 and 'ToBeReviewed' in row['whiteboard'] :
print(' ', end='')
print(formatEasy(row))

if runMsg == "dump" :
print("\n\n*** easyHacks with more than 5 comments:")
bugs = []
for key, row in easyHacks.items():
if row['comments'] >= 5 :
bugs.append(optimize_bug(get_bug(key)))
fp = open('bz_comments.json', 'w')
json.dump(bugs, f, ensure_ascii=False, indent=4, sort_keys=True)
fp.close()
xTot = len(bugs)
print(' wrote {} entries to bz_comments.json'.format(xTot))




if __name__ == '__main__':
# check command line options
doESC = True
if len(sys.argv) > 1 :
if sys.argv[1] != 'esc' :
doESC = False

# get data from bugzilla and gerrit
easyHacks = get_easyHacks()
needsDevEval = get_count_needsDevEval()
gerritOpen = get_gerrit(False)
gerritContributor = get_gerrit(True)

if doESC :
ESC_report(easyHacks, gerritOpen, gerritContributor, needsDevEval)
else :
DAY_report(sys.argv[1],easyHacks, gerritOpen, gerritContributor)
print('\n\nend of report')

    (1-1/1)