# Versionamiento de código fuente

Para el sistema de versionamiento de software se deberán cumplir las siguientes reglas:

* Todos los proyectos nuevos deberán funcionar con el sistema de control de versiones *[Git](https://en.wikipedia.org/wiki/Git)*.
* No se deberán versionar archivos de más de 5 MB.
* Evitar versionar archivos binarios.

## Repositorios

Todos los repositorios asociados a herramientas, plataformas, procesos y demás temas relacionados deben pertenecer a la organización [Dirección de Conocimiento](https://github.com/PEM-Humboldt). La creación de repositorios está restringida a los propietarios de la organización. En caso de que a un investigador se le asigne la creación de un repositorio, obtendrá permisos temporales y deberá tener en cuenta lo siguiente:

* Asignar el repositorio a un [equipo de trabajo](https://github.com/orgs/PEM-Humboldt/teams). El equipo le será indicado en la tarea.
* Añadir los siguientes archivos al repositorio:
  * **LICENSE:** Usar la licencia MIT, a menos que se le indique otra.
  * **README.md:** Añadir información del proyecto. Si se desconoce, dejar el archivo en blanco
  * **.gitignore:** Usar una plantilla para el lenguaje que se vaya a utilizar. Si se desconoce, dejar el archivo en blanco.
  * **.gitattributes:** Usar una plantilla para el lenguaje que se vaya a utilizar. Si se desconoce, dejar el archivo en blanco.
* Crear la rama *develop* a partir de la rama *main*.
* Proteger ambas ramas:
  * No permitir *push* forzados
  * Requerir revisiones sobre los *PR*
  * Aplicar las reglas para los administradores también
* Poner la rama *develop* como rama por defecto

**NOTA:** Puede construir fácilmente archivos *gitignore* y *gitattributes* con las herramientas web [*gitignore.io*](http://gitignore.io) y [*gitattributes.io*](http://gitattributes.io).

## *Git flow*

### Commits

Se recomienda realizar commits con pocos cambios y con nombres cortos y concretos. Todos los commits deberán escribirse en Inglés.

Condiciones en los commits:

* Cada commit debe ser funcional. Es decir, al hacer checkout a un commit específico la aplicación debe funcionar sin errores de código.
* Dejar al final, o incluso en una rama aparte optimizaciones y otros ajustes que se encuentren necesarios durante el desarrollo de la tarea.
* Deben ser escritos de tal forma que complementen la frase: *If applied, this commit will*…
* Cuando un mensaje sea muy grande, debe dividirse en varias líneas y la primera debe ser el “asunto” del commit, debe separarse por una línea en blanco del resto del commit, y el resto del commit puede ser una descripción o una lista de puntos para explicar más detalles.

### *Pull Requests* y *Merge Requests* (*PRs* y *MRs*)

* Antes de crear un *PR* (*Pull Request*) o *MR* (*Merge Requests*), se debe comprobar la funcionalidad del proyecto y los posibles eventos o errores que se hayan ejecutado en la plataforma de desarrollo (*GitHub*, *GitLab*) al ejecutar el comando *push*. En caso de existir errores, se deben solucionar antes de crear el *PR*.

  **Nota:** Para el caso de *GitHub*, se recomienda ejecutar las acciones de *github actions* de manera local. Para eso puede usar [act](https://github.com/nektos/act) (vea [aquí](https://medium.com/@debasishkumardas5/running-github-actions-locally-a-complete-guide-for-windows-mac-and-linux-users-34c45999c7cd) un instructivo).

* Al crear un *PR*, se debe seleccionar la rama que se trabajó el destino dependerá del tipo de desarrollo que se esté realizando (*feature*, *release* o *hotfix*). Recuerde que el orden de estas ramas está invertido en GitLab (para los *MR*)
* En caso de haber conflictos, el desarrollador que crea el *PR* debe resolverlos.
* Siempre se deben asignar revisores al *PR*.
* Al crear un PR/MR en la sección *Associated issues* de la plantilla se debe enlazar la tarea correspondiente usando las palabras mágicas (nunca a través del título). Puede ver las instrucciones para [GitLab](https://linear.app/docs/gitlab#use-a-magic-word) y para [GitHub](https://linear.app/docs/github#magic-words)

#### Consideraciones
* En caso de haber más de 2 revisores en el *PR*, se debe tener en cuenta:
  * En casi todos los repositorios es suficiente con que uno lo apruebe. Pero la cantidad de aprobaciones necesarias es determinada por la sensibilidad de la tarea.
  * Si un revisor solicita cambios, esa misma persona debe aprobar después.
  * Más de un revisor puede solicitar cambios. Luego, se deberá tener la aprobación de todos los que hayan solicitado cambios.
* En el GitLab interno no se tiene plantilla para los MR, se debe copiar de alguno de los repositorios de GitHub
* Para aprobar en el GitLab interno e debe reaccionar con pulgar arriba y se debe avisar con comentario en la tarea porque ese GitLab no envía correos

### Revisores

Los revisores deben verificar en cada *PR* los siguientes puntos:

* Un correcto funcionamiento del proyecto
* Que la tarea, los criterios de aceptación y consideraciones se estén cumpliendo. Este paso se puede evitar en algunos casos, pero eso será mencionado en la tarea.
* No debe haber código comentado.
* No debe haber impresiones a consola (ejemplo: *console.log*, *print*, *p*, *system.out.println*)
* El archivo *readme* debe estar actualizado en caso de ser necesario. Por ejemplo, si se introducen o cambian variables de configuración. (Como regla general, el archivo *readme* siempre debe estar al día).
* El código ha sido documentado de acuerdo a las prácticas del repositorio / proyecto.
* Los nombres de las funciones y variables son claros de acuerdo a su uso.
* No hay código sin usar (variables, funciones, clases, sentencias sueltas, etc).
* El código en general es entendible y lo suficientemente óptimo.
  * Se debe buscar un balance entre optimización (entiéndase como evitar redundancias, repeticiones, estructuras de datos adecuadas, etc) y legibilidad del código.
  * Para el caso de JavaScript e implementaciones asíncronas prestar especial atención a las condiciones de carrera.
* Si el *PR* incluye una nueva dependencia en el proyecto, hacer una breve investigación sobre la dependencia para verificar que no tenga problemas de seguridad, que la actualicen con cierta frecuencia y que efectivamente sea necesaria.

### Ramas

El nombre de una rama debe tener el nombre del usuario del instituto, un símbolo de barra o *slash* (“/”) y el identificador de la tarea a resolver. Por ejemplo: *pperez/LIB-01*, *pgonzalez/LIB-042*

Una tarea puede ser de tipo *feature*, lo cual implica que se lleva a desarrollo (rama *develop*) o de tipo *hotfix*, la cual se lleva tanto a producción (rama *master* o *main*) como a desarrollo (rama *develop*). El flujo de trabajo con estas ramas tienen cosas en común, pero también sus diferencias.

Adicionalmente están las ramas *release*, que por lo regular tendrán una tarea asociada, pero es principalmente para marcar la dedicación en un sprint determinado y actualizar la documentación en otras ubicaciones.

#### Rama *Feature*

A continuación se presenta una guía del flujo de una rama tipo *feature*. Aquí se consideran tanto los pasos y recomendaciones para el encargado de hacer la tarea, como para los revisores.

![Manejo de ramas tipo "feature"](/resources/diagrams/git-flow/branches-feature.drawio.png)

#### Rama *Release*

A continuación se presenta una guía del flujo de una rama tipo *release*. Aquí se consideran tanto los pasos y recomendaciones para el encargado de hacer el lanzamiento, como para los revisores.
> **Nota temporal importante**: El flujo presentado a continuación se ve modificado mientras se termina el cambio de modelo de las aplicaciones para funcionar con ambiente productivo en la nube. Ver los diagramas de [la rama temporal feature/aws-pipelines](#temporal-rama-featureaws-pipelines) para más información

![Manejo de ramas tipo "release"](/resources/diagrams/git-flow/branches-release.drawio.png)

#### Rama *Hotfix*

Las tareas de estas ramas son para corregir algo urgente que no da tiempo de esperar a un lanzamiento.

A continuación se presenta una guía del flujo de una rama tipo *hotfix*. Aquí se consideran tanto los pasos y recomendaciones para el encargado de hacer el ajuste, como para los revisores.

![Manejo de ramas tipo "hotfix"](/resources/diagrams/git-flow/branches-hotfix.drawio.png)

#### [Temporal] Rama feature/aws-pipelines

Esta es una rama tempotal creada durante la migración de los ambientes de producción a la nube. Hasta que se estabilicen todas las plataformas en este nuevo modelo, se manejará esta rama como espejo de master, ya que los commits en esta rama son los que disparan los pipelines de despliegue en la nube.

Una vez tengamos (Humboldt) el control sobre los piplenes, considero (Erika) que lo mejor es dispararlos con la creación de tags en la rama master.

Por el momento este es el panorama de los despliegues.

##### Si hay conflictos

```mermaid
---
config:
    theme: default
    gitGraph:
        mainBranchOrder: 1
        rotateCommitLabel: true
---
gitGraph
commit
branch develop order:3
checkout develop
commit
branch release/1.11.0 order:2
checkout release/1.11.0
commit
checkout main
branch feature/aws-pipelines order:0
checkout feature/aws-pipelines
commit
checkout release/1.11.0
merge main id:"conflictos-con-main"
merge feature/aws-pipelines id:"conflictos-con-pipelines"
checkout main
merge release/1.11.0
checkout feature/aws-pipelines
merge release/1.11.0 tag:"dispara-deploy"
checkout release/1.11.0
merge develop id:"conflictos-con-develop"
checkout develop
merge release/1.11.0
```
##### Si no hay conflictos

```mermaid
---
config:
    theme: default
    gitGraph:
        mainBranchOrder: 1
        rotateCommitLabel: true
---
gitGraph
commit
branch develop order:3
checkout develop
commit
branch release/1.11.0 order:2
checkout release/1.11.0
commit
checkout main
branch feature/aws-pipelines order:0
checkout feature/aws-pipelines
commit
checkout main
merge release/1.11.0
checkout feature/aws-pipelines
merge release/1.11.0 tag:"dispara-deploy"
checkout release/1.11.0
checkout develop
merge release/1.11.0
```

### Lanzamientos y etiquetas (Releases, tags)

Al crear un lanzamiento, se debe tener en cuenta lo siguiente:

1. Seleccionar la rama *main*/*master* para crear el lanzamiento
2. Ir a la sección "Releases" y seleccionar "Create a new release"
3. Asignar o crear una nueva etiqueta de la forma: **\<\#1\>.\<\#2\>.\<\#3\>** (ver [Versionamiento semántico](semantic-versioning.md)). **La rama target siempre será main o master**
4. El título del release debe ser únicamente la etiqueta siguiendo el estilo ya establecido: **\<\#1\>.\<\#2\>.\<\#3\>**. No debe contener palabras adicionales. (p. ej *Título: 1.0.0*)
5. En la descripción del lanzamiento, redactar los cambios de la nueva versión teniendo en cuenta los siguiente:
   1. No especificar cada commit ni cada tarea, solo los cambios en funcionalidades completas.
   2. No detallar cambios técnicos. Por ejemplo, solo “*dependency update*” en lugar de listar todas las dependencias que se cambiaron

---
* volver al [inicio](/README.md)
* volver a las [normas de desarrollo](/docs/development-rules/README.md)
