# Plan de version v1.0.0 — gitea-dashboard ## Objectif Livrer un dashboard CLI fonctionnel qui affiche en une commande l'etat de tous les repos Gitea : issues ouvertes, derniere release, milestones. Premiere version utilisable. ## Track **Major initial** (v1.0.0, nouveau projet) : 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> (12) -> 13 --- ## Budget de scope | Critere | Valeur | |---------|--------| | Max fichiers par phase | 4 | | Total fichiers estimes | 8 (4 modules + 4 tests) | ### Inclus - Client API Gitea avec auth token et pagination - Collecte des donnees : repos, issues (hors PRs), derniere release, milestones ouvertes - Affichage Rich : tableau repos + section milestones + indicateurs visuels - Point d'entree CLI avec configuration par variables d'environnement - Gestion des cas limites (repos sans release, sans milestone, forks, archives) ### Exclus - Interface web ou GUI - Mode watch / rafraichissement automatique - Filtrage par owner/organisation - Modification de donnees Gitea (lecture seule) - Notifications ou alertes - Framework CLI (argparse, click, typer) ### Differe (v1.1+) - Parallelisation des appels API (ThreadPoolExecutor) - Filtrage/tri des repos (par nom, activite, owner) - Cache des reponses API - Options CLI (--format, --filter, --sort) --- ## Etapes skippees | Etape | Nom | Raison | |-------|-----|--------| | 12 | Deploy | Outil CLI local, pas de deploiement serveur | --- ## Phase 1 : Client API et collecte de donnees **Goal** : Disposer d'un client API Gitea fonctionnel et d'un collecteur qui agrege les donnees de tous les repos. **Issues Gitea** : fixes #1, fixes #2 ### Fichiers | Action | Fichier | Modifications | Cross-references | |--------|---------|---------------|------------------| | Create | `src/gitea_dashboard/client.py` | Client API Gitea : auth, requetes GET, pagination | `collector.py` (consommateur) | | Create | `src/gitea_dashboard/collector.py` | Collecte et agregation des donnees repos | `client.py` (dependance), `display.py` (producteur de donnees) | | Create | `tests/test_client.py` | Tests unitaires du client API avec mocks | `client.py` | | Create | `tests/test_collector.py` | Tests unitaires du collecteur avec mocks | `collector.py` | ### Interfaces #### client.py ```python class GiteaClient: """Client API Gitea en lecture seule.""" def __init__(self, base_url: str, token: str) -> None: """Initialise le client avec l'URL de base et le token API.""" def get_repos(self) -> list[dict]: """Retourne tous les repos de l'utilisateur (pagination automatique). Endpoint: GET /api/v1/user/repos """ def get_latest_release(self, owner: str, repo: str) -> dict | None: """Retourne la derniere release du repo, ou None si aucune. Endpoint: GET /api/v1/repos/{owner}/{repo}/releases/latest Gere HTTP 404 en retournant None. """ def get_milestones(self, owner: str, repo: str) -> list[dict]: """Retourne les milestones ouvertes du repo. Endpoint: GET /api/v1/repos/{owner}/{repo}/milestones?state=open """ ``` Methode privee interne pour la pagination : ```python def _get_paginated(self, endpoint: str, params: dict | None = None) -> list[dict]: """Requete GET avec pagination automatique. Boucle tant que len(page) == limit (50). """ ``` #### collector.py ```python @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}] def collect_all(client: GiteaClient) -> list[RepoData]: """Collecte les donnees de tous les repos. Pour chaque repo : enrichit avec release et milestones. """ ``` ### Comportement attendu 1. `GiteaClient("http://192.168.0.106:3000", "token123")` cree un client 2. `client.get_repos()` retourne la liste complete (pagination transparente si > 50 repos) 3. `client.get_latest_release("admin", "mon-repo")` retourne `{"tag_name": "v1.0", "published_at": "..."}` ou `None` 4. `collect_all(client)` retourne une liste de `RepoData` pour chaque repo, meme ceux sans release ou milestone ### Tests - `test_client.py` : mock de `requests.Session` pour tester auth header, pagination (1 page, 2 pages), 404 sur release - `test_collector.py` : mock de `GiteaClient` pour tester l'agregation, les cas limites (repo sans release, sans milestone, fork, archive) ### Livrable Le client peut interroger l'API Gitea et le collecteur produit une liste de `RepoData` prete pour l'affichage. Les tests passent. --- ## Phase 2 : Affichage Rich et point d'entree CLI **Goal** : Afficher les donnees collectees dans un dashboard terminal lisible et fournir le point d'entree executable. **Issues Gitea** : fixes #3, fixes #4 ### Fichiers | Action | Fichier | Modifications | Cross-references | |--------|---------|---------------|------------------| | Create | `src/gitea_dashboard/display.py` | Formatage et affichage Rich | `collector.py` (consomme `RepoData`) | | Modify | `src/gitea_dashboard/cli.py` | Orchestration : config -> client -> collecte -> affichage | `client.py`, `collector.py`, `display.py` | | Create | `tests/test_display.py` | Tests du formatage (capture console Rich) | `display.py` | | Create | `tests/test_cli.py` | Tests d'integration du point d'entree | `cli.py` | ### Interfaces #### display.py ```python from rich.console import Console def render_dashboard(repos: list[RepoData], console: Console | None = None) -> None: """Affiche le dashboard complet dans le terminal. - Tableau principal : nom repo, indicateurs (fork/archive/mirror), issues ouvertes, derniere release (tag + date relative) - Section milestones : par repo ayant des milestones, nom, progression (closed/total), date echeance Le parametre console permet l'injection pour les tests. """ ``` #### cli.py (modification) ```python import sys import os def main() -> None: """Point d'entree principal. 1. Lit GITEA_URL (defaut: http://192.168.0.106:3000) et GITEA_TOKEN (requis) 2. Cree le GiteaClient 3. Collecte les donnees via collect_all() 4. Affiche via render_dashboard() 5. Gere les erreurs : config manquante, connexion refusee, timeout """ ``` ### Comportement attendu Execution nominale : ``` $ export GITEA_TOKEN=abc123 $ gitea-dashboard Gitea Dashboard ┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓ ┃ Repo ┃ Issues ┃ Release ┃ ┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩ │ mon-projet │ 3 │ v1.2.0 (il y a 2j) │ │ autre-repo [F] │ 0 │ — │ │ archive [A] │ 1 │ v0.1.0 (il y a 6m) │ └──────────────────┴────────┴─────────────────────┘ Milestones mon-projet / v2.0 : 3/5 (60%) — echeance 2026-04-01 ``` Erreur de configuration : ``` $ gitea-dashboard Erreur : GITEA_TOKEN non defini. Exportez la variable d'environnement. ``` ### Tests - `test_display.py` : capture de la sortie Rich via `Console(file=StringIO())`, verification du contenu (noms de repos, indicateurs, gestion des valeurs None) - `test_cli.py` : mock des variables d'environnement, mock du client API, verification des messages d'erreur ### Livrable `gitea-dashboard` est executable, affiche un dashboard lisible, et gere proprement les erreurs. Tous les tests passent. --- ## Phase 3 : Smoke test et documentation **Goal** : Valider le fonctionnement reel sur l'instance Gitea et documenter le projet. **Dependances** : phases 1 et 2 terminees, acces a l'instance Gitea (192.168.0.106:3000) **Composants cles** : - Test E2E manuel sur l'instance reelle - Checklist de validation (repos avec/sans release, avec/sans milestone, forks) - README.md a jour (installation, usage, configuration) - CHANGELOG.md pour la v1.0.0 --- ## Architecture des modules | Module | Responsabilite | Dependances | |--------|---------------|-------------| | `client.py` | Communication API Gitea (auth, requetes, pagination) | `requests` | | `collector.py` | Agregation des donnees de tous les repos | `client.py` | | `display.py` | Formatage et rendu terminal | `rich`, `collector.py` (types) | | `cli.py` | Point d'entree, configuration, orchestration | tous les modules | --- ## Risques d'audit | Zone | Risque | Severite estimee | |------|--------|-----------------| | `client.py` — pagination | Boucle infinie si l'API repond toujours `limit` elements | major | | `client.py` — gestion erreurs | Erreurs HTTP non-404 non gerees (500, timeout, connexion) | major | | `cli.py` — token en clair | Affichage accidentel du token dans les logs/erreurs | critical | | `collector.py` — types | Champs API manquants ou renommes entre versions Gitea | minor | --- ## Issues Gitea rattachees | Issue | Titre | Phase | |-------|-------|-------| | [#1](https://gitea.tsmse.fr/admin/gitea-dashboard/issues/1) | Client API Gitea avec authentification et pagination | Phase 1 | | [#2](https://gitea.tsmse.fr/admin/gitea-dashboard/issues/2) | Collecte des donnees : repos, issues, releases, milestones | Phase 1 | | [#3](https://gitea.tsmse.fr/admin/gitea-dashboard/issues/3) | Affichage dashboard avec Rich (tableaux, couleurs) | Phase 2 | | [#4](https://gitea.tsmse.fr/admin/gitea-dashboard/issues/4) | Point d'entree CLI et configuration | Phase 2 | **Milestone** : [v1.0.0](https://gitea.tsmse.fr/admin/gitea-dashboard/milestone/30) --- ## Dependances | Dependance | Type | Version | |------------|------|---------| | Python | Runtime | >= 3.10 | | requests | Librairie | >= 2.31 | | rich | Librairie | >= 13.0 | | pytest | Dev | >= 7.0 | | ruff | Dev | >= 0.4 | | Instance Gitea | Service externe | 1.25.1 a 192.168.0.106:3000 |