¿Qué es GitHub Actions? Explicación y caso de uso
¿Qué es GitHub Actions?
GitHub Actions es una plataforma de automatización de flujos de trabajo dentro de GitHub. Permite automatizar tareas repetitivas en el ciclo de vida del desarrollo de software, como:
- Compilación y pruebas
- Implementación
- Notificaciones
- Análisis de código
- Integración con otras herramientas
¿Para qué sirve?
Tienes la capacidad de simplificar y agilizar tu proceso de desarrollo de software. Automatiza las tareas que antes requerían tiempo y esfuerzo manual, lo que te permite dedicar más tiempo a la creación y mejora de tu proyecto.
Desde la compilación y pruebas de tu código, hasta la implementación y notificaciones de nuevos cambios, te ofrece la flexibilidad y potencia necesarias para optimizar tus flujos de trabajo.
Además, también puedes aprovechar la funcionalidad de análisis de código para identificar posibles errores, mejorar la calidad y asegurar que tu proyecto cumpla con los estándares establecidos.
Integrar tu proyecto con otras herramientas es otro beneficio clave. Puedes conectar fácilmente tu repositorio con servicios externos, como servicios de implementación continua, sistemas de gestión de incidencias o plataformas de pruebas automatizadas.
¿Cómo nos puede ayudar en el ciclo de vida del desarrollo de software?
GitHub Actions puede ayudarte en todas las etapas del ciclo de vida del desarrollo de software, desde la planificación hasta la implementación:
- Planificación: Puedes crear flujos de trabajo para automatizar la creación de tickets, la asignación de tareas y la gestión de versiones.
- Desarrollo: Puedes automatizar la compilación, las pruebas y la linting de tu código.
- Pruebas: Puedes ejecutar pruebas automatizadas para asegurarte de que tu código funciona correctamente.
- Implementación: Puedes automatizar la implementación de tu código a producción.
- Mantenimiento: Puedes configurar flujos de trabajo para monitorizar tu código y detectar errores.
¿Por qué deberíamos implementarlas?
Algunos de los muchos beneficios que tiene son:
- Mejora la productividad: Ahorra tiempo y esfuerzo al automatizar tareas repetitivas.
- Mejora la calidad del código: Reduce el número de errores y mejora la calidad general del código.
- Aumenta la colaboración: Facilita la colaboración entre los miembros del equipo.
- Reduce costes: Elimina la necesidad de herramientas de automatización adicionales.
- Escala tu desarrollo: Te permite escalar tu proceso de desarrollo a medida que tu proyecto crece.
Tecnologías
El stack de versiones que se usarán para el desarrollo del proyecto es el siguiente:
- Node (20.11.1)
- Pnpm (8.15.4)
Objetivo
Vamos a aprender a definir flujos de trabajo con GitHub Actions. Posteriormente, implementaremos un flujo de integración (CI) y otro de despliegue (CD), haciendo uso de GitHub Pages para publicar nuestro proyecto de forma automática.
Introducción, ¿Qué es un workflow?
Un workflow, o flujo de trabajo, es la unidad principal a la hora de trabajar con GitHub Actions. Es un archivo YAML (o yml) en el que se definen las configuraciones. En un proyecto puede haber uno o varios workflows definidos.
Componentes principales
A continuación vamos a definir los diferentes componentes que nos podemos encontrar.
- Workflow
- Es un proceso automatizado configurable que ejecuta uno o más jobs.
- Se define en un archivo YAML con la extensión .yml en el directorio .github/workflows de cada repositorio.
- Un repositorio puede tener varios workflows.
- El archivo YAML define el nombre del workflow, los eventos que lo activan, los jobs que se ejecutan y el orden de ejecución.
- Job
- Es un conjunto de tareas o steps que se ejecutan en el mismo runner.
- Un workflow puede tener uno o más jobs.
- Los jobs se ejecutan de forma secuencial.
- En él se define el sistema operativo del runner donde se ejecuta y los steps que se ejecutan.
- Se definen bajo la etiqueta jobs
- Step
- Es una tarea individual que puede ser un script de shell o un action.
- Un job puede tener uno o más steps.
- Los steps se ejecutan en orden.
- En él se define el nombre del step, el tipo de step (script o action) y los comandos o la acción que se ejecuta.
- Se definen bajo la etiqueta steps
- Action
- Es una aplicación o script personalizado que realiza una tarea compleja de forma repetitiva.
- Se pueden encontrar y reutilizar actions en el GitHub Marketplace.
- Las actions se pueden usar en steps de un job.
- En él se define el nombre de la action y la versión que se usa.
Otros conceptos:
- Evento
- Es una acción que desencadena la ejecución de un workflow.
- Los eventos pueden ser internos (por ejemplo, un push a una rama específica) o externos (por ejemplo, una llamada a una API).
- El archivo YAML define los eventos que activan el workflow.
- Runner
- Es un servidor donde se ejecutan los workflows.
- GitHub proporciona runners con diferentes sistemas operativos (Ubuntu, Windows, macOS).
- También se pueden configurar runners propios.
- El archivo YAML define el sistema operativo del runner donde se ejecuta el job.
- GitHub Marketplace
- Es una página donde se pueden encontrar y reutilizar actions creadas por la comunidad.
- Hay más de 17.000 actions disponibles en el Marketplace.
- Las actions se pueden buscar por categoría, nombre o funcionalidad.
Puntos clave:
- Los workflows, jobs, steps y actions se encapsulan uno a otro.
- Un workflow puede tener uno o más jobs, un job puede tener uno o más steps, y un step puede usar uno o más actions.
- Los jobs se ejecutan en runners con diferentes sistemas operativos.
- Se pueden tener diferentes workflows para diferentes tareas (integración continua, despliegue continuo, automatización de tareas, etc.).
- Los workflows se definen en archivos YAML con una sintaxis específica.
Ahora que ya sabemos todo lo necesario, ¡comencemos con el proyecto!
Preparación del proyecto
Ejecutamos el siguiente comando para crear un proyecto de NextJS y completamos los prompts.
pnpm create next-app
What is your project named? > github-actions-workflow
Would you like to use TypeScript? > Yes
Would you like to use ESLint? > Yes
Would you like to use Tailwind CSS? > Yes
Would you like to use `src/` directory? > No
Would you like to use App Router? (recommended) > Yes
Would you like to customize the default import alias (@/*)? > No
Ahora vamos a configurar el archivo next.config.mjs de nuestro proyecto. Cambiamos el tipo de output a «export» para indicar que queremos generar un sitio estático que no hace uso de NodeJS. Y cambiamos el basePath y assetPrefix porque las páginas desplegadas en GitHub Pages no apuntan al root, sino a {github_username}.github.io/{repository_name}.
next.config.mjs
// Name of our GitHub repository
const GITHUB_REPO_NAME = 'github-actions-workflow';
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
basePath: `/${GITHUB_REPO_NAME}`,
assetPrefix: `/${GITHUB_REPO_NAME}/`,
trailingSlash: true,
images: {
unoptimized: true,
}
};
export default nextConfig;
Le quitamos el / de la ruta a las imágenes. También modificamos un poco el texto que viene por defecto para que al desplegar podamos comprobar que están nuestros cambios.
page.tsx
import Image from "next/image";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
¡Me han desplegado automáticamente con GitHub Actions!
</p>
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
<a
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{" "}
<Image
src="vercel.svg"
alt="Vercel Logo"
className="dark:invert"
width={100}
height={24}
priority
/>
</a>
</div>
</div>
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-full sm:before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full sm:after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
<Image
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
src="next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>
...
</main>
);
}
Definición de los workflows
Vamos a crear la carpeta .github en el root del proyecto, y dentro de ésta crearemos la carpeta workflow. Dentro de ésta carpeta crearemos varios archivos. El primero, auto-integrate.yml y el segundo, auto-deploy.yml.
Workflow de integración
Definiremos un workflow que escuche los eventos de pull request en la rama staging de nuestro repositorio. También le daremos permisos de write sobre las pull request para que pueda ejecutar acciones sobre ellas.
auto-integrate.yml
# Workflow for linting and integrate a Pull Request into Staging branch
name: Auto integrate Pull Request
run-name: Automatically integrates Pull Requests into Staging branch (with checks and approvals)
# Trigger on pull request events for the 'staging' branch
on:
pull_request:
branches: [ staging ]
# Grant write access to pull requests for necessary actions
permissions:
pull-requests: write
Dentro de este workflow tendremos diferentes jobs. El primero ejecutará el linter para comprobar que la pull request tiene el formato correcto. Seguidamente se aprobará. Después, se le pondrá un label, en nuestro caso: «automerge«. Y como último job, se mergeará la pull request.
Cabe recalcar que usaremos la etiqueta needs en todos los jobs, y estos se convertirán en pasos secuenciales en los cuales si uno falla todo el proceso se detendrá.
Para el último job necesitaremos crear un Personal Access Token en GitHub, ya que sino no se hará el trigger de evento de merge, y el siguiente workflow nunca será ejecutado.
auto-integrate.yml
jobs:
lint:
# Change 'ivanpajon' to your github username if you fork this project
if: github.event.pull_request.user.login == 'ivanpajon'
name: Lint project before approve
runs-on: ubuntu-latest
env:
NODE_VERSION: 20
steps:
- uses: actions/[email protected]
- uses: pnpm/action-setup@v3
with:
version: 8
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/[email protected]
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run Linter
run: pnpm run lint
# Consider additional checks like run tests
auto-approve-pr:
# Trigger this job after the 'lint' job successfully completes
needs: lint
name: Auto approve Pull Request
runs-on: ubuntu-latest
# Auto approve
steps:
- uses: hmarr/auto-approve-action@v4
auto-label-pr:
# Trigger this job after 'auto-approve-pr' successfully completes
needs: auto-approve-pr
name: Auto label Pull Request if approved
runs-on: ubuntu-latest
steps:
- name: Auto label when approved
uses: koj-co/label-approved-action@master
with:
# Label to trigger auto merge
labels: "automerge"
# Require at least one approval
approvals: 1
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
auto-merge-pr:
# Trigger this job after 'auto-approve-pr' successfully completes
needs: auto-label-pr
name: Auto merge Pull Request if labeled
runs-on: ubuntu-latest
# Grant write permissions to content for merging
permissions:
contents: write
steps:
- name: Auto-merge if labeled
uses: "pascalgn/[email protected]"
env:
# Use Personal Access Token to merge
GITHUB_TOKEN: "${{ secrets.GH_PAT }}"
¡Listo! Ahora cada vez que se cree una pull request se ejecutará nuestro workflow.
Workflow de despliegue
Solo nos queda el workflow de despliegue (CD). Para ello seguiremos los mismos pasos anteriores, crearemos un archivo llamado auto-deploy.yml en la carpeta .github/workflows.
En este caso el workflow será ejecutado cuando se cierre una pull request sobre la rama staging. Y también le daremos los permisos necesarios para desplegar nuestro proyecto a GitHub Pages.
auto-deploy.yml
# Workflow for building and deploying a Next.js site to GitHub Pages
name: Auto deploy to GitHub Pages
run-name: Automatically deploys to GitHub Pages
on:
# Runs on pull request merged
pull_request:
types: [ closed ]
branches: [ staging ]
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
Para este workflow definiremos dos jobs. El primero estará encargado de hacer el build y preparar el despliegue. Y el segundo, hará el despliegue en GitHub Pages.
El job del build además contará con una validación extra que comprobará que la pull request fue cerrada por un merge, y que la misma contaba con el label «automerge«.
auto-deploy.yml
jobs:
# Build job
build:
# Run only if the Pull Request was closed because of a merge and has the 'automerge' label
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'automerge')
name: Build and prepare for deployment
env:
NODE_VERSION: 20
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/[email protected]
- uses: pnpm/action-setup@v3
with:
version: 8
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/[email protected]
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm run build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./out
# Deployment job
deploy:
# Trigger this job after the 'build' job successfully completes
needs: build
name: Deploy to GitHub Pages
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages!
id: deployment
uses: actions/deploy-pages@v4
¡Lo tenemos! Ya terminamos nuestros flujos de integración y despliegue.
Probando los workflows
Subimos el proyecto a nuestro Github. Y una vez accedemos al repositorio abrimos la pestaña de Actions. Después de habilitar los GitHub Actions en nuestro repositorio encontraremos los dos workflows que hemos definido.
En la pestaña Settings tendremos que configurar un par de opciones. Una para indicar que vamos a desplegar a GitHub Pages mediante GitHub Actions, y otra para darle permisos de crear y aprobar pull requests a GitHub Actions.
Además, tendremos que crear nuestro Personal Access Token y agregarlo como secreto del repositorio.
Ahora tenemos que crear la rama staging. En mi caso uso GitKraken como cliente de git asi que lo haré desde ahí.
A continuación, crearemos la primera pull request para llevar los cambios de la rama develop a la rama staging.
Y podemos ver como la creación de la pull request ha hecho trigger de nuestro flujo de integración.
Automáticamente, cuando finalice este workflow, se hará trigger del workflow de despliegue. Y también podremos monitorizarlo.
¡Ya tenemos nuestro proyecto desplegado! Esto es realmente increíble. De una forma automatizada hemos conseguido desplegar nuestro proyecto en GitHub Pages, y gracias a la configuración de los workflows, cada vez que hagamos cambios y queramos desplegar de nuevo no tendremos más que crear una nueva pull request 🥳.
Como podrás observar, en el resultado del job de despliegue se nos muestra un enlace a nuestro proyecto desplegado. Si accedemos veremos el texto «¡Me han desplegado automáticamente con GitHub Actions!» que modificamos. Puedes consultar el de este proyecto aquí.
Github
Todo el código fuente lo puedes encontrar aquí.
Analyst Frontend Developer en Comunytek (BBVA CIB – NOVA).
Autodidacta, apasionado de las nuevas tecnologías y de los proyectos DIY.