Skip to content
Snippets Groups Projects
Commit 02c5b870 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Finished milestone issue enumerator / burndown generator

parent 03571388
No related branches found
No related tags found
No related merge requests found
......@@ -202,6 +202,9 @@ class GitlabIssue:
def __ne__(self, other: "GitlabIssue") -> bool:
return not self.__eq__(other)
def __hash__(self) -> int:
return self.get_universal_issue_id()
# other git_issue fields:
# project_id
# title
......@@ -353,6 +356,9 @@ class GitlabCommit:
def __ne__(self, other: "GitlabCommit") -> bool:
return not self.__eq__(other)
def __hash__(self) -> int:
return hash(self.get_id())
# git_commit fields:
# comments
# discussions
......@@ -450,6 +456,9 @@ class GitlabMilestone:
def __ne__(self, other: "GitlabMilestone") -> bool:
return not self.__eq__(other)
def __hash__(self) -> int:
return self.git_milestone.id
# other git_milestone fields:
# id
# iid
......
import textwrap
from datetime import date
from math import log10, floor
from typing import Tuple
......
import csv
from datetime import timedelta, time
from dateutil import tz
from api.gitlab_classes import *
from course import Course
# noinspection PyShadowingNames
def write_issue_enumeration(milestone: GitlabMilestone, filename: str) -> None:
fieldnames = ['Issue', 'Created', 'Closed', 'Assignee', 'Participants']
with open(filename, mode='w') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
for issue in sorted(milestone.get_issues(), key=lambda i: i.get_project_issue_id()):
writer.writerow({
fieldnames[0]: issue.get_project_issue_id(),
fieldnames[1]: issue.get_created_at(),
fieldnames[2]: issue.get_closed_at() if issue.get_closed_at() is not None else '(open)',
fieldnames[3]: issue.get_assignee(),
fieldnames[4]: issue.get_participants()
})
def write_issue_burndown(milestone: GitlabMilestone, filename: str) -> None:
timezone = tz.gettz('America/Chicago')
start: datetime = datetime.combine(date=(milestone.get_start_date()), time=time.min, tzinfo=timezone)
due: datetime = datetime.combine(date=(milestone.get_due_date()), time=time.max, tzinfo=timezone)
end: datetime = datetime.combine(date=date.today(), time=time.max, tzinfo=timezone)
step: timedelta = timedelta(hours=1)
window: datetime = start
issues: List[GitlabIssue] = milestone.get_issues()
timeline = []
while window <= due and window <= end:
existing_open_issues = set()
new_issues = set()
closed_issues = set()
for issue in issues:
if window <= issue.get_created_at() < window + step:
new_issues.add(issue)
elif issue.is_closed() and issue.get_closed_at() < window + step:
closed_issues.add(issue)
elif issue.get_created_at() < window:
existing_open_issues.add(issue)
else:
assert issue.get_created_at() >= window + step,\
'Window starts at {Window}. Issue {issue} was not open before the window, was not created during ' \
'the window, was not closed before the end of the window, and was not created after the window.'
timeline.append({
'Window': window,
'Open Issues': len(existing_open_issues),
'New Issues': len(new_issues),
'Closed Issues': len(closed_issues)
})
window += step
if len(timeline) == 0:
timeline.append({
'Window': start,
'Open Issues': 0,
'New Issues': 0,
'Closed Issues': 0
})
while window <= due:
timeline.append({
'Window': window,
'Open Issues': timeline[-1]['Open Issues'] + timeline[-1]['New Issues'],
'New Issues': 0,
'Closed Issues': timeline[-1]['Closed Issues']
})
window += step
if window != due:
timeline.append({
'Window': due,
'Open Issues': timeline[-1]['Open Issues'] + timeline[-1]['New Issues'],
'New Issues': 0,
'Closed Issues': timeline[-1]['Closed Issues']
})
fieldnames = ['Window', 'Open Issues', 'New Issues', 'Closed Issues']
with open(filename, mode='w') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
for moment in timeline:
writer.writerow(moment)
if __name__ == '__main__':
projects = sorted(list(filter(lambda p: p.get_name().startswith('36team'),
projects = sorted(list(filter(lambda p: p.get_name().startswith('36team'), ## TODO soft-code prefix
GitlabProject.get_projects_by_group(Course.gitlab_namespace))),
key=lambda p: p.get_name())
for project in projects:
milestones = sorted(project.get_milestones(), key=lambda m: m.get_title())
print('\n\n')
if len(milestones) == 0:
print(f'Project: {project} has no milestones')
else:
for milestone in milestones:
print(f'Project: {project}\tMilestone: {milestone}')
for issue in sorted(milestone.get_issues(), key=lambda i: i.get_project_issue_id()):
print(f'\tIssue {issue}')
print(f'\t\tCreated at {issue.get_created_at()}, assigned to {issue.get_assignee()}, updated at {issue.get_updated_at()}, closed at {issue.get_closed_at()}.')
print(f'\t\tParticipants: {issue.get_participants()}')
write_issue_enumeration(milestone=milestone,
filename=f'{project.get_name()}-'
f'{milestone.get_title().replace(" ", "_")}-'
f'issues.csv')
write_issue_burndown(milestone=milestone,
filename=f'{project.get_name()}-'
f'{milestone.get_title().replace(" ", "_")}-'
f'burndown.csv')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment