260 lines
9.5 KiB
Markdown
260 lines
9.5 KiB
Markdown
<!-- Type: reference (Diataxis). Style: factuel, structure par phases, actionnable par le builder. -->
|
|
|
|
# Plan de version v1.1.0 — gitea-dashboard
|
|
|
|
## Objectif
|
|
|
|
Permettre a l'utilisateur de filtrer l'affichage du dashboard par nom de repo (inclusion et exclusion), via des options CLI. Premiere evolution fonctionnelle du dashboard.
|
|
|
|
## Track
|
|
|
|
**Minor** : 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> (12) -> 13
|
|
|
|
---
|
|
|
|
## Budget de scope
|
|
|
|
| Critere | Valeur |
|
|
|---------|--------|
|
|
| Max fichiers par phase | 4 |
|
|
| Total fichiers estimes | 6 (3 modules modifies + 3 fichiers de tests modifies) |
|
|
|
|
### Inclus
|
|
|
|
- Option CLI `--repo` / `-r` pour filtrer par nom(s) de repo (inclusion)
|
|
- Option CLI `--exclude` / `-x` pour exclure des repos par nom
|
|
- Filtrage par sous-chaine (match partiel, insensible a la casse)
|
|
- Filtrage applicable aux deux options (cumulable : `--repo X --exclude Y`)
|
|
- Ajout d'argparse pour le parsing des options CLI
|
|
- Tests unitaires du filtrage et tests d'integration CLI
|
|
|
|
### Exclus
|
|
|
|
- Filtrage par owner/organisation (hors scope, pas de demande)
|
|
- Filtrage par regex (sous-chaine suffit pour v1.1.0)
|
|
- Filtrage par labels, activite ou date
|
|
- Tri des resultats (differe)
|
|
- Options `--format`, `--sort` (differees)
|
|
- Parallelisation des appels API (ADR-003, differee)
|
|
|
|
### Differe (v1.2+)
|
|
|
|
- Filtrage par owner/organisation
|
|
- Option `--sort` (par nom, issues, date de release)
|
|
- Cache des reponses API
|
|
- Option `--format` (json, csv)
|
|
|
|
---
|
|
|
|
## Etapes skippees
|
|
|
|
| Etape | Nom | Raison |
|
|
|-------|-----|--------|
|
|
| 1 | Discovery | Projet existant, discovery v1.0.0 suffisante |
|
|
| 2 | Project creation | Projet existant |
|
|
| 3 | Specs | Minor — specs couvertes par l'issue #5 et ce plan |
|
|
| 4 | Research | Pas de technologie nouvelle (argparse est stdlib) |
|
|
| 5 | Roadmap | Minor — roadmap existante, issue #5 deja creee |
|
|
| 12 | Deploy | Outil CLI local, pas de deploiement serveur |
|
|
|
|
---
|
|
|
|
## Phase 1 : Parsing CLI et logique de filtrage
|
|
|
|
**Goal** : Ajouter les options `--repo` et `--exclude` a la CLI et implementer la logique de filtrage dans le collecteur.
|
|
|
|
**Issues Gitea** : fixes #5
|
|
|
|
### Fichiers
|
|
|
|
| Action | Fichier | Modifications | Cross-references |
|
|
|--------|---------|---------------|------------------|
|
|
| Modify | `src/gitea_dashboard/cli.py` | Ajouter argparse, options `--repo`/`-r` et `--exclude`/`-x`, passer les filtres a `collect_all()` | `collector.py` (passe les filtres) |
|
|
| Modify | `src/gitea_dashboard/collector.py` | Ajouter parametres `include` et `exclude` a `collect_all()`, logique de filtrage | `cli.py` (appele avec filtres), `client.py` (inchange) |
|
|
| Modify | `tests/test_cli.py` | Tests argparse, passage des filtres, combinaison d'options | `cli.py` |
|
|
| Modify | `tests/test_collector.py` | Tests du filtrage : inclusion, exclusion, combinaison, casse, sous-chaine | `collector.py` |
|
|
|
|
### Interfaces
|
|
|
|
#### cli.py (modifications)
|
|
|
|
```python
|
|
import argparse
|
|
|
|
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
|
"""Parse les arguments CLI.
|
|
|
|
Options:
|
|
--repo / -r : noms de repos a inclure (repeatable)
|
|
--exclude / -x : noms de repos a exclure (repeatable)
|
|
|
|
Returns:
|
|
Namespace avec .repo (list[str] | None) et .exclude (list[str] | None)
|
|
"""
|
|
|
|
def main(argv: list[str] | None = None) -> None:
|
|
"""Point d'entree principal.
|
|
|
|
Modification : accepte argv pour testabilite.
|
|
Appelle parse_args(), puis passe include/exclude a collect_all().
|
|
"""
|
|
```
|
|
|
|
Pourquoi `parse_args` separe de `main` : testabilite. On peut tester le parsing seul sans mocker l'environnement complet.
|
|
|
|
Pourquoi `argv` en parametre de `main` : permet aux tests d'injecter des arguments sans patcher `sys.argv`.
|
|
|
|
#### collector.py (modifications)
|
|
|
|
```python
|
|
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.
|
|
"""
|
|
```
|
|
|
|
Pourquoi le filtrage est dans `collector.py` et non `cli.py` : le collecteur est responsable de "quels repos collecter". Cela evite de polluer le CLI avec de la logique metier et garde la testabilite (on teste le filtrage sans mocker argparse).
|
|
|
|
Pourquoi le filtrage est post-fetch (apres `get_repos()`) et non pre-fetch : l'API Gitea `/user/repos` ne supporte pas de filtre par nom cote serveur. On doit recuperer tous les repos puis filtrer localement.
|
|
|
|
### Comportement attendu
|
|
|
|
1. Sans options, comportement identique a v1.0.0 :
|
|
```
|
|
$ gitea-dashboard
|
|
# Affiche tous les repos (aucun changement)
|
|
```
|
|
|
|
2. Filtrage par inclusion :
|
|
```
|
|
$ gitea-dashboard --repo dashboard --repo infra
|
|
# Affiche uniquement les repos dont le nom contient "dashboard" ou "infra"
|
|
```
|
|
|
|
3. Filtrage par exclusion :
|
|
```
|
|
$ gitea-dashboard --exclude fork --exclude test
|
|
# Affiche tous les repos sauf ceux dont le nom contient "fork" ou "test"
|
|
```
|
|
|
|
4. Combinaison inclusion + exclusion :
|
|
```
|
|
$ gitea-dashboard --repo projet -x old
|
|
# Inclut les repos contenant "projet", puis exclut ceux contenant "old"
|
|
```
|
|
|
|
5. Insensibilite a la casse :
|
|
```
|
|
$ gitea-dashboard --repo Dashboard
|
|
# Match "gitea-dashboard", "Dashboard-test", etc.
|
|
```
|
|
|
|
6. Aucun repo ne correspond :
|
|
```
|
|
$ gitea-dashboard --repo inexistant
|
|
# Affiche "Aucun repo trouve." (comportement existant de render_dashboard)
|
|
```
|
|
|
|
### Tests
|
|
|
|
#### test_cli.py (ajouts)
|
|
|
|
- `test_parse_args_no_options` : retourne `Namespace(repo=None, exclude=None)`
|
|
- `test_parse_args_single_repo` : `--repo foo` -> `Namespace(repo=["foo"], ...)`
|
|
- `test_parse_args_multiple_repo` : `--repo foo --repo bar` -> `Namespace(repo=["foo", "bar"], ...)`
|
|
- `test_parse_args_short_flags` : `-r foo -x bar` fonctionne comme les formes longues
|
|
- `test_main_passes_filters_to_collect_all` : verifie que `collect_all` est appele avec les bons `include`/`exclude`
|
|
- `test_main_no_filters_passes_none` : sans options, `collect_all(client, include=None, exclude=None)`
|
|
|
|
#### test_collector.py (ajouts)
|
|
|
|
- `test_collect_all_no_filter` : comportement identique a v1.0.0 (retrocompatibilite)
|
|
- `test_collect_all_include_single` : filtre par une sous-chaine
|
|
- `test_collect_all_include_multiple` : filtre par plusieurs sous-chaines (OR)
|
|
- `test_collect_all_exclude_single` : exclut par une sous-chaine
|
|
- `test_collect_all_include_and_exclude` : inclusion puis exclusion
|
|
- `test_collect_all_case_insensitive` : "Dashboard" matche "gitea-dashboard"
|
|
- `test_collect_all_no_match` : retourne une liste vide si aucun repo ne correspond
|
|
- `test_collect_all_exclude_all` : retourne une liste vide si tout est exclu
|
|
|
|
### Livrable
|
|
|
|
La commande `gitea-dashboard --repo X -x Y` filtre l'affichage. Sans options, le comportement est identique a v1.0.0. Tous les tests passent (existants + nouveaux).
|
|
|
|
---
|
|
|
|
## Phase 2 : Smoke test et documentation
|
|
|
|
**Goal** : Valider le filtrage sur l'instance reelle et mettre a jour la documentation.
|
|
|
|
**Dependances** : phase 1 terminee, acces a l'instance Gitea (192.168.0.106:3000)
|
|
|
|
**Composants cles** :
|
|
|
|
- Test E2E manuel : `gitea-dashboard --repo dashboard`, `gitea-dashboard -x fork`, combinaison
|
|
- Verification de la retrocompatibilite : `gitea-dashboard` sans options
|
|
- Mise a jour de README.md (section usage avec les nouvelles options)
|
|
- Mise a jour de CHANGELOG.md (section Added pour v1.1.0)
|
|
- Mise a jour de `--help` (automatique via argparse)
|
|
|
|
---
|
|
|
|
## Architecture des modules (impact)
|
|
|
|
Le changement est minimal et respecte l'architecture existante (ADR-002) :
|
|
|
|
| Module | Impact | Detail |
|
|
|--------|--------|--------|
|
|
| `cli.py` | Modifie | Ajout argparse + passage des filtres |
|
|
| `collector.py` | Modifie | Nouveaux parametres `include`/`exclude` dans `collect_all()` |
|
|
| `client.py` | Inchange | Aucun impact (le filtrage est local, pas API) |
|
|
| `display.py` | Inchange | Recoit toujours `list[RepoData]`, ne sait pas si c'est filtre |
|
|
|
|
Pas de nouveau module. La signature de `collect_all()` est modifiee avec des parametres optionnels : **retrocompatible** (les parametres ont des valeurs par defaut `None`).
|
|
|
|
---
|
|
|
|
## Risques d'audit
|
|
|
|
| Zone | Risque | Severite estimee |
|
|
|------|--------|-----------------|
|
|
| `cli.py` — argparse | Interaction entre `argv` et `sys.argv` : s'assurer que `parse_args(None)` delegue bien a `sys.argv` | minor |
|
|
| `collector.py` — filtrage | Match partiel trop agressif (ex: `--repo a` matche tous les repos contenant "a") | minor |
|
|
| `collector.py` — ordre include/exclude | L'ordre d'application doit etre documente et teste | minor |
|
|
| `cli.py` — retrocompatibilite | Entry point `main()` ne doit pas casser si appele sans arguments | major |
|
|
|
|
---
|
|
|
|
## Issues Gitea rattachees
|
|
|
|
| Issue | Titre | Phase |
|
|
|-------|-------|-------|
|
|
| [#5](https://gitea.tsmse.fr/admin/gitea-dashboard/issues/5) | Ajouter le filtrage par repo | Phase 1 |
|
|
|
|
---
|
|
|
|
## Dependances
|
|
|
|
| Dependance | Type | Version |
|
|
|------------|------|---------|
|
|
| Python | Runtime | >= 3.10 |
|
|
| argparse | Stdlib | inclus dans Python |
|
|
| requests | Librairie | >= 2.31 (inchange) |
|
|
| rich | Librairie | >= 13.0 (inchange) |
|
|
| pytest | Dev | >= 7.0 (inchange) |
|
|
| ruff | Dev | >= 0.4 (inchange) |
|
|
| Instance Gitea | Service externe | 192.168.0.106:3000 |
|