addons-cm/tools/issue_bot
GitHub Copilot 87c2d1d1d3
Some checks failed
CI / lint (pull_request) Successful in 31s
CI / test (pull_request) Failing after 11m29s
CI / review (pull_request) Has been skipped
[IMP] ci: test the ISOLATE addons in their own database
website_sale_disable_cart removes the cart from every website once
installed, which breaks website_membership_signup_required when CI installs
everything together. The repo is shared by clients that never install them
together: run_tests.py now tests each ISOLATE addon in its own database,
after the rest, and ci.yml isolates website_sale_disable_cart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:04:56 +02:00
..
bot.py [ADD] ci: Forgejo Actions CI and Claude bots ported from ecocentral 2026-10-04 14:34:58 +02:00
prompt.md [ADD] ci: Forgejo Actions CI and Claude bots ported from ecocentral 2026-10-04 14:34:58 +02:00
README.md [IMP] ci: test the ISOLATE addons in their own database 2026-10-04 15:04:56 +02:00

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: orquestador. Habla con la API de Forgejo, prepara un clon limpio, lanza claude -p y publica el resultado.
  • prompt.md: instrucciones del bot (criterios y tono), comunes a todos los repos.
  • ../../.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: 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, 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):

    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 lanza ../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.

Los addons de ISOLATE (en ci.yml) se prueban cada uno en su propia base de datos, después del resto: son los que con solo estar instalados cambian el comportamiento de otros addons del repo, que es compartido por clientes que no los instalan juntos. Por ejemplo, website_sale_disable_cart quita el carrito a todos los sitios web.

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:

*/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:

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/ 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.