Merge branch 'develop'
- fix todo for server without tk - split claude.md into rules - integrate rtk for optimisation agent IA - todo to add command for claude - todo i18n use english key - more space when print command into execute.py - todo integrate deploy local clone - script format
This commit is contained in:
commit
b1eeeb6053
22 changed files with 1387 additions and 785 deletions
14
.claude/rules/01-versions.md
Normal file
14
.claude/rules/01-versions.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Versions supportées
|
||||||
|
|
||||||
|
| Odoo | Python | Poetry | Statut |
|
||||||
|
|-------|----------|--------|------------|
|
||||||
|
| 18.0 | 3.12.10 | 2.1.3 | **Défaut** |
|
||||||
|
| 17.0 | 3.10.18 | 1.8.3 | Actif |
|
||||||
|
| 16.0 | 3.10.18 | 1.8.3 | Actif |
|
||||||
|
| 15.0 | 3.8.20 | 1.8.3 | Déprécié |
|
||||||
|
| 14.0 | 3.8.20 | 1.5.0 | Déprécié |
|
||||||
|
| 13.0 | 3.7.17 | 1.5.0 | Déprécié |
|
||||||
|
| 12.0 | 3.7.17 | 1.5.0 | Déprécié |
|
||||||
|
|
||||||
|
Configuration dans `conf/supported_version_erplibre.json`.
|
||||||
|
Fichiers de version : `.odoo-version`, `.erplibre-version`, `.poetry-version`, `.python-odoo-version`.
|
||||||
45
.claude/rules/02-project-structure.md
Normal file
45
.claude/rules/02-project-structure.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Structure du projet
|
||||||
|
|
||||||
|
```
|
||||||
|
erplibre/
|
||||||
|
├── Makefile # Orchestrateur principal (inclut conf/make.*.Makefile)
|
||||||
|
├── run.sh / odoo_bin.sh # Lanceurs Odoo (venv + PYTHONPATH)
|
||||||
|
├── env_var.sh # Variables d'environnement globales
|
||||||
|
├── conf/ # Configuration : Makefiles modulaires, versions, manifests CSV
|
||||||
|
│ ├── make.installation.Makefile
|
||||||
|
│ ├── make.test.Makefile
|
||||||
|
│ ├── make.database.Makefile
|
||||||
|
│ ├── make.docker.Makefile
|
||||||
|
│ ├── make.code_generator.Makefile
|
||||||
|
│ ├── make.installation.poetry.Makefile
|
||||||
|
│ └── supported_version_erplibre.json
|
||||||
|
├── manifest/ # Manifests Google Repo (XML) par version Odoo
|
||||||
|
│ └── git_manifest_odoo{12..18}.0.xml
|
||||||
|
├── requirement/ # Dépendances par version
|
||||||
|
│ ├── pyproject.odooXX.0_pythonY.Z.toml
|
||||||
|
│ ├── poetry.odooXX.0_pythonY.Z.lock
|
||||||
|
│ └── requirements.odooXX.0_pythonY.Z.txt
|
||||||
|
├── script/ # Scripts utilitaires (32+ catégories)
|
||||||
|
│ ├── todo/ # CLI interactif principal (todo.py)
|
||||||
|
│ ├── database/ # Opérations DB (restore, migrate, image_db)
|
||||||
|
│ ├── addons/ # Gestion des modules (install, update, uninstall)
|
||||||
|
│ ├── code_generator/ # Génération de modules Odoo
|
||||||
|
│ ├── version/ # Changement de version
|
||||||
|
│ ├── git/ # Opérations Git et Google Repo
|
||||||
|
│ ├── maintenance/ # Formatage (black, isort, prettier)
|
||||||
|
│ ├── test/ # Tests parallèles + coverage
|
||||||
|
│ ├── docker/ # Build/run Docker
|
||||||
|
│ ├── poetry/ # Gestion Poetry
|
||||||
|
│ ├── deployment/ # Déploiement production
|
||||||
|
│ └── selenium/ # Tests web automatisés
|
||||||
|
├── docker/ # Dockerfiles + docker-compose par version
|
||||||
|
├── addons/ # Répertoire des addons (géré par Google Repo)
|
||||||
|
│ ├── OCA_*/ # Modules OCA
|
||||||
|
│ ├── ERPLibre_*/ # Modules ERPLibre
|
||||||
|
│ ├── TechnoLibre_*/ # Code generator + templates
|
||||||
|
│ └── MathBenTech_*/ # Modules spécialisés
|
||||||
|
├── odoo{12..18}.0/ # Sources Odoo par version
|
||||||
|
├── doc/ # Documentation (DEVELOPMENT, PRODUCTION, MIGRATION, etc.)
|
||||||
|
├── test/ # Framework de test
|
||||||
|
└── private/ # Fichiers privés (non versionné)
|
||||||
|
```
|
||||||
63
.claude/rules/03-commands.md
Normal file
63
.claude/rules/03-commands.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Commandes essentielles
|
||||||
|
|
||||||
|
## Changement de version Odoo
|
||||||
|
```bash
|
||||||
|
make switch_odoo_18 # Passer à Odoo 18
|
||||||
|
make switch_odoo_17 # Passer à Odoo 17
|
||||||
|
make switch_odoo_16 # Passer à Odoo 16 (défaut)
|
||||||
|
make switch_odoo_15 # Passer à Odoo 15
|
||||||
|
make switch_odoo_14 # Passer à Odoo 14
|
||||||
|
make switch_odoo_13 # Passer à Odoo 13
|
||||||
|
make switch_odoo_12 # Passer à Odoo 12
|
||||||
|
make switch_odoo_16_update # Passer + mettre à jour les dépendances
|
||||||
|
```
|
||||||
|
|
||||||
|
## Exécution
|
||||||
|
```bash
|
||||||
|
make run # Lancer Odoo (port 8069)
|
||||||
|
make run_test # Lancer avec la DB "test"
|
||||||
|
./run.sh -d ma_base # Lancer avec une DB spécifique
|
||||||
|
./odoo_bin.sh [args] # Exécuter odoo-bin directement
|
||||||
|
```
|
||||||
|
|
||||||
|
## Base de données
|
||||||
|
```bash
|
||||||
|
make db_create_db_test # Créer la DB "test"
|
||||||
|
make db_clone_test_to_test2 # Cloner test -> test2
|
||||||
|
./script/database/db_restore.py --database NOM --image IMAGE
|
||||||
|
./script/addons/install_addons_dev.sh DB module1,module2
|
||||||
|
./script/addons/update_addons_all.sh DB
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
```bash
|
||||||
|
make test # Tests de base + format
|
||||||
|
make test_full_fast # Tests complets en parallèle
|
||||||
|
make test_full_fast_coverage # Avec couverture de code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Formatage du code
|
||||||
|
```bash
|
||||||
|
make format # Fichiers à commiter uniquement
|
||||||
|
make format_all # Tout formater (parallèle)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
```bash
|
||||||
|
make docker_run_daemon # Lancer en production
|
||||||
|
make docker_build_odoo_18 # Builder l'image Odoo 18
|
||||||
|
```
|
||||||
|
|
||||||
|
## Google Repo (gestion multi-dépôts)
|
||||||
|
```bash
|
||||||
|
make repo_show_status # Statut de tous les dépôts addons
|
||||||
|
make repo_configure_all # Configurer tous les dépôts
|
||||||
|
make repo_do_stash # Stash tous les dépôts
|
||||||
|
.venv.erplibre/bin/repo sync # Synchroniser les dépôts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```bash
|
||||||
|
make install_os # Dépendances système
|
||||||
|
make install_odoo_18 # Installer Odoo 18 complet
|
||||||
|
```
|
||||||
24
.claude/rules/04-code-conventions.md
Normal file
24
.claude/rules/04-code-conventions.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Conventions de code
|
||||||
|
|
||||||
|
## Python
|
||||||
|
- Formateur : **Black** (profil par défaut, ligne max 79 pour les modules Odoo)
|
||||||
|
- Imports : **isort** avec profil `black`, longueur de ligne 79
|
||||||
|
- Linting : **Flake8** avec bugbear, max-line-length 80, max-complexity 16
|
||||||
|
- Ignorer : E203, E501, W503 (compatibilité Black)
|
||||||
|
|
||||||
|
## XML / JSON / YAML
|
||||||
|
- Formateur : **Prettier** (via npm)
|
||||||
|
- Indentation : 4 espaces (XML/CSS/JS), 2 espaces (JSON/YAML)
|
||||||
|
|
||||||
|
## Fichiers
|
||||||
|
- Encodage : UTF-8
|
||||||
|
- Fins de ligne : LF (Unix)
|
||||||
|
- Indentation : 4 espaces (Python, XML, CSS, JS), 2 espaces (JSON, YAML, RST, MD)
|
||||||
|
- Retour à la ligne final : oui
|
||||||
|
- Espaces en fin de ligne : supprimés
|
||||||
|
|
||||||
|
## Git
|
||||||
|
- Branches : `develop` (développement), `master` (production)
|
||||||
|
- Pas de submodules Git — utilise **Google Repo** pour les addons
|
||||||
|
- Manifests XML dans `manifest/` pour chaque version Odoo
|
||||||
|
- Format de commit : `[TYPE] description` (ex: `[FIX]`, `[UPD]`, `[ADD]`, `[REM]`)
|
||||||
22
.claude/rules/05-environments.md
Normal file
22
.claude/rules/05-environments.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Architecture des environnements virtuels
|
||||||
|
|
||||||
|
```
|
||||||
|
.venv.erplibre/ # Venv ERPLibre (outils : repo, poetry, coverage)
|
||||||
|
.venv.odoo18/ # Venv Odoo 18 (Python 3.12)
|
||||||
|
.venv.odoo17/ # Venv Odoo 17 (Python 3.10)
|
||||||
|
.venv.odoo16/ # Venv Odoo 16 (Python 3.10)
|
||||||
|
.venv.odoo14/ # Venv Odoo 14 (Python 3.8)
|
||||||
|
.venv.odoo12/ # Venv Odoo 12 (Python 3.7)
|
||||||
|
```
|
||||||
|
|
||||||
|
Géré via **pyenv** pour les multiples versions de Python.
|
||||||
|
|
||||||
|
## Système de dépendances
|
||||||
|
|
||||||
|
Chaque version Odoo a son propre ensemble dans `requirement/` :
|
||||||
|
- `pyproject.odooXX.0_pythonY.Z.toml` — Configuration Poetry
|
||||||
|
- `poetry.odooXX.0_pythonY.Z.lock` — Lock file Poetry
|
||||||
|
- `requirements.odooXX.0_pythonY.Z.txt` — Requirements pip (fallback)
|
||||||
|
- `ignore_requirements.odooXX.0.txt` — Paquets à ignorer
|
||||||
|
|
||||||
|
Mise à jour : `./script/poetry/poetry_update.py`
|
||||||
9
.claude/rules/06-code-generator.md
Normal file
9
.claude/rules/06-code-generator.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Code Generator
|
||||||
|
|
||||||
|
ERPLibre inclut un système de génération de modules Odoo :
|
||||||
|
- `script/code_generator/new_project.py` — Créer un nouveau module
|
||||||
|
- `script/code_generator/create_from_existing_module.py` — Cloner un module existant
|
||||||
|
- `addons/TechnoLibre_odoo-code-generator/` — Moteur de génération
|
||||||
|
- `addons/TechnoLibre_odoo-code-generator-template/` — Templates
|
||||||
|
|
||||||
|
Documentation : `doc/CODE_GENERATOR.md`
|
||||||
55
.claude/rules/07-documentation.md
Normal file
55
.claude/rules/07-documentation.md
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Documentation multilingue
|
||||||
|
|
||||||
|
La documentation est bilingue (anglais/français) via **mmg** (Multilingual Markdown Generator).
|
||||||
|
|
||||||
|
## Fonctionnement
|
||||||
|
- Les fichiers sources sont les `.base.md` (contiennent les deux langues)
|
||||||
|
- `mmg` génère : `FICHIER.md` (anglais) et `FICHIER.fr.md` (français)
|
||||||
|
- Marqueurs : `<!-- [en] -->`, `<!-- [fr] -->`, `<!-- [common] -->` (blocs de code partagés)
|
||||||
|
|
||||||
|
## Commandes
|
||||||
|
```bash
|
||||||
|
make doc_markdown # Regénérer toute la doc multilingue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convention
|
||||||
|
- **Ne jamais modifier directement** les fichiers `.md` ou `.fr.md` générés
|
||||||
|
- Toujours modifier le fichier `.base.md` correspondant, puis exécuter `make doc_markdown`
|
||||||
|
- Les blocs de code vont dans `<!-- [common] -->`, le texte dans `<!-- [en] -->` et `<!-- [fr] -->`
|
||||||
|
- En-tête obligatoire dans chaque `.base.md` :
|
||||||
|
```
|
||||||
|
<!---------------------------->
|
||||||
|
<!-- multilingual suffix: en, fr -->
|
||||||
|
<!-- no suffix: en -->
|
||||||
|
<!---------------------------->
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers concernés (30 fichiers)
|
||||||
|
- Racine : `README`, `CHANGELOG`, `TODO`
|
||||||
|
- `doc/` : DEVELOPMENT, PRODUCTION, DISCOVER, RUN, MIGRATION, WINDOWS_INSTALLATION, FAQ, GIT_REPO, POETRY, RELEASE, UPDATE, CONTRIBUTION, HOWTO, TODO, CODE_GENERATOR
|
||||||
|
- `docker/` : README
|
||||||
|
- `script/*/` : database, deployment, fork_github_repo, nginx, restful, selenium (2), todo, odoo/migration
|
||||||
|
- `.github/ISSUE_TEMPLATE/` : bug_report, feature_request
|
||||||
|
|
||||||
|
## Internationalisation du CLI TODO (i18n)
|
||||||
|
|
||||||
|
Le CLI interactif `script/todo/todo.py` supporte le français et l'anglais.
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
- **`script/todo/todo_i18n.py`** — Module de traduction (dictionnaire `TRANSLATIONS`, fonctions `t()`, `get_lang()`, `set_lang()`)
|
||||||
|
- Les chaînes traduisibles utilisent `t("clé")` au lieu de texte en dur
|
||||||
|
- Les entrées de `todo.json` peuvent avoir un champ `prompt_description_key` résolu via `t()` (fallback sur `prompt_description`)
|
||||||
|
|
||||||
|
### Résolution de la langue (priorité)
|
||||||
|
1. Variable d'environnement `EL_LANG` (définie dans `env_var.sh`, défaut `"fr"`)
|
||||||
|
2. Défaut : `"fr"`
|
||||||
|
|
||||||
|
### Comportement
|
||||||
|
- Première exécution : prompt bilingue demande à l'utilisateur de choisir sa langue
|
||||||
|
- Le choix est persisté dans `env_var.sh`
|
||||||
|
- Changement de langue possible via le menu Execute > Langue/Language
|
||||||
|
|
||||||
|
### Ajouter une traduction
|
||||||
|
1. Ajouter la clé dans `TRANSLATIONS` de `todo_i18n.py` avec les valeurs `"fr"` et `"en"`
|
||||||
|
2. Remplacer la chaîne en dur par `t("ma_clé")` dans `todo.py`
|
||||||
|
3. Pour les entrées JSON : ajouter `"prompt_description_key": "ma_clé"` dans `todo.json`
|
||||||
9
.claude/rules/08-deployment.md
Normal file
9
.claude/rules/08-deployment.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Déploiement
|
||||||
|
|
||||||
|
- **Docker** : `docker-compose.yml` (PostgreSQL 18 + PostGIS 3.6)
|
||||||
|
- **Systemd** : `script/systemd/` pour les services
|
||||||
|
- **Nginx** : `script/nginx/` pour le reverse proxy
|
||||||
|
- **SSL** : Certbot pour les certificats
|
||||||
|
- **DNS** : `script/deployment/update_dns_cloudflare.py`
|
||||||
|
|
||||||
|
Plateformes supportées : Ubuntu 20.04-25.04, Linux Mint 22.3, Debian 12, Arch Linux, macOS (pyenv), Windows (WSL/Docker).
|
||||||
49
.claude/rules/09-workflow.md
Normal file
49
.claude/rules/09-workflow.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Workflow Orchestration
|
||||||
|
|
||||||
|
## 1. Plan Mode Default
|
||||||
|
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
|
||||||
|
- If something goes sideways, STOP and re-plan immediately
|
||||||
|
- Don't keep pushing.
|
||||||
|
- Use plan mode for verification steps, not just building
|
||||||
|
- Write detailed specs upfront to reduce ambiguity
|
||||||
|
|
||||||
|
## 2. Subagent Strategy
|
||||||
|
- Use subagents liberally to keep the main context window clean.
|
||||||
|
- Offload research, exploration, and parallel analysis to subagents
|
||||||
|
- For complex problems, throw more compute at it via subagents
|
||||||
|
- One task per subagent for focused execution
|
||||||
|
|
||||||
|
## 3. Self-Improvement Loop
|
||||||
|
- Capture Lessons: Update AGENT.md with any change in approach the user has asked you to make.
|
||||||
|
- Write rules for yourself that prevent the same mistake
|
||||||
|
- Ruthlessly iterate on these lessons until the mistake rate drops.
|
||||||
|
- Review lessons at session start for relevant project
|
||||||
|
|
||||||
|
## 4. Verification Before Done
|
||||||
|
- Never mark a task complete without proving it works
|
||||||
|
- Diff behavior between main and your changes when relevant
|
||||||
|
- Ask yourself, "Would a staff engineer approve this?"
|
||||||
|
- Run tests, check logs, and demonstrate correctness.
|
||||||
|
|
||||||
|
## 5. Demand Elegance (Balanced)
|
||||||
|
- For non-trivial changes, pause and ask, "Is there a more elegant way?"
|
||||||
|
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
|
||||||
|
- Skip this for simple, obvious fixes
|
||||||
|
- Don't over-engineer.
|
||||||
|
- Challenge your own work before presenting it
|
||||||
|
|
||||||
|
## 6. Autonomous Bug Fixing
|
||||||
|
- When given a bug report, just fix it. Don't ask for hand-holding
|
||||||
|
- Point at logs, errors, and failing tests.
|
||||||
|
- Then resolve them.
|
||||||
|
- Zero context switching required from the user
|
||||||
|
- Go fix failing CI tests without being told how
|
||||||
|
|
||||||
|
## Task Management
|
||||||
|
|
||||||
|
1. **Plan First**: Write a plan to `tasks/todo.md` with checkable items.
|
||||||
|
2. **Verify Plan**: Check in before starting implementation.
|
||||||
|
3. **Track Progress**: Mark items complete as you go.
|
||||||
|
4. **Explain Changes**: High-level summary at each step.
|
||||||
|
5. **Document Results**: Add review section to `tasks/todo.md`
|
||||||
|
6. **Capture Lessons**: Update `tasks/lessons.md` after corrections
|
||||||
316
CLAUDE.md
316
CLAUDE.md
|
|
@ -6,256 +6,6 @@ ERPLibre est un fork communautaire d'Odoo Community Edition (OCE) supportant les
|
||||||
Version actuelle : **1.6.0** | Licence : **AGPL-3.0+**
|
Version actuelle : **1.6.0** | Licence : **AGPL-3.0+**
|
||||||
Version Odoo par défaut : **18.0** (support officiel ERPLibre 1.6.0)
|
Version Odoo par défaut : **18.0** (support officiel ERPLibre 1.6.0)
|
||||||
|
|
||||||
## Versions supportées
|
|
||||||
|
|
||||||
| Odoo | Python | Poetry | Statut |
|
|
||||||
|-------|----------|--------|------------|
|
|
||||||
| 18.0 | 3.12.10 | 2.1.3 | **Défaut** |
|
|
||||||
| 17.0 | 3.10.18 | 1.8.3 | Actif |
|
|
||||||
| 16.0 | 3.10.18 | 1.8.3 | Actif |
|
|
||||||
| 15.0 | 3.8.20 | 1.8.3 | Déprécié |
|
|
||||||
| 14.0 | 3.8.20 | 1.5.0 | Déprécié |
|
|
||||||
| 13.0 | 3.7.17 | 1.5.0 | Déprécié |
|
|
||||||
| 12.0 | 3.7.17 | 1.5.0 | Déprécié |
|
|
||||||
|
|
||||||
Configuration dans `conf/supported_version_erplibre.json`.
|
|
||||||
Fichiers de version : `.odoo-version`, `.erplibre-version`, `.poetry-version`, `.python-odoo-version`.
|
|
||||||
|
|
||||||
## Structure du projet
|
|
||||||
|
|
||||||
```
|
|
||||||
erplibre/
|
|
||||||
├── Makefile # Orchestrateur principal (inclut conf/make.*.Makefile)
|
|
||||||
├── run.sh / odoo_bin.sh # Lanceurs Odoo (venv + PYTHONPATH)
|
|
||||||
├── env_var.sh # Variables d'environnement globales
|
|
||||||
├── conf/ # Configuration : Makefiles modulaires, versions, manifests CSV
|
|
||||||
│ ├── make.installation.Makefile
|
|
||||||
│ ├── make.test.Makefile
|
|
||||||
│ ├── make.database.Makefile
|
|
||||||
│ ├── make.docker.Makefile
|
|
||||||
│ ├── make.code_generator.Makefile
|
|
||||||
│ ├── make.installation.poetry.Makefile
|
|
||||||
│ └── supported_version_erplibre.json
|
|
||||||
├── manifest/ # Manifests Google Repo (XML) par version Odoo
|
|
||||||
│ └── git_manifest_odoo{12..18}.0.xml
|
|
||||||
├── requirement/ # Dépendances par version
|
|
||||||
│ ├── pyproject.odooXX.0_pythonY.Z.toml
|
|
||||||
│ ├── poetry.odooXX.0_pythonY.Z.lock
|
|
||||||
│ └── requirements.odooXX.0_pythonY.Z.txt
|
|
||||||
├── script/ # Scripts utilitaires (32+ catégories)
|
|
||||||
│ ├── todo/ # CLI interactif principal (todo.py)
|
|
||||||
│ ├── database/ # Opérations DB (restore, migrate, image_db)
|
|
||||||
│ ├── addons/ # Gestion des modules (install, update, uninstall)
|
|
||||||
│ ├── code_generator/ # Génération de modules Odoo
|
|
||||||
│ ├── version/ # Changement de version
|
|
||||||
│ ├── git/ # Opérations Git et Google Repo
|
|
||||||
│ ├── maintenance/ # Formatage (black, isort, prettier)
|
|
||||||
│ ├── test/ # Tests parallèles + coverage
|
|
||||||
│ ├── docker/ # Build/run Docker
|
|
||||||
│ ├── poetry/ # Gestion Poetry
|
|
||||||
│ ├── deployment/ # Déploiement production
|
|
||||||
│ └── selenium/ # Tests web automatisés
|
|
||||||
├── docker/ # Dockerfiles + docker-compose par version
|
|
||||||
├── addons/ # Répertoire des addons (géré par Google Repo)
|
|
||||||
│ ├── OCA_*/ # Modules OCA
|
|
||||||
│ ├── ERPLibre_*/ # Modules ERPLibre
|
|
||||||
│ ├── TechnoLibre_*/ # Code generator + templates
|
|
||||||
│ └── MathBenTech_*/ # Modules spécialisés
|
|
||||||
├── odoo{12..18}.0/ # Sources Odoo par version
|
|
||||||
├── doc/ # Documentation (DEVELOPMENT, PRODUCTION, MIGRATION, etc.)
|
|
||||||
├── test/ # Framework de test
|
|
||||||
└── private/ # Fichiers privés (non versionné)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commandes essentielles
|
|
||||||
|
|
||||||
### Changement de version Odoo
|
|
||||||
```bash
|
|
||||||
make switch_odoo_18 # Passer à Odoo 18
|
|
||||||
make switch_odoo_17 # Passer à Odoo 17
|
|
||||||
make switch_odoo_16 # Passer à Odoo 16 (défaut)
|
|
||||||
make switch_odoo_15 # Passer à Odoo 15
|
|
||||||
make switch_odoo_14 # Passer à Odoo 14
|
|
||||||
make switch_odoo_13 # Passer à Odoo 13
|
|
||||||
make switch_odoo_12 # Passer à Odoo 12
|
|
||||||
make switch_odoo_16_update # Passer + mettre à jour les dépendances
|
|
||||||
```
|
|
||||||
|
|
||||||
### Exécution
|
|
||||||
```bash
|
|
||||||
make run # Lancer Odoo (port 8069)
|
|
||||||
make run_test # Lancer avec la DB "test"
|
|
||||||
./run.sh -d ma_base # Lancer avec une DB spécifique
|
|
||||||
./odoo_bin.sh [args] # Exécuter odoo-bin directement
|
|
||||||
```
|
|
||||||
|
|
||||||
### Base de données
|
|
||||||
```bash
|
|
||||||
make db_create_db_test # Créer la DB "test"
|
|
||||||
make db_clone_test_to_test2 # Cloner test -> test2
|
|
||||||
./script/database/db_restore.py --database NOM --image IMAGE
|
|
||||||
./script/addons/install_addons_dev.sh DB module1,module2
|
|
||||||
./script/addons/update_addons_all.sh DB
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
```bash
|
|
||||||
make test # Tests de base + format
|
|
||||||
make test_full_fast # Tests complets en parallèle
|
|
||||||
make test_full_fast_coverage # Avec couverture de code
|
|
||||||
```
|
|
||||||
|
|
||||||
### Formatage du code
|
|
||||||
```bash
|
|
||||||
make format # Fichiers à commiter uniquement
|
|
||||||
make format_all # Tout formater (parallèle)
|
|
||||||
```
|
|
||||||
|
|
||||||
Outils : **Black** (Python, ligne max 79), **isort** (profil black, ligne max 79), **Prettier** (XML/JSON), **Flake8** (ligne max 80, complexité max 16).
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
```bash
|
|
||||||
make docker_run_daemon # Lancer en production
|
|
||||||
make docker_build_odoo_18 # Builder l'image Odoo 18
|
|
||||||
```
|
|
||||||
|
|
||||||
### Google Repo (gestion multi-dépôts)
|
|
||||||
```bash
|
|
||||||
make repo_show_status # Statut de tous les dépôts addons
|
|
||||||
make repo_configure_all # Configurer tous les dépôts
|
|
||||||
make repo_do_stash # Stash tous les dépôts
|
|
||||||
.venv.erplibre/bin/repo sync # Synchroniser les dépôts
|
|
||||||
```
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
```bash
|
|
||||||
make install_os # Dépendances système
|
|
||||||
make install_odoo_18 # Installer Odoo 18 complet
|
|
||||||
```
|
|
||||||
|
|
||||||
## Conventions de code
|
|
||||||
|
|
||||||
### Python
|
|
||||||
- Formateur : **Black** (profil par défaut, ligne max 79 pour les modules Odoo)
|
|
||||||
- Imports : **isort** avec profil `black`, longueur de ligne 79
|
|
||||||
- Linting : **Flake8** avec bugbear, max-line-length 80, max-complexity 16
|
|
||||||
- Ignorer : E203, E501, W503 (compatibilité Black)
|
|
||||||
|
|
||||||
### XML / JSON / YAML
|
|
||||||
- Formateur : **Prettier** (via npm)
|
|
||||||
- Indentation : 4 espaces (XML/CSS/JS), 2 espaces (JSON/YAML)
|
|
||||||
|
|
||||||
### Fichiers
|
|
||||||
- Encodage : UTF-8
|
|
||||||
- Fins de ligne : LF (Unix)
|
|
||||||
- Indentation : 4 espaces (Python, XML, CSS, JS), 2 espaces (JSON, YAML, RST, MD)
|
|
||||||
- Retour à la ligne final : oui
|
|
||||||
- Espaces en fin de ligne : supprimés
|
|
||||||
|
|
||||||
### Git
|
|
||||||
- Branches : `develop` (développement), `master` (production)
|
|
||||||
- Pas de submodules Git — utilise **Google Repo** pour les addons
|
|
||||||
- Manifests XML dans `manifest/` pour chaque version Odoo
|
|
||||||
|
|
||||||
## Architecture des environnements virtuels
|
|
||||||
|
|
||||||
```
|
|
||||||
.venv.erplibre/ # Venv ERPLibre (outils : repo, poetry, coverage)
|
|
||||||
.venv.odoo18/ # Venv Odoo 18 (Python 3.12)
|
|
||||||
.venv.odoo17/ # Venv Odoo 17 (Python 3.10)
|
|
||||||
.venv.odoo16/ # Venv Odoo 16 (Python 3.10)
|
|
||||||
.venv.odoo14/ # Venv Odoo 14 (Python 3.8)
|
|
||||||
.venv.odoo12/ # Venv Odoo 12 (Python 3.7)
|
|
||||||
```
|
|
||||||
|
|
||||||
Géré via **pyenv** pour les multiples versions de Python.
|
|
||||||
|
|
||||||
## Système de dépendances
|
|
||||||
|
|
||||||
Chaque version Odoo a son propre ensemble dans `requirement/` :
|
|
||||||
- `pyproject.odooXX.0_pythonY.Z.toml` — Configuration Poetry
|
|
||||||
- `poetry.odooXX.0_pythonY.Z.lock` — Lock file Poetry
|
|
||||||
- `requirements.odooXX.0_pythonY.Z.txt` — Requirements pip (fallback)
|
|
||||||
- `ignore_requirements.odooXX.0.txt` — Paquets à ignorer
|
|
||||||
|
|
||||||
Mise à jour : `./script/poetry/poetry_update.py`
|
|
||||||
|
|
||||||
## Code Generator
|
|
||||||
|
|
||||||
ERPLibre inclut un système de génération de modules Odoo :
|
|
||||||
- `script/code_generator/new_project.py` — Créer un nouveau module
|
|
||||||
- `script/code_generator/create_from_existing_module.py` — Cloner un module existant
|
|
||||||
- `addons/TechnoLibre_odoo-code-generator/` — Moteur de génération
|
|
||||||
- `addons/TechnoLibre_odoo-code-generator-template/` — Templates
|
|
||||||
|
|
||||||
Documentation : `doc/CODE_GENERATOR.md`
|
|
||||||
|
|
||||||
## Documentation multilingue
|
|
||||||
|
|
||||||
La documentation est bilingue (anglais/français) via **mmg** (Multilingual Markdown Generator).
|
|
||||||
|
|
||||||
### Fonctionnement
|
|
||||||
- Les fichiers sources sont les `.base.md` (contiennent les deux langues)
|
|
||||||
- `mmg` génère : `FICHIER.md` (anglais) et `FICHIER.fr.md` (français)
|
|
||||||
- Marqueurs : `<!-- [en] -->`, `<!-- [fr] -->`, `<!-- [common] -->` (blocs de code partagés)
|
|
||||||
|
|
||||||
### Commandes
|
|
||||||
```bash
|
|
||||||
make doc_markdown # Regénérer toute la doc multilingue
|
|
||||||
```
|
|
||||||
|
|
||||||
### Convention
|
|
||||||
- **Ne jamais modifier directement** les fichiers `.md` ou `.fr.md` générés
|
|
||||||
- Toujours modifier le fichier `.base.md` correspondant, puis exécuter `make doc_markdown`
|
|
||||||
- Les blocs de code vont dans `<!-- [common] -->`, le texte dans `<!-- [en] -->` et `<!-- [fr] -->`
|
|
||||||
- En-tête obligatoire dans chaque `.base.md` :
|
|
||||||
```
|
|
||||||
<!---------------------------->
|
|
||||||
<!-- multilingual suffix: en, fr -->
|
|
||||||
<!-- no suffix: en -->
|
|
||||||
<!---------------------------->
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fichiers concernés (30 fichiers)
|
|
||||||
- Racine : `README`, `CHANGELOG`, `TODO`
|
|
||||||
- `doc/` : DEVELOPMENT, PRODUCTION, DISCOVER, RUN, MIGRATION, WINDOWS_INSTALLATION, FAQ, GIT_REPO, POETRY, RELEASE, UPDATE, CONTRIBUTION, HOWTO, TODO, CODE_GENERATOR
|
|
||||||
- `docker/` : README
|
|
||||||
- `script/*/` : database, deployment, fork_github_repo, nginx, restful, selenium (2), todo, odoo/migration
|
|
||||||
- `.github/ISSUE_TEMPLATE/` : bug_report, feature_request
|
|
||||||
|
|
||||||
## Internationalisation du CLI TODO (i18n)
|
|
||||||
|
|
||||||
Le CLI interactif `script/todo/todo.py` supporte le français et l'anglais.
|
|
||||||
|
|
||||||
### Architecture
|
|
||||||
- **`script/todo/todo_i18n.py`** — Module de traduction (dictionnaire `TRANSLATIONS`, fonctions `t()`, `get_lang()`, `set_lang()`)
|
|
||||||
- Les chaînes traduisibles utilisent `t("clé")` au lieu de texte en dur
|
|
||||||
- Les entrées de `todo.json` peuvent avoir un champ `prompt_description_key` résolu via `t()` (fallback sur `prompt_description`)
|
|
||||||
|
|
||||||
### Résolution de la langue (priorité)
|
|
||||||
1. Variable d'environnement `EL_LANG` (définie dans `env_var.sh`, défaut `"fr"`)
|
|
||||||
2. Défaut : `"fr"`
|
|
||||||
|
|
||||||
### Comportement
|
|
||||||
- Première exécution : prompt bilingue demande à l'utilisateur de choisir sa langue
|
|
||||||
- Le choix est persisté dans `env_var.sh`
|
|
||||||
- Changement de langue possible via le menu Execute > Langue/Language
|
|
||||||
|
|
||||||
### Ajouter une traduction
|
|
||||||
1. Ajouter la clé dans `TRANSLATIONS` de `todo_i18n.py` avec les valeurs `"fr"` et `"en"`
|
|
||||||
2. Remplacer la chaîne en dur par `t("ma_clé")` dans `todo.py`
|
|
||||||
3. Pour les entrées JSON : ajouter `"prompt_description_key": "ma_clé"` dans `todo.json`
|
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
|
|
||||||
- **Docker** : `docker-compose.yml` (PostgreSQL 18 + PostGIS 3.6)
|
|
||||||
- **Systemd** : `script/systemd/` pour les services
|
|
||||||
- **Nginx** : `script/nginx/` pour le reverse proxy
|
|
||||||
- **SSL** : Certbot pour les certificats
|
|
||||||
- **DNS** : `script/deployment/update_dns_cloudflare.py`
|
|
||||||
|
|
||||||
Plateformes supportées : Ubuntu 20.04-25.04, Linux Mint 22.3, Debian 12, Arch Linux, macOS (pyenv), Windows (WSL/Docker).
|
|
||||||
|
|
||||||
## Points d'attention pour Claude
|
## Points d'attention pour Claude
|
||||||
|
|
||||||
- Toujours vérifier la version Odoo active avant de modifier du code (`cat .odoo-version`)
|
- Toujours vérifier la version Odoo active avant de modifier du code (`cat .odoo-version`)
|
||||||
|
|
@ -270,58 +20,24 @@ Plateformes supportées : Ubuntu 20.04-25.04, Linux Mint 22.3, Debian 12, Arch L
|
||||||
- Pour la documentation : modifier les `.base.md`, jamais les `.md` ou `.fr.md` directement
|
- Pour la documentation : modifier les `.base.md`, jamais les `.md` ou `.fr.md` directement
|
||||||
- Outil mmg disponible via `source .venv.erplibre/bin/activate && mmg`
|
- Outil mmg disponible via `source .venv.erplibre/bin/activate && mmg`
|
||||||
|
|
||||||
## Workflow Orchestration
|
|
||||||
|
|
||||||
### 1. Plan Mode Default
|
|
||||||
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
|
|
||||||
- If something goes sideways, STOP and re-plan immediately
|
|
||||||
- Don't keep pushing.
|
|
||||||
- Use plan mode for verification steps, not just building
|
|
||||||
- Write detailed specs upfront to reduce ambiguity
|
|
||||||
|
|
||||||
### 2. Subagent Strategy
|
|
||||||
- Use subagents liberally to keep the main context window clean.
|
|
||||||
- Offload research, exploration, and parallel analysis to subagents
|
|
||||||
- For complex problems, throw more compute at it via subagents
|
|
||||||
- One task per subagent for focused execution
|
|
||||||
|
|
||||||
### 3. Self-Improvement Loop
|
|
||||||
- Capture Lessons: Update AGENT.md with any change in approach the user has asked you to make.
|
|
||||||
- Write rules for yourself that prevent the same mistake
|
|
||||||
- Ruthlessly iterate on these lessons until the mistake rate drops.
|
|
||||||
- Review lessons at session start for relevant project
|
|
||||||
|
|
||||||
### 4. Verification Before Done
|
|
||||||
- Never mark a task complete without proving it works
|
|
||||||
- Diff behavior between main and your changes when relevant
|
|
||||||
- Ask yourself, "Would a staff engineer approve this?"
|
|
||||||
- Run tests, check logs, and demonstrate correctness.
|
|
||||||
|
|
||||||
### 5. Demand Elegance (Balanced)
|
|
||||||
- For non-trivial changes, pause and ask, "Is there a more elegant way?"
|
|
||||||
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
|
|
||||||
- Skip this for simple, obvious fixes
|
|
||||||
- Don't over-engineer.
|
|
||||||
- Challenge your own work before presenting it
|
|
||||||
|
|
||||||
### 6. Autonomous Bug Fixing
|
|
||||||
- When given a bug report, just fix it. Don't ask for hand-holding
|
|
||||||
- Point at logs, errors, and failing tests.
|
|
||||||
- Then resolve them.
|
|
||||||
- Zero context switching required from the user
|
|
||||||
- Go fix failing CI tests without being told how
|
|
||||||
|
|
||||||
## Task Management
|
|
||||||
|
|
||||||
1. **Plan First**: Write a plan to `tasks/todo.md` with checkable items.
|
|
||||||
2. **Verify Plan**: Check in before starting implementation.
|
|
||||||
3. **Track Progress**: Mark items complete as you go.
|
|
||||||
4. **Explain Changes**: High-level summary at each step.
|
|
||||||
5. **Document Results**: Add review section to `tasks/todo.md`
|
|
||||||
6. **Capture Lessons**: Update `tasks/lessons.md` after corrections
|
|
||||||
|
|
||||||
## Core Principles
|
## Core Principles
|
||||||
|
|
||||||
- **Simplicity First**: Make every change as simple as possible. Impact minimal code.
|
- **Simplicity First**: Make every change as simple as possible. Impact minimal code.
|
||||||
- **No Laziness**: Find root causes. No temporary fixes. Senior developer standards.
|
- **No Laziness**: Find root causes. No temporary fixes. Senior developer standards.
|
||||||
- **Minimal Impact**: Changes should only touch what's necessary. Avoid introducing bugs.
|
- **Minimal Impact**: Changes should only touch what's necessary. Avoid introducing bugs.
|
||||||
|
|
||||||
|
## Règles détaillées
|
||||||
|
|
||||||
|
Les instructions détaillées sont dans `.claude/rules/` :
|
||||||
|
|
||||||
|
| Fichier | Contenu |
|
||||||
|
|---------|---------|
|
||||||
|
| `01-versions.md` | Versions Odoo/Python/Poetry supportées |
|
||||||
|
| `02-project-structure.md` | Arborescence du projet |
|
||||||
|
| `03-commands.md` | Commandes essentielles (make, scripts) |
|
||||||
|
| `04-code-conventions.md` | Conventions Python, XML, fichiers, Git |
|
||||||
|
| `05-environments.md` | Venvs, pyenv, système de dépendances |
|
||||||
|
| `06-code-generator.md` | Génération de modules Odoo |
|
||||||
|
| `07-documentation.md` | Documentation multilingue (mmg) + i18n CLI |
|
||||||
|
| `08-deployment.md` | Docker, systemd, nginx, SSL, DNS |
|
||||||
|
| `09-workflow.md` | Workflow orchestration + task management |
|
||||||
|
|
|
||||||
143
conf/template_claude_commands_todo_add_command.md
Normal file
143
conf/template_claude_commands_todo_add_command.md
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
---
|
||||||
|
name: todo_add_command
|
||||||
|
description: "Add a new menu command to script/todo/todo.py with i18n support and optional todo.json entry."
|
||||||
|
allowed-tools:
|
||||||
|
- Read
|
||||||
|
- Edit
|
||||||
|
- Write
|
||||||
|
- Grep
|
||||||
|
- Glob
|
||||||
|
- Bash(python3 -m py_compile:*)
|
||||||
|
- Bash(python3 -c:*)
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
- Current todo.py menu structure: !`grep -n "def prompt_execute" script/todo/todo.py | head -20`
|
||||||
|
- Current todo.json sections: !`python3 -c "import json; d=json.load(open('script/todo/todo.json')); print('\n'.join(d.keys()))"`
|
||||||
|
- Current i18n keys count: !`grep -c fr.: script/todo/todo_i18n.py`
|
||||||
|
|
||||||
|
## Architecture Reference
|
||||||
|
|
||||||
|
### Files to modify
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|------|------|
|
||||||
|
| `script/todo/todo.py` | Main CLI — menu methods, business logic |
|
||||||
|
| `script/todo/todo_i18n.py` | Translations dict `TRANSLATIONS` with `"fr"` and `"en"` keys |
|
||||||
|
| `script/todo/todo.json` | Config-driven entries (optional, for `bash_command` or `makefile_cmd`) |
|
||||||
|
|
||||||
|
### Pattern A — Hardcoded menu entry (interactive logic)
|
||||||
|
|
||||||
|
Used when the command needs Python logic (user prompts, conditionals, API calls).
|
||||||
|
|
||||||
|
1. **Add i18n keys** in `todo_i18n.py` `TRANSLATIONS` dict:
|
||||||
|
```python
|
||||||
|
"my_feature_description": {
|
||||||
|
"fr": "Description en français",
|
||||||
|
"en": "English description",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add choice** in the parent menu method (e.g. `prompt_execute_git`):
|
||||||
|
```python
|
||||||
|
choices = [
|
||||||
|
...,
|
||||||
|
{"prompt_description": t("my_feature_description")},
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Add elif branch** in the same menu's while loop:
|
||||||
|
```python
|
||||||
|
elif status == "N":
|
||||||
|
self._my_feature()
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Add method** to the `TODO` class:
|
||||||
|
```python
|
||||||
|
def _my_feature(self):
|
||||||
|
# Implementation here
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern B — Config-driven entry (simple bash command)
|
||||||
|
|
||||||
|
Used when the command just runs a bash command or a make target.
|
||||||
|
|
||||||
|
1. **Add i18n key** in `todo_i18n.py` (use `prompt_description_key`).
|
||||||
|
|
||||||
|
2. **Add entry** in `todo.json` under the appropriate `*_from_makefile` section:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"prompt_description_key": "my_i18n_key",
|
||||||
|
"bash_command": "my-command --flag"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Or for make targets:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"prompt_description_key": "my_i18n_key",
|
||||||
|
"makefile_cmd": "my_make_target"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These are automatically picked up by `execute_from_configuration()`.
|
||||||
|
|
||||||
|
### Available menu sections
|
||||||
|
|
||||||
|
| Menu | Method | JSON key |
|
||||||
|
|------|--------|----------|
|
||||||
|
| Automation | `prompt_execute_function` | `function` |
|
||||||
|
| Code | `prompt_execute_code` | `code_from_makefile` |
|
||||||
|
| Config | `prompt_execute_config` | — |
|
||||||
|
| Database | `prompt_execute_database` | — |
|
||||||
|
| Doc | `prompt_execute_doc` | — |
|
||||||
|
| Git | `prompt_execute_git` | `git_from_makefile` |
|
||||||
|
| GPT code | `prompt_execute_gpt_code` | — |
|
||||||
|
| Network | `prompt_execute_network` | — |
|
||||||
|
| Process | `prompt_execute_process` | — |
|
||||||
|
| Run | `prompt_execute_instance` | `instance` |
|
||||||
|
| Security | `prompt_execute_security` | — |
|
||||||
|
| Test | `prompt_execute_test` | — |
|
||||||
|
| Update | `prompt_execute_update` | `update_from_makefile` |
|
||||||
|
|
||||||
|
### Key conventions
|
||||||
|
|
||||||
|
- i18n keys: `snake_case`, grouped by section with a comment header
|
||||||
|
- Method names: `_private_method` for actions, `prompt_execute_*` for submenus
|
||||||
|
- All user-facing strings must use `t("key")` — never hardcoded text
|
||||||
|
- Use `self.execute.exec_command_live(cmd, source_erplibre=False)` to run bash
|
||||||
|
- Use `input(t("prompt_key")).strip()` for user input
|
||||||
|
- Use `click.prompt(help_info)` for menu navigation
|
||||||
|
- Menu methods return `False` on back, use `self.fill_help_info(choices)` for formatting
|
||||||
|
|
||||||
|
## Task
|
||||||
|
|
||||||
|
Add a new command to the todo.py menu system. The user will describe what they want.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
1. **Determine the target menu section** from the user's description
|
||||||
|
2. **Choose Pattern A or B** based on complexity:
|
||||||
|
- Simple bash/make command → Pattern B (todo.json entry)
|
||||||
|
- Needs user interaction or logic → Pattern A (hardcoded method)
|
||||||
|
3. **Add i18n translations** in `todo_i18n.py` — always both `"fr"` and `"en"`
|
||||||
|
4. **Implement the feature** following the appropriate pattern
|
||||||
|
5. **Validate syntax**:
|
||||||
|
```bash
|
||||||
|
python3 -m py_compile script/todo/todo.py
|
||||||
|
python3 -m py_compile script/todo/todo_i18n.py
|
||||||
|
python3 -c "import json; json.load(open('script/todo/todo.json'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
- Keep menu numbering sequential — update all `elif` branches if inserting
|
||||||
|
- Group i18n keys with a `# Section name` comment
|
||||||
|
- Match existing code style (Black, 79 char lines for Odoo modules)
|
||||||
|
- Do not break existing menu entries or their numbering
|
||||||
|
- Test that `fill_help_info` and `execute_from_configuration` handle the new entry
|
||||||
|
|
||||||
|
## User Request
|
||||||
|
|
||||||
|
$ARGUMENTS
|
||||||
|
|
@ -96,9 +96,7 @@ def commit_by_directory():
|
||||||
run_git_command(f'cd "{config.path}" && git rm -r {directory}')
|
run_git_command(f'cd "{config.path}" && git rm -r {directory}')
|
||||||
|
|
||||||
# Crée le commit
|
# Crée le commit
|
||||||
commit_message = (
|
commit_message = f"[{mig_prefix_msg}] {directory}: Migration to {config.odoo_version}"
|
||||||
f"[{mig_prefix_msg}] {directory}: Migration to {config.odoo_version}"
|
|
||||||
)
|
|
||||||
commit_result = run_git_command(
|
commit_result = run_git_command(
|
||||||
f'cd "{config.path}" && git commit -m "{commit_message}"'
|
f'cd "{config.path}" && git commit -m "{commit_message}"'
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,28 +10,31 @@ def get_db_list_xmlrpc(odoo_url):
|
||||||
Retrieves the list of Odoo databases using the XML-RPC API.
|
Retrieves the list of Odoo databases using the XML-RPC API.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
common = xmlrpc.client.ServerProxy(f'{odoo_url}/xmlrpc/db')
|
common = xmlrpc.client.ServerProxy(f"{odoo_url}/xmlrpc/db")
|
||||||
db_list = common.list()
|
db_list = common.list()
|
||||||
return db_list
|
return db_list
|
||||||
except xmlrpc.client.Fault as e:
|
except xmlrpc.client.Fault as e:
|
||||||
print(f"XML-RPC Error: {e.faultCode} - {e.faultString}", file=sys.stderr)
|
print(
|
||||||
|
f"XML-RPC Error: {e.faultCode} - {e.faultString}", file=sys.stderr
|
||||||
|
)
|
||||||
return []
|
return []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Connection Error: {e}", file=sys.stderr)
|
print(f"Connection Error: {e}", file=sys.stderr)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# --- CLI using Click ---
|
# --- CLI using Click ---
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option(
|
@click.option(
|
||||||
'--odoo-url',
|
"--odoo-url",
|
||||||
default='http://localhost:8069',
|
default="http://localhost:8069",
|
||||||
help='URL of the Odoo server.',
|
help="URL of the Odoo server.",
|
||||||
show_default=True
|
show_default=True,
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
'--raw',
|
"--raw",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
help='Output one database per line, without extra formatting. Useful for scripting.'
|
help="Output one database per line, without extra formatting. Useful for scripting.",
|
||||||
)
|
)
|
||||||
def list_databases(odoo_url, raw=False):
|
def list_databases(odoo_url, raw=False):
|
||||||
"""
|
"""
|
||||||
|
|
@ -56,5 +59,5 @@ def list_databases(odoo_url, raw=False):
|
||||||
|
|
||||||
|
|
||||||
# --- Script Execution ---
|
# --- Script Execution ---
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
list_databases()
|
list_databases()
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ class Execute:
|
||||||
command = self.cmd_source_default % command
|
command = self.cmd_source_default % command
|
||||||
|
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print("🏠 ⬇ Execute command :")
|
print("🏠 ⬇ Execute command :\n")
|
||||||
print(command)
|
print(command)
|
||||||
output_lines = []
|
output_lines = []
|
||||||
|
|
||||||
|
|
@ -172,10 +172,10 @@ class Execute:
|
||||||
duration_delta = datetime.timedelta(seconds=duration_sec)
|
duration_delta = datetime.timedelta(seconds=duration_sec)
|
||||||
human_time = humanize.precisedelta(duration_delta)
|
human_time = humanize.precisedelta(duration_delta)
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(f"🏠 ⬆ Executed ({human_time}) :")
|
print(f"🏠 ⬆ Executed ({human_time}) :\n")
|
||||||
else:
|
else:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :")
|
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :\n")
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(command)
|
print(command)
|
||||||
print()
|
print()
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,7 @@ Use --production-ready for /srv/git (requires root).
|
||||||
type=int,
|
type=int,
|
||||||
default=DEFAULT_JOBS,
|
default=DEFAULT_JOBS,
|
||||||
help=(
|
help=(
|
||||||
"Parallel jobs for init/remote/push"
|
"Parallel jobs for init/remote/push" f" (default: {DEFAULT_JOBS})"
|
||||||
f" (default: {DEFAULT_JOBS})"
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
@ -247,11 +246,7 @@ def get_erplibre_root_project(erplibre_root):
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
revision = (
|
revision = result.stdout.strip() if result.returncode == 0 else "master"
|
||||||
result.stdout.strip()
|
|
||||||
if result.returncode == 0
|
|
||||||
else "master"
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name": ERPLIBRE_REPO_NAME,
|
"name": ERPLIBRE_REPO_NAME,
|
||||||
|
|
@ -278,19 +273,13 @@ async def _init_single_bare_repo(git_path, project, semaphore):
|
||||||
return "skipped"
|
return "skipped"
|
||||||
|
|
||||||
_logger.info(f" Creating: {bare_path}")
|
_logger.info(f" Creating: {bare_path}")
|
||||||
_, err, rc = await _run_git(
|
_, err, rc = await _run_git("git", "init", "--bare", bare_path)
|
||||||
"git", "init", "--bare", bare_path
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
_logger.warning(
|
_logger.warning(f" Init failed: {bare_path}: {err.strip()}")
|
||||||
f" Init failed: {bare_path}: {err.strip()}"
|
|
||||||
)
|
|
||||||
return "error"
|
return "error"
|
||||||
|
|
||||||
# Enable git daemon export
|
# Enable git daemon export
|
||||||
export_file = os.path.join(
|
export_file = os.path.join(bare_path, "git-daemon-export-ok")
|
||||||
bare_path, "git-daemon-export-ok"
|
|
||||||
)
|
|
||||||
open(export_file, "w").close()
|
open(export_file, "w").close()
|
||||||
|
|
||||||
# Allow pushing from shallow clones
|
# Allow pushing from shallow clones
|
||||||
|
|
@ -312,10 +301,7 @@ async def init_bare_repos(git_path, projects, jobs):
|
||||||
semaphore = asyncio.Semaphore(jobs)
|
semaphore = asyncio.Semaphore(jobs)
|
||||||
|
|
||||||
results = await asyncio.gather(
|
results = await asyncio.gather(
|
||||||
*[
|
*[_init_single_bare_repo(git_path, p, semaphore) for p in projects]
|
||||||
_init_single_bare_repo(git_path, p, semaphore)
|
|
||||||
for p in projects
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
created = results.count("created")
|
created = results.count("created")
|
||||||
|
|
@ -352,9 +338,7 @@ async def _add_single_remote(
|
||||||
):
|
):
|
||||||
"""Add or update remote for a single repo (async)."""
|
"""Add or update remote for a single repo (async)."""
|
||||||
async with semaphore:
|
async with semaphore:
|
||||||
repo_path = os.path.join(
|
repo_path = os.path.join(erplibre_root, project["path"])
|
||||||
erplibre_root, project["path"]
|
|
||||||
)
|
|
||||||
if not os.path.isdir(repo_path):
|
if not os.path.isdir(repo_path):
|
||||||
_logger.warning(f" Not found: {repo_path}")
|
_logger.warning(f" Not found: {repo_path}")
|
||||||
return "error"
|
return "error"
|
||||||
|
|
@ -368,9 +352,7 @@ async def _add_single_remote(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if remote already exists
|
# Check if remote already exists
|
||||||
stdout, _, _ = await _run_git(
|
stdout, _, _ = await _run_git("git", "-C", repo_path, "remote")
|
||||||
"git", "-C", repo_path, "remote"
|
|
||||||
)
|
|
||||||
existing_remotes = stdout.strip().split("\n")
|
existing_remotes = stdout.strip().split("\n")
|
||||||
|
|
||||||
if remote_name in existing_remotes:
|
if remote_name in existing_remotes:
|
||||||
|
|
@ -403,8 +385,7 @@ async def _add_single_remote(
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
_logger.warning(
|
_logger.warning(
|
||||||
f" add failed for"
|
f" add failed for" f" {project['path']}: {err.strip()}"
|
||||||
f" {project['path']}: {err.strip()}"
|
|
||||||
)
|
)
|
||||||
return "error"
|
return "error"
|
||||||
_logger.info(f" Added: {project['path']}")
|
_logger.info(f" Added: {project['path']}")
|
||||||
|
|
@ -447,10 +428,7 @@ async def add_remotes(
|
||||||
added = results.count("added")
|
added = results.count("added")
|
||||||
updated = results.count("updated")
|
updated = results.count("updated")
|
||||||
errors = results.count("error")
|
errors = results.count("error")
|
||||||
print(
|
print(f"Remotes: {added} added, {updated} updated," f" {errors} errors")
|
||||||
f"Remotes: {added} added, {updated} updated,"
|
|
||||||
f" {errors} errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# --- Async workers for push ---
|
# --- Async workers for push ---
|
||||||
|
|
@ -458,9 +436,7 @@ async def add_remotes(
|
||||||
|
|
||||||
async def _is_detached_head(repo_path):
|
async def _is_detached_head(repo_path):
|
||||||
"""Check if a repo is in detached HEAD state."""
|
"""Check if a repo is in detached HEAD state."""
|
||||||
_, _, rc = await _run_git(
|
_, _, rc = await _run_git("git", "-C", repo_path, "symbolic-ref", "HEAD")
|
||||||
"git", "-C", repo_path, "symbolic-ref", "HEAD"
|
|
||||||
)
|
|
||||||
return rc != 0
|
return rc != 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -471,9 +447,7 @@ async def _checkout_manifest_branch(repo_path, revision):
|
||||||
on the exact commit. We create/checkout a local branch
|
on the exact commit. We create/checkout a local branch
|
||||||
matching the manifest revision so git push works.
|
matching the manifest revision so git push works.
|
||||||
"""
|
"""
|
||||||
branch = (
|
branch = revision.split("/")[-1] if "/" in revision else revision
|
||||||
revision.split("/")[-1] if "/" in revision else revision
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if local branch already exists
|
# Check if local branch already exists
|
||||||
_, _, rc = await _run_git(
|
_, _, rc = await _run_git(
|
||||||
|
|
@ -485,9 +459,7 @@ async def _checkout_manifest_branch(repo_path, revision):
|
||||||
f"refs/heads/{branch}",
|
f"refs/heads/{branch}",
|
||||||
)
|
)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
await _run_git(
|
await _run_git("git", "-C", repo_path, "checkout", branch)
|
||||||
"git", "-C", repo_path, "checkout", branch
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await _run_git(
|
await _run_git(
|
||||||
"git",
|
"git",
|
||||||
|
|
@ -514,9 +486,7 @@ async def _update_bare_head(git_path, project):
|
||||||
revision = project.get("revision", "")
|
revision = project.get("revision", "")
|
||||||
if not revision:
|
if not revision:
|
||||||
return
|
return
|
||||||
branch = (
|
branch = revision.split("/")[-1] if "/" in revision else revision
|
||||||
revision.split("/")[-1] if "/" in revision else revision
|
|
||||||
)
|
|
||||||
await _run_git(
|
await _run_git(
|
||||||
"git",
|
"git",
|
||||||
"-C",
|
"-C",
|
||||||
|
|
@ -529,20 +499,10 @@ async def _update_bare_head(git_path, project):
|
||||||
|
|
||||||
async def _try_unshallow(repo_path, project, remote_name):
|
async def _try_unshallow(repo_path, project, remote_name):
|
||||||
"""Try to unshallow a repo by fetching full history."""
|
"""Try to unshallow a repo by fetching full history."""
|
||||||
shallow_file = os.path.join(
|
shallow_file = os.path.join(repo_path, ".git", "shallow")
|
||||||
repo_path, ".git", "shallow"
|
_logger.info(f" Unshallowing {project['path']}...")
|
||||||
)
|
stdout, _, _ = await _run_git("git", "-C", repo_path, "remote")
|
||||||
_logger.info(
|
remotes = [r for r in stdout.strip().split("\n") if r and r != remote_name]
|
||||||
f" Unshallowing {project['path']}..."
|
|
||||||
)
|
|
||||||
stdout, _, _ = await _run_git(
|
|
||||||
"git", "-C", repo_path, "remote"
|
|
||||||
)
|
|
||||||
remotes = [
|
|
||||||
r
|
|
||||||
for r in stdout.strip().split("\n")
|
|
||||||
if r and r != remote_name
|
|
||||||
]
|
|
||||||
manifest_remote = project.get("remote", "")
|
manifest_remote = project.get("remote", "")
|
||||||
if manifest_remote in remotes:
|
if manifest_remote in remotes:
|
||||||
remotes.remove(manifest_remote)
|
remotes.remove(manifest_remote)
|
||||||
|
|
@ -562,9 +522,7 @@ async def _try_unshallow(repo_path, project, remote_name):
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
continue
|
continue
|
||||||
if not os.path.exists(shallow_file):
|
if not os.path.exists(shallow_file):
|
||||||
_logger.info(
|
_logger.info(f" Unshallowed via {try_remote}")
|
||||||
f" Unshallowed via {try_remote}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
if os.path.exists(shallow_file):
|
if os.path.exists(shallow_file):
|
||||||
_logger.warning(
|
_logger.warning(
|
||||||
|
|
@ -585,30 +543,22 @@ async def _push_single_repo(
|
||||||
):
|
):
|
||||||
"""Push a single repo to local remote (async)."""
|
"""Push a single repo to local remote (async)."""
|
||||||
async with semaphore:
|
async with semaphore:
|
||||||
repo_path = os.path.join(
|
repo_path = os.path.join(erplibre_root, project["path"])
|
||||||
erplibre_root, project["path"]
|
|
||||||
)
|
|
||||||
if not os.path.isdir(repo_path):
|
if not os.path.isdir(repo_path):
|
||||||
_logger.warning(f" Not found: {repo_path}")
|
_logger.warning(f" Not found: {repo_path}")
|
||||||
return "error", False
|
return "error", False
|
||||||
|
|
||||||
# Handle shallow repos
|
# Handle shallow repos
|
||||||
shallow_file = os.path.join(
|
shallow_file = os.path.join(repo_path, ".git", "shallow")
|
||||||
repo_path, ".git", "shallow"
|
|
||||||
)
|
|
||||||
if os.path.exists(shallow_file):
|
if os.path.exists(shallow_file):
|
||||||
if unshallow:
|
if unshallow:
|
||||||
await _try_unshallow(
|
await _try_unshallow(repo_path, project, remote_name)
|
||||||
repo_path, project, remote_name
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# Enable shallow push on bare repo
|
# Enable shallow push on bare repo
|
||||||
repo_name = project["name"]
|
repo_name = project["name"]
|
||||||
if not repo_name.endswith(".git"):
|
if not repo_name.endswith(".git"):
|
||||||
repo_name += ".git"
|
repo_name += ".git"
|
||||||
bare_path = os.path.join(
|
bare_path = os.path.join(git_path, repo_name)
|
||||||
git_path, repo_name
|
|
||||||
)
|
|
||||||
if os.path.isdir(bare_path):
|
if os.path.isdir(bare_path):
|
||||||
await _run_git(
|
await _run_git(
|
||||||
"git",
|
"git",
|
||||||
|
|
@ -618,19 +568,14 @@ async def _push_single_repo(
|
||||||
"receive.shallowUpdate",
|
"receive.shallowUpdate",
|
||||||
"true",
|
"true",
|
||||||
)
|
)
|
||||||
_logger.info(
|
_logger.info(f" Shallow push for" f" {project['path']}")
|
||||||
f" Shallow push for"
|
|
||||||
f" {project['path']}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Handle detached HEAD: checkout manifest branch
|
# Handle detached HEAD: checkout manifest branch
|
||||||
did_checkout = False
|
did_checkout = False
|
||||||
if await _is_detached_head(repo_path):
|
if await _is_detached_head(repo_path):
|
||||||
revision = project.get("revision", "")
|
revision = project.get("revision", "")
|
||||||
if revision:
|
if revision:
|
||||||
branch = await _checkout_manifest_branch(
|
branch = await _checkout_manifest_branch(repo_path, revision)
|
||||||
repo_path, revision
|
|
||||||
)
|
|
||||||
_logger.info(
|
_logger.info(
|
||||||
f" Checkout {branch} for"
|
f" Checkout {branch} for"
|
||||||
f" {project['path']}"
|
f" {project['path']}"
|
||||||
|
|
@ -663,9 +608,7 @@ async def _push_single_repo(
|
||||||
"push",
|
"push",
|
||||||
remote_name,
|
remote_name,
|
||||||
]
|
]
|
||||||
_, err, rc = await _run_git(
|
_, err, rc = await _run_git(*cmd, timeout=120)
|
||||||
*cmd, timeout=120
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
_logger.warning(
|
_logger.warning(
|
||||||
f" Push failed for"
|
f" Push failed for"
|
||||||
|
|
@ -675,14 +618,10 @@ async def _push_single_repo(
|
||||||
return "error", did_checkout
|
return "error", did_checkout
|
||||||
else:
|
else:
|
||||||
await _update_bare_head(git_path, project)
|
await _update_bare_head(git_path, project)
|
||||||
_logger.info(
|
_logger.info(f" Pushed: {project['path']}")
|
||||||
f" Pushed: {project['path']}"
|
|
||||||
)
|
|
||||||
return "pushed", did_checkout
|
return "pushed", did_checkout
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
_logger.warning(
|
_logger.warning(f" Timeout pushing {project['path']}")
|
||||||
f" Timeout pushing {project['path']}"
|
|
||||||
)
|
|
||||||
return "error", did_checkout
|
return "error", did_checkout
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -744,8 +683,7 @@ def print_clone_commands(git_path, projects, port):
|
||||||
if clone_path == ".":
|
if clone_path == ".":
|
||||||
clone_path = "erplibre"
|
clone_path = "erplibre"
|
||||||
lines.append(
|
lines.append(
|
||||||
f" git clone {base_url}/{repo_name}"
|
f" git clone {base_url}/{repo_name}" f" {clone_path}"
|
||||||
f" {clone_path}"
|
|
||||||
)
|
)
|
||||||
lines.sort()
|
lines.sort()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,10 @@ def get_pull_request_repo(
|
||||||
parsed_url = parse(upstream_url)
|
parsed_url = parse(upstream_url)
|
||||||
|
|
||||||
status, user = gh.user.get()
|
status, user = gh.user.get()
|
||||||
user_name = (
|
user_name = user["login"] if not organization_name else organization_name
|
||||||
user["login"] if not organization_name else organization_name
|
status, lst_pull = gh.repos[user_name][parsed_url.repo].pulls.get()
|
||||||
)
|
|
||||||
status, lst_pull = (
|
|
||||||
gh.repos[user_name][parsed_url.repo].pulls.get()
|
|
||||||
)
|
|
||||||
if type(lst_pull) is dict:
|
if type(lst_pull) is dict:
|
||||||
print(
|
print(f"For url {upstream_url}," f" got {lst_pull.get('message')}")
|
||||||
f"For url {upstream_url},"
|
|
||||||
f" got {lst_pull.get('message')}"
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
for pull in lst_pull:
|
for pull in lst_pull:
|
||||||
|
|
@ -53,26 +46,21 @@ def fork_repo(
|
||||||
parsed_url = parse(upstream_url)
|
parsed_url = parse(upstream_url)
|
||||||
|
|
||||||
status, user = gh.user.get()
|
status, user = gh.user.get()
|
||||||
user_name = (
|
user_name = user["login"] if not organization_name else organization_name
|
||||||
user["login"] if not organization_name else organization_name
|
status, forked_repo = gh.repos[user_name][parsed_url.repo].get()
|
||||||
)
|
|
||||||
status, forked_repo = (
|
|
||||||
gh.repos[user_name][parsed_url.repo].get()
|
|
||||||
)
|
|
||||||
if status == 404:
|
if status == 404:
|
||||||
status, upstream_repo = (
|
status, upstream_repo = gh.repos[parsed_url.owner][
|
||||||
gh.repos[parsed_url.owner][parsed_url.repo].get()
|
parsed_url.repo
|
||||||
)
|
].get()
|
||||||
if status == 404:
|
if status == 404:
|
||||||
print("Unable to find repo %s" % upstream_url)
|
print("Unable to find repo %s" % upstream_url)
|
||||||
exit(1)
|
exit(1)
|
||||||
args = {}
|
args = {}
|
||||||
if organization_name:
|
if organization_name:
|
||||||
args["organization"] = organization_name
|
args["organization"] = organization_name
|
||||||
status, forked_repo = (
|
status, forked_repo = gh.repos[parsed_url.owner][
|
||||||
gh.repos[parsed_url.owner][parsed_url.repo]
|
parsed_url.repo
|
||||||
.forks.post(**args)
|
].forks.post(**args)
|
||||||
)
|
|
||||||
if status == 404:
|
if status == 404:
|
||||||
print(
|
print(
|
||||||
f"{Fore.RED}Error{Style.RESET_ALL} when forking"
|
f"{Fore.RED}Error{Style.RESET_ALL} when forking"
|
||||||
|
|
@ -82,23 +70,16 @@ def fork_repo(
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
print(
|
print(
|
||||||
"Forked %s to %s"
|
"Forked %s to %s" % (upstream_url, forked_repo["html_url"])
|
||||||
% (upstream_url, forked_repo["html_url"])
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
print(forked_repo)
|
print(forked_repo)
|
||||||
print(upstream_url)
|
print(upstream_url)
|
||||||
elif status == 202:
|
elif status == 202:
|
||||||
print(
|
print("Forked repo %s already exists" % forked_repo["full_name"])
|
||||||
"Forked repo %s already exists"
|
|
||||||
% forked_repo["full_name"]
|
|
||||||
)
|
|
||||||
elif status != 200:
|
elif status != 200:
|
||||||
print(
|
print("Status not supported: %s - %s" % (status, forked_repo))
|
||||||
"Status not supported: %s - %s"
|
|
||||||
% (status, forked_repo)
|
|
||||||
)
|
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -110,9 +91,7 @@ def add_and_fetch_remote(
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
working_repo = Repo(repo_info.relative_path)
|
working_repo = Repo(repo_info.relative_path)
|
||||||
if repo_info.organization in [
|
if repo_info.organization in [a.name for a in working_repo.remotes]:
|
||||||
a.name for a in working_repo.remotes
|
|
||||||
]:
|
|
||||||
print(
|
print(
|
||||||
f'Remote "{repo_info.organization}" already exist'
|
f'Remote "{repo_info.organization}" already exist'
|
||||||
f" in {repo_info.relative_path}"
|
f" in {repo_info.relative_path}"
|
||||||
|
|
@ -122,8 +101,7 @@ def add_and_fetch_remote(
|
||||||
print(f"New repo {repo_info.relative_path}")
|
print(f"New repo {repo_info.relative_path}")
|
||||||
if not root_repo:
|
if not root_repo:
|
||||||
print(
|
print(
|
||||||
"Missing git repository to root for repo"
|
"Missing git repository to root for repo" f" {repo_info.path}"
|
||||||
f" {repo_info.path}"
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if branch_name:
|
if branch_name:
|
||||||
|
|
@ -149,16 +127,14 @@ def add_and_fetch_remote(
|
||||||
# Add remote
|
# Add remote
|
||||||
upstream_remote = retry(
|
upstream_remote = retry(
|
||||||
wait_exponential_multiplier=1000, stop_max_delay=15000
|
wait_exponential_multiplier=1000, stop_max_delay=15000
|
||||||
)(working_repo.create_remote)(
|
)(working_repo.create_remote)(repo_info.organization, repo_info.url_https)
|
||||||
repo_info.organization, repo_info.url_https
|
|
||||||
)
|
|
||||||
print(
|
print(
|
||||||
'Remote "%s" created for %s'
|
'Remote "%s" created for %s'
|
||||||
% (repo_info.organization, repo_info.url_https)
|
% (repo_info.organization, repo_info.url_https)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fetch the remote
|
# Fetch the remote
|
||||||
retry(
|
retry(wait_exponential_multiplier=1000, stop_max_delay=15000)(
|
||||||
wait_exponential_multiplier=1000, stop_max_delay=15000
|
upstream_remote.fetch
|
||||||
)(upstream_remote.fetch)()
|
)()
|
||||||
print('Remote "%s" fetched' % repo_info.organization)
|
print('Remote "%s" fetched' % repo_info.organization)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ _logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
PROJECT_NAME = os.path.basename(os.getcwd())
|
PROJECT_NAME = os.path.basename(os.getcwd())
|
||||||
IDEA_PATH = "./.idea"
|
IDEA_PATH = "./.idea"
|
||||||
DEFAULT_ODOO_BIN = "./odoo/odoo-bin" # Need this to replace static configuration
|
DEFAULT_ODOO_BIN = (
|
||||||
|
"./odoo/odoo-bin" # Need this to replace static configuration
|
||||||
|
)
|
||||||
IDEA_MISC = os.path.join(IDEA_PATH, "misc.xml")
|
IDEA_MISC = os.path.join(IDEA_PATH, "misc.xml")
|
||||||
IDEA_WORKSPACE = os.path.join(IDEA_PATH, "workspace.xml")
|
IDEA_WORKSPACE = os.path.join(IDEA_PATH, "workspace.xml")
|
||||||
VCS_WORKSPACE = os.path.join(IDEA_PATH, "vcs.xml")
|
VCS_WORKSPACE = os.path.join(IDEA_PATH, "vcs.xml")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||||
|
|
||||||
installed_modules = env["ir.module.module"].search([('state', '=', 'installed')])
|
installed_modules = env["ir.module.module"].search(
|
||||||
|
[("state", "=", "installed")]
|
||||||
|
)
|
||||||
|
|
||||||
print("Installed modules:")
|
print("Installed modules:")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,20 @@ print("Running a script in the Odoo shell!")
|
||||||
# ERROR: insert or update on table "discuss_channel_member" violates foreign key constraint "discuss_channel_member_channel_id_fkey"
|
# ERROR: insert or update on table "discuss_channel_member" violates foreign key constraint "discuss_channel_member_channel_id_fkey"
|
||||||
# DÉTAIL : Key (channel_id)=(3) is not present in table "discuss_channel".
|
# DÉTAIL : Key (channel_id)=(3) is not present in table "discuss_channel".
|
||||||
|
|
||||||
env.cr.execute("""
|
env.cr.execute(
|
||||||
|
"""
|
||||||
ALTER TABLE discuss_channel
|
ALTER TABLE discuss_channel
|
||||||
DROP CONSTRAINT discuss_channel_channel_type_not_null;
|
DROP CONSTRAINT discuss_channel_channel_type_not_null;
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
env.cr.commit()
|
env.cr.commit()
|
||||||
|
|
||||||
#env.cr.execute("SELECT to_regclass('public.discuss_channel');")
|
# env.cr.execute("SELECT to_regclass('public.discuss_channel');")
|
||||||
#print("table:", env.cr.fetchone())
|
# print("table:", env.cr.fetchone())
|
||||||
|
|
||||||
#print(
|
# print(
|
||||||
# "model discuss.channel:",
|
# "model discuss.channel:",
|
||||||
# env["ir.model"].search([("model", "=", "discuss.channel")]),
|
# env["ir.model"].search([("model", "=", "discuss.channel")]),
|
||||||
#)
|
# )
|
||||||
|
|
||||||
print("End fix migration with update mail postgresql 17 to postgresql 18.")
|
print("End fix migration with update mail postgresql 17 to postgresql 18.")
|
||||||
|
|
|
||||||
|
|
@ -10,47 +10,52 @@
|
||||||
},
|
},
|
||||||
"instance": [
|
"instance": [
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_instance_test",
|
"prompt_description_key": "Test - Minimal base instance",
|
||||||
"makefile_cmd": "db_restore_erplibre_base_db_test",
|
"makefile_cmd": "db_restore_erplibre_base_db_test",
|
||||||
"database": "test"
|
"database": "test"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_robot_minimal",
|
"prompt_description_key": "Open RobotLibre 🤖 minimal",
|
||||||
"makefile_cmd": "robot_libre",
|
"makefile_cmd": "robot_libre",
|
||||||
"database": "robotlibre"
|
"database": "robotlibre"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_robot_search",
|
"prompt_description_key": "Open RobotLibre 🤖 with search enabled",
|
||||||
"makefile_cmd": "robot_libre_all",
|
"makefile_cmd": "robot_libre_all",
|
||||||
"database": "robotlibre"
|
"database": "robotlibre"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"function": [
|
"function": [
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_open_erplibre_todo",
|
"prompt_description_key": "Open ERPLibre with TODO 🤖",
|
||||||
"command": "./.venv.erplibre/bin/python ./script/selenium/web_login.py"
|
"command": "./.venv.erplibre/bin/python ./script/selenium/web_login.py"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"update_from_makefile": [
|
"update_from_makefile": [
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_update_erplibre_base_test",
|
"prompt_description_key": "Update all erplibre_base on database test",
|
||||||
"makefile_cmd": "db_erplibre_base_db_test_update_all",
|
"makefile_cmd": "db_erplibre_base_db_test_update_all",
|
||||||
"database": "test"
|
"database": "test"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"code_from_makefile": [
|
"code_from_makefile": [
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_show_code_status",
|
"prompt_description_key": "Show code status",
|
||||||
"makefile_cmd": "repo_show_status"
|
"makefile_cmd": "repo_show_status"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_stash_all_code",
|
"prompt_description_key": "Stash all code",
|
||||||
"makefile_cmd": "repo_do_stash"
|
"makefile_cmd": "repo_do_stash"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"prompt_description_key": "json_format_modified_code",
|
"prompt_description_key": "Format modified code",
|
||||||
"makefile_cmd": "format"
|
"makefile_cmd": "format"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"git_from_makefile": []
|
"git_from_makefile": [
|
||||||
|
{
|
||||||
|
"prompt_description_key": "Configure git local editor to vim",
|
||||||
|
"bash_command": "git config --global core.editor \"vim\""
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -15,539 +15,732 @@ TRANSLATIONS = {
|
||||||
"fr": "L'importation est un succès!",
|
"fr": "L'importation est un succès!",
|
||||||
"en": "Importation success!",
|
"en": "Importation success!",
|
||||||
},
|
},
|
||||||
"opening": {
|
"Opening TODO ...": {
|
||||||
"fr": "Ouverture de TODO en cours ...",
|
"fr": "Ouverture de TODO en cours ...",
|
||||||
"en": "Opening TODO ...",
|
"en": "Opening TODO ...",
|
||||||
},
|
},
|
||||||
"enter_directives": {
|
"=> Enter your choice by number and press Enter!": {
|
||||||
"fr": "=> Entre tes directives par son chiffre et fait Entrée!",
|
"fr": "=> Entre tes directives par son chiffre et fait Entrée!",
|
||||||
"en": "=> Enter your choice by number and press Enter!",
|
"en": "=> Enter your choice by number and press Enter!",
|
||||||
},
|
},
|
||||||
"command": {
|
"Command:": {
|
||||||
"fr": "Commande :",
|
"fr": "Commande :",
|
||||||
"en": "Command:",
|
"en": "Command:",
|
||||||
},
|
},
|
||||||
"menu_execute": {
|
"Execute": {
|
||||||
"fr": "Exécution",
|
"fr": "Exécution",
|
||||||
"en": "Execute",
|
"en": "Execute",
|
||||||
},
|
},
|
||||||
"menu_install": {
|
"Install": {
|
||||||
"fr": "Installation",
|
"fr": "Installation",
|
||||||
"en": "Install",
|
"en": "Install",
|
||||||
},
|
},
|
||||||
"menu_question": {
|
"Question": {
|
||||||
"fr": "Question",
|
"fr": "Question",
|
||||||
"en": "Question",
|
"en": "Question",
|
||||||
},
|
},
|
||||||
"menu_fork": {
|
"Fork - Open TODO in a new tab": {
|
||||||
"fr": "Fork - Ouvre TODO dans une nouvelle tabulation",
|
"fr": "Fork - Ouvre TODO dans une nouvelle tabulation",
|
||||||
"en": "Fork - Open TODO in a new tab",
|
"en": "Fork - Open TODO in a new tab",
|
||||||
},
|
},
|
||||||
"menu_quit": {
|
"Quit": {
|
||||||
"fr": "Quitter",
|
"fr": "Quitter",
|
||||||
"en": "Quit",
|
"en": "Quit",
|
||||||
},
|
},
|
||||||
"cmd_not_found": {
|
"Command not found !": {
|
||||||
"fr": "Commande non trouvée !",
|
"fr": "Commande non trouvée !",
|
||||||
"en": "Command not found !",
|
"en": "Command not found !",
|
||||||
},
|
},
|
||||||
"back": {
|
"Back": {
|
||||||
"fr": "Retour",
|
"fr": "Retour",
|
||||||
"en": "Back",
|
"en": "Back",
|
||||||
},
|
},
|
||||||
# Execute submenu
|
# Execute submenu
|
||||||
"menu_run": {
|
"Run - Execute and install an instance": {
|
||||||
"fr": "Run - Exécuter et installer une instance",
|
"fr": "Run - Exécuter et installer une instance",
|
||||||
"en": "Run - Execute and install an instance",
|
"en": "Run - Execute and install an instance",
|
||||||
},
|
},
|
||||||
"menu_automation": {
|
"Automation - Demonstration of developed features": {
|
||||||
"fr": "Automatisation - Demonstration des fonctions développées",
|
"fr": "Automatisation - Demonstration des fonctions développées",
|
||||||
"en": "Automation - Demonstration of developed features",
|
"en": "Automation - Demonstration of developed features",
|
||||||
},
|
},
|
||||||
"menu_update": {
|
"Update - Update all developed staging source code": {
|
||||||
"fr": "Mise à jour - Update all developed staging source code",
|
"fr": "Mise à jour - Update all developed staging source code",
|
||||||
"en": "Update - Update all developed staging source code",
|
"en": "Update - Update all developed staging source code",
|
||||||
},
|
},
|
||||||
"menu_code": {
|
"Code - Developer tools": {
|
||||||
"fr": "Code - Outil pour développeur",
|
"fr": "Code - Outil pour développeur",
|
||||||
"en": "Code - Developer tools",
|
"en": "Code - Developer tools",
|
||||||
},
|
},
|
||||||
"menu_doc": {
|
"Doc - Documentation search": {
|
||||||
"fr": "Doc - Recherche de documentation",
|
"fr": "Doc - Recherche de documentation",
|
||||||
"en": "Doc - Documentation search",
|
"en": "Doc - Documentation search",
|
||||||
},
|
},
|
||||||
"menu_database": {
|
"Database - Database tools": {
|
||||||
"fr": "Database - Outils sur les bases de données",
|
"fr": "Database - Outils sur les bases de données",
|
||||||
"en": "Database - Database tools",
|
"en": "Database - Database tools",
|
||||||
},
|
},
|
||||||
"menu_process": {
|
"Process - Execution tools": {
|
||||||
"fr": "Process - Outils sur les executions",
|
"fr": "Process - Outils sur les executions",
|
||||||
"en": "Process - Execution tools",
|
"en": "Process - Execution tools",
|
||||||
},
|
},
|
||||||
"menu_config": {
|
"Config - Configuration file management": {
|
||||||
"fr": "Config - Traitement du fichier de configuration",
|
"fr": "Config - Traitement du fichier de configuration",
|
||||||
"en": "Config - Configuration file management",
|
"en": "Config - Configuration file management",
|
||||||
},
|
},
|
||||||
"menu_network": {
|
"Network - Network tools": {
|
||||||
"fr": "Réseau - Outil réseautique",
|
"fr": "Réseau - Outil réseautique",
|
||||||
"en": "Network - Network tools",
|
"en": "Network - Network tools",
|
||||||
},
|
},
|
||||||
"menu_security": {
|
"Security - Dependency security audit": {
|
||||||
"fr": "Sécurité - Audit de sécurité des dépendances",
|
"fr": "Sécurité - Audit de sécurité des dépendances",
|
||||||
"en": "Security - Dependency security audit",
|
"en": "Security - Dependency security audit",
|
||||||
},
|
},
|
||||||
"menu_lang": {
|
"RTK - CLI proxy to reduce LLM token consumption": {
|
||||||
|
"fr": "RTK - Proxy CLI pour réduire la consommation de tokens LLM",
|
||||||
|
"en": "RTK - CLI proxy to reduce LLM token consumption",
|
||||||
|
},
|
||||||
|
"Language - Change language / Changer la langue": {
|
||||||
"fr": "Langue - Changer la langue / Change language",
|
"fr": "Langue - Changer la langue / Change language",
|
||||||
"en": "Language - Change language / Changer la langue",
|
"en": "Language - Change language / Changer la langue",
|
||||||
},
|
},
|
||||||
|
# Deploy section
|
||||||
|
"Deploy - Deploy ERPLibre locally": {
|
||||||
|
"fr": "Déploiement - Déployer ERPLibre localement",
|
||||||
|
"en": "Deploy - Deploy ERPLibre locally",
|
||||||
|
},
|
||||||
|
"Deploy ERPLibre to a local directory!": {
|
||||||
|
"fr": "Déployer ERPLibre dans un répertoire local!",
|
||||||
|
"en": "Deploy ERPLibre to a local directory!",
|
||||||
|
},
|
||||||
|
"Clone ERPLibre locally (git clone)": {
|
||||||
|
"fr": "Cloner ERPLibre localement (git clone)",
|
||||||
|
"en": "Clone ERPLibre locally (git clone)",
|
||||||
|
},
|
||||||
|
"Target directory path (default: ~/erplibre): ": {
|
||||||
|
"fr": "Chemin du répertoire cible (défaut: ~/erplibre) : ",
|
||||||
|
"en": "Target directory path (default: ~/erplibre): ",
|
||||||
|
},
|
||||||
|
"Directory already exists: ": {
|
||||||
|
"fr": "Le répertoire existe déjà : ",
|
||||||
|
"en": "Directory already exists: ",
|
||||||
|
},
|
||||||
|
"Cloning ERPLibre...": {
|
||||||
|
"fr": "Clonage d'ERPLibre en cours...",
|
||||||
|
"en": "Cloning ERPLibre...",
|
||||||
|
},
|
||||||
|
"ERPLibre cloned successfully to: ": {
|
||||||
|
"fr": "ERPLibre cloné avec succès dans : ",
|
||||||
|
"en": "ERPLibre cloned successfully to: ",
|
||||||
|
},
|
||||||
|
"Error cloning ERPLibre: ": {
|
||||||
|
"fr": "Erreur lors du clonage d'ERPLibre : ",
|
||||||
|
"en": "Error cloning ERPLibre: ",
|
||||||
|
},
|
||||||
|
# RTK (Rust Token Killer)
|
||||||
|
"Manage RTK (Rust Token Killer) for token optimization!": {
|
||||||
|
"fr": "Gérer RTK (Rust Token Killer) pour optimiser les tokens!",
|
||||||
|
"en": "Manage RTK (Rust Token Killer) for token optimization!",
|
||||||
|
},
|
||||||
|
"Install RTK": {
|
||||||
|
"fr": "Installer RTK",
|
||||||
|
"en": "Install RTK",
|
||||||
|
},
|
||||||
|
"Check RTK version": {
|
||||||
|
"fr": "Vérifier la version de RTK",
|
||||||
|
"en": "Check RTK version",
|
||||||
|
},
|
||||||
|
"Show cumulative token savings": {
|
||||||
|
"fr": "Afficher les économies de tokens cumulées",
|
||||||
|
"en": "Show cumulative token savings",
|
||||||
|
},
|
||||||
|
"Discover optimization opportunities": {
|
||||||
|
"fr": "Identifier les opportunités d'optimisation",
|
||||||
|
"en": "Discover optimization opportunities",
|
||||||
|
},
|
||||||
|
"Initialize global auto-rewrite hook": {
|
||||||
|
"fr": "Initialiser le hook auto-rewrite global",
|
||||||
|
"en": "Initialize global auto-rewrite hook",
|
||||||
|
},
|
||||||
|
"Check RTK status": {
|
||||||
|
"fr": "Vérifier le statut de RTK",
|
||||||
|
"en": "Check RTK status",
|
||||||
|
},
|
||||||
|
"RTK is not installed. Use option 1 to install it.": {
|
||||||
|
"fr": "RTK n'est pas installé. Utilisez l'option 1 pour l'installer.",
|
||||||
|
"en": "RTK is not installed. Use option 1 to install it.",
|
||||||
|
},
|
||||||
|
"RTK is installed, version: ": {
|
||||||
|
"fr": "RTK est installé, version : ",
|
||||||
|
"en": "RTK is installed, version: ",
|
||||||
|
},
|
||||||
|
"Global auto-rewrite hook: active": {
|
||||||
|
"fr": "Hook auto-rewrite global : actif",
|
||||||
|
"en": "Global auto-rewrite hook: active",
|
||||||
|
},
|
||||||
|
"Global auto-rewrite hook: inactive": {
|
||||||
|
"fr": "Hook auto-rewrite global : inactif",
|
||||||
|
"en": "Global auto-rewrite hook: inactive",
|
||||||
|
},
|
||||||
|
"Installation method:": {
|
||||||
|
"fr": "Méthode d'installation :",
|
||||||
|
"en": "Installation method:",
|
||||||
|
},
|
||||||
|
"curl - Automatic install script": {
|
||||||
|
"fr": "curl - Script d'installation automatique",
|
||||||
|
"en": "curl - Automatic install script",
|
||||||
|
},
|
||||||
|
"brew - Homebrew (macOS/Linux)": {
|
||||||
|
"fr": "brew - Homebrew (macOS/Linux)",
|
||||||
|
"en": "brew - Homebrew (macOS/Linux)",
|
||||||
|
},
|
||||||
|
"cargo - Build from source (Rust required)": {
|
||||||
|
"fr": "cargo - Compilation depuis les sources (Rust requis)",
|
||||||
|
"en": "cargo - Build from source (Rust required)",
|
||||||
|
},
|
||||||
# Prompts and messages
|
# Prompts and messages
|
||||||
"enter_password": {
|
"Enter your password: ": {
|
||||||
"fr": "Entrez votre mot de passe : ",
|
"fr": "Entrez votre mot de passe : ",
|
||||||
"en": "Enter your password: ",
|
"en": "Enter your password: ",
|
||||||
},
|
},
|
||||||
"ia_prompt": {
|
"Write your question ": {
|
||||||
"fr": "Écrit moi ta question ",
|
"fr": "Écrit moi ta question ",
|
||||||
"en": "Write your question ",
|
"en": "Write your question ",
|
||||||
},
|
},
|
||||||
"new_instance_confirm": {
|
"Do you want a new instance?": {
|
||||||
"fr": "Voulez-vous une nouvelle instance?",
|
"fr": "Voulez-vous une nouvelle instance?",
|
||||||
"en": "Do you want a new instance?",
|
"en": "Do you want a new instance?",
|
||||||
},
|
},
|
||||||
"ssh_port_forwarding": {
|
"SSH port-forwarding": {
|
||||||
"fr": "SSH port-forwarding",
|
"fr": "SSH port-forwarding",
|
||||||
"en": "SSH port-forwarding",
|
"en": "SSH port-forwarding",
|
||||||
},
|
},
|
||||||
"network_performance_request_per_second": {
|
"Network performance request per second": {
|
||||||
"fr": "Performance réseau en requêtes par seconde",
|
"fr": "Performance réseau en requêtes par seconde",
|
||||||
"en": "Network performance request per second",
|
"en": "Network performance request per second",
|
||||||
},
|
},
|
||||||
"setup_queue_job_for_parallelism": {
|
"Setup queue job for parallelism": {
|
||||||
"fr": "Configurer la file d'attente pour l'exécution parallèle",
|
"fr": "Configurer la file d'attente pour l'exécution parallèle",
|
||||||
"en": "Setup queue job for parallelism",
|
"en": "Setup queue job for parallelism",
|
||||||
},
|
},
|
||||||
"choose_database": {
|
"Choose your database": {
|
||||||
"fr": "Choisir sa base de données",
|
"fr": "Choisir sa base de données",
|
||||||
"en": "Choose your database",
|
"en": "Choose your database",
|
||||||
},
|
},
|
||||||
"update_dev": {
|
"Development update": {
|
||||||
"fr": "Mise à jour du développement",
|
"fr": "Mise à jour du développement",
|
||||||
"en": "Development update",
|
"en": "Development update",
|
||||||
},
|
},
|
||||||
"code_need": {
|
"What do you need for development?": {
|
||||||
"fr": "Qu'avez-vous de besoin pour développer?",
|
"fr": "Qu'avez-vous de besoin pour développer?",
|
||||||
"en": "What do you need for development?",
|
"en": "What do you need for development?",
|
||||||
},
|
},
|
||||||
"doc_search": {
|
"Looking for documentation?": {
|
||||||
"fr": "Vous cherchez de la documentation?",
|
"fr": "Vous cherchez de la documentation?",
|
||||||
"en": "Looking for documentation?",
|
"en": "Looking for documentation?",
|
||||||
},
|
},
|
||||||
"db_modify": {
|
"Make changes to databases!": {
|
||||||
"fr": "Faites des modifications sur les bases de données!",
|
"fr": "Faites des modifications sur les bases de données!",
|
||||||
"en": "Make changes to databases!",
|
"en": "Make changes to databases!",
|
||||||
},
|
},
|
||||||
"process_manage": {
|
"Manage execution processes!": {
|
||||||
"fr": "Manipuler les processus d'exécution!",
|
"fr": "Manipuler les processus d'exécution!",
|
||||||
"en": "Manage execution processes!",
|
"en": "Manage execution processes!",
|
||||||
},
|
},
|
||||||
"config_manage": {
|
"Manage ERPLibre and Odoo configuration!": {
|
||||||
"fr": "Manipuler la configuration ERPLibre et Odoo!",
|
"fr": "Manipuler la configuration ERPLibre et Odoo!",
|
||||||
"en": "Manage ERPLibre and Odoo configuration!",
|
"en": "Manage ERPLibre and Odoo configuration!",
|
||||||
},
|
},
|
||||||
"network_tools": {
|
"Network tools!": {
|
||||||
"fr": "Outil réseautique!",
|
"fr": "Outil réseautique!",
|
||||||
"en": "Network tools!",
|
"en": "Network tools!",
|
||||||
},
|
},
|
||||||
"security_audit": {
|
"Dependency security audit!": {
|
||||||
"fr": "Audit de securite des dépendances!",
|
"fr": "Audit de securite des dépendances!",
|
||||||
"en": "Dependency security audit!",
|
"en": "Dependency security audit!",
|
||||||
},
|
},
|
||||||
"script_failed": {
|
"The Bash script failed with return code": {
|
||||||
"fr": "Le script Bash a échoué avec le code de retour",
|
"fr": "Le script Bash a échoué avec le code de retour",
|
||||||
"en": "The Bash script failed with return code",
|
"en": "The Bash script failed with return code",
|
||||||
},
|
},
|
||||||
"no_env_installed": {
|
"No installed environment found. Install an Odoo version first.": {
|
||||||
"fr": "Aucun environnement installe trouve. Installez d'abord une version d'Odoo.",
|
"fr": "Aucun environnement installe trouve. Installez d'abord une version d'Odoo.",
|
||||||
"en": "No installed environment found. Install an Odoo version first.",
|
"en": "No installed environment found. Install an Odoo version first.",
|
||||||
},
|
},
|
||||||
"choose_env_audit": {
|
"Choose an environment for the audit:": {
|
||||||
"fr": "Choisir un environnement pour l'audit :",
|
"fr": "Choisir un environnement pour l'audit :",
|
||||||
"en": "Choose an environment for the audit:",
|
"en": "Choose an environment for the audit:",
|
||||||
},
|
},
|
||||||
"selection": {
|
"Select: ": {
|
||||||
"fr": "Sélection : ",
|
"fr": "Sélection : ",
|
||||||
"en": "Select: ",
|
"en": "Select: ",
|
||||||
},
|
},
|
||||||
"error_value": {
|
"Error, cannot understand value": {
|
||||||
"fr": "Erreur, impossible de comprendre la valeur",
|
"fr": "Erreur, impossible de comprendre la valeur",
|
||||||
"en": "Error, cannot understand value",
|
"en": "Error, cannot understand value",
|
||||||
},
|
},
|
||||||
"dep_file_not_found": {
|
"Dependencies file not found: ": {
|
||||||
"fr": "Fichier de dépendances introuvable : ",
|
"fr": "Fichier de dépendances introuvable : ",
|
||||||
"en": "Dependencies file not found: ",
|
"en": "Dependencies file not found: ",
|
||||||
},
|
},
|
||||||
"execution": {
|
"Execution: ": {
|
||||||
"fr": "Execution : ",
|
"fr": "Execution : ",
|
||||||
"en": "Execution: ",
|
"en": "Execution: ",
|
||||||
},
|
},
|
||||||
"current": {
|
"Current": {
|
||||||
"fr": "Actuel",
|
"fr": "Actuel",
|
||||||
"en": "Current",
|
"en": "Current",
|
||||||
},
|
},
|
||||||
"default": {
|
"Default": {
|
||||||
"fr": "Défaut",
|
"fr": "Défaut",
|
||||||
"en": "Default",
|
"en": "Default",
|
||||||
},
|
},
|
||||||
"reboot_todo": {
|
"Reboot TODO ...": {
|
||||||
"fr": "Reboot TODO ...",
|
"fr": "Reboot TODO ...",
|
||||||
"en": "Reboot TODO ...",
|
"en": "Reboot TODO ...",
|
||||||
},
|
},
|
||||||
"pip_audit_desc": {
|
"pip-audit - Check vulnerabilities on Python environments": {
|
||||||
"fr": "pip-audit - Verifier les vulnérabilités sur les environnements Python",
|
"fr": "pip-audit - Verifier les vulnérabilités sur les environnements Python",
|
||||||
"en": "pip-audit - Check vulnerabilities on Python environments",
|
"en": "pip-audit - Check vulnerabilities on Python environments",
|
||||||
},
|
},
|
||||||
"will_execute": {
|
"Will execute:": {
|
||||||
"fr": "Va exécuter :",
|
"fr": "Va exécuter :",
|
||||||
"en": "Will execute:",
|
"en": "Will execute:",
|
||||||
},
|
},
|
||||||
"choose_version": {
|
"Choose a version:": {
|
||||||
"fr": "Choisir une version :",
|
"fr": "Choisir une version :",
|
||||||
"en": "Choose a version:",
|
"en": "Choose a version:",
|
||||||
},
|
},
|
||||||
"error_cannot_understand": {
|
|
||||||
"fr": "Erreur, impossible de comprendre la valeur",
|
|
||||||
"en": "Error, cannot understand value",
|
|
||||||
},
|
|
||||||
# todo.json translatable prompt_descriptions
|
# todo.json translatable prompt_descriptions
|
||||||
"json_instance_test": {
|
"Test - Minimal base instance": {
|
||||||
"fr": "Test - Instance de base minimale",
|
"fr": "Test - Instance de base minimale",
|
||||||
"en": "Test - Minimal base instance",
|
"en": "Test - Minimal base instance",
|
||||||
},
|
},
|
||||||
"json_robot_minimal": {
|
"Open RobotLibre 🤖 minimal": {
|
||||||
"fr": "Ouvrir RobotLibre 🤖 minimal",
|
"fr": "Ouvrir RobotLibre 🤖 minimal",
|
||||||
"en": "Open RobotLibre 🤖 minimal",
|
"en": "Open RobotLibre 🤖 minimal",
|
||||||
},
|
},
|
||||||
"json_robot_search": {
|
"Open RobotLibre 🤖 with search enabled": {
|
||||||
"fr": "Ouvrir RobotLibre 🤖 en activant la recherche",
|
"fr": "Ouvrir RobotLibre 🤖 en activant la recherche",
|
||||||
"en": "Open RobotLibre 🤖 with search enabled",
|
"en": "Open RobotLibre 🤖 with search enabled",
|
||||||
},
|
},
|
||||||
"json_open_erplibre_todo": {
|
"Open ERPLibre with TODO 🤖": {
|
||||||
"fr": "Ouvrir ERPLibre avec TODO 🤖",
|
"fr": "Ouvrir ERPLibre avec TODO 🤖",
|
||||||
"en": "Open ERPLibre with TODO 🤖",
|
"en": "Open ERPLibre with TODO 🤖",
|
||||||
},
|
},
|
||||||
"json_update_erplibre_base_test": {
|
"Update all erplibre_base on database test": {
|
||||||
"fr": "Mise à jour de tous les erplibre_base sur la base de données test",
|
"fr": "Mise à jour de tous les erplibre_base sur la base de données test",
|
||||||
"en": "Update all erplibre_base on database test",
|
"en": "Update all erplibre_base on database test",
|
||||||
},
|
},
|
||||||
"json_show_code_status": {
|
"Show code status": {
|
||||||
"fr": "Afficher le statut du code",
|
"fr": "Afficher le statut du code",
|
||||||
"en": "Show code status",
|
"en": "Show code status",
|
||||||
},
|
},
|
||||||
"json_stash_all_code": {
|
"Stash all code": {
|
||||||
"fr": "Remiser tout le code",
|
"fr": "Remiser tout le code",
|
||||||
"en": "Stash all code",
|
"en": "Stash all code",
|
||||||
},
|
},
|
||||||
"json_format_modified_code": {
|
"Format modified code": {
|
||||||
"fr": "Formater le code modifié",
|
"fr": "Formater le code modifié",
|
||||||
"en": "Format modified code",
|
"en": "Format modified code",
|
||||||
},
|
},
|
||||||
# todo.py hardcoded prompt_descriptions
|
# todo.py hardcoded prompt_descriptions
|
||||||
"mobile_compile_run": {
|
"Mobile - Compile and run software": {
|
||||||
"fr": "Mobile - Compiler et exécuter le logiciel",
|
"fr": "Mobile - Compiler et exécuter le logiciel",
|
||||||
"en": "Mobile - Compile and run software",
|
"en": "Mobile - Compile and run software",
|
||||||
},
|
},
|
||||||
"upgrade_odoo_migration": {
|
"Upgrade Odoo - Migration Database": {
|
||||||
"fr": "Mise à jour Odoo - Migration de base de données",
|
"fr": "Mise à jour Odoo - Migration de base de données",
|
||||||
"en": "Upgrade Odoo - Migration Database",
|
"en": "Upgrade Odoo - Migration Database",
|
||||||
},
|
},
|
||||||
"upgrade_poetry_dependency": {
|
"Upgrade Poetry - Dependency of Odoo": {
|
||||||
"fr": "Mise à jour Poetry - Dépendances d'Odoo",
|
"fr": "Mise à jour Poetry - Dépendances d'Odoo",
|
||||||
"en": "Upgrade Poetry - Dependency of Odoo",
|
"en": "Upgrade Poetry - Dependency of Odoo",
|
||||||
},
|
},
|
||||||
"open_shell": {
|
"Open SHELL": {
|
||||||
"fr": "Ouvrir le SHELL",
|
"fr": "Ouvrir le SHELL",
|
||||||
"en": "Open SHELL",
|
"en": "Open SHELL",
|
||||||
},
|
},
|
||||||
"upgrade_module": {
|
"Upgrade Module": {
|
||||||
"fr": "Mise à jour de module",
|
"fr": "Mise à jour de module",
|
||||||
"en": "Upgrade Module",
|
"en": "Upgrade Module",
|
||||||
},
|
},
|
||||||
"debug": {
|
"Debug": {
|
||||||
"fr": "Débogage",
|
"fr": "Débogage",
|
||||||
"en": "Debug",
|
"en": "Debug",
|
||||||
},
|
},
|
||||||
"migration_module_coverage": {
|
"Migration module coverage": {
|
||||||
"fr": "Couverture de migration des modules",
|
"fr": "Couverture de migration des modules",
|
||||||
"en": "Migration module coverage",
|
"en": "Migration module coverage",
|
||||||
},
|
},
|
||||||
"what_change_between_version": {
|
"What change between version": {
|
||||||
"fr": "Quels changements entre les versions",
|
"fr": "Quels changements entre les versions",
|
||||||
"en": "What change between version",
|
"en": "What change between version",
|
||||||
},
|
},
|
||||||
"oca_guidelines": {
|
"OCA guidelines": {
|
||||||
"fr": "Directives OCA",
|
"fr": "Directives OCA",
|
||||||
"en": "OCA guidelines",
|
"en": "OCA guidelines",
|
||||||
},
|
},
|
||||||
"oca_migration_odoo_19": {
|
"OCA migration Odoo 19 milestone": {
|
||||||
"fr": "Migration OCA Odoo 19 - Jalons",
|
"fr": "Migration OCA Odoo 19 - Jalons",
|
||||||
"en": "OCA migration Odoo 19 milestone",
|
"en": "OCA migration Odoo 19 milestone",
|
||||||
},
|
},
|
||||||
"download_db_backup": {
|
"Download database to create backup (.zip)": {
|
||||||
"fr": "Télécharger une base de données pour créer une sauvegarde (.zip)",
|
"fr": "Télécharger une base de données pour créer une sauvegarde (.zip)",
|
||||||
"en": "Download database to create backup (.zip)",
|
"en": "Download database to create backup (.zip)",
|
||||||
},
|
},
|
||||||
"restore_from_backup": {
|
"Restore from backup (.zip)": {
|
||||||
"fr": "Restaurer a partir d'une sauvegarde (.zip)",
|
"fr": "Restaurer a partir d'une sauvegarde (.zip)",
|
||||||
"en": "Restore from backup (.zip)",
|
"en": "Restore from backup (.zip)",
|
||||||
},
|
},
|
||||||
"create_backup": {
|
"Create backup (.zip)": {
|
||||||
"fr": "Créer une sauvegarde (.zip)",
|
"fr": "Créer une sauvegarde (.zip)",
|
||||||
"en": "Create backup (.zip)",
|
"en": "Create backup (.zip)",
|
||||||
},
|
},
|
||||||
"kill_process_port": {
|
"Kill Odoo process from actual port": {
|
||||||
"fr": "Terminer le processus Odoo du port actuel",
|
"fr": "Terminer le processus Odoo du port actuel",
|
||||||
"en": "Kill Odoo process from actual port",
|
"en": "Kill Odoo process from actual port",
|
||||||
},
|
},
|
||||||
"kill_git_daemon": {
|
"Kill git daemon server process": {
|
||||||
"fr": "Terminer le processus du serveur git daemon",
|
"fr": "Terminer le processus du serveur git daemon",
|
||||||
"en": "Kill git daemon server process",
|
"en": "Kill git daemon server process",
|
||||||
},
|
},
|
||||||
"kill_git_daemon_done": {
|
"Git daemon process killed.": {
|
||||||
"fr": "Processus git daemon terminé.",
|
"fr": "Processus git daemon terminé.",
|
||||||
"en": "Git daemon process killed.",
|
"en": "Git daemon process killed.",
|
||||||
},
|
},
|
||||||
"generate_all_config": {
|
"Generate all configuration": {
|
||||||
"fr": "Générer toute la configuration",
|
"fr": "Générer toute la configuration",
|
||||||
"en": "Generate all configuration",
|
"en": "Generate all configuration",
|
||||||
},
|
},
|
||||||
"generate_from_preconfig": {
|
"Generate from pre-configuration": {
|
||||||
"fr": "Générer a partir de la pre-configuration",
|
"fr": "Générer a partir de la pre-configuration",
|
||||||
"en": "Generate from pre-configuration",
|
"en": "Generate from pre-configuration",
|
||||||
},
|
},
|
||||||
"generate_from_backup": {
|
"Generate from backup file": {
|
||||||
"fr": "Générer a partir d'un fichier de sauvegarde",
|
"fr": "Générer a partir d'un fichier de sauvegarde",
|
||||||
"en": "Generate from backup file",
|
"en": "Generate from backup file",
|
||||||
},
|
},
|
||||||
"generate_from_database": {
|
"Generate from database": {
|
||||||
"fr": "Générer a partir de la base de données",
|
"fr": "Générer a partir de la base de données",
|
||||||
"en": "Generate from database",
|
"en": "Generate from database",
|
||||||
},
|
},
|
||||||
"preconfig_base": {
|
"base": {
|
||||||
"fr": "base",
|
"fr": "base",
|
||||||
"en": "base",
|
"en": "base",
|
||||||
},
|
},
|
||||||
"preconfig_base_code_generator": {
|
"base + code_generator": {
|
||||||
"fr": "base + code_generator",
|
"fr": "base + code_generator",
|
||||||
"en": "base + code_generator",
|
"en": "base + code_generator",
|
||||||
},
|
},
|
||||||
"preconfig_base_image_db": {
|
"base + image_db": {
|
||||||
"fr": "base + image_db",
|
"fr": "base + image_db",
|
||||||
"en": "base + image_db",
|
"en": "base + image_db",
|
||||||
},
|
},
|
||||||
"preconfig_all": {
|
"all": {
|
||||||
"fr": "tout",
|
"fr": "tout",
|
||||||
"en": "all",
|
"en": "all",
|
||||||
},
|
},
|
||||||
"debug_todo_py": {
|
"Debug todo.py": {
|
||||||
"fr": "Débogage todo.py",
|
"fr": "Débogage todo.py",
|
||||||
"en": "Debug todo.py",
|
"en": "Debug todo.py",
|
||||||
},
|
},
|
||||||
# Test section
|
# Test section
|
||||||
"menu_test": {
|
"Test - Test an Odoo module": {
|
||||||
"fr": "Test - Tester un module Odoo",
|
"fr": "Test - Tester un module Odoo",
|
||||||
"en": "Test - Test an Odoo module",
|
"en": "Test - Test an Odoo module",
|
||||||
},
|
},
|
||||||
"test_description": {
|
"Test an Odoo module on a temporary database!": {
|
||||||
"fr": "Tester un module Odoo sur une base de données temporaire!",
|
"fr": "Tester un module Odoo sur une base de données temporaire!",
|
||||||
"en": "Test an Odoo module on a temporary database!",
|
"en": "Test an Odoo module on a temporary database!",
|
||||||
},
|
},
|
||||||
"test_run_module": {
|
"Test a module": {
|
||||||
"fr": "Tester un module",
|
"fr": "Tester un module",
|
||||||
"en": "Test a module",
|
"en": "Test a module",
|
||||||
},
|
},
|
||||||
"test_run_module_coverage": {
|
"Test a module with code coverage": {
|
||||||
"fr": "Tester un module avec couverture de code",
|
"fr": "Tester un module avec couverture de code",
|
||||||
"en": "Test a module with code coverage",
|
"en": "Test a module with code coverage",
|
||||||
},
|
},
|
||||||
"test_run_unit_tests": {
|
"ERPLibre unit tests": {
|
||||||
"fr": "Tests unitaires ERPLibre",
|
"fr": "Tests unitaires ERPLibre",
|
||||||
"en": "ERPLibre unit tests",
|
"en": "ERPLibre unit tests",
|
||||||
},
|
},
|
||||||
"test_unit_running": {
|
"Running unit tests": {
|
||||||
"fr": "Exécution des tests unitaires",
|
"fr": "Exécution des tests unitaires",
|
||||||
"en": "Running unit tests",
|
"en": "Running unit tests",
|
||||||
},
|
},
|
||||||
"test_unit_success": {
|
"All unit tests passed": {
|
||||||
"fr": "Tous les tests unitaires ont réussi",
|
"fr": "Tous les tests unitaires ont réussi",
|
||||||
"en": "All unit tests passed",
|
"en": "All unit tests passed",
|
||||||
},
|
},
|
||||||
"test_unit_failed": {
|
"Some unit tests failed, exit code": {
|
||||||
"fr": "Des tests unitaires ont échoué, code de sortie",
|
"fr": "Des tests unitaires ont échoué, code de sortie",
|
||||||
"en": "Some unit tests failed, exit code",
|
"en": "Some unit tests failed, exit code",
|
||||||
},
|
},
|
||||||
"test_enter_module_name": {
|
"Module name to test: ": {
|
||||||
"fr": "Nom du module à tester : ",
|
"fr": "Nom du module à tester : ",
|
||||||
"en": "Module name to test: ",
|
"en": "Module name to test: ",
|
||||||
},
|
},
|
||||||
"test_db_name": {
|
"Temporary database name (default: test_todo_tmp): ": {
|
||||||
"fr": "Nom de la base de données temporaire (défaut: test_todo_tmp) : ",
|
"fr": "Nom de la base de données temporaire (défaut: test_todo_tmp) : ",
|
||||||
"en": "Temporary database name (default: test_todo_tmp): ",
|
"en": "Temporary database name (default: test_todo_tmp): ",
|
||||||
},
|
},
|
||||||
"test_install_extra_modules": {
|
"Extra modules to install (comma-separated, empty for none): ": {
|
||||||
"fr": "Modules supplémentaires à installer (séparés par des virgules, vide pour aucun) : ",
|
"fr": "Modules supplémentaires à installer (séparés par des virgules, vide pour aucun) : ",
|
||||||
"en": "Extra modules to install (comma-separated, empty for none): ",
|
"en": "Extra modules to install (comma-separated, empty for none): ",
|
||||||
},
|
},
|
||||||
"test_log_level": {
|
"Log level (default: test): ": {
|
||||||
"fr": "Niveau de log (défaut: test) : ",
|
"fr": "Niveau de log (défaut: test) : ",
|
||||||
"en": "Log level (default: test): ",
|
"en": "Log level (default: test): ",
|
||||||
},
|
},
|
||||||
"test_creating_db": {
|
"Creating temporary database": {
|
||||||
"fr": "Création de la base de données temporaire",
|
"fr": "Création de la base de données temporaire",
|
||||||
"en": "Creating temporary database",
|
"en": "Creating temporary database",
|
||||||
},
|
},
|
||||||
"test_installing_modules": {
|
"Installing modules": {
|
||||||
"fr": "Installation des modules",
|
"fr": "Installation des modules",
|
||||||
"en": "Installing modules",
|
"en": "Installing modules",
|
||||||
},
|
},
|
||||||
"test_running": {
|
"Running tests": {
|
||||||
"fr": "Exécution des tests",
|
"fr": "Exécution des tests",
|
||||||
"en": "Running tests",
|
"en": "Running tests",
|
||||||
},
|
},
|
||||||
"test_cleaning_db": {
|
"Cleaning up temporary database": {
|
||||||
"fr": "Suppression de la base de données temporaire",
|
"fr": "Suppression de la base de données temporaire",
|
||||||
"en": "Cleaning up temporary database",
|
"en": "Cleaning up temporary database",
|
||||||
},
|
},
|
||||||
"test_keep_db": {
|
"Keep the temporary database? (y/N): ": {
|
||||||
"fr": "Conserver la base de données temporaire? (o/N) : ",
|
"fr": "Conserver la base de données temporaire? (o/N) : ",
|
||||||
"en": "Keep the temporary database? (y/N): ",
|
"en": "Keep the temporary database? (y/N): ",
|
||||||
},
|
},
|
||||||
"test_db_kept": {
|
"Database kept": {
|
||||||
"fr": "Base de données conservée",
|
"fr": "Base de données conservée",
|
||||||
"en": "Database kept",
|
"en": "Database kept",
|
||||||
},
|
},
|
||||||
"test_success": {
|
"Tests completed successfully!": {
|
||||||
"fr": "Tests terminés avec succès!",
|
"fr": "Tests terminés avec succès!",
|
||||||
"en": "Tests completed successfully!",
|
"en": "Tests completed successfully!",
|
||||||
},
|
},
|
||||||
"test_failed": {
|
"Tests failed with return code": {
|
||||||
"fr": "Les tests ont échoué avec le code de retour",
|
"fr": "Les tests ont échoué avec le code de retour",
|
||||||
"en": "Tests failed with return code",
|
"en": "Tests failed with return code",
|
||||||
},
|
},
|
||||||
"test_module_required": {
|
"Module name is required!": {
|
||||||
"fr": "Le nom du module est requis!",
|
"fr": "Le nom du module est requis!",
|
||||||
"en": "Module name is required!",
|
"en": "Module name is required!",
|
||||||
},
|
},
|
||||||
# Git section
|
# Git section
|
||||||
"menu_git": {
|
"Git - Git tools": {
|
||||||
"fr": "Git - Outils Git",
|
"fr": "Git - Outils Git",
|
||||||
"en": "Git - Git tools",
|
"en": "Git - Git tools",
|
||||||
},
|
},
|
||||||
"git_manage": {
|
"Git management tools!": {
|
||||||
"fr": "Outils de gestion Git!",
|
"fr": "Outils de gestion Git!",
|
||||||
"en": "Git management tools!",
|
"en": "Git management tools!",
|
||||||
},
|
},
|
||||||
"git_local_server": {
|
"Local git server": {
|
||||||
"fr": "Serveur git local",
|
"fr": "Serveur git local",
|
||||||
"en": "Local git server",
|
"en": "Local git server",
|
||||||
},
|
},
|
||||||
"git_repo_manage": {
|
"Manage local git repository server!": {
|
||||||
"fr": "Gérer le serveur de dépôts git local!",
|
"fr": "Gérer le serveur de dépôts git local!",
|
||||||
"en": "Manage local git repository server!",
|
"en": "Manage local git repository server!",
|
||||||
},
|
},
|
||||||
"git_repo_deploy_local": {
|
"Deploy a local git server (~/.git-server)": {
|
||||||
"fr": "Déployer un serveur git local (~/.git-server)",
|
"fr": "Déployer un serveur git local (~/.git-server)",
|
||||||
"en": "Deploy a local git server (~/.git-server)",
|
"en": "Deploy a local git server (~/.git-server)",
|
||||||
},
|
},
|
||||||
"git_repo_deploy_production": {
|
"Deploy a production git server (/srv/git, root required)": {
|
||||||
"fr": "Déployer un serveur git production (/srv/git, root requis)",
|
"fr": "Déployer un serveur git production (/srv/git, root requis)",
|
||||||
"en": "Deploy a production git server (/srv/git, root required)",
|
"en": "Deploy a production git server (/srv/git, root required)",
|
||||||
},
|
},
|
||||||
"git_repo_deploy_starting": {
|
"Starting git server deployment...": {
|
||||||
"fr": "Démarrage du déploiement du serveur git...",
|
"fr": "Démarrage du déploiement du serveur git...",
|
||||||
"en": "Starting git server deployment...",
|
"en": "Starting git server deployment...",
|
||||||
},
|
},
|
||||||
"git_mode_local": {
|
"Local mode (~/.git-server)": {
|
||||||
"fr": "Mode local (~/.git-server)",
|
"fr": "Mode local (~/.git-server)",
|
||||||
"en": "Local mode (~/.git-server)",
|
"en": "Local mode (~/.git-server)",
|
||||||
},
|
},
|
||||||
"git_mode_production": {
|
"Production mode (/srv/git, root required)": {
|
||||||
"fr": "Mode production (/srv/git, root requis)",
|
"fr": "Mode production (/srv/git, root requis)",
|
||||||
"en": "Production mode (/srv/git, root required)",
|
"en": "Production mode (/srv/git, root required)",
|
||||||
},
|
},
|
||||||
"git_action_all": {
|
"Run all (init + remote + push + serve)": {
|
||||||
"fr": "Tout exécuter (init + remote + push + serve)",
|
"fr": "Tout exécuter (init + remote + push + serve)",
|
||||||
"en": "Run all (init + remote + push + serve)",
|
"en": "Run all (init + remote + push + serve)",
|
||||||
},
|
},
|
||||||
"git_action_init": {
|
"Init - Create bare repos": {
|
||||||
"fr": "Init - Créer les bare repos",
|
"fr": "Init - Créer les bare repos",
|
||||||
"en": "Init - Create bare repos",
|
"en": "Init - Create bare repos",
|
||||||
},
|
},
|
||||||
"git_action_remote": {
|
"Remote - Add local remotes": {
|
||||||
"fr": "Remote - Ajouter les remotes locaux",
|
"fr": "Remote - Ajouter les remotes locaux",
|
||||||
"en": "Remote - Add local remotes",
|
"en": "Remote - Add local remotes",
|
||||||
},
|
},
|
||||||
"git_action_push": {
|
"Push - Push to local server": {
|
||||||
"fr": "Push - Pousser vers le serveur local",
|
"fr": "Push - Pousser vers le serveur local",
|
||||||
"en": "Push - Push to local server",
|
"en": "Push - Push to local server",
|
||||||
},
|
},
|
||||||
"git_action_serve": {
|
"Serve - Start git daemon": {
|
||||||
"fr": "Serve - Démarrer le daemon git",
|
"fr": "Serve - Démarrer le daemon git",
|
||||||
"en": "Serve - Start git daemon",
|
"en": "Serve - Start git daemon",
|
||||||
},
|
},
|
||||||
|
# Git remote add
|
||||||
|
"Add a remote to a local repository": {
|
||||||
|
"fr": "Ajouter un remote vers un dépôt local",
|
||||||
|
"en": "Add a remote to a local repository",
|
||||||
|
},
|
||||||
|
"Remote name (default: localhost): ": {
|
||||||
|
"fr": "Nom du remote (défaut: localhost) : ",
|
||||||
|
"en": "Remote name (default: localhost): ",
|
||||||
|
},
|
||||||
|
"Repository address (e.g.: git://192.168.1.100/my-repo.git): ": {
|
||||||
|
"fr": "Adresse du dépôt (ex: git://192.168.1.100/mon-repo.git) : ",
|
||||||
|
"en": "Repository address (e.g.: git://192.168.1.100/my-repo.git): ",
|
||||||
|
},
|
||||||
|
"Repository address is required!": {
|
||||||
|
"fr": "L'adresse du dépôt est requise!",
|
||||||
|
"en": "Repository address is required!",
|
||||||
|
},
|
||||||
|
"Remote added successfully!": {
|
||||||
|
"fr": "Remote ajouté avec succès!",
|
||||||
|
"en": "Remote added successfully!",
|
||||||
|
},
|
||||||
|
"Error adding remote: ": {
|
||||||
|
"fr": "Erreur lors de l'ajout du remote : ",
|
||||||
|
"en": "Error adding remote: ",
|
||||||
|
},
|
||||||
|
# Git config vim
|
||||||
|
"Configure git local editor to vim": {
|
||||||
|
"fr": "Configuration git local par vim",
|
||||||
|
"en": "Configure git local editor to vim",
|
||||||
|
},
|
||||||
|
"Git editor configured to vim successfully!": {
|
||||||
|
"fr": "Éditeur git configuré sur vim avec succès!",
|
||||||
|
"en": "Git editor configured to vim successfully!",
|
||||||
|
},
|
||||||
|
"Error during configuration: ": {
|
||||||
|
"fr": "Erreur lors de la configuration : ",
|
||||||
|
"en": "Error during configuration: ",
|
||||||
|
},
|
||||||
|
# GPT code - Claude automation
|
||||||
|
"Add an automation with Claude in todo.py": {
|
||||||
|
"fr": "Ajouter une automatisation avec Claude dans todo.py",
|
||||||
|
"en": "Add an automation with Claude in todo.py",
|
||||||
|
},
|
||||||
|
"Description of the command to add: ": {
|
||||||
|
"fr": "Description de la commande à ajouter : ",
|
||||||
|
"en": "Description of the command to add: ",
|
||||||
|
},
|
||||||
|
"Bash command to execute: ": {
|
||||||
|
"fr": "Commande bash à exécuter : ",
|
||||||
|
"en": "Bash command to execute: ",
|
||||||
|
},
|
||||||
|
"Menu section (git/code/config/network/process): ": {
|
||||||
|
"fr": "Section du menu (git/code/config/network/process) : ",
|
||||||
|
"en": "Menu section (git/code/config/network/process): ",
|
||||||
|
},
|
||||||
|
"Automation added successfully in todo.json!": {
|
||||||
|
"fr": "Automatisation ajoutée avec succès dans todo.json!",
|
||||||
|
"en": "Automation added successfully in todo.json!",
|
||||||
|
},
|
||||||
|
"Error adding automation: ": {
|
||||||
|
"fr": "Erreur lors de l'ajout de l'automatisation : ",
|
||||||
|
"en": "Error adding automation: ",
|
||||||
|
},
|
||||||
# Language selection
|
# Language selection
|
||||||
"lang_prompt": {
|
"Choose language / Choisir la langue": {
|
||||||
"fr": "Choisir la langue / Choose language",
|
"fr": "Choisir la langue / Choose language",
|
||||||
"en": "Choose language / Choisir la langue",
|
"en": "Choose language / Choisir la langue",
|
||||||
},
|
},
|
||||||
"lang_french": {
|
"French": {
|
||||||
"fr": "Francais",
|
"fr": "Francais",
|
||||||
"en": "French",
|
"en": "French",
|
||||||
},
|
},
|
||||||
"lang_english": {
|
"English": {
|
||||||
"fr": "Anglais",
|
"fr": "Anglais",
|
||||||
"en": "English",
|
"en": "English",
|
||||||
},
|
},
|
||||||
"lang_changed": {
|
"Language changed to: English": {
|
||||||
"fr": "Langue changée pour : Francais",
|
"fr": "Langue changée pour : Francais",
|
||||||
"en": "Language changed to: English",
|
"en": "Language changed to: English",
|
||||||
},
|
},
|
||||||
"execution_time": {
|
"TODO execution time": {
|
||||||
"fr": "Temps d'exécution TODO",
|
"fr": "Temps d'exécution TODO",
|
||||||
"en": "TODO execution time",
|
"en": "TODO execution time",
|
||||||
},
|
},
|
||||||
"keyboard_interrupt": {
|
"Keyboard interrupt": {
|
||||||
"fr": "Interruption clavier",
|
"fr": "Interruption clavier",
|
||||||
"en": "Keyboard interrupt",
|
"en": "Keyboard interrupt",
|
||||||
},
|
},
|
||||||
# GPT code section
|
# GPT code section
|
||||||
"menu_gpt_code": {
|
"GPT code - AI assistant tools": {
|
||||||
"fr": "GPT code - Outils d'assistant IA",
|
"fr": "GPT code - Outils d'assistant IA",
|
||||||
"en": "GPT code - AI assistant tools",
|
"en": "GPT code - AI assistant tools",
|
||||||
},
|
},
|
||||||
"gpt_code_manage": {
|
"AI assistant tools for development!": {
|
||||||
"fr": "Outils d'assistant IA pour le développement!",
|
"fr": "Outils d'assistant IA pour le développement!",
|
||||||
"en": "AI assistant tools for development!",
|
"en": "AI assistant tools for development!",
|
||||||
},
|
},
|
||||||
"gpt_code_claude_commit": {
|
"Configure Claude Code configurations": {
|
||||||
"fr": "Configurer le commit Claude Code",
|
"fr": "Configurer les configurations Claude Code",
|
||||||
"en": "Configure Claude Code commit",
|
"en": "Configure Claude Code configurations",
|
||||||
},
|
},
|
||||||
"gpt_code_enter_name": {
|
"Commit - OCA/Odoo commit command": {
|
||||||
|
"fr": "Commit - Commande de commit OCA/Odoo",
|
||||||
|
"en": "Commit - OCA/Odoo commit command",
|
||||||
|
},
|
||||||
|
"Todo Add Command - Add a command to todo.py menu": {
|
||||||
|
"fr": "Todo Add Command - Ajouter une commande au menu todo.py",
|
||||||
|
"en": "Todo Add Command - Add a command to todo.py menu",
|
||||||
|
},
|
||||||
|
"Enter your full name: ": {
|
||||||
"fr": "Entrez votre nom complet : ",
|
"fr": "Entrez votre nom complet : ",
|
||||||
"en": "Enter your full name: ",
|
"en": "Enter your full name: ",
|
||||||
},
|
},
|
||||||
"gpt_code_enter_email": {
|
"Enter your email: ": {
|
||||||
"fr": "Entrez votre courriel : ",
|
"fr": "Entrez votre courriel : ",
|
||||||
"en": "Enter your email: ",
|
"en": "Enter your email: ",
|
||||||
},
|
},
|
||||||
"gpt_code_commit_exists": {
|
"Deploy Claude Code commands!": {
|
||||||
"fr": "Le fichier ~/.claude/commands/commit.md existe déjà. Aucune action effectuée.",
|
"fr": "Déployer les commandes Claude Code!",
|
||||||
"en": "File ~/.claude/commands/commit.md already exists. No action taken.",
|
"en": "Deploy Claude Code commands!",
|
||||||
},
|
},
|
||||||
"gpt_code_commit_created": {
|
"Show installed custom commands": {
|
||||||
"fr": "Fichier ~/.claude/commands/commit.md créé avec succès!",
|
"fr": "Afficher les commandes personnalisées installées",
|
||||||
"en": "File ~/.claude/commands/commit.md created successfully!",
|
"en": "Show installed custom commands",
|
||||||
},
|
},
|
||||||
"gpt_code_commit_error": {
|
"No custom commands found in ~/.claude/commands/": {
|
||||||
|
"fr": "Aucune commande personnalisée trouvée dans ~/.claude/commands/",
|
||||||
|
"en": "No custom commands found in ~/.claude/commands/",
|
||||||
|
},
|
||||||
|
"Claude Code custom commands:": {
|
||||||
|
"fr": "Commandes personnalisées Claude Code :",
|
||||||
|
"en": "Claude Code custom commands:",
|
||||||
|
},
|
||||||
|
"Total:": {
|
||||||
|
"fr": "Total :",
|
||||||
|
"en": "Total:",
|
||||||
|
},
|
||||||
|
"File already exists: ": {
|
||||||
|
"fr": "Le fichier existe déjà : ",
|
||||||
|
"en": "File already exists: ",
|
||||||
|
},
|
||||||
|
"Do you want to overwrite the file? (y/Y): ": {
|
||||||
|
"fr": "Voulez-vous écraser le fichier? (y/Y) : ",
|
||||||
|
"en": "Do you want to overwrite the file? (y/Y): ",
|
||||||
|
},
|
||||||
|
"Nothing to do.": {
|
||||||
|
"fr": "Rien à faire.",
|
||||||
|
"en": "Nothing to do.",
|
||||||
|
},
|
||||||
|
"File created successfully: ": {
|
||||||
|
"fr": "Fichier créé avec succès : ",
|
||||||
|
"en": "File created successfully: ",
|
||||||
|
},
|
||||||
|
"Error creating file: ": {
|
||||||
"fr": "Erreur lors de la création du fichier : ",
|
"fr": "Erreur lors de la création du fichier : ",
|
||||||
"en": "Error creating file: ",
|
"en": "Error creating file: ",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue