Files
tryton-db-migration/doc/MODELLVERGLEICH.md
T

97 lines
4.3 KiB
Markdown
Raw Normal View History

# Modellbaum-Vergleich (5.0 ↔ 8.0)
Werkzeug für die [Testdaten-Pipeline](TESTDATEN.md): Bevor Testdaten von
Hand ergänzt werden, erstmal statisch (kein laufendes Tryton nötig)
Schwarz auf Weiß sehen, welche Modelle/Felder es in einer Version
überhaupt gibt - damit weder Felder aus 8.0 übernommen werden, die es in
5.0 noch gar nicht gibt (würde beim Anlegen nur Fehler werfen), noch
Aufwand in Modelle gesteckt wird, die sich zwischen den Versionen gar
nicht verändert haben.
## Workflow
### 1. `extract_model_tree.py` – Modellbaum aus dem Quellcode ziehen
Scannt den Python-Code ausgewählter Module per AST (kein Import, keine
laufende Instanz) und baut pro Modell (`__name__`) die Liste aller per
`fields.X(...)` definierten Felder, mit Typ, Relationsziel
(Many2One/One2Many/Many2Many/One2One/Reference) und - falls literal im
Code erkennbar - `required`. Modelle werden über PoolMeta-Erweiterungen
hinweg zusammengeführt: Fügt z. B. `stock_split` eine Klasse mit
`__name__ = 'stock.move'` hinzu, landen deren Felder unter demselben
Modell-Eintrag, mit Vermerk, aus welchem Modul sie stammen.
Pro Modell wird zusätzlich `persisted` erkannt (erbt die Klasse `ModelSQL`
o. ä., oder nur `ModelView` - dann ist es ein reines Wizard-/
Transient-Formular ohne eigene Tabelle).
```bash
python3 extract_model_tree.py --repo /mnt/tryton \
--modules company country currency party product ... \
--output reports/model_tree_5.0.json --report reports/model_tree_5.0.md
```
Für eine zweite Version denselben Befehl gegen einen zweiten Checkout
laufen lassen (z. B. per `git worktree add /tmp/tryton-8.0 8.0`, ohne den
Haupt-Checkout umzuschalten).
### 2. `model_diff.py` – zwei Modellbäume vergleichen
Sortiert jedes Modell in eine von fünf Kategorien:
- **entfernt** – Modell gibt es in Version A, nicht mehr in B
- **geändert** – Feld(er) entfernt oder Typ/Relation/required geändert →
echter Kandidat für einen Vergleichslauf
- **neu** – Modell gibt es erst in B
- **nur ergänzt** – nur neue Felder dazugekommen, Rest unverändert
- **unverändert** – komplett identisch geblieben
```bash
python3 model_diff.py --tree-a reports/model_tree_5.0.json --label-a 5.0 \
--tree-b reports/model_tree_8.0.json --label-b 8.0 \
--output reports/model_diff.json --report reports/model_diff.md
```
### 3. `model_coverage.py` – gegen die aktuelle Testdaten-Abdeckung abgleichen
Vergleicht einen Modellbaum mit einer gemergten `dataset.yaml`
(`reports/<version>_testdata_merged.yaml`, siehe
[TESTDATEN.md](TESTDATEN.md)) und zeigt komplett unabgedeckte Modelle sowie
pro teilweise abgedecktem Modell die ungenutzten Felder (required zuerst).
Drei Kategorien werden aus der Liste unabgedeckter Modelle per Default
herausgefiltert (nie von Hand testdatenrelevant, jeweils per Flag wieder
einschaltbar):
- `ir.*`/`res.*`-Kernmodelle (`--include-framework`)
- Wizard-/Transient-Formulare, `persisted: false` (`--include-transient`)
- automatisch verwaltete Many2Many-Verknüpfungstabellen, erkennbar am
Bindestrich im Namen wie `party.party-party.category`
(`--include-relations`)
Mit `--diff reports/model_diff.json` wird zusätzlich pro Modell die
Diff-Kategorie aus Schritt 2 eingeblendet und die Liste danach sortiert:
`geändert`/`entfernt` zuerst (lohnt sich, dort Testdaten zu ergänzen),
`nur ergänzt`/`unverändert` zuletzt (dort ist über den reinen
Codevergleich hinaus erstmal nichts Auffälliges zu erwarten).
```bash
python3 model_coverage.py --model-tree reports/model_tree_5.0.json \
--dataset reports/5_testdata_merged.yaml --diff reports/model_diff.json \
--report reports/coverage_5.0.md
```
## Bekannte Grenzen
- Rein statische Analyse: Felder, die nicht als einfaches
`name = fields.X(...)` auf Klassenebene stehen (z. B. per Schleife/Helper
dynamisch erzeugt), werden nicht erkannt.
- `persisted`-Erkennung ist eine Textsuche über die Basisklassen-Ausdrücke
(`ModelSQL`/`Workflow`/`DeactivableMixin`) - deckt den Normalfall ab, ist
aber kein echtes Type-Checking.
- Erkennt nur Unterschiede auf Ebene der Feld-**Definition** im Code
(Typ/Relation/required). Laufzeitverhalten wie Constraints, Defaults oder
DB-Spaltenpräzision kann trotzdem abweichen, ohne hier aufzufallen - dafür
bleibt der eigentliche Testlauf über `create_dataset.py`/
`compare_snapshots.py` nötig.