Files
gitea-dashboard/src/gitea_dashboard/collector.py
sylvain 4c66fbe98d feat(v1.2.0): retry API, dernier commit, tri, coloration, export JSON
- client.py: _get_with_retry (max 2 retries, backoff lineaire), get_latest_commit
- collector.py: champ last_commit_date dans RepoData
- display.py: colonne "Dernier commit", _sort_repos (name/issues/release/activity),
  _colorize_milestone_due (rouge/jaune/vert selon echeance)
- cli.py: options --sort/-s et --format/-f (table/json)
- exporter.py: nouveau module, repos_to_dicts + export_json
- 88 tests (35 nouveaux), ruff clean

fixes #8, fixes #7, fixes #10, fixes #9, fixes #6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 03:58:45 +01:00

82 lines
2.6 KiB
Python

"""Collecte et agregation des donnees repos Gitea."""
from __future__ import annotations
from dataclasses import dataclass
from gitea_dashboard.client import GiteaClient
@dataclass
class RepoData:
"""Donnees agregees d'un repo."""
name: str
full_name: str
description: str
open_issues: int # open_issues_count - open_pr_counter
is_fork: bool
is_archived: bool
is_mirror: bool
latest_release: dict | None # {tag_name, published_at} ou None
milestones: list[dict] # [{title, open_issues, closed_issues, due_on}]
last_commit_date: str | None # ISO 8601, ex: "2026-03-10T14:30:00Z"
def _matches_any(name: str, patterns: list[str]) -> bool:
"""Return True if name contains any of the patterns (case-insensitive)."""
name_lower = name.lower()
return any(p.lower() in name_lower for p in patterns)
def collect_all(
client: GiteaClient,
include: list[str] | None = None,
exclude: list[str] | None = None,
) -> list[RepoData]:
"""Collecte les donnees des repos, avec filtrage optionnel.
Args:
client: Client API Gitea.
include: Si fourni, ne garde que les repos dont le nom contient
au moins une des sous-chaines (insensible a la casse).
exclude: Si fourni, exclut les repos dont le nom contient
au moins une des sous-chaines (insensible a la casse).
Ordre d'application : include d'abord (si present), puis exclude.
Si include est None ou vide, tous les repos sont inclus avant l'etape exclude.
"""
repos = client.get_repos()
# Filtrage post-fetch : l'API Gitea ne supporte pas le filtre par nom
if include:
repos = [r for r in repos if _matches_any(r["name"], include)]
if exclude:
repos = [r for r in repos if not _matches_any(r["name"], exclude)]
result: list[RepoData] = []
for repo in repos:
owner = repo["owner"]["login"]
name = repo["name"]
commit = client.get_latest_commit(owner, name)
last_commit_date = commit["created"] if commit else None
result.append(
RepoData(
name=name,
full_name=repo["full_name"],
description=repo.get("description", "") or "",
open_issues=repo["open_issues_count"] - repo["open_pr_counter"],
is_fork=repo["fork"],
is_archived=repo["archived"],
is_mirror=repo["mirror"],
latest_release=client.get_latest_release(owner, name),
milestones=client.get_milestones(owner, name),
last_commit_date=last_commit_date,
)
)
return result