# Bot de revisión de PR Revisa con Claude los pull requests de `CriptoMart/addons-cm` en Forgejo cuando ya han pasado el linter y los tests, y deja un comentario con lo que encuentra. No aprueba, no bloquea y no fusiona: la decisión sigue siendo de quien revisa. - [review.py](review.py): orquestador. Decide si toca revisar, prepara la cabeza del PR, lanza `claude -p` y publica el comentario. Reutiliza la API de Forgejo, el clon y la llamada a Claude del [bot de incidencias](../issue_bot/bot.py). - [prompt.md](prompt.md): instrucciones de la revisión, comunes a todos los repos. - [i18n.py](i18n.py): prepara y repasa los `.po`. - [../../.gitea/issue-bot.md](../../.gitea/issue-bot.md): qué es este repo y sus convenciones, entre ellas la de idiomas. Es el mismo fichero que usa el bot de incidencias. ## Qué revisa | Parte | Qué busca | | ---------------------- | -------------------------------------------------------------------------------------------------------------- | | Seguridad y permisos | ACL que faltan o sobran, reglas de registro, `sudo()`, métodos públicos, controladores, SQL a mano | | Idiomas y traducciones | Textos en un idioma que no es el del addon o que Odoo no puede traducir (`_()` mal usado) | | Flujos de Odoo | Sobrescrituras, otras entradas al mismo modelo, otros addons que tocan lo mismo, datos que ya hay en producción | Cada hallazgo lleva gravedad (alta, media, baja), fichero y línea, el caso concreto y un arreglo propuesto. Estilo, formato y lo que cubren los tests no entran: de eso ya se han ocupado el linter y el CI. ## Cuándo actúa | Disparo | Dónde | | ------------------------------------------ | ------------------------------------------------------------------------ | | El CI de un PR pasa lint y test | job `review` de [ci.yml](../../.gitea/workflows/ci.yml) (`needs`) | | Se quita la marca WIP o se pone `i18n` | [pr-bot.yml](../../.gitea/workflows/pr-bot.yml), si el CI ya había pasado | Se salta los PR cerrados, los marcados como WIP (`WIP:` o `[WIP]` en el título), los que no van contra `18.0` y los que llevan la etiqueta `no-bot`. Revisa cada commit una sola vez y deja de hacerlo tras `BOT_MAX_REVIEWS` revisiones del mismo PR. Cada revisión nueva sustituye a la anterior: repite lo que sigue vigente y deja fuera lo arreglado. ## Traducciones (etiqueta `i18n`) Por defecto el bot solo revisa los textos. Con la etiqueta `i18n` en el PR, además: 1. Recoge el `.pot` de cada addon que toca el PR. Lo exporta Odoo en el job `test`, cuando los tests pasan, y lo deja en la caché del runner (`BOT_POT_DIR//`). 2. Pone al día `i18n/.pot` y prepara un `.po` por idioma de `BOT_I18N_LANGS` (`es`, `eu`, `ca`, `gl`) con los términos de todo el addon. 3. Claude rellena los `msgstr` vacíos. Un `.po` nuevo que se quede sin ninguna traducción no se crea. 4. Se descartan las traducciones que no conservan los marcadores (`%s`, `%(nombre)s`) del original. 5. El bot sube el resultado a la rama del PR en un commit `[I18N] : …`. Ese commit pasa el CI como cualquier otro, pero no se vuelve a revisar. Poner la etiqueta en un PR ya revisado lanza otra pasada, esta vez con las traducciones. Los addons que el CI no instala (`EXCLUDE` en `ci.yml`) no tienen `.pot` y se quedan como están. Riesgo aceptado: el `.pot` sale de una caché en la que el job `test`, que ejecuta el código del PR, puede escribir. Un test malicioso podría dejar un `.pot` falso para el commit de otro PR, y si ese PR lleva la etiqueta, el bot subiría a su rama términos que no salen de su código. Solo afecta a ficheros `i18n/`, solo con la etiqueta y solo con acceso de escritura al repo, que es privado. Lo de fondo es que todos los jobs comparten `issue-bot-cache`; si algún día entra código menos fiable, el job `test` debería tener su propia caché. ## Puesta en marcha Usa la misma imagen, la misma cuenta (`claudia_eco`) y los mismos secretos que el bot de incidencias: ver su [README](../issue_bot/README.md), que a su vez remite al de ecocentral para el runner. Solo hay que añadir: 1. La etiqueta `i18n` en el repo de Forgejo. 2. La caché que comparten los jobs. Ya está si el runner monta `issue-bot-cache:/root/.cache` como dice el README del runner; los `.pot` van en `/root/.cache/eco-pr-bot/pot` y se borran solos a los 14 días. El job `review` corre con el `review.py` de la propia rama del PR, así que los PR abiertos antes de fusionar este bot no se revisan hasta que incorporen `18.0`. ## A mano En una máquina con `claude` autenticado, `python3-polib` y el token en `~/.config/gitea-addons-cm.token`: ```bash python3 tools/pr_bot/review.py run 217 --dry-run # enseña lo que publicaría python3 tools/pr_bot/review.py run 217 --force # repite un commit ya revisado ``` Sin `--ci-passed` comprueba en Forgejo que el commit tiene lint y test en verde. Fuera del runner no hay `.pot` del CI, así que las traducciones no se tocan aunque el PR lleve la etiqueta. ## Configuración Las variables del bot de incidencias (`BOT_FORGEJO_*`, `BOT_REPO_DIR`, `BOT_ODOO_SRC`, `BOT_MODEL`, `BOT_MAX_BUDGET_USD`, `BOT_TIMEOUT`) valen igual aquí. Propias de este bot: | Variable | Por defecto | | --------------------------------- | --------------------------------------------------- | | `BOT_MAX_REVIEWS` (por PR) | `6` | | `BOT_CI_CONTEXTS` (separados por `,`) | `CI / lint (pull_request),CI / test (pull_request)` | | `BOT_I18N_LABEL` | `i18n` | | `BOT_I18N_LANGS` | `es,eu,ca,gl` | | `BOT_POT_DIR` | `~/.cache/eco-pr-bot/pot` |