Workflows de entrega continua con el modelo de rama por incidencia

¿Ramas prolíficas y entrega continua? Ya lo creo.

Sarah Goff-Dupont Sarah Goff-Dupont

Como he explicado a fondo en "Entrega continua con la potencia extra de Git", el uso extensivo de ramas en el flujo de trabajo de entrega continua es Good Thing™. Ayuda a mantener las ramas más importantes limpias y listas para su publicación, permite a los desarrolladores probar cosas nuevas sin poner trabas a sus compañeros de equipo y, si se hace bien, facilita el seguimiento de proyectos.

Desde hace años, utilizamos un flujo de trabajo con el modelo de rama por incidencia, lo mismo que muchos de nuestros clientes. Hemos incluido el soporte para ello en Jira Software y en las herramientas para desarrolladores de Atlassian para que no solo sea una práctica recomendada, sino también sencilla. Por todo esto, vamos a ver con detalle el modelo de rama por incidencia y cómo encaja con los tres flujos de trabajo de entrega continua más habituales: productos SaaS, productos instalados o móviles, y Gitflow (que puede funcionar con cualquier tipo de producto).

Flujo de trabajo básico de rama por incidencia

El nombre lo dice todo: crea una rama de desarrollo para cada incidencia en la que trabajes (o para cada cambio de código que hagas y que debería rastrearse en Jira Software). Después, haz el trabajo de implementación y de pruebas en esa rama. Al terminar, envía una solicitud de incorporación de cambios, fusiona y publica cuando esté todo listo.

Captura de pantalla de flujo de trabajo básico | CI/CD de Atlassian

Este es el procedimiento paso a paso con herramientas de Atlassian.

Paso 0: Configura las integraciones de herramientas

Colabora con tu administrador de Atlassian de confianza para integrar Jira Software, Bitbucket y Bamboo. Ten en cuenta que puedes combinar opciones de Cloud y de Server. Por ejemplo, varios equipos de Atlassian utilizan Jira Software Server, Bamboo Server y Bitbucket Cloud. Si prefieres trabajar con Git a través de una interfaz gráfica, en lugar de con línea de comandos, te recomiendo Sourcetree. Es gratuito, así que no se me ocurre ni una sola razón para no probarlo. Cuando lo hayas instalado, conecta Sourcetree con tus repositorios.

También tienes que hacer obviedades como crear incidencias para hacer un seguimiento de tu trabajo, configurar un repositorio o dos, y configurar tareas de implementación y compilaciones.

Paso 1: Crea una rama

Abre la incidencia en Jira Software, asígnatela y ponla en progreso para que el equipo esté al tanto. En el lado derecho está el panel de desarrollo: haz clic en el enlace para crear una rama. Si tienes más de un gestor de repositorios conectado, verás una pantalla para elegir cuál va a administrar tu rama. Si no es así, pasarás directamente a la siguiente pantalla, en la que configurarás la rama.

Captura de pantalla de creación de flujos de trabajo de ramas | CI/CD de Atlassian

Fíjate en que Bitbucket ha seleccionado la clave de incidencia (MKT-15886 en este caso) y la ha utilizado como parte del nombre de rama. Esto hace que sucedan cosas por arte de magia, como enviar información de implementación, confirmación, compilación y solicitud de incorporación de cambios de nuevo al panel de Desarrollo. Las claves de incidencia desencadenan todo tipo de enlaces y automatizaciones en el flujo de trabajo de entrega continua, así que asegúrate de incluirlas en los nombres de tus ramas, tanto si trabajas con línea de comandos como por interfaz de usuario.

Ten en cuenta los menús desplegables que te permiten seleccionar un prefijo para la rama según el tipo (solución de error, función, versión, etc.), y la rama primaria o etiqueta a partir de la que crear la nueva rama. Suponiendo que Bamboo crea y somete a pruebas la rama que selecciones, se te indicará si la rama está limpia en ese momento. ¡No pierdas esto de vista! Lo último que necesitas es una rama nueva que esté perjudicada de alguna forma.

Cuando esté todo a tu gusto, haz clic en la opción para crear una rama y Bitbucket se encargará del resto.

Paso 2: Programa, prueba y repite

Seguramente esta parte te suena: si aún no lo has hecho, clona el repositorio de forma local, extrae la nueva rama y empieza a programar. Para cuando hagas el primer envío a la nueva rama, Bamboo ya la habrá detectado en tu repositorio y habrá configurado la integración continua mediante la función de ramas de plan (siempre que tengas habilitada la gestión automática de ramas). Básicamente, Bamboo busca nuevas ramas en tu repositorio y les aplica las compilaciones que hayas configurado para la rama principal.

También te recomiendo habilitar la fusión automática a través de Bamboo. Al principio de cada compilación, Bamboo puede extraer dos ramas, fusionarlas y, a continuación, ejecutar la compilación con respecto al código fusionado. De esta forma, para esta etapa del flujo de trabajo de entrega continua, fusionas cambios de la rama principal en la rama de función, con lo que, al crear una rama, no te apartarás de la rama principal y podrás saber rápidamente si los cambios combinan bien con los cambios en la rama principal.

Captura de pantalla del actualizador de ramas | CI/CD de Atlassian

Si la fusión automática no va contigo, fusiona la rama principal con la rama (o haz una fusión mediante cambio de base) y lanza una compilación para comprobar que no haya sorpresas desagradables... o para arreglarlas, si las hay. Una vez terminada la implementación y superadas todas las pruebas, lo tendrás todo listo para el siguiente paso.

Paso 3: Fusiona

Como miembros respetables de nuestros equipos, nunca nos lanzamos a fusionar en la rama principal ni en cualquier otra rama crítica sin antes realizar una solicitud de incorporación de cambios, la única forma aceptable de revisión de código en el universo conocido.

Puedes crear solicitudes de incorporación de cambios desde la línea de comandos o con SourceTree, pero pasar por la interfaz de usuario de Bitbucket ofrece algunas ventajas. Para empezar, tienes la oportunidad de comparar tu rama con la rama de destino. Muchas veces, ver las diferencias entre ambas saca a la luz cosas que retocarás al momento. A continuación, en la pantalla de comparación de ramas, pulsa el botón para crear solicitud de incorporación de cambios, elige a los revisores… y listo.

Captura de solicitud de incorporación de cambios de los flujos de trabajo de Bitbucket | CI/CD de Atlassian

Bitbucket es, sinceramente, bastante molón con respecto a las solicitudes de incorporación de cambios. Aparte de las cosas habituales, como comentarios de comparación lateral y en línea, también puedes definir reglas. Algunos equipos de desarrollo en Atlassian definen una regla por la que las solicitudes de incorporación de cambios solo se pueden fusionar después de que las aprueben, al menos, dos personas. Otros equipos asignan un cuidador: los permisos de la rama objetivo se definen de forma que solo el cuidador puedan llevar a cabo las fusiones. Y todos los equipos deben activar la regla que evita que una solicitud de incorporación de cambios se fusione si hay compilaciones fallidas en esa rama.

Consejo profesional: En la rama principal y en la rama desde la que publiques, te interesa compilar nada más hacer el envío. Configura un desencadenador de compilación automático en Bamboo, con unos plazos de sondeo estrictos o una notificación de inserción de Bitbucket.

Paso 4: lanzar (¡pero correctamente!)

(¿Hay algún fan de Devo en la sala? "When some new code comes along, you must ship it". ¿No? Vale… Mejor sigo con lo mío.)

Captura de compilación de implementación de flujos de trabajo de Bamboo | CI/CD de Atlassian

Una vez que la compilación esté en verde en la rama de publicación, en principio estará todo listo para el lanzamiento. Digo "en principio" porque lanzarlo o no de inmediato dependerá, en realidad, del equipo. (¿Cumple todos los criterios de aceptación? ¿Ha habido suficientes pruebas de carga con los artefactos?)

Por supuesto, puedes usar Bamboo para implementar automáticamente la compilación en un entorno de ensayo o directamente en la producción, si estás en una implementación continua. Sin embargo, esta opción no es adecuada para todos los equipos ni para todos los productos, como estamos a punto de ver.

En estas secciones, repasaremos los pasos del 1 al 4 y veremos las diferencias (si es que las hay) con el flujo de trabajo de rama por incidencia básico.

Flujo de trabajo de entrega continua para productos SaaS

En lo que respecta a las ramas con las que trabajas y a la forma en la que se mueve el código entre ellas, el flujo de trabajo SaaS es idéntico al flujo de trabajo básico.

Captura de pantalla de flujos de trabajo SaaS | CI/CD de Atlassian

Paso 1: Crea una rama

Lo único que hay que tener en cuenta aquí es que los equipos de SaaS suelen crear sus ramas de función a partir de la rama principal.

Paso 2: Programa, prueba y repite

Los equipos SaaS suelen querer acercarse lo más posible a la implementación continua y tener el lujo de trabajar con un producto adecuado para ello. Para que esto sea factible, deberás automatizar las implementaciones en un entorno de ensayo o prueba dentro de este paso, en lugar de esperar a que termine el paso de solicitud de incorporación de cambios.

Por suerte, cada vez es más fácil montar y tirar abajo entornos ligeros sobre la marcha, gracias a tecnologías como Puppet, Chef, Docker y Vagrant. (Me encantaría poder ahondar en este punto, pero lo reservo para otro artículo…). Además, Bamboo admite implementaciones automatizadas desde cualquier rama. Por lo tanto, ya trabajes con entornos temporales o persistentes, puedes configurarlos para que todas las compilaciones correctas de tu rama se implementen en un entorno en el que puedan pasar por una serie de pruebas de interfaz y/o de carga automatizadas.

Supongamos que ya has creado un proyecto de implementación en Bamboo asociado con este plan de compilación. Incorpora (o crea) las configuraciones de Bamboo para el entorno en el que quieres hacer la implementación y crea un desencadenador que implemente automáticamente cada compilación de rama correcta.

Captura de pantalla del entorno de prueba | CI/CD de Atlassian

Aunque tu equipo no sueñe con la implementación continua y prefiera tomar una decisión humana sobre cuándo lanzar, implementar compilaciones de ramas correctas en un entorno es una buena idea, ya que te ofrece a ti y a tus compañeros de equipo la oportunidad de hacer alguna prueba exploratoria antes de realizar la fusión.

Paso 3: Fusiona

El número de entornos de preproducción que utiliza el equipo influirá en el punto exacto en el que se avanza a este paso. Normalmente, los desarrolladores ejecutarán pruebas en proceso en su rama con cada compilación y, si se superan, harán la implementación en un entorno de prueba para hacer pruebas de interfaz de usuario, de carga y/o exploratorias. Una vez que todo esté correcto en la prueba, crean la solicitud de incorporación de cambios y hacen la fusión con la rama desde la que se hace la publicación (habitualmente, la rama principal).

Paso 4: Lánzalo

Ya has cerrado el círculo: has fusionado de nuevo con la rama principal y superado las pruebas de verificación. En este punto también observamos opciones muy diferentes entre equipos.

Hay equipos que desencadenan una implementación automática después de cada compilación correcta de la rama principal (en cuyo caso, los indicadores de funciones son esenciales). Otros equipos esperan a que haya una cantidad importante de cambios en la rama principal para etiquetar una publicación y desencadenar una implementación. De igual forma, algunos equipos implementan directamente a la producción y otros pasan la compilación al entorno de ensayo para hacer una ronda final de comprobaciones de estado antes del lanzamiento.

No hay una fórmula mágica para llevar el código de la rama principal al cliente. Mientras automatices lo máximo posible, irás por buen camino.

Flujo de trabajo de entrega continua para productos instalados

La principal diferencia con el flujo de trabajo básico de rama por incidencia es la existencia de ramas de larga duración para albergar todas las versiones que soportes en cada momento. En productos B2B empresariales como los de Atlassian, seguramente tengas media docena de estas ramas (o incluso más). En aplicaciones móviles, pueden ser solo 2 o 3 (o menos).

Captura de pantalla de flujo de trabajo de múltiples versiones | CI/CD de Atlassian

Paso 1: Crea una rama

El punto desde donde crees una rama dependerá del tipo de cambio que vas a hacer. ¿Es una solución de error de la versión que enviaste la semana anterior? ¿O la nueva funcionalidad del próximo lanzamiento?

En este último caso, crearás ramas desde la rama principal. En el primer caso, basarás tu rama en la rama para la versión más temprana a la que esté destinado el cambio (es decir, la primera versión en la que apareció el error).

Paso 2: Programa, prueba y repite

Como con los productos de SaaS, es una buena idea implementar compilaciones correctas de tu rama en un entorno de pruebas una vez que tienes en marcha las pruebas del proceso. Sin embargo, las razones por las que es una buena idea son un tanto diferentes.

Actualizar una versión con correcciones de errores es mucho más problemático con productos instalados que con productos SaaS (para tu equipo, y también para tus clientes). En otras palabras, los errores detectados son mucho más costosos.

Por eso, en este flujo de trabajo, implementar en un entorno de prueba para hacer pruebas de interfaz de usuario, carga y/o exploratorias no debe considerarse en ningún caso opcional. Por cierto, yo tampoco consideraría opcionales las pruebas exploratorias. Pero esto es irse por las ramas…

Paso 3: fusionar

Aquí es donde la cosa se pone interesante.

Si estás trabajando en algo para una próxima publicación, harás una solicitud de incorporación de cambios y fusionarás tu rama con la rama principal, igual que en el flujo de trabajo básico. Sin embargo, si has basado la rama en una rama de versión estable, primero harás la fusión con esa rama y comprobarás que se superan allí todas las pruebas. Luego, volverás a versiones anteriores que necesitan la misma actualización e irás probando cada una de ellas. Para terminar, harás la fusión con la rama principal para que todas las versiones futuras tengan el mismo cambio.

Captura de pantalla de flujo de trabajo de múltiples versiones | CI/CD de Atlassian

Tus herramientas de Atlassian pueden ser de ayuda de un par de formas. En primer lugar, puedes hacer que Bitbucket encadene automáticamente las fusiones por las ramas de versión estable. Asegúrate de que tienes todas las ramas configuradas para realizar compilaciones automáticamente cada vez que recibas nuevo código.

Si lo prefieres, puedes utilizar la fusión automática de Bamboo (de la que hemos hablado ya) para mover los cambios entre ramas de versiones estables. En este caso, sin embargo, utiliza la opción de Gatekeeper.

Captura de pantalla de Gatekeeper | CI/CD de Atlassian

Por ejemplo, supongamos que has fusionado una corrección de errores con la rama para la versión 1.2. Ve a las configuraciones de rama de plan de esa rama y configúrala para que se fusione automáticamente con la rama de v1.1, y así sucesivamente.

Paso 3.5: Crea una rama de versión estable

Por supuesto, si estás trabajando en novedades para una nueva versión, cortarás una nueva rama de versión estable en cuanto tengas un número importante de funciones listas (al decir "listas", nos referimos que están implementadas, probadas, bendecidas, etc.). Por lo general, la rama se corta de la rama principal y, como esta, está configurada para hacer la compilación y las pruebas automáticamente cada vez que se envían cambios.

Si descubres (bueno, en realidad, cuando descubras) que se necesitan más cambios antes de lanzar la versión, corta ramas de función a partir de la rama de versión estable. Cuando los cambios estén listos, fusiona con la rama de versión estable y haz allí las pruebas. Suponiendo que todo vaya bien, aplica los cambios también en la rama principal, como en el esquema anterior.

Tú decides si el equipo utilizará solicitudes de incorporación de cambios para las fusiones en cascada. Es una buena medida de seguridad, pero las solicitudes de incorporación de cambios y las funciones de fusión automatizadas que ofrecen Bitbucket y Bamboo no se mezclan. Por eso, sopesa las ventajas de la automatización y las ventajas de hacer revisiones de código adicionales.

Paso 4: Lánzalo

Cuando la rama de versión estable supere las pruebas en proceso, es hora de pasar a la implementación. Tu equipo y tú debéis decidir dónde se hará la implementación. Casi todos los equipos llevan la publicación a un entorno de ensayo en primer lugar. Otros, en cambio, confían lo bastante en las pruebas como para lanzar directamente a producción.

Entrega continua al estilo Gitflow

En lugar de una única rama principal, este concepto utiliza dos ramas para hacer un seguimiento del historial del proyecto. Mientras que la rama principal contiene etiquetas y/o confirmaciones que registran el historial de publicaciones oficiales del proyecto, una rama de integración compartida (generalmente denominada "de desarrollo") da a los equipos un lugar donde descubrir errores y cambios incompatibles.

Captura de pantalla de Gitflow | CI/CD de Atlassian

Paso 1: Crea una rama

De nuevo, la diferencia con el flujo de trabajo básico es desde dónde se crea la rama. En las nuevas tareas de desarrollo, la rama de función se basará en la de desarrollo (¡asegúrate de elegir una confirmación limpia desde la que crear las ramas!). En las correcciones de errores en una versión que ya hayas lanzado, la rama de función se basará en una rama de versión estable (no aparece en la imagen anterior, pero ya te haces una idea). Para obtener más información sobre las variaciones de Gitflow y sus estructuras de ramificación, consulta nuestro tutorial. Bitbucket admite todas las variaciones, así como permisos de rama con los que puedes controlar el acceso a ramas de versión o principales.

Con independencia del sitio desde donde crees las ramas, utiliza la función de actualización de ramas de Bamboo (de la que ya hemos hablado) para incorporar cambios desde la rama principal a tu rama de función con cada compilación. Descubrirás incidencias de integración de inmediato y podrás corregirlas en la rama de función, en lugar de detectarlas cuando hayas fusionado con la rama de desarrollo (y de haberla contaminado).

Con el modelo de Gitflow, es posible publicar desde la rama principal o desde ramas de versiones estables. La regla de oro es hacer de tu publicación la rama principal de las compilaciones de Bamboo (esto entrará en juego en el momento de implementar) y habilitar ramas de plan para que todas las ramas pasen por pruebas exhaustivas.

Paso 2: Programa, prueba y repite

Con Gitflow, el paso de pruebas se pone interesante. Utilizarás ramas de plan en Bamboo para poner a prueba tu rama de función (como en todos los flujos de trabajo de entrega continua), pero esta es la diferencia: cuando la implementación esté completa y todas las pruebas se superen, fusionarás con la rama de desarrollo y no con la rama principal.

El desarrollo es como la coctelera donde pueden mezclarse todos los cambios de tu equipo, y querrás obtener un feedback de cada confirmación para poder facilitar la depuración de fallos de pruebas (es decir, menos cambios que revisar entre las compilaciones). La mejor forma de garantizarlo es configurar el desarrollo para activar compilaciones en función de las notificaciones push de Bitbucket. Al sondear el repositorio de forma periódica, se capturarán cambios a veces a partir de varias confirmaciones en una sola compilación porque el desarrollo recibe cambios con mucha frecuencia: es más adecuado para las ramas cuyos cambios están más separados entre sí.

Captura de pantalla de tipo de desencadenador | CI/CD de Atlassian

Consejo profesional: Otra ventaja de las compilaciones desencadenadas por repositorio para la rama de desarrollo es que usa la CPU de Bamboo con eficiencia, como ya expliqué en Repositorios de Git compatibles con CI. Esto supone una gran diferencia para equipos que realizan entrega continua a gran escala.

Al igual que con el flujo de trabajo básico, asegúrate de fusionar la rama de desarrollo con la rama de función (o realiza una fusión mediante cambio de base) y de ejecutar pruebas una última vez antes de pasar a la de desarrollo.

Paso 3: Fusiona

Crear una solicitud de incorporación de cambios al fusionar la rama de función con la de desarrollo es una práctica estándar. Hacer revisiones de código por colegas en esta etapa es mucho más sencillo que retrasarlo hasta que estés listo para el lanzamiento, ya que en este caso tendrías que revisar a la vez todos los cambios que se han hecho desde la última publicación. Gracias, pero no.

Inevitablemente, fusionarás tu rama de función con la de desarrollo para detectar allí fallos de prueba. En lugar de hacer cambios directamente en la rama de desarrollo, extrae la rama de nuevo y hazlo todo allí. Por ejemplo, la mayoría de los equipos de Atlassian han acordado no hacer confirmaciones directamente en la rama principal, sino fusionar confirmaciones.

Paso 4: Lánzalo

Designar tu rama de publicación como la rama principal para el plan de compilación en Bamboo te pone en la línea de salida para simplificar bastante tus proyectos de implementación. Sea cual sea la rama principal del plan de compilación, esa será automáticamente la rama principal para tus tareas de implementación, aunque también puedes configurar el proyecto de implementación para que implemente compilaciones a partir de ramas de función.

Al igual que con el flujo de trabajo de SaaS, puedes crear automáticamente etiquetas en la rama principal a partir de cada compilación correcta de la rama de desarrollo e implementar directamente a partir de esas etiquetas. Si lo prefieres, puedes esperar a que se añadan varias funciones a la rama de desarrollo y crear la etiqueta a mano. Depende de si estás avanzando hacia la implementación continua o si te mantienes con la entrega continua. Gitflow se adapta a ambos conceptos.

¡Caramba! Cuatro flujos de trabajo, cinco diagramas y unas 3200 palabras más tarde, aquí estamos. (Si sigues leyendo esto, ¡enhorabuena!)

Esperemos que ahora tengas una idea básica de cómo Jira Software, Bitbucket y Bamboo se combinan para respaldar el modelo de rama por incidencia en la entrega continua. Si no es así, escríbeme por Twitter y dime cómo puedo mejorar este artículo: es uno de los importantes.

Al menos, hemos visto lo útil que te resultará crear una rama por cada incidencia en la que trabajes. No pondrás trabas a tus compañeros de equipo y tus ramas más importantes estarán siempre limpias y listas para publicar en cualquier momento. Así que, dilo conmigo:

Crear la rama perfecta a partir de tu workflow es algo estupendo.

¡Que te diviertas haciendo ramas!