A continuación les presento una manera sencilla de como configurar la integración y despliegue continuo del proyecto por medio de GitHub actions, luego de una larga reticencia por mi parte para finalmente probar esta tecnología.
No hace mucho fue que los problé, en un pequeño proyecto de fin de semana, del cual hablé en el artículo Creando un jurado online (parte 1). Ahí fue donde vi el potencial y las cosas que se podían hacer. Resulta, que al igual que en Gitlab se pueden utilizar de manera completamente gratuita y pueden probarlo en sus proyectos personales sin ningún problema.
La configuración de los Action de GitHub puede ser muy sencilla de crear. Puede hacerse de manera manual creando el archivo en el proyecto o si es la primera vez, hacer uso de las plantillas iniciales que GitHub provee con una amplia gama de tecnologías.
En mi caso, que ya cuento con proyectos utilizando la integración de GitHub relacionada a Nodejs, pues todo se resume a crear la carpeta .github en el proyecto y luego dentro otra carpeta con el nombre de workflow, quedando la raíz de esta manera: .github/workfow.
Dentro de la carpeta workflow se crea el archivo que describe la integración continua en formato yml. Una de las primeras cuestiones que hay que tener en cuenta antes de entrar en materia, es la estructura básica de la configuración de nuestro GitHub action. A continuación muestro una configuración básica y previamente explicaré como funciona:
# ci-cd.yml
name: CI/CD
on: [ push, pull_request ]
jobs:
job1:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 12.x, 14.x ]
steps:
- name: Clone project from the repository
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Install project dependencies
run: npm ci
En el archivo anterior lo que se puede ver, es un pipeline que instala las dependencias del proyecto, primeramente con node12 y luego con node14.
Explicando detalladamente la configuración anterior, sería lo siguiente:
El caso anterior es un ejemplo bien sencillo de la configuración de un pipeline, con solo agregar la ejecución de los tests del proyecto podría ser perfectamente un pipeline válido y utilizable en cualquier proyecto.
Como primer paso, tiene todo el sentido del mundo determinar en la integración continua: el comprobar la validez de nuestro código antes de hacer ninguna operación de despliegue que pueda destruir lo que debidamente se encuentra funcionando en producción o cualquier otro environment.
A continuación, un ejemplo de como quedaría el archivo de configuraciones:
name: CI/CD
on: [ push, pull_request ]
jobs:
# BUILD PROJECT AND DEPENDENCIES
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 12.x ]
steps:
- uses: actions/checkout@v2
- name: Cache project node-modules
uses: actions/cache@v2
with:
path: 'node_modules'
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
# pipeline actions
- run: npm ci
- run: npm run build
# RUN TESTS AND LINT
test:
needs: [ build ]
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 12.x ]
steps:
- uses: actions/checkout@v2
- name: Cache project node-modules
uses: actions/cache@v2
with:
path: 'node_modules'
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Install codecov dependency
run: npm install -g codecov
# pipeline actions
- run: npm run lint
- run: npm test
- run: codecov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
En el ejemplo anterior se presentan 2 jobs, el primero permite instalar las dependencias y construir el proyecto, y en el segundo ejemplo se ejecutan el chequeo de estilo (lint), los tests y luego se sube el coverage a codecov.io.
Para el despliegue del proyecto en un hosting, se hará uso de algunos actions que por medio de SSH permiten copiar el proyecto a donde se determine y previamente ejecutar los mismo.
A continuación, un ejemplo de cómo puede quedar la configuración de nuestro job para desplegar el proyecto:
name: Deployment CI
on: [ push, pull_request ]
jobs:
...
# DEPLOY BLOG (PRODUCTION)
deploy:
needs: [ test ]
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Copy project to the hosting
uses: easingthemes/ssh-deploy@v2.1.5
env:
SSH_PRIVATE_KEY: $ {{ secrets.SERVER_SSH_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: ""
REMOTE_HOST: $ {{ secrets.REMOTE_HOST }}
REMOTE_USER: $ {{ secrets.REMOTE_USER }}
TARGET: $ {{ secrets.PROD__REMOTE_TARGET }}
- name: Deploy project with docker in hosting
uses: garygrossgarten/github-action-ssh@release
with:
command: cd $ {{ secrets.PROD__REMOTE_TARGET }} && docker-compose up -d
host: $ {{ secrets.REMOTE_HOST }}
username: $ {{ secrets.REMOTE_USER }}
privateKey: $ {{ secrets.SERVER_SSH_KEY}}
En las configuraciones anteriores se hace referencia en varias ocasiones a los secrets de GitHub en los jobs. Para configurar nuevos secrets en el proyecto, hay que ir a las configuraciones del proyecto:
Dentro de las configuraciones se elegir el área destinada a los secrets:
Y por último, crear un nuevo secret.
De esta manera pueden crear todos los secrets que necesiten en el proyecto.
Para más referencias sobre el tema, pueden revisar el repositorio de Binary Coffee en Github:
También pueden revisar la documentación oficial de GitHub actions:
Espero que la experiencia compartida sirva para que de forma más eficiente y rápida puedan configurar la integración continua de sus proyectos con GitHub Actions.
Happy Coding!!!