feat: initial project structure
- GitLabClient: REST Events API z paginacją, pobieranie członków grupy - Aggregator: zliczanie commitów, MR, komentarzy per użytkownik - Exporter: generowanie pliku Excel (openpyxl) ze stylami - main.py: CLI (click) + .env support - README, .env.example, requirements.txt, .gitignore
This commit is contained in:
69
aggregator.py
Normal file
69
aggregator.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Agregator — przetwarza eventy GitLab na statystyki per użytkownik.
|
||||
"""
|
||||
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class UserStats:
|
||||
name: str = ""
|
||||
username: str = ""
|
||||
user_id: int = 0
|
||||
commits: int = 0
|
||||
merge_requests: int = 0
|
||||
comments: int = 0
|
||||
other: int = 0
|
||||
|
||||
@property
|
||||
def total_contributions(self) -> int:
|
||||
return self.commits + self.merge_requests + self.comments + self.other
|
||||
|
||||
|
||||
class Aggregator:
|
||||
def __init__(self):
|
||||
self._stats: dict[int, UserStats] = defaultdict(UserStats)
|
||||
|
||||
def process_events(self, events: list[dict]) -> None:
|
||||
"""
|
||||
Przetwarza listę eventów GitLab i agreguje statystyki.
|
||||
|
||||
Typy akcji:
|
||||
- pushed → commit
|
||||
- merged → merge request
|
||||
- commented → komentarz
|
||||
- created/closed/reopened → inne
|
||||
"""
|
||||
for event in events:
|
||||
author = event.get("author") or {}
|
||||
uid = author.get("id") or event.get("author_id")
|
||||
if not uid:
|
||||
continue
|
||||
|
||||
stats = self._stats[uid]
|
||||
stats.user_id = uid
|
||||
stats.name = author.get("name", stats.name)
|
||||
stats.username = author.get("username", stats.username)
|
||||
|
||||
action = event.get("action_name", "")
|
||||
|
||||
if action == "pushed to" or action == "pushed new":
|
||||
# Liczymy commity z push events
|
||||
push_data = event.get("push_data") or {}
|
||||
commit_count = push_data.get("commit_count", 1)
|
||||
stats.commits += max(commit_count, 1)
|
||||
elif action in ("accepted", "merged"):
|
||||
stats.merge_requests += 1
|
||||
elif action == "commented on":
|
||||
stats.comments += 1
|
||||
else:
|
||||
stats.other += 1
|
||||
|
||||
def get_stats(self) -> list[UserStats]:
|
||||
"""Zwraca listę statystyk posortowaną malejąco po contributions."""
|
||||
return sorted(
|
||||
self._stats.values(),
|
||||
key=lambda s: s.total_contributions,
|
||||
reverse=True,
|
||||
)
|
||||
Reference in New Issue
Block a user