Modelo de versiones
YY.M.patch.build-type, donde YY es el año con dos dígitos, M es el mes de lanzamiento (sin cero a la izquierda), patch es el número de parche dentro de la rama, build es un número de compilación que aumenta de forma monotónica y type es stable o lts.
Ejemplo: 25.3.8.23-lts — LTS de marzo de 2025, parche 8, compilación 23.
Hay dos líneas de versiones:
- Las versiones estables se publican aproximadamente una vez al mes. Las tres versiones estables más recientes reciben parches, lo que supone aproximadamente tres meses de soporte activo por versión.
- Las versiones LTS (Long-Term Support) se publican en marzo y agosto de cada año. Se admiten simultáneamente dos versiones LTS, cada una durante al menos 12 meses.
Política de backport
- Correcciones de seguridad — siempre se incluyen en backport.
- Correcciones de errores críticos (exceptions (errores lógicos), pérdida de datos, resultados incorrectos, problemas de RBAC) — se seleccionan automáticamente para backport según las reglas generales; se identifican con la etiqueta
pr-critical-bugfix, que hace quepr-must-backportse añada automáticamente. - Correcciones de estabilidad y regresiones — se llevan a backport cuando el riesgo del cambio es bajo en comparación con el riesgo de dejar el error sin corregir; se identifican con
pr-must-backport, añadida manualmente por los mantenedores. - Correcciones de errores menores con una solución alternativa disponible — por lo general, no se incluyen en backport para evitar desestabilizar las ramas de lanzamiento.
- Nuevas funcionalidades, mejoras y trabajo de rendimiento — no se llevan a backport.
pr-must-backport es la anulación manual que usan los mantenedores para marcar una PR para backport. La etiqueta pr-critical-bugfix hace que pr-must-backport se añada automáticamente mediante el hook de CI (consulta pr_labels_and_category.py).
Escalado de conflictos. Cuando el backport automático no puede resolver conflictos de merge, igualmente debe crearse una PR de cherry-pick y asignarse al autor, a quien hizo el merge y a los asignados existentes de la PR original para que una persona pueda resolver los conflictos y completar el backport.
Herramienta de backport
tests/ci/cherry_pick.py. La herramienta se ejecuta como un flujo de trabajo de GitHub Actions en la infraestructura de ClickHouse y cubre todos los requisitos: detectar las ramas de lanzamiento activas, seleccionar los PR aptos para backport, realizar el procedimiento de cherry-pick y backport en dos fases, gestionar conflictos, aplicar la política de demora y mantener las etiquetas sincronizadas.
El objetivo a largo plazo es extraer esta implementación y convertirla en una herramienta independiente de Python de código abierto que otros proyectos puedan adoptar. El diseño previsto es:
- Configurable — todos los parámetros de la política (etiquetas válidas, ventana de demora, umbrales de PR obsoletos, comportamiento durante el rolling-out, etc.) se expresan en un archivo de configuración para que la herramienta pueda adaptarse a los requisitos de backport de cualquier proyecto sin necesidad de cambiar el código.
- Distribuible — empaquetada como un wheel de Python autocontenido e instalable desde PyPI, sin depender de la infraestructura de CI de ClickHouse.
- Programable — expone un modelo de objetos claro para pull requests, etiquetas y ramas de lanzamiento, de modo que los usuarios puedan crear flujos de trabajo personalizados sobre el motor principal.
Pruebas
- un conjunto configurable de ramas que representan líneas de versión,
- pull requests con varias combinaciones de etiquetas de backport,
- PR de lanzamiento con la etiqueta
releaseque apuntan a las ramas de lanzamiento.
Ramas de lanzamiento activas
release) sigue abierta en GitHub. La automatización de backport las detecta dinámicamente en cada ejecución, por lo que no es necesario realizar cambios de configuración cuando se crea una nueva versión o una antigua llega al final de su ciclo de vida.
Una rama de lanzamiento puede estar en estado rolling-out (su PR de lanzamiento lleva la etiqueta rolling-out) durante el período en que se está desplegando una nueva versión. Los backports generales se pausan en las ramas en rolling-out para evitar complicar el despliegue. Las etiquetas específicas de versión (por ejemplo, v25.3-must-backport) prevalecen sobre esto y fuerzan el backport incluso durante un despliegue.
Implementación
Descripción general
CherryPick de GitHub Actions (.github/workflows/cherry_pick.yml), implementado en tests/ci/cherry_pick.py. Opera mediante la API de GitHub y operaciones locales de git en un runner style-checker-aarch64 autoalojado.
El proceso consta de dos etapas para cada par (original PR, release branch):
- Se crea una cherry-pick PR para aislar la resolución de conflictos del destino real del merge. Si no hay conflictos, se hace merge automáticamente.
- Se crea una backport PR contra la release branch real, con los cambios del cherry-pick compactados en un único commit.
Etiquetas
Nomenclatura de ramas y PR
N y rama de lanzamiento release/X.Y:
- Rama de cherry-pick:
cherrypick/release/X.Y/N - Rama de backport:
backport/release/X.Y/N - Título del PR de cherry-pick:
Cherry pick #N to release/X.Y: <original title> - Título del PR de backport:
Backport #N to release/X.Y: <original title>
Proceso paso a paso
1. Descubrir las versiones activas
BackportPRs.receive_release_prs consulta GitHub para obtener todos los PR abiertos con la etiqueta release. Las referencias de cabecera de estos PR son los nombres de las ramas de lanzamiento (por ejemplo, release/25.3). A partir de ellas, se deriva un conjunto de etiquetas de compatibilidad: v25.3-must-backport, etc.
2. Encontrar PR para backport
BackportPRs.receive_prs_for_backport usa la API de búsqueda de GitHub para encontrar PR fusionados que:
- tengan al menos una etiqueta de backport (
pr-must-backport,pr-must-backport-force,pr-critical-bugfixo una etiqueta específica de versión), y - no tengan ya
pr-backports-created, y - se hayan fusionado después de la fecha del commit más antiguo encontrada en cualquier rama de lanzamiento, y
- se hayan actualizado en los últimos 90 días (para mantener eficiente la consulta de búsqueda).
3. Gestión de ramas con rolling-out
rolling-out, las etiquetas generales de backport (pr-must-backport, pr-critical-bugfix) no se aplican a esa rama. El bot cierra cualquier PR de cherry-pick o backport creada previamente para esa rama con un comentario explicativo. Una etiqueta específica de versión (por ejemplo, v25.3-must-backport) siempre prevalece sobre esta regla. pr-must-backport-force omite la comprobación de rolling-out para todas las ramas.
4. Etapa de cherry-pick (ReleaseBranch.create_cherrypick)
- Haz checkout de la rama de lanzamiento y crea una rama de backport (
backport/release/X.Y/N) a partir de ella. - Ejecuta
git merge -s ourscontra el primer padre del commit de merge para crear una base de merge sintética sin cambios de contenido. - Fuerza la creación de una rama de cherry-pick (
cherrypick/release/X.Y/N) que apunte directamente al commit de merge del PR original. - Intenta hacer
git merge --no-commit --no-ffde la rama de cherry-pick en la rama de backport:- Si ya está al día, el cambio ya está presente en la rama de lanzamiento — márcalo como completado y omítelo.
- En caso contrario (con o sin conflictos), haz reset y push de ambas ramas.
- Crea el PR de cherry-pick dirigido a
backport/release/X.Y/Ndesdecherrypick/release/X.Y/N, con las etiquetaspr-cherrypickydo not test. - Propaga
pr-bugfixopr-critical-bugfixdesde el PR original, si corresponde. - Las personas asignadas no se establecen en este punto; solo se añaden cuando se detectan conflictos.
5. Fusión automática de los PR de cherry-pick sin conflictos
6. Etapa de backport (ReleaseBranch.create_backport)
- Cambie a la rama de backport y actualícela con
git pull. - Encuentre el merge-base entre la rama de lanzamiento y la rama de backport.
- Ejecute
git reset --softhasta el merge-base, consolidando todos los commits aplicados con cherry-pick en uno solo. - Cree un commit con el título de la PR de backport como mensaje.
- Haga force-push de la rama de backport y abra una PR de backport dirigida a la rama de lanzamiento real.
- Añada a la PR la etiqueta
pr-backport(ypr-bugfix/pr-critical-bugfix, si corresponde). - Asigne la PR al autor de la PR original, a la persona que la fusionó y a las personas ya asignadas (excluyendo las cuentas de bots).
7. Finalización
pr-backports-created al PR original.
8. Comprobación previa
ReleaseBranch.pre_check ejecuta git merge-base --is-ancestor para comprobar que el commit de merge no sea ya alcanzable desde la rama de lanzamiento. Si lo es, la PR se considera ya backporteada y se omite.
Gestión de PR de cherry-pick obsoletos
CherryPickPRs se ejecuta al inicio de cada ejecución horaria y gestiona dos escenarios:
- PR de cherry-pick huérfanos: Si la rama de lanzamiento de un PR de cherry-pick ya no tiene un PR de lanzamiento abierto (es decir, la versión está cerrada), el PR de cherry-pick se cierra automáticamente.
- PR de cherry-pick reabiertos: Si un PR original ya tiene
pr-backports-created, pero un PR de cherry-pick asociado sigue abierto, la etiquetapr-backports-createdse elimina del PR original para que pueda volver a procesarse.
- Después de 3 días sin actualizaciones, el bot publica un comentario de recordatorio mencionando a las personas asignadas.
- Después de 7 días sin actualizaciones, el bot publica un comentario de cierre y cierra el PR.
Resolución de conflictos
cherry-pick tiene conflictos, el PR de cherry-pick se deja abierto para que una persona los resuelva. El bot se lo asigna al autor del PR original, a quien lo fusionó y a las personas asignadas. Después de resolver los conflictos y de fusionar el PR de cherry-pick, el bot crea el PR de backport en la siguiente ejecución horaria.
Para descartar por completo un backport, cierra el PR de cherry-pick. El bot lo considerará omitido intencionalmente.
Para recrear desde cero un PR de cherry-pick dañado:
- Elimina la etiqueta
pr-cherrypickdel PR decherry-pick. - Elimina la rama
cherrypick/.... - Elimina
pr-backports-createddel PR original si está presente.
CI para PR de backport
BackportPR, definido en ci/workflows/backport_branches.py) en lugar del flujo de trabajo estándar para pull requests. Este flujo de trabajo ejecuta un subconjunto representativo de CI: compilaciones con ASan/UBSan y TSan, compilaciones de lanzamiento, compilaciones para macOS, pruebas funcionales con ASan, pruebas de estrés con TSan y pruebas de integración. Valida que la rama de backport tenga entre 1 y 50 commits y al menos un archivo modificado (lo verifica check_backport_branch.py).
Autenticación
ROBOT_CLICKHOUSE_SSH_KEY) para las operaciones de git push. Las llamadas a la API de GitHub se autentican mediante get_best_robot_token, que selecciona el token con más cuota disponible de un conjunto almacenado en SSM (/github-tokens). ROBOT_CLICKHOUSE_COMMIT_TOKEN se usa en el paso de checkout del flujo de trabajo de Actions, no para las llamadas a la API. Las cuentas de robot (robot-clickhouse, clickhouse-gh) se excluyen al asignar la persona responsable.
Caché de la API de GitHub
GitHubCache (de cache_utils.py) guarda de forma persistente la caché de objetos de PyGithub en S3, lo que reduce las llamadas a la API en las ejecuciones horarias. La caché se descarga al inicio y se sube al final de cada ejecución.
Manejo de errores
BackportException. En CI, esto desencadena una notificación a través de CIBuddy en el chat del equipo.