*[Orden tienen las cosas](#orden-tienen-las-cosas)
*[Manos a la obra](#manos-a-la-obra)
*[Crear el *fork* con su rama *upstream-master*](#crear-el-fork-con-su-rama-upstream-master)
*[Actualizar la rama *upstream-master* en el *fork*](#actualizar-la-rama-upstream-master-en-el-fork)
*[Comenzar a trabajar un nuevo feature/mejora](#comenzar-a-trabajar-un-nuevo-featuremejora)
*[¿Solicitud de fusión rechazada?](#solicitud-de-fusión-rechazada)
## Introducción
Al trabajar en la implementación de un nuevo servicio en Ansible, una tarea cotidiana y más que recomendable es buscar en [la galaxia](https://galaxy.ansible.com)*roles* públicos que ya implementen lo que se necesita.
Muchas veces encontramos uno o mas *roles* que cumplen a la perfección el 90% de lo que precisamos, pero les falta algún detalle menor o no son completamente compatibles con el sistema operativo que vamos a utilizar.
Lo natural es aprovechar el avance de la comunidad, partiendo de esa gran base de código, y agregar las características que se consideran necesarias. Una vez concretada la mejora, incorporamos el *role* a nuestro proyecto particular y **¡listo!**
¿Listo? ¿Qué sucede si luego el *role* original sigue evolucionando e incorpora algún feature o mejora de seguridad que nos interesa? ¿Y si la licencia del proyecto original obliga a recompartir el código (por ejemplo GNU-GPL)? **¿Por qué necesitas que te obliguen para compartir?** ¿Cómo gestionamos dos bases de código que bifurcaron y evolucionaron independientemente?
**Todo esto lo solucionamos creando y trabajando en *forks*.** Pero, ¿qué entendemos por *fork*?
> Crear un *fork* es producir una copia propia del repositorio de alguien más. Los *forks* actúan como una especie de vínculo entre el repositorio original y el propio. Se puede enviar solicitudes de fusión para ayudar a mejorar los proyectos de otros, proponiendo cambios al proyecto original sin necesidad de ser miembro.
Al realizar nuestras mejoras sobre un *fork*, mantenemos el histórico del repositorio original (en adelante *upstream*). Esto hace extremadamente fácil y práctico a los responsables del proyecto, integrar los cambios que podamos proponer en una solicitud de fusión (*merge/pull request*). Igual de práctico será para nosotros, integrar en el propio repositorio, los avances del *upstream*.
## Orden tienen las cosas
[Ansible Galaxy](https://galaxy.ansible.com) se integra solo con GitHub, por lo tanto todos los *roles* públicos se encuentran en repositorios de esta plataforma. Como consecuencia, los *roles* públicos en los que colaboramos, son *forkeados* en el namespace de [nuestra organización GitHub](https://github.com/UdelaRInterior).
Tratándose de una organización, muchas veces hay varios miembros del equipo *DevOps* trabajando en simultáneo sobre un mismo *fork*, eventualmente uno retoma el trabajo de otro. Acordamos entonces un flujo estándar de trabajo que nos permita mantener el código ordenado y optimizado para proponer solicitudes de fusión y para actualizarnos desde el *upstream*.
Este flujo es casi idéntico al [empleado para desarrollos propios](flujo-de-trabajo-con-Git-en-Gitlab-y-GitHub), trabajamos cada feature/mejora en una rama específica, con el agregado de una rama espejo (*mirror*) de *master* del *upstream*.
Esta rama espejo, denominada `upstream-master`, nos permite mantener en nuestro repositorio (el *fork*) una réplica exacta del *upstream*, desde la cual partir al crear cada nueva rama para trabajar un feature. Al mismo tiempo, nos permite mantener nuestra rama *master* libre, puediendo transformarse en una versión alternativa al *upstream*, en caso que nuestras solicitudes de fusión no sean aceptadas.
## Manos a la obra
Gestionar correctamente la rama `upstream-master` es una tarea sencilla, pero en la que hay que ser cuidadoso.
A continuación se documenta paso a paso los procedimientos correctos para:
### Crear el *fork* con su rama `upstream-master`
* Una vez localizado en GitHub el repositorio del *role* de interés, [crear el fork](https://guides.github.com/activities/forking/) en el namespace `UdelaRInterior`.
* Clonar el flamante repositorio *fork*. Bien puede ser mediante un simple `git clone`, o a través de un archivo `requirements.yml` y el utilitario [`ansible-galaxy` con la opción `-g`](entorno-de-desarrollo-operaciones#manual)
* Procedemos a agregar el remoto del repositorio *upstream*, y lo nombramos precisamente `upstream`. (La dirección remota del *upstream* lo obtenemos del mismo modo que si lo fuéramos clonar)
**Si venimos haciendo todo bien, las historias de `origin/upstream-master` y `upstream/master` serán identicas, por lo que el `pull` se completará automáticamente sin conflictos**
* Con la rama `upstream-master` ya actualizada en local, solo resta reflejar la actualización en `origin` (nuestro *fork*)
Como ya se comentó, cualquier nuevo feature/mejora se trabajará en una rama específica. Como podrá sospecharse, dicha rama deberá crearse desde `upstream-master` previamente actualizado. De este modo partiremos lo más "limpios" posible para luego proponer el feature/mejora al proyecto *upstream*.
**Es importante tener en cuenta que una solicitud de fusión (*pull request* en GitHub), implica llevar una rama del *fork* a otra del *upstream*. Estas ramas quedan vinculadas durante todo el ciclo de vida de las solicitud de fusión, por lo tanto cualquier commit que se agregue a la rama propuesta será anexado a la solicitud de fusión**. Esta es otra razón por la que trabajar asuntos independientes en ramas independientes. De lo contrario los solicitudes de fusión que se envíen serán muy confusas, reduciendo las posibilidades de ser aceptada.
---
### ¿Solicitud de fusión rechazada?
Eventualmente, si los features/mejoras propuestas no son aceptadas, querremos utilizarlos de todas formas. En este escenario, que debemos evitar siempre que sea posible, podremos fusionar esas ramas en nuestro propio *master*, y pasar a utilizar el *role* en la "versión del *fork*". Análogamente, podremos seguir integrando las mejoras que se agreguen en *upstream*.