
Compartir:
Yonatan ha estado involucrado en algunos proyectos impresionantes en la academia y la industria - desde C / C ++ a través de Matlab a PHP y javascript. Fue director de tecnología en Webiks y arquitecto de software en WalkMe. Actualmente es arquitecto de software en Vonage e instructor de egghead.
Configuración de CI/CD con acciones de Github
Tiempo de lectura: 8 minutos
La integración continua y el despliegue continuo son imprescindibles para las organizaciones que desean escalar y entregar software de alta calidad a gran velocidad. Este artículo te guía a través del proceso de uso de acciones de github para construir flujos de CI/CD.
¿Qué es CI/CD?
CI/CD es un proceso que conecta el desarrollo con el despliegue a través de un proceso de integración automatizado. La idea es permitir a los desarrolladores introducir cambios en el código como único paso necesario para desplegar esos cambios.
La canalización CI permite que el trabajo en equipo progrese sin problemas automatizando las normas y garantizando la calidad del software. Herramientas como los linters y las pruebas automatizadas proporcionan información que permite integrar los cambios en la rama principal. Estos cambios integrados acaban enviándose a los usuarios finales (producción).
El proceso de CD recibe el código probado y aprobado. Confirma que todos los artefactos necesarios se despliegan en el lugar correcto. Algunos ejemplos: desplegar una aplicación web en un servidor, publicar una biblioteca en el repositorio de un gestor de paquetes o publicar una aplicación móvil en la tienda de aplicaciones.
La automatización de estos procesos garantiza dos cosas importantes: el proceso se realiza con rapidez y es mucho menos propenso a errores.
¿Quiere saber cómo los equipos aceleran sus procesos de desarrollo, integración y despliegue? ¿Preparado para crear una nueva canalización de CI/CD? Póngase en marcha.
Flujo básico de CI/CD
Empuje un cambio a una rama de características.
Crear una Pull Request para este cambio
El CI se pone en marcha y ejecuta lo siguiente:
Lint, probar, construir
Una vez que el CI finaliza, marca el PR como válido y comienza el proceso de Revisión del Código.
Cuando se aprueba el PR, el código se fusiona en master
Tras la fusión, se inicia el proceso de CD:
Lint, Test, Bump version, Deploy
Construiremos un CI/CD para una aplicación sencilla, que puedes clonar aquí.
Añadir un flujo de trabajo de Github a su proyecto
Crea una carpeta .github/workflows. Vamos a añadir nuestras acciones github dentro de esta carpeta. Las acciones se establecen en archivos yaml en una estructura bastante sencilla que consta de tres partes:
nombre: el nombre del flujo de trabajo, en nuestro caso Test and Build
en: el disparador que inicia el flujo de trabajo cuando se cumplen las condiciones. En nuestro caso, queremos que el flujo de trabajo se ejecute cuando se cree y envíe un pull request. Veremos ejemplos de otros disparadores más adelante en el tutorial.
trabajos: los comandos reales que se ejecutan en el flujo. Pueden ser varios trabajos que se ejecutan en paralelo o trabajos que dependen unos de otros. En este ejemplo hay un trabajo llamado build-testque sólo se ejecuta en ubuntu-latest OS.
name: Test and Build
on:
pull_request:
branches:
- main
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup NodeJS 14
uses: actions/setup-node@v1
with:
node-version: 14
- name: Install yarn
run: npm install -g yarn
- name: Install dependencies
run: yarn install
- name: Test
run: yarn testEl primer paso comprueba el repositorio, utilizando una acción pre-hecha actions/checkout@v2 del mercado de acciones. Pasamos la variable fetch-depth: 0 usando la variable con que indica que el proceso de comprobación obtendrá el repositorio con todo su historial. Los siguientes pasos son para la instalación y ejecución de comandos bash.
Creación de un flujo de trabajo de integración continua
Activar el flujo con una Pull Request
Poner en marcha la máquina
Instalar nodeJs en la máquina
Consultar el repositorio
Instalar dependencias
Test, Lint, Build
Mostrar los resultados en la página PR
Primeros pasos
Si aún no has clonado el repositorio, hazlo ahora y crea una rama "add-ci".
Cree un archivo
.github/workflows/ci.ymly copia el contenido de este fichero al nuevo archivo.Confirme los cambios y envíelos a la nueva rama. Abre un pull request desde la nueva rama a la rama principal.
Si miras el pull request en github, deberías ver las pruebas ejecutándose:

Verás que github ya conoce el nombre del flujo de trabajo, el nombre del trabajo y el disparador. Una vez completado, debería verse así:

¿Puede detectar algún problema en el proceso?
Añadir reglas de fusión
El primer problema es que el Fusionar pull request ya estaba disponible durante el proceso CI, cuando sólo queremos que la fusión esté disponible si se han completado todos los flujos de trabajo requeridos.
Podemos arreglar esto en la configuración del repositorio yendo a: Configuración>Regiones>Añadir regla

Aquí seleccionaremos Requerir que las comprobaciones de estado pasen antes de fusionar y comprobaremos todo lo que hay debajo. Verá todos los flujos de trabajo que se requieren para permitir la fusión - en nuestro caso sólo tenemos build-test.

Para Patrón de nombre de rama inserte main y cree la regla. Y si vuelves a la página de pull request, verás que no se pueden fusionar pull requests antes de que pasen las pruebas, a no ser, claro, que tengas privilegios de administrador.

Fusión tras la revisión del código
Antes de seguir adelante, también tenemos que decidir cómo manejar el paso de Pull Requests. Hay tres enfoques principales:
Permitir a cualquiera fusionar una vez superadas las pruebas
Fusión automática una vez superadas las pruebas
Exigir una revisión del código para fusionar
Optaremos por la primera opción, que es la más común, y que podemos cambiar editando la regla de bifurcación que acabamos de crear. Al principio de la lista marcamos Requerir revisiones de pull request antes de fusionar y pulsa guardar.
Se acabó la integración continua. ¡Ahora todos los nuevos Pull Requests serán probados y revisados antes de ser fusionados en el main! El siguiente paso es el despliegue.
Creación de un flujo de trabajo de despliegue continuo
El despliegue puede ser cualquier cosa, desde subir archivos estáticos a github, a publicar paquetes npm, a desplegar una malla completa de microservicios. Este es el proceso que seguiremos para nuestra aplicación una vez que el código se fusione con el repositorio principal:
Instalar dependencias
Prueba
Versión Bump
Construya
Etiquetar el comunicado
Publicar en npm
Despliegue de la aplicación de demostración
Examinemos diferentes partes del archivo yaml que gestiona las acciones:
El desencadenante
Estas son las condiciones en las que se ejecutará nuestro código de despliegue. Se activará en un pull request que haya sido cerrado y fusionado.
name: Test, Build and Deploy
on:
pull_request:
types: [closed]
jobs:
build-test-release:
if: github.event.action == 'closed' && github.event.pull_request.merged == true
runs-on: ubuntu-latest
Permisos de acciones Git
En el paso de comprobación, añadiremos una línea extra que no teníamos en el archivo yaml anterior:
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.CI_REPOSITORY_ACCESS_TOKEN }}Necesitamos establecer explícitamente el token para poder hacer cosas para las que el token por defecto, secrets.GITHUB_TOKENno tiene permisos. En nuestro caso, vamos a querer enviar un cambio a main sin una revisión de código, por lo que necesitamos un token con privilegios de administrador. Establecemos este token en Configuración -> Secretos.
Aumentar las versiones de los paquetes
Este paso difiere de un proyecto a otro. La idea es subir la versión del paquete que pretendes publicar en el repositorio de paquetes. Haremos esto repasando todas las librerías que han cambiado en esta rama, y subiremos su versión NPM:
- name: Raise version of affected libraries
run: |
LATEST_TAG=$(git tag -l "v*" --sort=-version:refname | head -n 1)
LIBS=$(yarn nx affected:libs --base=$LATEST_TAG --head=HEAD --plain | awk 'NR > 2 && $1 != "Done" { print $1 }')
for LIBRARY in $LIBS
do
cd ./libs/$LIBRARY
npm version minor --no-git-tag-version --no-push
echo "Bumping $LIBRARY"
cd ..
cd ..
done
npm version minor --no-git-tag-version --no-push
Tenga en cuenta que estamos utilizando NX, un marco de gestión monorepo, que ayuda a hacer construcciones y desarrollo mucho más rápido. Utilizamos la función affected que nos indica qué bibliotecas se han visto "afectadas" por el PR.
Construya
El proceso de compilación también utiliza la función affected también. Construye las bibliotecas modificadas que han cambiado desde la rama principal con preajustes de producción:
- name: Build components
run: yarn nx affected:build --prod --with-deps --base=main Etiquetar el comunicado
El etiquetado de liberación se realiza en dos pasos:
La primera, get-npm-versionutiliza una acción del mercado que extrae la versión del paquete principal. El segundo paso confirma los cambios realizados en el paso Raise version mencionado anteriormente, crea una etiqueta con la versión del nuevo package.json y envía el cambio.
¿Recuerdas el CI_REPOSITORY_ACCESS_TOKEN secreto? Aquí es donde entra en juego. Debido a que impedimos la fusión a maestro sin una revisión pull request, necesitamos un token de administrador para esta parte, lo que nos permitirá eludir la regla y empujar los cambios de forma automática.
- name: get-npm-version
id: package-version
uses: martinbeentjes/npm-get-version-action@master
- name: Tag the release
run: |
git fetch
git config user.email "unicorn.ci@yonatankra.com"
git config user.name "Unicorn CI"
git add --all
git commit -m "update versions to ${{ steps.package-version.outputs.current-version }}"
git push
- name: Tag release
run: |
git tag -a v${{ steps.package-version.outputs.current-version }} -m "tag release v${{ steps.package-version.outputs.current-version }}"
git push --follow-tags Despliegue de la aplicación de demostración
Por último, creamos nuestra aplicación y la desplegamos:
- name: Build Demo
run: yarn build:deploy
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: dist/apps/unicorn-hunt # The folder the action should deploy.
CLEAN: true # Automatically remove deleted files from the deploy branchPuede encontrar el código yaml completo aquí
Optimización del flujo CI/CD
Uso de la caché en las acciones de github
Si has seguido a lo largo y creado el flujo de CI / CD, usted puede notar que está tomando un tiempo para ejecutarse. Una solución fácil para eso es utilizar la caché y ahorrar en tiempos de instalación de dependencias, algo que también podemos hacer con las acciones de github.
El almacenamiento en caché funciona comprobando la existencia de una coincidencia en la caché y, si se encuentra, omite el paso de instalación de dependencias. Este es el aspecto del código:
- name: Install yarn
run: npm install -g yarn
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Cache yarn dependencies
uses: actions/cache@v2
id: yarn-cache
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**\node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn installEl primer paso instala yarn globalmente. El segundo obtiene la ruta de la carpeta de caché de yarn. A continuación, el paso de caché utiliza la acción de caché y pasa las rutas a la caché (node_modules y la carpeta de caché de yarn) y le da una clave de caché mediante el hash del archivo yarn.lock. De esta forma, si instaláramos una nueva dependencia o actualizáramos una dependencia, se produciría un cache miss. El paso final establece una condición en el paso install-dependencies utilizando el parámetro cache-hit establecida por la acción de caché.
Modularizar el proceso
Así que el CI/CD está funcionando. Está utilizando la caché. Antes mencionamos que también nos gustaría publicar nuestras dos bibliotecas en la carpeta libs en npm. Técnicamente podemos añadir otro paso a nuestro proceso de CD, pero eso podría hacerlo engorroso y difícil de mantener.
En su lugar, dividimos el proceso en flujos de trabajo separados que son activados por el proceso principal del CD. El CD levantaría entonces una versión, que activaría los otros procesos, causando el despliegue y la publicación en NPM.
Además de una mejor mantenibilidad, esto también permite una mejor gestión de errores. Porque supongamos que el versionado y la publicación han tenido éxito, pero el despliegue ha fallado. Esto nos permite ejecutar el despliegue de nuevo y depurar hasta que tenga éxito.
El código completo de la solución puede encontrarse aquí.
Resumen
En este artículo hemos construido un proceso CI/CD usando acciones de github.
Empezamos añadiendo el proceso CI que ejecuta las pruebas y dice a nuestros revisores de código que el Pull Request está listo para revisión. También aprendimos cómo bloquear la fusión en una rama sin pasar las pruebas y una revisión. Hemos visto un código CI simplificado, pero puedes añadir más comandos bash a la fase de pruebas, o incluso añadir más pasos como linting o prettier.
A continuación, creamos un proceso de CD que bate las versiones y despliega la demo. Aprendimos a almacenar en caché la instalación de dependencias para ahorrar tiempo y a modularizar el proceso de CD para tener más control y facilidad de mantenimiento.
Hay mucho más que se puede hacer con las acciones de github. Esperamos que este tutorial te haya ayudado a crear un proceso de CI/CD útil y significativo para tu equipo.
Compartir:
Yonatan ha estado involucrado en algunos proyectos impresionantes en la academia y la industria - desde C / C ++ a través de Matlab a PHP y javascript. Fue director de tecnología en Webiks y arquitecto de software en WalkMe. Actualmente es arquitecto de software en Vonage e instructor de egghead.