Skip to content

Commit 22858cb

Browse files
committed
Add Git Commit by Author capabilities
1 parent 1fe26e1 commit 22858cb

File tree

2 files changed

+97
-6
lines changed

2 files changed

+97
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ project's version. Not Yet Implemented means it does not exist yet:
6868
| **All Branches (Sorted by Most Recent Commit)** | Completed ✔️ | Lists all branches ordered by latest commit date. |
6969
| **All Contributors (Sorted by Name)** | Completed ✔️ | Displays all contributors sorted alphabetically. |
7070
| **New Contributors (Sorted by Email)** | Completed ✔️ | Lists new contributors sorted by their email addresses. |
71-
| **Git Commits per Author** | Stubbed 🛠️ | Counts commits made by each author. |
71+
| **Git Commits per Author** | Completed ✔️ | Counts commits made by each author. |
7272
| **Git Commits per Date** | Stubbed 🛠️ | Counts commits based on the date. |
7373
| **Git Commits per Month** | Stubbed 🛠️ | Counts commits based on the monthly. |
7474
| **Git Commits per Year** | Stubbed 🛠️ | Counts commits based on the year. |

git_py_stats/list_cmds.py

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import collections
6+
import re
67
from datetime import datetime, timezone
78
from typing import Dict, Optional
89

@@ -285,13 +286,103 @@ def git_commits_per_author() -> None:
285286
Shows the number of commits per author.
286287
"""
287288

288-
cmd = ['git', 'shortlog', '-s', '-n']
289+
# Original authors command:
290+
# git -c log.showSignature=false log --use-mailmap \
291+
# $_merges "$_since" "$_until" $_log_options \
292+
# | grep -i Author: | cut -c9-
293+
294+
# Original co-authors command:
295+
# git -c log.showSignature=false log --author="$c" \
296+
# --reverse --use-mailmap $_merges "$_since" "$_until" \
297+
# --format='%at' $_log_options $_pathspec | head -n 1
298+
cmd = [
299+
'git',
300+
'-c', 'log.showSignature=false',
301+
'log',
302+
'--use-mailmap',
303+
'--no-merges',
304+
'--pretty=format:Author:%aN <%aE>%n%b'
305+
]
306+
289307
output = run_git_command(cmd)
290-
if output:
291-
print("Git commits per author:")
292-
print(output)
293-
else:
308+
if not output:
294309
print('No commits found.')
310+
return
311+
312+
# Initialize commit count dictionary
313+
commit_counts = {}
314+
315+
# Total commits (including co-authored commits)
316+
total_commits = 0
317+
318+
# Regular expressions for parsing the author(s)
319+
author_regex = re.compile(r'^Author:\s*(.+)$', re.IGNORECASE)
320+
coauthor_regex = re.compile(r'^Co-Authored-by:\s*(.+)$', re.IGNORECASE)
321+
322+
# Process each line of the git output
323+
for line in output.split('\n'):
324+
author_match = author_regex.match(line)
325+
coauthor_match = coauthor_regex.match(line)
326+
327+
# Handle author
328+
if author_match:
329+
author_info = author_match.group(1).strip()
330+
author_name = extract_name(author_info)
331+
if author_name:
332+
commit_counts[author_name] = commit_counts.get(author_name, 0) + 1
333+
total_commits += 1
334+
335+
# Handle co-author
336+
elif coauthor_match:
337+
coauthor_info = coauthor_match.group(1).strip()
338+
coauthor_name = extract_name(coauthor_info)
339+
if coauthor_name:
340+
commit_counts[coauthor_name] = commit_counts.get(coauthor_name, 0) + 1
341+
total_commits += 1
342+
343+
# Handle case if nothing is found
344+
if total_commits == 0:
345+
print("No commits found.")
346+
return
347+
348+
# Prepare a list of contributors with counts and percentages
349+
contributors_list = []
350+
for author, count in commit_counts.items():
351+
percentage = (count / total_commits) * 100
352+
contributors_list.append((count, author, percentage))
353+
354+
# Sort the list by commit count in descending order
355+
contributors_list.sort(key=lambda x: x[0], reverse=True)
356+
357+
# Fancy stuff for making the commit count alignment kosher
358+
max_count = contributors_list[0][0]
359+
count_width = len(str(max_count)) + 1 # Extra space for alignment
360+
361+
# Print all the fun stuff. Finally...
362+
print('Git commits per author:\n')
363+
for count, author, percentage in contributors_list:
364+
print(f"\t{count:<{count_width}} {author:<30} {percentage:5.1f}%")
365+
366+
367+
def extract_name(author_info: str) -> Optional[str]:
368+
"""
369+
Extracts the author's name from the author information string.
370+
371+
Args:
372+
author_info (str): The author information string (e.g., "Name <email@example.com>").
373+
374+
Returns:
375+
Optional[str]: The extracted author name, or None if extraction fails.
376+
"""
377+
378+
# Use regex to extract the name before the email
379+
# Mostly a helper function for commits
380+
# NOTE: Should we move this into a separate file with other helper funcs?
381+
match = re.match(r'^([^<]+)', author_info)
382+
if match:
383+
return match.group(1).strip()
384+
else:
385+
return None
295386

296387

297388
def git_commits_per_date() -> None:

0 commit comments

Comments
 (0)