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

Now shows contributions by file type

- Hand-edited changes (source code, markdown, etc) show *line* changes
- Binary files and auto-generated changes (html, fxml, etc) show *file*
  changes
parent 15adf237
No related branches found
No related tags found
No related merge requests found
......@@ -215,6 +215,12 @@ class GitlabCommit:
def is_merge(self) -> bool:
return len(self.gitlab_commit.parent_ids) > 1
def get_id(self) -> str:
return self.gitlab_commit.id
def get_short_id(self) -> str:
return self.gitlab_commit.short_id
# noinspection PyShadowingNames
def get_diffs(self) -> List[Dict[str, Union[str, int]]]:
diffs: List[Dict[str, Union[str, int]]] = []
......@@ -234,6 +240,34 @@ class GitlabCommit:
deletions += diff['-']
return max(insertions, deletions)
# noinspection PyShadowingNames
def get_diff_size_by_filetype(self) -> Dict[str, int]:
binary_like_text_files = {"css", "csv", "fxml", "html"} # TODO soft-code this
# noinspection SpellCheckingInspection
binary_files = {"docx", "gif", "jpg", "jpeg", "pdf", "png", "pptx", "svg", "xlsx"} # TODO this, too
return_diff: Dict[str, int] = {}
insert_diff: Dict[str, int] = {}
delete_diff: Dict[str, int] = {}
if not self.is_merge():
for diff in self.get_diffs():
file = diff['file'].split('.')
if len(file) == 1:
filetype = 'no type'
else:
filetype = file[-1]
if filetype not in return_diff.keys():
return_diff[filetype] = 0
insert_diff[filetype] = 0
delete_diff[filetype] = 0
if filetype in binary_files.union(binary_like_text_files):
insert_diff[filetype] += 1
else:
insert_diff[filetype] += diff['+']
delete_diff[filetype] += diff['-']
for key in return_diff.keys():
return_diff[key] = max(insert_diff[key], delete_diff[key])
return return_diff
@staticmethod
def _number_of_lines_too_long(lines, subject_line_length, message_line_length):
# noinspection PyUnusedLocal
......
import math
import textwrap
from datetime import date
from math import ceil, log10
from math import log10, floor
from typing import Tuple
from gitlab import GitlabError
......@@ -94,8 +93,24 @@ def get_project_prefix(canvas_groups):
return prefix
def _combine_typed_contributions(typed_sizes: Tuple[Dict[str, int]]) -> Dict[str, int]:
combined_typed_size: Dict[str, int] = {}
keys: Set[str] = set()
for typed_size in typed_sizes:
keys = keys.union(typed_size.keys())
for key in keys:
combined_typed_size[key] = 0
for typed_size in typed_sizes:
if key in typed_size.keys():
combined_typed_size[key] += typed_size[key]
return combined_typed_size
def display_git_contributions(project: GitlabProject):
# TODO: recognize that this only works for projects in namespace; will need to ask whether to retrieve project.
binary_like_text_files = {"css", "csv", "fxml", "html"} # TODO soft-code this
# noinspection SpellCheckingInspection
binary_files = {"docx", "gif", "jpg", "jpeg", "pdf", "png", "pptx", "svg", "xlsx"} # TODO this, too
# noinspection PyUnusedLocal
project_commits: List[GitlabCommit]
if assignment_start_date == '':
......@@ -103,6 +118,7 @@ def display_git_contributions(project: GitlabProject):
else:
project_commits = project.get_commits(after_date=assignment_start_date)
contributions: Dict[str, int] = {} # TODO: also broaden to multiple branches?
typed_contributions: Dict[str, Dict[str, int]] = {}
timestamps: Dict[str, List[datetime]] = {}
contributors: Set[Tuple[str, str]] = set()
# noinspection PyShadowingNames
......@@ -111,24 +127,33 @@ def display_git_contributions(project: GitlabProject):
author = commit.get_author()
contributors.add((author['name'], author['email']))
email = author['email'] # TODO: manage aliases
size = commit.get_diff_size() # TODO: distinguish between file types
size = commit.get_diff_size()
typed_size = commit.get_diff_size_by_filetype()
if email != 'bohn@unl.edu': # TODO: un-hard-code this -- may not be necessary with a starting date
if email not in contributions:
contributions[email] = 0
typed_contributions[email] = {}
timestamps[email] = []
contributions[email] += size
typed_sizes: Tuple[Dict[str, int]] = (typed_contributions[email], typed_size)
typed_contributions[email] = _combine_typed_contributions(typed_sizes)
timestamps[email].append(commit.get_timestamp())
print(f'Contributions by each partner to {project} :')
for contribution in contributions:
contributor = list(filter(lambda c: c[1] == contribution, contributors))[0]
email = contributor[1]
typed_contribution = typed_contributions[email]
timestamps[email].sort()
number_of_commits = len(timestamps[email])
print(f'\t{contributor}')
print(
f'\t{str(contributions[contribution]).rjust(5)} line changes in {str(number_of_commits).rjust(3)} commits')
f'\t{str(contributions[contribution]).rjust(5)} total line changes in '
f'{str(number_of_commits).rjust(3)} commits')
for filetype in sorted(typed_contribution.keys()):
change_type = 'file' if filetype in binary_files.union(binary_like_text_files) else 'line'
print(f'\t\t\t{filetype} {str(typed_contribution[filetype]).rjust(10-len(filetype))} {change_type} changes')
print(f'\t\tFirst commit: {timestamps[email][0]}')
print(f'\t\tMedian commit: {timestamps[email][math.floor(number_of_commits/2)]}')
print(f'\t\tMedian commit: {timestamps[email][floor(number_of_commits/2)]}')
print(f'\t\tLast commit: {timestamps[email][-1]}')
......@@ -171,8 +196,7 @@ if __name__ == '__main__':
if option is options[1]:
print('Which group?')
student_groups = [select_from_list(student_groups, 'student group')]
zero_padding: int = ceil(log10(len(projects))) # remove this after 24pair is graded
# zero_padding: int = floor(log10(len(projects))) + 1 # leaving this here until 24pair is graded
zero_padding: int = floor(log10(len(projects))) + 1
assignment_start_date = get_assignment_start() # TODO: only need this if grading git histories
for student_group in student_groups: # TODO: Skip past graded groups
input(f'\n\nPress Enter to grade {student_group}')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment