Configuración de Proyectos de Python Parte V
'Configuración de Proyectos de Python V'
Dominando el Arte de la Configuración de Proyectos de Python: Una Guía Paso a Paso
Tanto si eres un desarrollador experimentado como si estás empezando con 🐍 Python, es importante saber cómo construir proyectos sólidos y mantenibles. Este tutorial te guiará a través del proceso de configuración de un proyecto de Python utilizando algunas de las herramientas más populares y efectivas de la industria. Aprenderás cómo utilizar GitHub y GitHub Actions para el control de versiones y la integración continua, así como otras herramientas para pruebas, documentación, empaquetado y distribución. El tutorial se inspira en recursos como Hypermodern Python y Best Practices for a new Python project. Sin embargo, esta no es la única forma de hacer las cosas y es posible que tengas preferencias u opiniones diferentes. El tutorial está destinado a principiantes, pero también cubre algunos temas avanzados. En cada sección, automatizarás algunas tareas y agregarás insignias a tu proyecto para mostrar tu progreso y logros.
El repositorio de esta serie se puede encontrar en github.com/johschmidt42/python-project-johannes
Esta parte fue inspirada por esta publicación de blog:
Liberación Semántica con Python, Poetry & GitHub Actions 🚀 Estoy planeando agregar algunas características a Dr. Sven gracias al interés de mis colegas. Antes de hacerlo, necesitaba…
Requisitos
- Sistema Operativo (OS): Linux, Unix, macOS, Windows (WSL2 con p. ej. Ubuntu 20.04 LTS)
- Herramientas: python3.10, bash, git, tree
- Sistema de Control de Versiones (VCS) Host: GitHub
- Herramienta de Integración Continua (CI): GitHub Actions
Se espera que estés familiarizado con el sistema de control de versiones (VCS) git. Si no lo estás, aquí tienes un repaso: Introducción a Git
- Generative AI ¿Hacia dónde se dirige el mundo?
- Revolucionando los Restaurantes El Poder de la Inteligencia Artific...
- Cómo optimizar tu presupuesto de marketing
Los commits se basarán en las mejores prácticas para los commits de git y los commits convencionales. Existe el complemento de commit convencional para PyCharm o una extensión de VSCode que te ayuda a escribir commits en este formato.
Visión General
- Parte I (GitHub, IDE)
- Parte II (Formateo, Linting, CI)
- Parte III (Pruebas, CI)
- Parte IV (Documentación, CI/CD)
- Parte V (Versionado y Lanzamientos, CI/CD)
- Parte VI (Contenerización, Docker, CI/CD)
Estructura
- Estrategia de Ramificación de Git (Flujo de GitHub)
- ¿Qué es un lanzamiento? (zip, tar.gz)
- Versionado Semántico (v0.1.0)
- Crear un lanzamiento manualmente (git tag, GitHub)
- Crear un lanzamiento automáticamente (commits convencionales, versiones semánticas)
- CI/CD (release.yml)
- Crear un Token de Acceso Personal (PAT)
- Flujo de GitHub Actions (Orquestación de flujos de trabajo)
- Insignia (Lanzamiento)
- Bonus (Aplicar commits convencionales)
El lanzamiento de software es un paso importante en el proceso de desarrollo de software, ya que pone a disposición de los usuarios nuevas características y correcciones de errores. Un aspecto clave del lanzamiento de software es el versionado, que ayuda a realizar un seguimiento y comunicar los cambios realizados en cada lanzamiento. El versionado semántico es un estándar ampliamente utilizado para el versionado de software, que utiliza un número de versión en el formato de Mayor.Menor.Parche (por ejemplo, 1.2.3) para indicar el nivel de cambios realizados en un lanzamiento.
Los commits convencionales son una especificación para agregar significado legible por humanos y por máquinas a los mensajes de commit. Es una forma de formatear los mensajes de commit de manera consistente, lo que facilita determinar el tipo de cambio realizado. Los commits convencionales se utilizan comúnmente en conjunto con el versionado semántico, ya que los mensajes de commit se pueden utilizar para determinar automáticamente el número de versión de un lanzamiento. Juntos, el versionado semántico y los commits convencionales proporcionan una forma clara y consistente de realizar un seguimiento y comunicar los cambios realizados en cada lanzamiento de un proyecto de software.
Estrategia de ramificación en Git
Existen muchas estrategias de ramificación diferentes para Git. Muchas personas se inclinan hacia GitFlow (o variantes), Three Flow o Trunk based Flows. Algunos utilizan estrategias intermedias, como esta. Yo estoy utilizando la estrategia de ramificación de GitHub Flow, que es muy simple. En esta estrategia, todas las correcciones de errores y características tienen su propia rama separada, y cuando están completas, cada rama se fusiona con la rama principal y se implementa. Simple, bonito y fácil.

Sea cual sea tu estrategia, al final fusionas una solicitud de extracción y (probablemente) creas una versión.
¿Qué es una versión?
En resumen, una versión es empaquetar el código de una versión (por ejemplo, un archivo zip) y ponerlo en producción (lo que sea que esto signifique para ti).
La gestión de versiones puede ser complicada. Por lo tanto, debe haber una forma concisa que sigas (y que otros sigan), que defina qué significa una versión y qué cambia entre una versión y la siguiente. Si no llevas un registro de los cambios entre las versiones, es probable que no entiendas qué se ha cambiado en cada versión y no puedas identificar problemas que podrían haberse introducido con el nuevo código. Sin un registro de cambios, puede ser difícil entender cómo ha evolucionado el software con el tiempo. También puede dificultar deshacer cambios si es necesario.
Versionado semántico
El versionado semántico es simplemente un esquema de números y una práctica estándar en la industria del desarrollo de software. Indica el nivel de cambios entre esta versión y la anterior. Hay tres partes en un número de versión semántica, como 1.8.42, que siguen el patrón de:
- MAYOR.MENOR.PARCHES
Cada uno de ellos significa un grado de cambio diferente. Una versión de PARCHES indica correcciones de errores o cambios triviales (por ejemplo, de 1.0.0 a 1.0.1). Una versión de MENOR indica agregar/quitar funcionalidad o cambios compatibles con versiones anteriores de la funcionalidad (por ejemplo, de 1.0.0 a 1.1.0). Una versión MAYOR indica agregar/quitar funcionalidad y cambios potencialmente incompatibles, como cambios disruptivos (por ejemplo, de 1.0.0 a 2.0.0).
Recomiendo una charla de Mike Miles si quieres una introducción visual sobre las versiones con versionado semántico. Es un resumen de lo que son las versiones y cómo el versionado semántico con etiquetas de git nos permite crear versiones.
Sobre las etiquetas de git: Hay etiquetas ligeras y etiquetas anotadas en git. Una etiqueta ligera es simplemente un puntero a un commit específico, mientras que una etiqueta anotada es un objeto completo en git.
Crear una versión manualmente
Creemos primero una versión manualmente y luego la automatizaremos.
Si recuerdas, el archivo __init__.py
de nuestro ejemplo_app contiene la versión:
# src/example_app/__init__.py__version__ = "0.1.0"
así como el archivo pyproject.toml
:
# pyproject.toml[tool.poetry]name = "example_app"version = "0.1.0"...
Entonces, lo primero que debemos hacer es crear una etiqueta anotada de git llamada v0.1.0
y añadirla al commit más reciente en la rama principal:
> git tag -a v0.1.0 -m "versión v0.1.0"
Ten en cuenta que si no se especifica un hash de commit al final del comando, git usará el commit actual en el que te encuentras.
Puedes obtener una lista de etiquetas con:
> git tagv0.1.0
y si deseas eliminarla:
> git tag -d v0.1.0Etiqueta 'v0.1.0' eliminada
y obtener más información sobre la etiqueta con:
> git show v0.1.0etiqueta v0.1.0Autor: Johannes Schmidt <[email protected]>Fecha: sábado, 7 de enero de 2023 12:55:15 +0100versión v0.1.0commit efc9a445cd42ce2f7ddfbe75ffaed1a5bc8e0f11 (HEAD -> main, tag: v0.1.0, origin/main, origin/HEAD)Autor: Johannes Schmidt <[email protected]>Fecha: lunes, 2 de enero de 2023 11:20:25 +0100...
Podemos enviar la nueva etiqueta creada al origen con
> git push origin v0.1.0Enumerando objetos: 1, hecho.Contando objetos: 100% (1/1), hecho.Escribiendo objetos: 100% (1/1), 171 bytes | 171.00 KiB/s, hecho.Total 1 (delta 0), reusado 0 (delta 0), pack-reusado 0A github.com:johschmidt42/python-project-johannes.git * [nueva etiqueta] v0.1.0 -> v0.1.0
de modo que esta etiqueta git ahora está disponible en GitHub:
Vamos a crear manualmente una nueva versión en GitHub con esta etiqueta git:
Hacemos clic en Crear una nueva versión
, seleccionamos nuestra etiqueta existente (que ya está asociada a un commit) y luego generamos automáticamente las notas de la versión haciendo clic en el botón Generar notas de la versión
antes de finalmente publicar la versión con el botón Publicar versión
.
GitHub creará automáticamente un tar
y un zip
(activos) para el código fuente, ¡pero no compilará la aplicación! El resultado se verá así:
En resumen, los pasos para una versión son:
- crear una nueva rama desde tu rama predeterminada (por ejemplo, rama de características o corrección)
- realizar cambios y aumentar la versión (por ejemplo, pyproject.toml y __init__.py )
- confirmar la característica/corrección de errores en la rama predeterminada (probablemente a través de una solicitud de extracción)
- añadir una etiqueta git anotada (versión semántica) al commit
- publicar la versión en GitHub con alguna información adicional
Crear una versión automáticamente
Como programadores, no nos gusta repetirnos. Así que hay muchas herramientas que hacen que estos pasos sean muy fáciles para nosotros. Aquí, presentaré Semantic Releases, una herramienta específicamente para proyectos de Python.
Es una herramienta que establece automáticamente un número de versión en tu repositorio, etiqueta el código con el número de versión y crea una versión. ¡Y todo esto se hace utilizando el contenido de mensajes en el estilo de Conventional Commit.
Commits Convencionales
¿Cuál es la conexión entre versionado semántico y commits convencionales?
¡Ciertos tipos de commit se pueden utilizar para determinar automáticamente un aumento en la versión semántica!
- Un commit de
fix
es un parche. - Un commit de
feat
es una mejora menor. - Un commit con
BREAKING CHANGE
o!
es una mejora mayor.
Otros tipos, como build
, chore
, ci
, docs
, style
, refactor
, perf
, test
generalmente no aumentan la versión.
¡Consulta la sección de bonificación al final para saber cómo hacer que los commits convencionales sean obligatorios en tu proyecto!
Versiones Semánticas Automáticas (localmente)
Podemos agregar la biblioteca con:
> poetry add --group semver python-semantic-release
Repasemos la configuración que nos permite generar automáticamente registros de cambios y versiones. En el pyproject.toml
, podemos agregar semantic_release como una herramienta:
# pyproject.toml...[tool.semantic_release]branch = "main"version_variable = "src/example_app/__init__.py:__version__"version_toml = "pyproject.toml:tool.poetry.version"version_source = "tag"commit_version_number = true # requerido para version_source = "tag"tag_commit = trueupload_to_pypi = falseupload_to_release = falsehvcs = "github" # también se admite gitlab
branch
: especifica la rama en la que se basará el lanzamiento, en este caso la rama “main”.version_variable
: especifica la ruta del archivo y el nombre de la variable que contiene el número de versión en el código fuente. En este caso, el número de versión se almacena en la variable__version__
en el archivosrc/example_app/__init__.py
.version_toml
: especifica la ruta del archivo y el nombre de la variable que contiene el número de versión en el archivopyproject.toml
. En este caso, el número de versión se almacena en la variabletool.poetry.version
del archivopyproject.toml
.version_source
: especifica la fuente del número de versión. En este caso, el número de versión se obtiene del tag (en lugar del commit).commit_version_number
: este parámetro es requerido cuandoversion_source = "tag"
. Especifica si el número de versión debe ser confirmado en el repositorio o no. En este caso, se establece en true, lo que significa que el número de versión se confirmará.tag_commit
: especifica si se debe crear una nueva etiqueta para el commit de lanzamiento. En este caso, se establece en true, lo que significa que se creará una nueva etiqueta.upload_to_pypi
: especifica si el paquete debe ser cargado en el repositorio de paquetes PyPI. En este caso, se establece en false, lo que significa que el paquete no se cargará en PyPI.upload_to_release
: especifica si el paquete debe ser cargado en la página de lanzamientos de GitHub. En este caso, se establece en false, lo que significa que el paquete no se cargará en los lanzamientos de GitHub.hvcs
: especifica el sistema de control de versiones de alojamiento del proyecto. En este caso, se establece en “github”, lo que significa que el proyecto está alojado en GitHub. También se admite “gitlab”.
Podemos actualizar los archivos donde hemos definido la versión del proyecto/módulo. Para esto, usamos la variable version_variable
para archivos normales y version_toml
para archivos .toml. El version_source
define la fuente de verdad para la versión. Debido a que la versión en estos dos archivos está estrechamente relacionada con las etiquetas anotadas de git, por ejemplo, creamos una etiqueta de git con cada lanzamiento automáticamente (la bandera tag_commit
se establece en true), podemos utilizar la fuente tag
en lugar del valor predeterminado commit
que busca la última versión en los mensajes de commit. Para poder actualizar los archivos y confirmar los cambios, necesitamos establecer la bandera commit_version_number
en true. Debido a que no queremos cargar nada en el índice de Python PyPi, la bandera upload_to_pypi
se establece en false. Y por ahora no queremos cargar nada en nuestros lanzamientos. El hvcs
se establece en github
(predeterminado), otros valores pueden ser: gitlab
.
Podemos probar esto localmente ejecutando algunos comandos, que agregaré directamente a nuestro Makefile:
# Makefile...##@ Lanzamientosversión-actual: ## devuelve la versión actual @semantic-release print-version --currentversión-siguiente: ## devuelve la versión siguiente @semantic-release print-version --nextchangelog-actual: ## devuelve el registro de cambios actual @semantic-release changelog --releasedchangelog-siguiente: ## devuelve el registro de cambios siguiente @semantic-release changelog --unreleasedpublicar-noop: ## comando de publicación (modo sin operación) @semantic-release publish --noop
Con el comando versión-actual obtenemos la versión de la última etiqueta de git en el árbol de git:
> make versión-actual0.1.0
Si agregamos algunos commits en estilo de commit convencional, por ejemplo, feat: nueva característica genial
o fix: error molesto
, entonces el comando versión-siguiente calculará el aumento de versión para eso:
> make next-version0.2.0
En este momento, no tenemos un archivo CHANGELOG en nuestro proyecto, por lo que cuando ejecutemos:
> make current-changelog
la salida estará vacía. Pero basados en los commits, podemos crear el próximo registro de cambios con:
> make next-changelog### Característica* Agregar versiones ([#8](https://github.com/johschmidt42/python-project-johannes/issues/8)) ([`5343f46`](https://github.com/johschmidt42/python-project-johannes/commit/5343f46d9879cc8af273a315698dd307a4bafb4d))* Docstrings ([#5](https://github.com/johschmidt42/python-project-johannes/issues/5)) ([`fb2fa04`](https://github.com/johschmidt42/python-project-johannes/commit/fb2fa0446d1614052c133824150354d1f05a52e9))* Agregar aplicación en app.py ([`3f07683`](https://github.com/johschmidt42/python-project-johannes/commit/3f07683e787b708c31235c9c5357fb45b4b9f02d))### Documentación* Agregar barra de búsqueda y URL de GitHub ([#6](https://github.com/johschmidt42/python-project-johannes/issues/6)) ([`3df7c48`](https://github.com/johschmidt42/python-project-johannes/commit/3df7c483eca91f2954e80321a7034ae3edb2074b))* Agregar páginas de insignias a README.py ([`b76651c`](https://github.com/johschmidt42/python-project-johannes/commit/b76651c5ecb5ab2571bca1663ffc338febd55b25))* Agregar documentación a Makefile ([#3](https://github.com/johschmidt42/python-project-johannes/issues/3)) ([`2294ee1`](https://github.com/johschmidt42/python-project-johannes/commit/2294ee105b238410bcfd7b9530e065e5e0381d7a))
Si empujamos nuevos commits (directamente a main o a través de un PR), ahora podemos publicar una nueva versión con:
> semantic-release publish
El comando de publicación realizará una secuencia de acciones:
- Actualizar o crear el archivo de registro de cambios.
- Ejecutar semantic-release version .
- Hacer push de los cambios a git.
- Ejecutar build_command y cargar el archivo de distribución en tu repositorio.
- Ejecutar semantic-release changelog y publicar en tu proveedor de VCS.
- Adjuntar los archivos creados por build_command a las versiones de GitHub.
Cada paso puede ser configurado o desactivado, ¡por supuesto!
CI/CD
Vamos a crear un pipeline de CI con GitHub Actions que ejecute el comando de publicación de semantic-release con cada commit en la rama principal.
Aunque la estructura general se mantiene igual que en lint.yml , test.yml o pages.yml , hay algunos cambios que deben mencionarse. En el paso Checkout repository
, agregamos un nuevo token que se utiliza para hacer checkout de la rama. Esto se debe a que el valor predeterminado GITHUB_TOKEN
no tiene los permisos requeridos para operar en ramas protegidas. Por lo tanto, debemos usar un secreto ( GH_TOKEN ) que contenga un Token de Acceso Personal con permisos. Mostraré más adelante cómo se puede generar el Token de Acceso Personal. También definimos fetch-depth: 0
para obtener todo el historial de todas las ramas y etiquetas.
with: ref: ${{ github.head_ref }} token: ${{ secrets.GH_TOKEN }} fetch-depth: 0
Instalamos solo las dependencias necesarias para la herramienta semantic-release con:
- name: Instalar requisitos run: poetry install --only semver
En el último paso, cambiamos algunas configuraciones de git y ejecutamos el comando de publicación de semantic-release:
- name: Publicación Semántica de Python env: GH_TOKEN: ${{ secrets.GH_TOKEN }} run: | set -o pipefail # Establecer detalles de git git config --global user.name "github-actions" git config --global user.email "[email protected]" # Ejecutar semantic-release poetry run semantic-release publish -v DEBUG -D commit_author="github-actions <[email protected]>"
Cambiando la configuración de git, el usuario que realiza los commits será “github-actions”. Ejecutamos el comando de publicación con registros de depuración (stdout) y establecemos el commit_author
como “github-actions” de manera explícita. Alternativamente a este comando, podríamos utilizar la acción de GitHub de semantic-release directamente, pero los pasos de configuración para ejecutar el comando de publicación son muy pocos y la acción utiliza un contenedor de Docker que debe descargarse cada vez. Por eso, prefiero hacer un paso de ejecución simple en su lugar.
Debido a que el comando de publicación realizará un commit, podrías preocuparte de que terminemos en un bucle infinito de ejecución de flujos de trabajo. Pero no te preocupes, el commit resultante no activará otra ejecución de flujos de trabajo de GitHub Actions. Esto se debe a las limitaciones establecidas por GitHub .
Crear un Token de Acceso Personal (PAT)
Los tokens de acceso personal son una alternativa al uso de contraseñas para autenticarse en GitHub Enterprise Server al utilizar la API de GitHub o la línea de comandos . Los tokens de acceso personal están destinados a acceder a los recursos de GitHub en tu nombre. Para acceder a los recursos en nombre de una organización, o para integraciones de larga duración, debes utilizar una aplicación de GitHub. Para obtener más información, consulta “Acerca de las aplicaciones”.
En otras palabras: Podemos crear un T oken de A cceso P ersonal y hacer que las acciones de GitHub almacenen y utilicen ese secreto para realizar ciertas operaciones en nuestro nombre. Ten en cuenta que, si el PAT se ve comprometido, podría utilizarse para realizar acciones maliciosas en tus repositorios de GitHub. Por lo tanto, se recomienda utilizar aplicaciones de autenticación OAuth de GitHub y aplicaciones de GitHub en organizaciones. Para los fines de este tutorial, utilizaremos un PAT para permitir que el pipeline de acciones de GitHub opere en nuestro nombre.
Puedes crear un nuevo token de acceso navegando hasta la sección Configuración
de tu usuario de GitHub y siguiendo las instrucciones resumidas en Crear un Token de Acceso Personal . Esto nos dará una ventana que se verá así:

Al seleccionar los alcances, definimos los permisos que tendrá el token. Para nuestro caso de uso, necesitamos acceso de envío a los repositorios, por lo que el nuevo PAT GH_TOKEN
debe tener el ámbito de permisos repo
. Ese ámbito autorizaría los envíos a las ramas protegidas, siempre y cuando no tengas configurada la opción “Incluir administradores” en la configuración de la rama protegida.
Volviendo a la vista general del repositorio, en el menú Configuración, podemos agregar una configuración de entorno o una configuración de repositorio en la sección Secretos:
Los secretos del repositorio son específicos de un solo repositorio (y de todos los entornos utilizados en él), mientras que los secretos de entorno son específicos de un entorno. El runner de GitHub se puede configurar para ejecutarse en un entorno específico, lo que le permite acceder a los secretos del entorno. Esto tiene sentido al pensar en diferentes etapas (por ejemplo, DEV vs PROD), pero para este tutorial estoy bien con un secreto de repositorio .
Flujo de Acciones de GitHub
Ahora que tenemos algunos pipelines (linting, testing, releasing, documentation), debemos pensar en el flujo de acciones con un commit en main! Hay algunas cosas de las que debemos ser conscientes, algunas de ellas específicas de GitHub.
Idealmente, queremos que un commit en main genere un evento de envío que active los flujos de trabajo de Testing y Linting. Si tienen éxito, ejecutamos el flujo de trabajo de release, que es responsable de detectar si debe haber un incremento de versión basado en los commits convencionales. Si es así, el flujo de trabajo de release enviará directamente a main, incrementando las versiones, agregando una etiqueta git y creando una release. Una release publicada debería, por ejemplo, actualizar la documentación mediante la ejecución del flujo de trabajo de documentación.

Problemas y consideraciones
- Si lees el último párrafo con atención o has echado un vistazo al diagrama de flujo de arriba, es posible que hayas notado que hay dos commits en main. Uno inicial (es decir, de una PR) y otro segundo para el lanzamiento. ¡Debido a que nuestro lint.yml y test.yml reaccionan a eventos de push en la rama principal, se ejecutarían dos veces! Deberíamos evitar que se ejecute dos veces para ahorrar recursos. Para lograr esto, podemos agregar la cadena
[skip ci]
a nuestro mensaje de commit de versión. Un mensaje de commit personalizado se puede definir en el archivo pyproject.toml para la herramienta semantic_release.
# pyproject.toml...[tool.semantic_release]...commit_message = "{version} [skip ci]" # omitir la activación de las canalizaciones de CI para commits de versión...
2. La página de flujo de trabajo pages.yml se ejecuta actualmente en un evento de push a main. Actualizar la documentación podría ser algo que solo queramos hacer si hay un nuevo lanzamiento (es posible que estemos haciendo referencia a la versión en la documentación). Podemos cambiar el desencadenador en el archivo pages.yml en consecuencia:
# pages.ymlname: Documentationon: release: types: [published]
La construcción de la documentación ahora requerirá un lanzamiento publicado.
3. El flujo de trabajo de lanzamiento debería depender del éxito del flujo de trabajo de linting y pruebas. Actualmente no hemos definido dependencias en nuestros archivos de flujo de trabajo. Podríamos hacer que estos flujos de trabajo dependan de la finalización de ejecuciones de flujos de trabajo definidos en una rama específica con el evento workflow_run
. Sin embargo, si especificamos múltiples workflows
para el evento workflow_run
:
on: workflow_run: workflows: [Testing, Linting] types: - completed branches: - main
¡solo uno de los flujos de trabajo debe completarse! Esto no es lo que queremos. Esperamos que todos los flujos de trabajo se completen (y tengan éxito). Solo entonces se debe ejecutar el flujo de trabajo de lanzamiento. Esto contrasta con lo que obtenemos cuando definimos dependencias entre trabajos en un solo flujo de trabajo. Lee más sobre esta inconsistencia y deficiencia aquí.
Como alternativa, podríamos usar una ejecución secuencial de canalizaciones:
El gran inconveniente de esta idea es que a) no permite la ejecución paralela y b) no podremos ver el gráfico de dependencias en GitHub.
Solución
Actualmente, la única forma que veo de lidiar con los problemas mencionados anteriormente es orquestar los flujos de trabajo en un flujo de trabajo orquestador.
Creemos este archivo de flujo de trabajo:
El orquestador se activa cuando hacemos push a la rama main
.
Solo si los flujos de trabajo de Testing y Linting tienen éxito, se llama al flujo de trabajo de lanzamiento. Esto se define con la palabra clave needs
. Si deseamos tener un control más granular sobre la ejecución de trabajos (flujos de trabajo), considera también usar la palabra clave if
. Pero ten en cuenta el comportamiento confuso explicado en este artículo.
Para que nuestros flujos de trabajo lint.yml
, test.yml
y release.yml
sean llamables por otro flujo de trabajo, debemos actualizar los desencadenadores:
# lint.yml---name: Lintingon: pull_request: branches: - main workflow_call:jobs:...
# test.yml---name: Testingon: pull_request: branches: - main workflow_call:jobs:...
# release.yml---name: Releaseon: workflow_call:jobs:...
Ahora el nuevo flujo de trabajo (Release) solo se ejecutará si los flujos de trabajo para la verificación de calidad, en este caso el linting y las pruebas, tienen éxito.
Insignia
Para crear una insignia, en esta ocasión, utilizaré la plataforma shields.io.
Es un sitio web que genera insignias para proyectos, las cuales muestran información como la versión, el estado de construcción y la cobertura de código. Ofrece una amplia gama de plantillas y permite personalizar la apariencia y crear insignias personalizadas. Las insignias se actualizan automáticamente, proporcionando información en tiempo real sobre el proyecto.
Para una insignia de lanzamiento, seleccioné GitHub release (latest SemVer)
:
El código markdown de la insignia se puede copiar y agregar al archivo README.md:
Nuestra página de inicio de GitHub ahora se ve así ❤ (he limpiado un poco y proporcionado una descripción):
¡Felicidades! ¡Has completado la parte principal de este tutorial! Has aprendido los pasos esenciales para gestionar lanzamientos de software. Comenzamos creando manualmente un lanzamiento y luego aprovechamos el poder de Conventional Commits para automatizar nuestro proceso de lanzamiento a través de un pipeline de CI, que se encarga de la numeración de versiones en nuestro nombre. Para finalizar, agregamos una insignia en nuestro archivo README.md, que proporciona una visualización clara y concisa de la última versión de nuestro proyecto para nuestros usuarios. Con estas técnicas en mano, podrás gestionar tus lanzamientos de software de manera eficiente y efectiva.
La próxima parte será la última parte, ¡que cubre: Containerización!
Únete a VoAGI con mi enlace de referencia – Johannes Schmidt
Lee todas las historias de Johannes Schmidt (y miles de otros escritores en VoAGI). Tu cuota de membresía directamente…
johschmidt42.medium.com
Bonus
Asegurar Commits Convencionales
Hemos visto que los commits en un formato definido pueden ayudarnos con la numeración de versiones. En un proyecto colaborativo, probablemente queramos imponer este formato para todos los commits en la rama predeterminada. Dos herramientas populares pueden ayudar a los desarrolladores a seguir el formato de commits convencionales:
- commitizen
- commitlint
Sin embargo, algunos desarrolladores sienten que estas herramientas son un poco restrictivas y evitan usarlas*. Por lo tanto, probablemente no sea una buena idea confiar únicamente en que siempre haya commits convencionales. Por lo tanto, tiene sentido imponer reglas, como el formato de commit convencional, en el lado del servidor.
*Lo mismo se aplica a los hooks de pre-commit, por eso los excluí en esta serie.
Desafortunadamente, actualmente no es posible (mayo de 2023) bloquear los commits basados en reglas en GitHub, ya que esta función aún está pendiente. Pero podemos intentar acercarnos lo más posible a través de reglas de protección de rama y un flujo de trabajo de CI. Entonces, aquí están las cosas que requerimos para tal estrategia en nuestro repositorio:
- Los commits en la rama predeterminada protegida (por ejemplo, main) deberían estar restringidos a pull requests (PR).
- Solo se deben permitir commits aplastados*
- El mensaje de commit predeterminado presentado al fusionar una pull request con squash debería ser el título de la pull request
Si la única forma de realizar un commit en la rama predeterminada protegida (por ejemplo, main) es a través de una pull request (solo commits aplastados), podemos usar una Acción de GitHub, como amannn/action-semantic-pull-request, que asegura que el título de la pull request coincida con las especificaciones de Commits Convencionales. Entonces, cuando hacemos squash y merge
de la rama de la PR (suponiendo que todas las tuberías requeridas tengan éxito), el mensaje de commit sugerido es el título de la PR, que se verificó previamente en la ejecución de la acción de GitHub.
*La estrategia de squash y merge es un método popular para fusionar cambios de código desde una rama de características a la rama principal, que implica condensar múltiples commits en una sola commit. Esto crea un historial de git lineal y consistente, donde cada commit representa un cambio específico. Sin embargo, este método tiene sus desventajas, ya que descarta el historial de commits granulares, que puede ser valioso para comprender el proceso de desarrollo. Si bien es posible utilizar la fusión con rebase para conservar esta información, puede introducir complejidad en el flujo de trabajo. En este sentido, la estrategia de squash y merge se prefiere por su simplicidad.
Flujo de trabajo
Creemos el flujo de trabajo de GitHub Actions para esta estrategia:
El evento de activación pull_request_target
se explica aquí. Utilizo los tipos sugeridos opened
, edited
, synchronize
. El GITHUB_TOKEN
se pasa como env
a la acción. Por lo tanto, cada vez que se cambia el título en un PR, se activa el pipeline. Solo tiene éxito si el título del PR está en el formato de commit convencional.
Tenga en cuenta que
debe tener esta configuración en la rama principal para que la acción se ejecute en absoluto (por ejemplo, no se ejecutará dentro de un PR que agregue la acción inicialmente). Además, si cambia la configuración en un PR, los cambios no se reflejarán para el PR actual, solo los siguientes después de que los cambios estén en la rama principal.
Por lo tanto, debemos tener este flujo de trabajo en nuestra rama predeterminada main
primero, solo entonces podremos verlo en acción.
Reglas de protección de la rama
A continuación, en la sección Configuración del repositorio de GitHub, podemos crear una regla de protección de la rama para la rama principal:

Ahora un commit requiere un PR con verificaciones de estado aprobadas (flujo de trabajo requerido) antes de fusionar*.
Un flujo de trabajo requerido se activa por eventos de pull request y aparece como una verificación de estado requerida, que bloquea la capacidad de fusionar el pull request hasta que el flujo de trabajo requerido tenga éxito.

Los propietarios de la organización tienen la capacidad de hacer cumplir flujos de trabajo específicos dentro de su organización, como requerir una verificación de estado en los pull request. Desafortunadamente, esta función solo está disponible para organizaciones y no se puede activar para cuentas individuales, por lo tanto, no es posible bloquear la fusión.
*Tenga en cuenta que las reglas no se aplicarán en un repositorio privado hasta que se mueva a una cuenta de GitHub Team o Enterprise !
Estrategia de squash y merge
Finalmente, podemos configurar las opciones de PR para utilizar el título del PR como el mensaje de commit predeterminado cuando seleccionamos el botón squash y merge:

De esta manera, vemos una ventana como esta:

Tenga en cuenta que un desarrollador puede alterar el nombre del título durante la fusión, ¡lo que eludiría la estrategia!
Aunque aún no podemos asegurar completamente los commits convencionales en GitHub, debemos intentar acercarnos lo más posible.