Skip to content

chore(ti/licenciamiento): etapa oneshot con dos jobs manuales para...

Rafael Bautista requested to merge ti into qa

chore(ti/licenciamiento): etapa oneshot con dos jobs manuales para materializar en qa la hoja que la vista dejo de leer en vivo

QUE ES ESTO, EN UNA LINEA Un boton en el pipeline que escribe en ti_licencias de QA exactamente los mismos datos que la vista de Licenciamiento ya venia mostrando — no una fuente nueva, no un sync recurrente, no un cambio de contrato.

POR QUE HACE FALTA Hasta 375ec704 ("la vista lee la tabla y gana captura; se retira la hoja") el endpoint de Licenciamiento leia la pestaña "Licencias" del libro "Data KPIS Infraestructura" EN VIVO, en cada request, y agregaba en memoria. Ese commit invirtio la direccion: la verdad pasa a vivir en la tabla ti_licencias y la hoja se abandona, para que el modulo gane captura propia (CRUD + RBAC) en vez de depender de que alguien edite un Google Sheet.

La consecuencia operativa no se cubrio. Base.metadata.create_all crea ti_licencias VACIA al arrancar el backend, y nada en .gitlab-ci.yml la puebla: el deploy solo corre backend/migrations/run.sh y scripts/backfill_canonicals.py. En QA eso deja GET /api/ti/licencias/dashboard/stats respondiendo 200 con total: 0 — verificado en Network: la pantalla monta bien, el RBAC pasa, la ruta existe, y no hay un solo renglon que pintar. En local la misma carga si se hizo y la tabla tiene 1,252 filas, todas origen='sheet'.

QUE NO ES No introduce una dependencia nueva de Google. Es el MISMO spreadsheet id (1YbiNC5lAKDhf2wJWBNwg7Q8Oj0HU_Frljp78h79Ce4I), la MISMA cuenta de servicio (backend/service_account.json, que deploy_qa ya preserva via git clean -e), el MISMO scope de solo lectura y las MISMAS filas que el endpoint viejo leia en cada request. Lo unico que cambia es CUANDO se lee — una vez, a mano, en vez de en cada peticion — y DONDE aterriza: una tabla persistente en vez de un dict que moria con la respuesta HTTP.

Tampoco toca el esquema. Cero DDL, cero migracion, cero cambio de modelo, cero cambio de router o de front. El unico archivo tocado es .gitlab-ci.yml.

POR QUE MANUAL Y NO UN PASO DE deploy_qa La carga es one-shot por diseño. Colgarla del deploy la convertiria en un sync que re-lee Google en cada despliegue, que es exactamente lo contrario de lo que 375ec704 decidio. El operador aprieta el boton una vez y despues el bloque se borra.

POR QUE LA ETAPA oneshot Y NO LA ETAPA deploy Un job en la misma etapa que deploy_qa correria en paralelo con el. La carga tiene que ocurrir DESPUES de que docker compose up --build levanto el backend nuevo, porque es ese arranque el que garantiza —via create_all— que la tabla destino existe. Una etapa posterior serializa eso sin depender de needs:.

POR QUE SIN LA LLAVE environment: El job no despliega: no cambia la version corriendo, no debe aparecer en el historial de deployments del entorno qa ni marcarlo como re-desplegado. Como efecto lateral util, omitirla lo saca del gate de Protected Environments, que solo deja disparar a usuarios con rol de deployer.

IDEMPOTENCIA — POR CONSTRUCCION, NO POR GUARDA EXTERNA backend/scripts/import_licencias_sheet.py conserva como PK el Id de la columna A de la hoja (entero denso y unico, 1..1252). Re-correrlo ACTUALIZA la fila existente en vez de duplicarla. Ademas:

  • Nunca pisa una fila con origen='portal' ni una dada de baja: si la hoja y el portal difieren, gana el portal, que es la fuente de verdad desde la carga.
  • El cruce de empresa se resuelve EN QA contra empresas_grupo_caabsa via services/empresas_catalogo_lookup.build_canon_index. No se copian empresa_id de otro entorno — seria correcto por casualidad o incorrecto en silencio. Lo que no cruza se queda como empresa_texto y se reporta aparte.
  • La columna PORTAFOLIO de la hoja se ignora a proposito: trae taxonomia CCC y la vista usa la del catalogo de /admin.
  • Al terminar reposiciona la secuencia de ti_licencias.id al maximo + 1, sin lo cual la primera alta desde el formulario chocaria con la PK.

Por eso apply no lleva guarda de "solo si la tabla esta vacia": una guarda asi impediria un reintento legitimo si la primera corrida fallara a la mitad, y no aporta seguridad que el script no de ya.

LOS DOS JOBS licencias_import_qa_dryrun — allow_failure: true. Imprime el conteo previo y corre el script con --dry-run: reporta altas, actualizaciones, cuantas filas cruzan contra el catalogo de QA y cuales traen campos criticos vacios. NO escribe. Puede fallar sin ensuciar el pipeline. licencias_import_qa_apply — allow_failure: false. Conteo previo, carga, y conteo posterior agrupado por origen para que el log deje constancia del antes y el despues en vez de terminar mudo.

Ambos con when: manual bajo rules: y acotados a $CI_COMMIT_BRANCH == "qa", asi que no existen en pipelines de merge request ni en main.

RETIRO Estos dos jobs, la etapa oneshot y el script se borran en el commit siguiente a la carga, como pide el docstring del propio script. Ese mismo commit lleva el bloque equivalente para deploy_prod —donde el contenedor es caabsa_postgres y el compose es docker-compose.yml—, porque main sigue en c85a6b6a (20 de agosto) y va a toparse con la tabla vacia en cuanto qa llegue ahi.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

Merge request reports

Loading