Skip to content

Commit 1fe26e1

Browse files
committed
Implement New Contributors functionality
* Implements the new_contributors() function, albeit slightly different from the original version. First, we see if there is a name associated with an email. If there is, print it out together with the email. Otherwise, just print out the email
1 parent 846d9b1 commit 1fe26e1

File tree

5 files changed

+107
-18
lines changed

5 files changed

+107
-18
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ project's version. Not Yet Implemented means it does not exist yet:
6767
| **Branch Tree View** | Completed ✔️ | Visual representation of the branch hierarchy. |
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. |
70-
| **New Contributors (Sorted by Email)** | Stubbed 🛠️ | Lists new contributors sorted by their email addresses. |
70+
| **New Contributors (Sorted by Email)** | Completed ✔️ | Lists new contributors sorted by their email addresses. |
7171
| **Git Commits per Author** | Stubbed 🛠️ | 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. |
@@ -96,14 +96,16 @@ there may be instances where this version differs from the base project by desig
9696
The following is a list of differences that this project will maintain compared to
9797
the parent project:
9898

99-
* Author and branch names can be passed via cmdline without interaction by
100-
the user. This means you can now do `git-py-stats -L "John Doe"` instead of
101-
being prompted to enter the name after executing the non-interactive cmd.
99+
* Author, dates, and branch names can be passed via cmdline without interaction
100+
by the user. This means you can now do `git-py-stats -L "John Doe"` instead
101+
of being prompted to enter the name after executing the non-interactive cmd.
102102
* CSV output is now saved to a file instead of printing out to the terminal.
103103
This file will be saved to wherever the process was executed. The name will
104104
be `git_daily_stats.csv`
105105
* JSON output is saved to a file wherever the process was executed instead of
106106
one that is provided by the user. The name will be `git_log.json`
107+
* The New Contributors function shows the user's name next to the email in case
108+
no known mailmap has been implemented for that user.
107109

108110
## Requirements
109111

git_py_stats/arg_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def parse_arguments(argv: Optional[List[str]] = None) -> Namespace:
8484
)
8585
parser.add_argument(
8686
'-n', '--new-contributors',
87-
action='store_true',
87+
metavar='DATE',
8888
help='List everyone who made their first contribution since a specified date'
8989
)
9090
parser.add_argument(

git_py_stats/interactive_mode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def handle_interactive_mode() -> None:
1818
'8': list_cmds.branch_tree,
1919
'9': list_cmds.branches_by_date,
2020
'10': list_cmds.contributors,
21-
'11': list_cmds.new_contributors,
21+
'11': lambda: list_cmds.new_contributors(input("Enter cutoff date (YYYY-MM-DD): ")),
2222
'12': list_cmds.git_commits_per_author,
2323
'13': list_cmds.git_commits_per_date,
2424
'14': list_cmds.git_commits_per_month,

git_py_stats/list_cmds.py

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,23 +172,110 @@ def contributors() -> None:
172172
else:
173173
print('No contributors found.')
174174

175-
def new_contributors() -> None:
175+
def new_contributors(new_date: str) -> None:
176176
"""
177-
Lists contributors sorted by email.
177+
Lists all new contributors to a repo since the specified date.
178+
179+
Args:
180+
new_date (str): Cutoff date for being considered "new" in 'YYYY-MM-DD' format.
181+
182+
Returns:
183+
None
178184
"""
179-
180-
cmd = ['git', 'log', '--format=%aN|%aE']
185+
186+
# Attempt to handle date in YYYY-MM-DD format
187+
try:
188+
new_date_dt = datetime.strptime(new_date, '%Y-%m-%d')
189+
new_date_ts = int(new_date_dt.timestamp())
190+
except ValueError:
191+
print("Invalid date format. Please use YYYY-MM-DD.")
192+
return
193+
194+
# User adjustable vars
195+
# TODO: Fix these later on
196+
merges = "--no-merges"
197+
since = "" # Include the world for now
198+
until = ""
199+
log_options = ""
200+
pathspec = ""
201+
202+
# Original command:
203+
# git -c log.showSignature=false log --use-mailmap $_merges \
204+
# "$_since" "$_until" --format='%aE' $_log_options \
205+
# $_pathspec | sort -u
206+
cmd = [
207+
'git',
208+
'-c', 'log.showSignature=false',
209+
'log',
210+
'--use-mailmap',
211+
merges,
212+
since,
213+
until,
214+
'--format=%aE|%at',
215+
log_options,
216+
pathspec
217+
]
218+
219+
# Remove any empty strings from the command to prevent Git misinterpretation
220+
# Needed when we start messing with datetime stuff
221+
cmd = [arg for arg in cmd if arg]
222+
181223
output = run_git_command(cmd)
182224
if output:
183-
contributors = set(output.split('\n'))
184-
new_contributors_list = sorted(contributors, key=lambda x: x.split('|')[1])
185-
print("New contributors:")
186-
for contributor in new_contributors_list:
225+
# Dictionary to store the earliest commit timestamp for each contributor
226+
contributors_dict = {}
227+
228+
# Process each line of the Git output
229+
for line in output.split('\n'):
187230
try:
188-
name, email = contributor.split('|')
189-
print(f"{name} <{email}>")
231+
email, timestamp = line.split('|')
232+
timestamp = int(timestamp)
233+
# If the contributor is not in the dictionary or the current timestamp is earlier
234+
if email not in contributors_dict or timestamp < contributors_dict[email]:
235+
contributors_dict[email] = timestamp
190236
except ValueError:
191-
continue # Skip lines that don't match the expected format
237+
continue # Skip lines that don't match format
238+
239+
# List to hold new contributors
240+
new_contributors_list = []
241+
242+
# Iterate over contributors to find those who are new since 'new_date'
243+
for email, first_commit_ts in contributors_dict.items():
244+
if first_commit_ts >= new_date_ts:
245+
# Retrieve the contributor's name
246+
# Original command:
247+
# git -c log.showSignature=false log --author="$c" \
248+
# --reverse --use-mailmap $_merges "$_since" "$_until" \
249+
# --format='%at' $_log_options $_pathspec | head -n 1
250+
name_cmd = [
251+
'git',
252+
'-c', 'log.showSignature=false',
253+
'log',
254+
'--use-mailmap',
255+
'--format=%aN',
256+
'--author=' + email,
257+
'-n', '1'
258+
]
259+
260+
# Grab name + email if we can. Otherwise, just grab email
261+
name = run_git_command(name_cmd)
262+
if name:
263+
new_contributors_list.append((name, email))
264+
else:
265+
new_contributors_list.append(("", email))
266+
267+
# Sort the list alphabetically by name to match the original
268+
# and print all of this out
269+
if new_contributors_list:
270+
print(f"New contributors since {new_date}:\n")
271+
sorted_new_contributors = sorted(new_contributors_list, key=lambda x: (x[0], x[1]))
272+
for idx, (name, email) in enumerate(sorted_new_contributors, 1):
273+
if name:
274+
print(f"{name} <{email}>")
275+
else:
276+
print(f"<{email}>")
277+
else:
278+
print("No new contributors found since the specified date.")
192279
else:
193280
print('No contributors found.')
194281

git_py_stats/non_interactive_mode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def handle_non_interactive_mode(args) -> None:
2323
'branch_tree': list_cmds.branch_tree,
2424
'branches_by_date': list_cmds.branches_by_date,
2525
'contributors': list_cmds.contributors,
26-
'new_contributors': list_cmds.new_contributors,
26+
'new_contributors': lambda: list_cmds.new_contributors(args.new_contributors),
2727
'commits_per_author': list_cmds.git_commits_per_author,
2828
'commits_per_day': list_cmds.git_commits_per_date,
2929
'commits_by_year': list_cmds.git_commits_per_year,

0 commit comments

Comments
 (0)