docs(v1.1.0): version plan and ADR — repo filtering feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sylvain
2026-03-11 04:30:07 +01:00
parent 85c3023b34
commit 8e8271be9d
2 changed files with 291 additions and 0 deletions

259
docs/plans/v1.1.0-plan.md Normal file
View File

@@ -0,0 +1,259 @@
<!-- 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 |