Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- 📈 Commit statistics at a glance
- 🗓️ Activity heatmap by day of week
- ⏰ Peak coding hours analysis
- 🔥 Commit streaks tracking
- 👥 Contributor insights
- 🎨 Beautiful terminal output
- 📤 JSON output for scripting
Expand Down
33 changes: 32 additions & 1 deletion gitstats/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ def stats(
"""Show commit statistics for a git repository."""
import json

from gitstats.parser import get_commit_stats, get_hourly_activity, get_weekly_activity
from gitstats.parser import (
get_commit_stats,
get_commit_streaks,
get_hourly_activity,
get_weekly_activity,
)

stats_data = get_commit_stats(path)

Expand All @@ -60,6 +65,8 @@ def stats(
console.print("[red]No commits found or not a git repository.[/]")
raise typer.Exit(1)

streaks = get_commit_streaks(stats_data["commits"])

if json_output:
# Build JSON output
output = {
Expand All @@ -69,6 +76,7 @@ def stats(
"first_commit": stats_data["first_commit"],
"last_commit": stats_data["last_commit"],
"authors": stats_data["author_stats"],
"streaks": streaks,
"weekly_activity": get_weekly_activity(stats_data["commits"]),
"hourly_activity": get_hourly_activity(stats_data["commits"]),
}
Expand All @@ -91,6 +99,9 @@ def stats(
# Show activity heatmap
_print_activity_heatmap(stats_data["commits"])

# Show streaks
_print_streaks(streaks)


def _print_author_table(author_stats: list[dict]) -> None:
"""Print a table of author statistics."""
Expand Down Expand Up @@ -152,5 +163,25 @@ def _print_activity_heatmap(commits: list[dict]) -> None:
console.print()


def _print_streaks(streaks: dict) -> None:
"""Print commit streak statistics."""
console.print("[bold]🔥 Commit Streaks[/]\n")

current = streaks["current_streak"]
longest = streaks["longest_streak"]
active_days = streaks["total_active_days"]

# Current streak with fire emojis based on length
if current > 0:
fires = "🔥" * min(current, 5)
console.print(f" [green]Current streak:[/] {current} days {fires}")
else:
console.print(" [dim]Current streak:[/] 0 days (no recent commits)")

console.print(f" [yellow]Longest streak:[/] {longest} days")
console.print(f" [cyan]Total active days:[/] {active_days}")
console.print()


if __name__ == "__main__":
app()
56 changes: 56 additions & 0 deletions gitstats/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,59 @@ def get_hourly_activity(commits: list[dict]) -> list[dict]:
}
for h in range(24)
]


def get_commit_streaks(commits: list[dict]) -> dict:
"""
Calculate commit streaks (consecutive days with commits).

Args:
commits: List of commit dictionaries

Returns:
Dictionary with streak statistics
"""
from datetime import timedelta

if not commits:
return {"current_streak": 0, "longest_streak": 0, "total_active_days": 0}

# Get unique dates (just the date part, no time)
commit_dates = sorted({commit["date"].date() for commit in commits})

if not commit_dates:
return {"current_streak": 0, "longest_streak": 0, "total_active_days": 0}

# Calculate streaks
streaks = []
current_streak = 1

for i in range(1, len(commit_dates)):
if commit_dates[i] - commit_dates[i - 1] == timedelta(days=1):
current_streak += 1
else:
streaks.append(current_streak)
current_streak = 1

streaks.append(current_streak)

longest_streak = max(streaks) if streaks else 0

# Check if current streak is active (last commit was today or yesterday)
from datetime import date

today = date.today()
last_commit_date = commit_dates[-1]
days_since_last = (today - last_commit_date).days

if days_since_last <= 1:
active_streak = streaks[-1] if streaks else 0
else:
active_streak = 0

return {
"current_streak": active_streak,
"longest_streak": longest_streak,
"total_active_days": len(commit_dates),
"last_commit_date": str(last_commit_date),
}
Loading