diff --git a/backend/app/services/forgejo_client.py b/backend/app/services/forgejo_client.py index a48cfa3..a48ee93 100644 --- a/backend/app/services/forgejo_client.py +++ b/backend/app/services/forgejo_client.py @@ -3,6 +3,8 @@ from __future__ import annotations import httpx +from datetime import datetime +from datetime import timezone as _tz from app.core.logging import get_logger @@ -398,19 +400,30 @@ class ForgejoAPIClient: break # empty or non-existent repo response.raise_for_status() data = response.json() - commits = data if isinstance(data, list) else [] + commits = data if isinstance(data, list) else data.get("commits") or data.get("data") or [] if not commits: break for commit in commits: s = commit.get("stats") or {} total_adds += int(s.get("additions") or 0) total_dels += int(s.get("deletions") or 0) - # Extract commit date for per-day activity counting + # Extract commit date for per-day activity counting. + # Normalise to UTC so Pipeline's day boundaries match Forgejo's + # contribution graph, which also uses UTC. Author dates from + # git clients configured with a local timezone would otherwise + # slice to the local date (e.g. "2026-05-26" from + # "2026-05-26T22:30:00-05:00") instead of the UTC date + # ("2026-05-27"), causing commits near midnight to land on the + # wrong day. commit_obj = commit.get("commit") or {} author_obj = commit_obj.get("author") or {} date_str: str = author_obj.get("date") or commit.get("created") or "" if date_str and len(date_str) >= 10: - day = date_str[:10] + try: + dt = datetime.fromisoformat(date_str.replace("Z", "+00:00")) + day = dt.astimezone(_tz.utc).strftime("%Y-%m-%d") + except (ValueError, OverflowError): + day = date_str[:10] day_counts[day] = day_counts.get(day, 0) + 1 if len(commits) < 50: break # last page