[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>
This commit is contained in:
parent
fad510f69e
commit
d9d9e8be2d
13 changed files with 2154 additions and 0 deletions
115
tools/pr_bot/README.md
Normal file
115
tools/pr_bot/README.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# 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` |
|
||||
Loading…
Add table
Add a link
Reference in a new issue