Skip to content

Commit 7b53df9

Browse files
committed
Implement changelogs()
* Essentially matches 1:1 functionality of the changelogs() function in git-quick-stats. Subtle differences occur with how commits in dates are being grouped, but that may be due to a bug in the parent project rather than a bug in this one. Some more investigation can be done after more features are implemented. * Updated tests based off of the changelogs() implementation * Added a chart in the README.md to better track functionality and adjusted some formatting slightly
1 parent bd07641 commit 7b53df9

File tree

5 files changed

+124
-46
lines changed

5 files changed

+124
-46
lines changed

README.md

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ and ease of maintenance.
88

99
![mainMenuScreenshot](https://github.com/user-attachments/assets/4c3f49d8-62a9-4208-a968-5270e36aa3b8)
1010

11-
1211
## Why Git Py Stats?
1312

1413
While `git-quick-stats` is a fantastic tool, it has some limitations due to its
@@ -44,20 +43,51 @@ Git Py Stats aims to maintain feature parity with the original `git-quick-stats`
4443

4544
and more in both interactive and non-interactive modes.
4645

47-
## Missing Features
48-
49-
Git Py Stats is currently in beta format. As such, it is missing the following:
50-
51-
- Git log since and until functionality
52-
- Git log limit functionality
53-
- Git log options functionality
54-
- Git pathspec functionality
55-
- Git merge view strategies
56-
- Git branch adjustability to customize what branch you're on
57-
- Color themes
58-
- Linux package installs (only installable via `pip` and locally currently)
59-
- macOS package installs
60-
- Lacks a Docker image
46+
## Feature Comparison
47+
48+
The following is a list of features that compares `git-py-stats` development
49+
with the capabilities `git-quick-stats` currently has. Completed means there
50+
exists essentially 1:1 functionality between the two projects. Stubbed means
51+
`git-py-stats` has the feature available, but it might not match the original
52+
project's version. Not Yet Implemented means it does not exist yet:
53+
54+
| Feature | Status | Description |
55+
|-------------------------------------------------|-------------------------|---------------------------------------------------------|
56+
| **UI** | Completed ✔️ | General UI when launching interactive mode |
57+
| **Interactive Mode** | Completed ✔️ | Enables interactive sessions for user inputs. |
58+
| **Non-interactive Mode** | Completed ✔️ | Allows usage without interactive prompts. |
59+
| **Contribution Stats** | Completed ✔️ | Displays overall contribution statistics. |
60+
| **Contribution Stats by Author** | Completed ✔️ | Shows contribution stats by individual authors. |
61+
| **Changelogs** | Completed ✔️ | Lists commit logs over 10 last days of commits. |
62+
| **Changelogs by Author** | Completed ✔️ | Filters changelogs based on the author. |
63+
| **Code Reviewers** | Completed ✔️ | Identifies code reviewers based on contribution. |
64+
| **My Daily Stats** | Stubbed 🛠️ | Tracks daily statistics customized for the user. |
65+
| **Output Daily Stats by Branch in CSV** | Stubbed 🛠️ | Exports daily branch stats in CSV format. |
66+
| **Save Git Log Output in JSON Format** | Stubbed 🛠️ | Stores git logs in JSON. |
67+
| **Branch Tree View** | Stubbed 🛠️ | Visual representation of the branch hierarchy. |
68+
| **All Branches (Sorted by Most Recent Commit)** | Stubbed 🛠️ | Lists all branches ordered by latest commit date. |
69+
| **All Contributors (Sorted by Name)** | Stubbed 🛠️ | Displays all contributors sorted alphabetically. |
70+
| **New Contributors (Sorted by Email)** | Stubbed 🛠️ | Lists new contributors sorted by their email addresses. |
71+
| **Git Commits per Author** | Stubbed 🛠️ | Counts commits made by each author. |
72+
| **Git Commits per Date** | Stubbed 🛠️ | Counts commits based on the date. |
73+
| **Git Commits per Month** | Stubbed 🛠️ | Counts commits based on the monthly. |
74+
| **Git Commits per Year** | Stubbed 🛠️ | Counts commits based on the year. |
75+
| **Git Commits per Weekday** | Stubbed 🛠️ | Counts commits based on the weekday. |
76+
| **Git Commits per Weekday by Author** | Stubbed 🛠️ | Shows weekday commit counts by given author. |
77+
| **Git Commits per Hour** | Stubbed 🛠️ | Counts commits based on the hour. |
78+
| **Git Commits per Hour by Author** | Stubbed 🛠️ | Shows hourly commit count hour by given author. |
79+
| **Git Commits per Timezone** | Stubbed 🛠️ | Counts commits based on timezones. |
80+
| **Git Commits per Timezone by Author** | Stubbed 🛠️ | Shows timezone-based commit counts by given author. |
81+
| **Since Variable Adjustable by User** | Not Yet Implemented ❌ | Allows users to set the starting point for commit logs. |
82+
| **Until Variable Adjustable by User** | Not Yet Implemented ❌ | Enables users to define the end point for commit logs. |
83+
| **Pathspec Variable Adjustable by User** | Not Yet Implemented ❌ | Filters commits based on specified path patterns. |
84+
| **Merge View Variable Adjustable by User** | Not Yet Implemented ❌ | Controls the inclusion of merge commits in views. |
85+
| **Limit Variable Adjustable by User** | Not Yet Implemented ❌ | Sets the maximum number of commits to display. |
86+
| **Log Options Variable Adjustable by User** | Not Yet Implemented ❌ | Customizes git log command options. |
87+
| **Legacy Theme** | Not Yet Implemented ❌ | Restores the previous visual theme of the application. |
88+
| **Linux Package Install** | Not Yet Implemented ❌ | Allows Linux users to install via a package manager. |
89+
| **macOS Package install** | Not Yet Implemented ❌ | Allows macOS users to install via brew. |
90+
| **Docker Development Image** | Not Yet Implemented ❌ | Provides a Docker development image for CI/CD. |
6191

6292
## Requirements
6393

@@ -97,7 +127,7 @@ Git Py Stats is currently in beta format. As such, it is missing the following:
97127
export PYTHONPATH=$(pwd):$PYTHONPATH
98128
```
99129
100-
4. **Verify the Installation**:
130+
3. **Verify the Installation**:
101131
102132
While inside of a valid git repo, type the following:
103133

git_py_stats/generate_cmds.py

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import collections
66
import csv
7-
import datetime
7+
from datetime import datetime, timedelta
88
import json
99
import os
1010
from typing import Optional, Dict, Any, List
@@ -126,8 +126,8 @@ def contribution_stats_by_author(branch: Optional[str] = None) -> None:
126126
files = len(stats['files'])
127127
commits = stats['commits']
128128
lines_changed = stats['lines_changed']
129-
first_commit = datetime.datetime.fromtimestamp(stats['first_commit']).strftime('%a %b %d %H:%M:%S %Y %z')
130-
last_commit = datetime.datetime.fromtimestamp(stats['last_commit']).strftime('%a %b %d %H:%M:%S %Y %z')
129+
first_commit = datetime.fromtimestamp(stats['first_commit']).strftime('%a %b %d %H:%M:%S %Y %z')
130+
last_commit = datetime.fromtimestamp(stats['last_commit']).strftime('%a %b %d %H:%M:%S %Y %z')
131131

132132
# Calculate percentages
133133
insertions_pct = (insertions / total_insertions * 100) if total_insertions else 0
@@ -153,30 +153,77 @@ def contribution_stats_by_author(branch: Optional[str] = None) -> None:
153153
print(f" commits: {total_commits:<6} (100%)\n")
154154

155155

156-
157-
def git_changelogs_last_10_days(author: Optional[str] = None) -> None:
156+
def changelogs(author: Optional[str] = None, limit: int = 10) -> None:
158157
"""
159-
Shows commit messages from the last 10 days. If an author is provided,
160-
it shows commit messages from that author.
158+
Shows commit messages grouped by date, for the last 'limit' dates where commits occurred.
159+
160+
Args:
161+
If an author is provided, it shows commit messages from that author.
162+
Otherwise, it passes 'None' and shows commits from all authors.
161163
"""
162164

163-
if author:
164-
cmd = ['git', 'log', '--author', author, '--since=10.days', '--oneline']
165-
else:
166-
cmd = ['git', 'log', '--since=10.days', '--oneline']
165+
# Initialize variables similar to the Bash version
166+
# TODO: Refactor this when we add global adjustment capabilities
167+
next_date = datetime.now().date()
168+
author_option = f'--author={author}' if author else ''
169+
merges_option = '--no-merges' # Adjust as per the Bash global variable _merges
170+
171+
# Get unique commit dates
172+
# Original version:
173+
# git -c log.showSignature=false log --use-mailmap $_merges --format="%cd" --date=short "${_author}"
174+
# "$_since" "$_until" $_log_options $_pathspec
175+
cmd = ['git', 'log', '--use-mailmap', merges_option, '--format=%cd', '--date=short']
176+
if author_option:
177+
cmd.append(author_option)
178+
179+
print('Git changelogs (last 10 commits)')
167180

181+
# Get commit dates
168182
output = run_git_command(cmd)
169-
if output:
170-
if author:
171-
print(f"Git changelogs by {author} (last 10 days):")
172-
else:
173-
print("Git changelogs (last 10 days):")
174-
print(output)
175-
else:
176-
if author:
177-
print(f'No changelogs available for author {author} in the last 10 days.')
178-
else:
179-
print('No changelogs available in the last 10 days.')
183+
if not output:
184+
print("No commits found.")
185+
return
186+
187+
# Process dates by splitting into date strings,
188+
# removing dupes, sorting in reverse chrono order,
189+
# and applying our limit defined above
190+
dates = output.strip().split('\n')
191+
dates = sorted(set(dates), reverse=True)
192+
dates = dates[:limit]
193+
194+
# Create the date/day format of [YYYY-MM-DD] - Day of week
195+
for date_str in dates:
196+
date = datetime.strptime(date_str, '%Y-%m-%d').date()
197+
day_of_week = date.strftime('%A')
198+
print(f"\n[{date_str} - {day_of_week}]")
199+
200+
since_date = (date - timedelta(days=1)).strftime('%Y-%m-%d')
201+
until_date = next_date.strftime('%Y-%m-%d')
202+
203+
# Build git log command for the date range
204+
# Note the space between the --format and *. This provides
205+
# the space should there be multiple entries per date string
206+
# Original version:
207+
# git -c log.showSignature=false log \
208+
# --use-mailmap $_merges --format=" * %s (%aN)" \
209+
# "${_author}" --since==$(date -d "$DATE - 1 day" +"%Y-%m-%d") \
210+
# --until=$next
211+
cmd = [
212+
'git', 'log', '--use-mailmap', merges_option,
213+
'--format= * %s (%aN)',
214+
f'--since={since_date}',
215+
f'--until={until_date}'
216+
]
217+
if author_option:
218+
cmd.append(author_option)
219+
220+
# Output everything to the terminal
221+
# Note the space added. This provides the initial space
222+
# before the asterisk for every initial entry
223+
output = run_git_command(cmd)
224+
if output:
225+
print(f" {output}")
226+
next_date = date # Update next_date for the next iteration
180227

181228

182229
def my_daily_status() -> None:

git_py_stats/interactive_mode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ def handle_interactive_mode() -> None:
1010
interactive_map = {
1111
'1': generate_cmds.contribution_stats_by_author,
1212
'2': lambda: generate_cmds.contribution_stats_by_author(input("Enter branch name: ")),
13-
'3': generate_cmds.git_changelogs_last_10_days,
14-
'4': lambda: generate_cmds.git_changelogs_last_10_days(input("Enter author name: ")),
13+
'3': generate_cmds.changelogs,
14+
'4': lambda: generate_cmds.changelogs(input("Enter author name: ")),
1515
'5': generate_cmds.my_daily_status,
1616
'6': generate_cmds.output_daily_stats_csv,
1717
'7': generate_cmds.save_git_log_output_json,

git_py_stats/non_interactive_mode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ def handle_non_interactive_mode(args) -> None:
1515
non_interactive_map = {
1616
'detailed_git_stats': generate_cmds.contribution_stats_by_author,
1717
'git_stats_by_branch': lambda: generate_cmds.contribution_stats_by_author(args.git_stats_by_branch),
18-
'changelogs': generate_cmds.git_changelogs_last_10_days,
19-
'changelogs_by_author': lambda: generate_cmds.git_changelogs_last_10_days(args.changelogs_by_author),
18+
'changelogs': generate_cmds.changelogs,
19+
'changelogs_by_author': lambda: generate_cmds.changelogs(args.changelogs_by_author),
2020
'my_daily_stats': generate_cmds.my_daily_status,
2121
'csv_output_by_branch': generate_cmds.output_daily_stats_csv,
2222
'json_output': generate_cmds.save_git_log_output_json,

git_py_stats/tests/test_generate_cmds.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
from unittest.mock import patch
3+
import datetime
34

45
from git_py_stats import generate_cmds
56

@@ -26,17 +27,17 @@ def test_contribution_stats_by_author(self, mock_print) -> None:
2627

2728
# Silence stdout
2829
@patch('git_py_stats.generate_cmds.print')
29-
def test_git_changelogs_last_10_days(self, mock_print) -> None:
30+
def test_changelogs(self, mock_print) -> None:
3031
"""
31-
Test case for git_changelogs_last_10_days in generate_cmds.
32+
Test case for changelogs in generate_cmds.
3233
33-
Checks if `git_changelogs_last_10_days` executes without errors and returns `None`.
34+
Checks if `changelogs` executes without errors and returns `None`.
3435
Print is mocked to prevent actual output during testing.
3536
3637
Verifies that the function returns `None` and that print was called at least once.
3738
"""
3839

39-
self.assertIsNone(generate_cmds.git_changelogs_last_10_days())
40+
self.assertIsNone(generate_cmds.changelogs())
4041
mock_print.assert_called()
4142

4243

0 commit comments

Comments
 (0)