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:
259
docs/plans/v1.1.0-plan.md
Normal file
259
docs/plans/v1.1.0-plan.md
Normal 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 |
|
||||
Reference in New Issue
Block a user