Last active
November 12, 2020 11:44
-
-
Save awaisdar001/313a5882564fb29aeac11b85e6ac5e9e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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', | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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