Skip to content

Instantly share code, notes, and snippets.

@awaisdar001
Last active November 12, 2020 11:44
Show Gist options
  • Save awaisdar001/313a5882564fb29aeac11b85e6ac5e9e to your computer and use it in GitHub Desktop.
Save awaisdar001/313a5882564fb29aeac11b85e6ac5e9e to your computer and use it in GitHub Desktop.
# https://docs.google.com/spreadsheets/d/1zR0acdQweKgfu391ZvmKh_UsqxWooDecgYVm0SUpGbw/edit#gid=1228758080
JIRA_SERVER = 'https://openedx.atlassian.net'
TOP_ISSUES_JQL = 'project = "Customer Requests" and team=87 and resolutiondate>={} and resolutiondate <= {}'
MAX_RESULTS = 1000
BUG_LABEL_LIST = [
'a11y',
'assets',
'async-task-tools',
'capa',
'ccx_course',
'certificates',
'checklist',
'codejail',
'cohorts',
'coursegraph',
'course-discovery',
'course-content',
'course-outline',
'content_experiment',
'data-export',
'db-transaction',
'discussion',
'dynamic-pacing',
'export',
'enrollment-track-groups',
'edx-submissions',
'edx-video-pipeline',
'edx-organizations',
'edxnotes',
'files_uploads',
'flaky_test',
'highlights',
'grading',
'gradebook',
'import',
'instructor-dashboard',
'instructor_task',
'instructor-report',
'insights',
'logs',
'library',
'LTI',
'masters',
'memory',
'notifier',
'ORA2',
'opaque-keys',
'prerequisites',
'proctoring',
'progress-page',
'publisher',
'studio',
'support-fee',
'translation',
'video',
'visual-progress',
'wiki',
'webpack',
'xblock_package',
'xml_authoring',
'XSS',
]
import os
from jira import JIRA
from constants import JIRA_SERVER
from settings import JIRA_USER, API_TOKEN
class JiraIssueWrapper(object):
def __init__(self, issue):
self.issue = issue
@property
def label(self):
return self.issue.fields.labels
@property
def title(self):
return self.issue.fields.summary
@property
def key(self):
return self.issue.key
@property
def reporter(self):
return self.issue.fields.reporter.displayName
class ReportsBase(object):
@staticmethod
def log(msg):
print("==> {}".format(msg))
class JiraBase(ReportsBase):
def __init__(self, *args, **kwargs):
self.user = os.environ.get('JIRA_USER', JIRA_USER)
self.api_token = os.environ.get('API_TOKEN', API_TOKEN)
self.jira = self.get_jira()
def get_jira(self):
if not self.credentials_are_valid():
raise Exception
self.log("Logging in as {}...".format(self.user))
return JIRA(server=JIRA_SERVER, basic_auth=(self.user, self.api_token))
def credentials_are_valid(self):
if not self.user:
self.log("ERROR: JIRA_USER not set. Set it by export JIRA_USER=foo")
return
if not self.api_token:
self.log("ERROR: API_TOKEN not set. Set it by export API_TOKEN=foo")
return
return True
@staticmethod
def get_issue_label(issue):
return issue.fields.labels
@staticmethod
def get_issue_title(issue):
return issue.fields.summary
@staticmethod
def get_issue_key(issue):
return issue.key
from datetime import datetime
from dateutil.relativedelta import relativedelta
def get_dates():
def get_previous_month_year():
current_date = datetime.now().date()
current_month, current_year = current_date.month, current_date.year
return current_month - 1, current_year
user_input = input('Enter `month-year` for report? (Leave blank for previous month): ')
if user_input:
month, year = user_input.split('-')
month, year = int(month), int(year)
else:
month, year = get_previous_month_year()
from_date = datetime(year=year, month=month, day=1)
to_date = from_date + relativedelta(months=1)
return from_date.date(), to_date.date()
def sort_by_values(data_dict):
"""sort by values"""
return {
k: v for k, v in sorted(data_dict.items(), key=lambda item: item[1], reverse=True)
}
from constants import BUG_LABEL_LIST, MAX_RESULTS
from jira_api import JiraBase
from lib import get_dates, sort_by_values
BUG_LABEL_GLOSSARY = {
label: 0 for label in BUG_LABEL_LIST
}
class MonthlyPerformanceReport(JiraBase):
matched_issues = []
unmatched_issues = []
current_month_issues_jql = None
def __init__(self, *args, **kwargs):
super(MonthlyPerformanceReport, self).__init__(*args, **kwargs)
self.from_date, self.to_date = get_dates()
def find_current_month_issues(self):
self.log('Finding issues between {} and {}'.format(self.from_date, self.to_date))
current_month_issues_jql = (
'type = BUG AND project = Educator AND created >= {} AND created <= {}'
).format(self.from_date, self.to_date)
return self.jira.search_issues(current_month_issues_jql, maxResults=MAX_RESULTS)
@staticmethod
def get_label_jql(from_date, to_date, label):
return (
'issuetype in (Bug) AND project = Educator AND createdDate >= {}'
' AND createdDate < {} AND labels={} ORDER BY createdDate DESC'
).format(from_date, to_date, label)
def _update_bug_label_glossary(self):
for issue in self.issues:
match_found = False
labels = self.get_issue_label(issue)
for label in labels:
if label in BUG_LABEL_GLOSSARY:
match_found = True
BUG_LABEL_GLOSSARY[label] += 1
if match_found:
self.matched_issues.append(issue)
else:
self.unmatched_issues.append(issue)
self.BUG_LABEL_GLOSSARY = sort_by_values(BUG_LABEL_GLOSSARY)
def print_matching_count(self):
print('*' * 50)
self.log('Found Issues: {}'.format(len(self.matched_issues)))
self.log('Unmatching Issues: {}'.format(len(self.unmatched_issues)))
print('*' * 50)
def get_stats(self):
self.issues = self.find_current_month_issues()
self.log('Calculating report for {} issues ...'.format(len(self.issues)))
self._update_bug_label_glossary()
self.print_matching_count()
self.print_details_of_unmatching_issues()
self.print_label_glossary_count()
def print_details_of_unmatching_issues(self):
self.log('Unmatching issues ...')
for issue in self.unmatched_issues:
print('{} -- {}'.format(self.get_issue_key(issue), self.get_issue_title(issue)))
def print_label_glossary_count(self):
self.log('Bug Label Glossary')
for label, count in self.BUG_LABEL_GLOSSARY.items():
if count > 0:
print('{} : {} -- {}'.format(label, count, self.get_label_jql(self.from_date, self.to_date, label)))
report = MonthlyPerformanceReport()
report.get_stats()
import constants as enums
from jira_api import JiraBase, JiraIssueWrapper
from lib import get_dates, sort_by_values
class HighestContributor(JiraBase):
def __init__(self, *args, **kwargs):
super(HighestContributor, self).__init__(*args, **kwargs)
self.all_contributors = {}
self.from_date, self.to_date = get_dates()
self.issues = self.wrap_issues(self.find_current_month_issues())
@staticmethod
def wrap_issues(issues):
return (JiraIssueWrapper(issue) for issue in issues)
@property
def contributors(self):
if not getattr(self, 'all_contributors'):
self.find_contributors()
return sort_by_values(self.all_contributors)
def find_current_month_issues(self):
self.log('Finding issues between {} and {}'.format(self.from_date, self.to_date))
current_month_issues_jql = enums.TOP_ISSUES_JQL.format(self.from_date, self.to_date)
return self.jira.search_issues('project = "Customer Requests" AND team = 87 AND ( (createdDate >= 2020-01-01 AND createdDate <= 2020-02-01) OR (resolutiondate >= 2020-01-01 AND resolutiondate <= 2020-02-01) ) ORDER BY resolved DESC, reporter ASC', maxResults=enums.MAX_RESULTS)
def find_contributors(self):
for issue in self.issues:
reporter = issue.reporter
self.all_contributors[reporter] = self.all_contributors.get(reporter, 0) + 1
self.log("Total Contributors: {}".format(len(self.all_contributors)))
def highest_contributor(self, top=1):
slice_dict_only_to_keys = list(self.contributors.keys())[:top]
for _key in slice_dict_only_to_keys:
self.log("Top Contributor: {} ({})".format(_key, self.contributors[_key]))
contributors = HighestContributor()
contributors.highest_contributor(top=3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment