addons-cm/tools/pr_bot/README.md
GitHub Copilot d9d9e8be2d
[ADD] ci: Forgejo Actions CI and Claude bots ported from ecocentral
Same system as ecocentral-18 (see its docs/CI-CD.md):

- ci.yml: lint (pre-commit), test (tools/ci/run_tests.py, OCA-style
  two-phase install) and review (PR bot, after lint and test).
- issue-bot.yml: the issue bot answers issues or opens a PR on bot/issue-N.
- pr-bot.yml: review when WIP is removed or the i18n label is added.
- .gitea/issue-bot.md: context for the bots; this repo is shared by
  several clients.

The bot scripts are copies of ecocentral's. Only the defaults differ (repo,
token and state files, i18n languages es,eu,ca,gl) along with the [I18N]
commit message and the references to the runner's sources.txt.

The jobs run on a second forgejo-runner registration (CriptoMart org) on
ecocentral's runner machine, sharing its image, mounts and cache. The
runner files (Dockerfile, update.sh, sources.txt) live in ecocentral.
Specific to this repo:

- ODOO_SRC_SKIP: the runner's /odoo-src/18.0 holds a clone of addons-cm,
  so test skips it and checks the PR checkout instead.
- BOT_BASE_BRANCH "18.0": the repo's default branch is 16.0.
- test PostgreSQL on port 54330: ecocentral's runs on 54329 and a test job
  from each repo can run at the same time.

The lint job fails until the repo is cleaned up with
pre-commit run --all-files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:34:58 +02:00

115 lines
6 KiB
Markdown

# 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/<commit>/`).
2. Pone al día `i18n/<addon>.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] <addons>: …`.
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` |