Por favor, usa versionado semántico en tus paquetes

GitHub avatar of Ivan Montilla
April 2, 2023
Post licensed under CC BY 4.0

Hace un tiempo publiqué una entrada en la que explicaba cómo generar automáticamente paquetes NuGet con GitHub Actions.

En esa entrada utilizaba la fecha y hora actual para asegurar que la versión del paquete generada era cada vez superior a la anterior. Aunque ya en ella señalaba que la versión de los ensamblados estaba diseñado para usar versionado semántico, pasé de aplicarla (grave error).

Lo que expongo en aquella entrada está basado en un caso real, por lo que poco tiempo después de estar utilizando este sistema de versionado basado en la fecha de generación del paquete, empezaron a llegar los problemas.

¿Qué es versionado semántico?

Según la especificación oficial, Semantic Versioning es un conjunto simple de reglas y requerimientos que dictan cómo asignar e incrementar los números de la versión. Esta diseñado para software que expone un API público como podrían ser paquetes NuGet o npm.

Recomiendo leer la especificación completa para entender todos los detalles, pero un resumen rápido es el siguiente:

¿Por qué usar versionado semántico?

Desde la especificación oficial se explica que simplemente conociendo el número de versión, puedes estar seguro de que la actualización va a ser compatible con tu software sin necesidad de hacer ningún cambio.

Personalmente, me ocurrió una vez que al actualizar un paquete de Laravel, este rompió por completo mi proyecto. Por aquel entonces yo no conocía las reglas de versionado semántico y aquella dependencia tampoco las aplicaba. Aquello me hizo perder varios días de trabajo.

Pero más allá de eso, otro motivo por el cual hacer uso de versionado semántico –más bien, no hacer uso de versionado por fecha– es conocer de un vistazo qué número de versión va primero. Es mucho más fácil ordenar de un simple vistazo las versiones 0.0.1, 0.0.2 y 0.0.3 que las versiones 2022.05.12.10214, 2022.05.12.20236 y 2022.05.13.1025.

Generando paquetes NuGet con versionado semántico

⚠ Info

NOTA: Si no tienes intención de generar paquetes NuGet con versionado semántico, puedes dejar de leer aquí. A partir de aquí ya no vamos a aportar nada nuevo relacionado con el versionado semántico.

⚠ Info

NOTA 2: Deberías leer primero aquella entrada, ya que aquí simplemente cubriré los cambios necesarios para actualizar de versionado por fecha a versionado semántico.

Una vez explicado que es el versionado semántico y por qué deberiamos de usarlo, toca actualizar el script que publiqué para generar y versionar paquetes NuGet automáticamente.

En aquel script de GitHub Action, lo que hacía es lanzar el workflow cada vez que había un push nuevo al repositorio. En ese instante momento, se toma la fecha y hora actual para generar la versión tanto de los ensamblados como de los paquetes.

Aquí si lanzamos un workflow con cada push, la cosa se complica más porque tenemos dos problemas:

Aunque es posible que esto se siga haciendo de forma automática con cada push, haciendo que la action revise el API pública en búsqueda de cambios y cogiendo el número de versión del paquete anterior, considero que es un trabajo excepcional.

He optado en cambio por añadir un botón que lance la action de forma manual en el que especifique que versión tendrá. GitHub Actions permite hacer esto con el evento workflow_dispatch.

Para ello vamos a modificar la sección on del fichero yml que define el workflow de la siguiente forma:

on:
  workflow_dispatch:
    inputs:
      version:
        required: true
        type: string

Una vez hecho esto, ahora podremos invocar este workflow de forma manual desde la pestaña “Actions” de nuestro repositorio.

Toca hacer más cambios, en el paso Set environment variables se obtiene la versión en base a la fecha y hora actual de la siguiente forma:

$now = [System.DateTimeOffset]::UtcNow
$version = $now.ToString("yyyy.MM.dd.") + [int]($now.TimeOfDay.TotalSeconds / 2)

Sin embargo, ahora debemos de obtenerla directamente del input, por lo que se simplifica de la siguiente forma:

$version = '{{ inputs.version }}'

Con esto ya estaría todo, no sería necesario hacer ningún cambio más. Ahora simplemente debemos de lanzar el workflow de forma manual cada vez que necesitemos un paquete nuevo.

Comments

Loading comments...

Write a comment on GitHub!