[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
157
tools/issue_bot/README.md
Normal file
157
tools/issue_bot/README.md
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# Bot de incidencias
|
||||
|
||||
Atiende con Claude las incidencias de `CriptoMart/addons-cm` en Forgejo: responde
|
||||
las preguntas funcionales o de configuración y abre un PR cuando hace falta código.
|
||||
|
||||
- [bot.py](bot.py): orquestador. Habla con la API de Forgejo, prepara un clon
|
||||
limpio, lanza `claude -p` y publica el resultado.
|
||||
- [prompt.md](prompt.md): instrucciones del bot (criterios y tono), comunes a
|
||||
todos los repos.
|
||||
- [../../.gitea/issue-bot.md](../../.gitea/issue-bot.md): qué es este repo
|
||||
(compartido entre clientes) y sus convenciones. Se añade a las instrucciones;
|
||||
es lo único que cambia de un repo a otro.
|
||||
- [../../.gitea/workflows/issue-bot.yml](../../.gitea/workflows/issue-bot.yml):
|
||||
disparo por Actions al abrir o comentar una incidencia.
|
||||
|
||||
## Qué hace con cada incidencia
|
||||
|
||||
Actúa cuando el último mensaje de una incidencia abierta es de una persona:
|
||||
|
||||
| Decisión | Acción |
|
||||
| ------------ | ------------------------------------------------------------ |
|
||||
| `answer` | Comenta la respuesta |
|
||||
| `needs_info` | Comenta pidiendo los datos que faltan |
|
||||
| `code` | Commit en `bot/issue-N`, push, PR contra `18.0` y comentario |
|
||||
| `none` | Nada |
|
||||
|
||||
No actúa sobre PR, incidencias cerradas ni las que llevan la etiqueta `no-bot`, y
|
||||
deja de responder tras `BOT_MAX_REPLIES` respuestas en la misma incidencia. Nunca
|
||||
fusiona ni cierra nada.
|
||||
|
||||
Claude trabaja sin el token de Forgejo y sin herramientas web: solo lee el repo y
|
||||
las fuentes de Odoo, edita ficheros y pasa pre-commit. Un cambio que toque
|
||||
`.gitea/`, `tools/ci/`, `tools/issue_bot/` o `tools/pr_bot/` se rechaza.
|
||||
|
||||
Los PR que abre los revisa después el [bot de revisión](../pr_bot/README.md),
|
||||
que comparte con este la imagen del runner, la cuenta y los secretos.
|
||||
|
||||
## Puesta en marcha
|
||||
|
||||
En Forgejo, una vez:
|
||||
|
||||
1. Dar a la cuenta del bot (`claudia_eco`) permiso de escritura en código,
|
||||
incidencias y PR: como colaborador con rol de escritura o desde un equipo
|
||||
propio, no desde el equipo de las personas del cliente.
|
||||
2. Proteger la rama `18.0` exigiendo aprobación, para que solo se fusione tras
|
||||
revisión.
|
||||
3. Crear la etiqueta `no-bot`.
|
||||
|
||||
### Con Actions
|
||||
|
||||
Los jobs corren en la máquina del runner de ecocentral, con su imagen (Claude
|
||||
Code, pre-commit, dependencias de Odoo 18 y Chromium) y sus montajes: las
|
||||
fuentes de Odoo/OCA en `/odoo-src` y la caché `issue-bot-cache`. Cómo se monta
|
||||
y se mantiene (`Dockerfile`, `update.sh`, `sources.txt`, `runner-config.yml`,
|
||||
cron semanal) está documentado en el `tools/issue_bot/README.md` de ecocentral,
|
||||
y sus ficheros viven allí: aquí no hay copia, para no tener dos listas de
|
||||
fuentes para una misma máquina.
|
||||
|
||||
Un runner de Forgejo solo atiende el ámbito en el que se registra, y este repo
|
||||
(organización `CriptoMart`) y el de ecocentral (`Ecocentral`) están en
|
||||
organizaciones distintas. Por eso en esa máquina hay un segundo registro,
|
||||
hecho en la organización `CriptoMart`, que comparte imagen, montajes y caché
|
||||
con el de ecocentral:
|
||||
|
||||
1. Con el usuario `runner`, una carpeta propia para el segundo daemon, con una
|
||||
copia del `runner-config.yml` de ecocentral (misma etiqueta, `network: host`,
|
||||
montajes, `valid_volumes`, `force_pull: false`, `capacity: 1`):
|
||||
|
||||
```bash
|
||||
mkdir ~/runner-criptomart && cd ~/runner-criptomart
|
||||
cp ~/<carpeta del runner de ecocentral>/runner-config.yml .
|
||||
forgejo-runner register --config runner-config.yml \
|
||||
--instance http://localhost:3000 --token <token> \
|
||||
--name criptomart --labels issue-bot:docker://eco-issue-bot:latest
|
||||
```
|
||||
|
||||
El token sale de los ajustes de Actions de la organización `CriptoMart`
|
||||
(Ajustes → Actions → Runners → Crear nuevo runner).
|
||||
|
||||
2. Un servicio aparte para este daemon (copia de la unidad de systemd del de
|
||||
ecocentral con `WorkingDirectory=` en `~/runner-criptomart` y
|
||||
`forgejo-runner daemon --config runner-config.yml`), y arrancarlo.
|
||||
|
||||
3. Activar Actions en el repo.
|
||||
|
||||
4. Secretos del repo: `BOT_FORGEJO_TOKEN` (token de `claudia_eco`) y uno de
|
||||
`ANTHROPIC_API_KEY` o `CLAUDE_CODE_OAUTH_TOKEN` (lo genera
|
||||
`claude setup-token`). Son secretos por repo: no se heredan de ecocentral.
|
||||
|
||||
Cada daemon tiene su `capacity: 1`, así que un job de cada repo puede correr a
|
||||
la vez. Por eso el PostgreSQL del job `test` de aquí escucha en el `54330` y no
|
||||
en el `54329` de ecocentral. Los dos comparten la caché `issue-bot-cache`
|
||||
(entornos de pre-commit y los `.pot` del bot de revisión, que van por commit).
|
||||
|
||||
### Tests del CI
|
||||
|
||||
En cada PR contra `18.0`, y en cada push a esa rama, el job `test` de
|
||||
[ci.yml](../../.gitea/workflows/ci.yml) lanza
|
||||
[../ci/run_tests.py](../ci/run_tests.py) con el esquema del CI de la OCA: crea
|
||||
una base de datos con las dependencias de los addons y después instala los
|
||||
addons con `--test-enable`, de modo que solo corren los tests del repo.
|
||||
PostgreSQL es un servicio del job, en el puerto 54330 de `127.0.0.1`.
|
||||
|
||||
Odoo arranca desde las fuentes montadas en `/odoo-src/18.0`, así que:
|
||||
|
||||
- Todo repo del que dependa un addon de aquí tiene que estar en la parte
|
||||
`18.0` del `sources.txt` del runner (en ecocentral). Si falta, el job falla
|
||||
diciendo qué módulo no encuentra, en lugar de dejar el addon sin probar.
|
||||
- Una dependencia Python nueva (`external_dependencies`) pide añadirla al
|
||||
`Dockerfile` del runner (en ecocentral).
|
||||
- Ambas cosas llegan al runner al ejecutar `update.sh`, no al fusionar.
|
||||
|
||||
`/odoo-src/18.0` trae también un clon de este repo, porque ecocentral depende
|
||||
de él. El job lo salta (`ODOO_SRC_SKIP: addons-cm` en `ci.yml`) y prueba el
|
||||
checkout del PR.
|
||||
|
||||
Los tests corren contra la OCB y la OCA de la última actualización semanal, no
|
||||
contra commits fijados.
|
||||
|
||||
### Sin Actions (poll)
|
||||
|
||||
En una máquina con `claude` autenticado, `pre-commit` y el token en
|
||||
`~/.config/gitea-addons-cm.token`:
|
||||
|
||||
```bash
|
||||
*/5 * * * * flock -n /tmp/addons-cm-issue-bot.lock python3 /ruta/al/repo/tools/issue_bot/bot.py poll
|
||||
```
|
||||
|
||||
El primer `poll` solo anota la hora: el histórico no se atiende. Para pasar el
|
||||
bot por incidencias ya abiertas:
|
||||
|
||||
```bash
|
||||
python3 tools/issue_bot/bot.py run 12 15 --dry-run # enseña lo que publicaría
|
||||
python3 tools/issue_bot/bot.py run 12 15
|
||||
```
|
||||
|
||||
## Configuración
|
||||
|
||||
| Variable | Por defecto |
|
||||
| ------------------------------------------- | --------------------------------------------- |
|
||||
| `BOT_FORGEJO_URL` | `https://git.criptomart.net` |
|
||||
| `BOT_FORGEJO_REPO` | `CriptoMart/addons-cm` |
|
||||
| `BOT_FORGEJO_TOKEN` / `..._TOKEN_FILE` | `~/.config/gitea-addons-cm.token` |
|
||||
| `BOT_REPO_DIR` (clon propio del bot) | `~/.cache/eco-issue-bot/addons-cm` |
|
||||
| `BOT_BASE_BRANCH` (`18.0` en los workflows) | rama por defecto del repo (`16.0`) |
|
||||
| `BOT_ODOO_SRC` (carpetas separadas por `:`) | `/media/snt/data/odoo` |
|
||||
| `BOT_MODEL` (pide Claude Code ≥ 2.1.280) | `claude-opus-5-5` |
|
||||
| `BOT_MAX_BUDGET_USD` (por incidencia) | `5` |
|
||||
| `BOT_TIMEOUT` (segundos) | `2400` |
|
||||
| `BOT_MAX_REPLIES` | `8` |
|
||||
| `BOT_STATE_FILE` | `~/.local/state/eco-issue-bot/addons-cm/since` |
|
||||
|
||||
`bot.py`, `prompt.md` y los ficheros de [../pr_bot/](../pr_bot/) son copia de
|
||||
los de ecocentral; solo cambian los valores por defecto de esta tabla, el de
|
||||
`BOT_I18N_LANGS`, las referencias al `sources.txt` del runner y el mensaje
|
||||
del commit de traducciones del bot de revisión (`[I18N] …`). Un arreglo en
|
||||
uno de los dos repos se copia tal cual al otro.
|
||||
Loading…
Add table
Add a link
Reference in a new issue