Cómo crear acciones utilizando GitHub Actions

0
2907

Las acciones de GitHub Actions son tareas que se pueden ejecutar en los flujos de trabajo o workflows que definimos en nuestro proyecto. Existen múltiples acciones en el Marketplace de GitHub que se pueden utilizar, como son «setup-java», «cache» o las que permiten cargar y descargar artefactos de nuestros proyectos. Además de todo eso, también podemos desarrollar nuestras propias acciones para usar en nuestro proyecto o hacerlas públicas para que otros desarrolladores puedan usarlas.

  1. Introducción
  2. Entorno
  3. Configurar metadatos de la acción
  4. Crear una acción con Docker
  5. Crear una acción con JavaScript
  6. Publicar nuestra acción en GitHub Marketplace
  7. Conclusiones
  8. Recursos

Introducción

Las acciones de GitHub Actions permiten a los desarrolladores realizar tareas que pueden interaccionar con el repositorio o hacer cualquier otro tipo de tareas como acceder a APIs para obtener y procesar cualquier tipo de información.

Estas acciones se pueden escribir tanto en JavaScript, como en Docker, lo que permite a los desarrolladores programar la funcionalidad en cualquier lenguaje que pueda correr en uno de estos contenedores.

En este tutorial se van a hacer dos proyectos sencillos que servirán para comprender la sintaxis con la que se especifican y desarrollan las acciones de GitHub. Dichos proyectos tendrán como entrada un texto y el número de veces que queremos repetirlo, para devolverlo como parámetro de salida. Se hará un ejemplo con Docker y otro con JavaScript. Se puede ver el ejemplo completo en este repositorio de GitHub: https://github.com/julenminer/ejemplo-de-acciones

Durante este tutorial también se van a utilizar flujos de trabajo (workflows), que serán los que hagan uso de las acciones que vamos a crear. Para conocer más sobre estos flujos, es recomendable leer el tutorial: Introducción a la sintaxis básica de GitHub Actions.

Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 14 (2,2 GHz Intel Core i7, 16GB 1600 MHz DDR3, 500GB Flash Storage)
  • GitHub y Github Actions

Configurar metadatos de la acción

La configuración de los metadatos es necesaria para hacer funcionar nuestra acción. Para definirlos se utilizan archivos YAML y el nombre del archivo debe ser action.yml  o action.yaml . Las acciones se pueden definir en diferentes rutas, pero en este ejemplo utilizaremos una ruta que es comúnmente utilizada para acciones que no van a ser publicadas en el Marketplace (más adelante veremos otras rutas), .github/actions/<ACTION_NAME>/action.yml , donde <ACTION_NAME> es el nombre que vamos a dar a nuestra acción (sin espacios).

Una vez tenemos el fichero creado, debemos empezar a configurarlo con la sintaxis YAML. Estos son algunos de los parámetros que se pueden o deben configurar:

  • name: obligatorio, es el nombre que le queremos dar a la acción.
  • autor: opcional, el nombre del autor.
  • description: obligatorio, la descripción de la acción.
  • inputs: opcional, sirve para definir los parámetros de entrada que va a tener nuestra acción. Esto va a permitir que el flujo de trabajo configure el comportamiento de la acción dependiendo de los valores que se le pasen. Para configurar cada uno de los parámetros de entrada, se debe especificar lo siguiente, con un nivel más de tabulación:
    • El nombre del input, que será el identificador que luego se use para obtener el valor de entrada. Este valor se escribe directamente, no le precede ninguna etiqueta (después se verá en un ejemplo). Los siguientes valores que siguen al nombre del input tienen un nivel más de tabulación.
    • description: obligatorio, es la descripción del parámetro.
    • required: obligatorio, un booleano que indica si el usuario de la acción debe especificar un parámetro obligatoriamente.
    • default: opcional, es un valor que tendrá por defecto el input si el usuario no especifica ninguno a la hora de usar la acción.
  • outputs: opcional, sirve para definir los valores que va a devolver la acción. Normalmente se usan para dar el resultado de una operación o petición. Estos datos de salida se podrán utilizar posteriormente en el flujo de trabajo. Para configurar los parámetros de salida de datos, se debe especificar lo siguiente, con un nivel más de tabulación, al mismo nivel que los inputs:
    • El nombre del output, que será el identificador en el que después se dejen los datos. Este valor se escribe directamente, no le precede ninguna etiqueta (después se verá en un ejemplo). Los siguientes valores que siguen al nombre del output tienen un nivel más de tabulación.
    • description: obligatorio, es la descripción del parámetro de salida.

Estos parámetros son los necesarios para definir una acción con GitHub Actions. Además de éstos, también se deben definir otros parámetros para que la acción sepa cómo debe ejecutar la aplicación JavaScript o el contenedor Docker, pero dichos parámetros se verán en la sección de cada uno.

También se puede configurar el branding para poner un icono a nuestra acción y que se muestre con el mismo. Los parámetros son:

  • branding: no es procedido de nada, es necesaria esta etiqueta para comenzar a definir el icono. Las siguientes etiquetas tienen un nivel más de tabulación.
  • icon: el nombre del icono que queremos poner de la biblioteca de Feather icons (https://feathericons.com/)
  • color: el color que queremos poner a nuestro branding. Las opciones son: white, yellow, blue, green, orange, red, purple, or gray-dark.

A continuación se muestra un ejemplo de cómo se define un archivo de metadatos con todos los parámetros que se han explicado anteriormente:

name: 'Acción de repetición'
author: 'Julen'
description: 'Repite un número de veces el texto indicado'

inputs:
	input_text:
		description: 'El texto que queremos repetir varias veces'
		required: true
	num_of_repeats:
		description: 'Número de veces que queremos que aparezca el texto'
		required: false
		default: '1'

outputs:
	output_text:
		description: 'El texto repetido el número de veces indicado'

# Aquí van los valores específicos para configurar Docker 
# o JavaScript, se explicarán más adelante.

branding:
	icon: 'rotate-cw'
	color: 'blue'

Crear una acción con Docker

Para crear una acción con contenedores de Docker se deben especificar el Dockerfile que va a crear el contenedor, los archivos que vaya a ejecutar dicho contenedor (por ejemplo un programa en Python) y el archivo de metadatos.

Primero escribiremos el archivo con los metadatos copiando la especificación del punto anterior y añadiendo los parámetros de Docker. Estos parámetros son:

  • runs: obligatorio, indica que se comienza a especificar cómo se va a ejecutar la acción. El resto de valores tienen un nivel mayor de tabulación.
  • using: obligatorio, qué tecnología se va a utilizar para la aplicación, en este caso docker.
  • image: obligatorio, la imagen de docker que queremos utilizar.
  • args: opcional, los argumentos de entrada para el contenedor. En este ejemplo no se van a configurar.
  • env: opcional, especifica las variables de entorno de configuración del contenedor en forma de clave-valor.
  • entrypoint: opcional, invalida el ENTRYPOINT de Docker y ejecuta las instrucciones que se especifiquen en un script. En este ejemplo no se va a configurar este parámetro. Se especificaría como entrypoint: ‘entrypoint.sh’ .
  • pre-entrypoint: opcional, permite ejecutar un script antes del ENTRYPOINT, se suele utilizar para realizar configuraciones antes de la ejecución. En este ejemplo no se va a configurar este parámetro. Se especificaría como pre-entrypoint: ‘pre-entrypoint.sh’ .
  • post-entrypoint: opcional, permite ejecutar un script después del ENTRYPOINT, se suele utilizar para realizar una limpieza. En este ejemplo no se va a configurar este parámetro. Se especificaría como post-entrypoint: ‘post-entrypoint.sh’ .

Teniendo los parámetros en cuenta, el archivo de configuración action.yml  de nuestro ejemplo es el siguiente:

name: 'Acción de repetición con Docker'
author: 'Julen'
description: 'Repite un número de veces el texto indicado'

inputs:
	input_text:
		description: 'El texto que queremos repetir varias veces'
		required: true
	num_of_repeats:
		description: 'Número de veces que queremos que aparezca el texto'
		required: false
		default: '1'

outputs:
	output_text:
		description: 'El texto repetido el número de veces indicado'

runs:
	using: 'docker'
	image: 'Dockerfile'

branding:
	icon: 'rotate-cw'
	color: 'blue'

Todos los archivos que tengan que ver con esta acción van a estar en la ruta .github/actions/docker-repeat  de este proyecto, ya que va a ser una acción privada y habrá más de una acción en el mismo repositorio. El siguiente paso va a ser crear la parte del contenedor y la aplicación que va ser la encargada de implementar la funcionalidad que queremos. La parte de la aplicación se puede hacer con diferentes lenguajes, los que sean soportados por contenedores Docker, en este caso se va a hacer con Python.

Empezaremos por crear los archivos de la aplicación de Python, lo haremos en la carpeta src  en la ruta de la acción. Creamos aquí un archivo main.py  que será en el que se recojan los parámetros de entrada y se escriba el parámetro de salida, con el siguiente contenido:

import os

# Get the input values
text = os.environ["INPUT_INPUT_TEXT"]
numOfRepeats = int(os.environ["INPUT_NUM_OF_REPEATS"])

outputText = ""
for i in range(numOfRepeats):
	outputText += text

# Set the output value
print(f"::set-output name=output_text::{outputText}")

Después de haber creado este archivo, el siguiente paso es crear el archivo Dockerfile que especificará el contenedor a crear y ejecutará la aplicación Python que se ha desarrollado anteriormente. El archivo Dockerfile tiene que estar en la misma ruta que el archivo action.yml , y su contenido es el siguiente:

FROM python:3

COPY . .

CMD ["python", "/src/main.py"]

Con la creación del archivo Dockerfile ya hemos terminado de definir nuestra acción y el siguiente paso será crear un flujo de trabajo (workflow) que sea el que se encargue de llamar a la acción para probar que funciona correctamente. Para ello vamos a crear el archivo action-workflow.yml  (se le puede dar cualquier nombre) en el directorio .github/workflows  y tendrá el siguiente contenido:

name: Workflow for our actions

on: [push]

jobs:
	run-docker-action:
		runs-on: ubuntu-latest

		steps:
			- uses: actions/checkout@v1

			- name: Docker repeat action
				uses: ./.github/actions/docker-repeat
				id: docker-action
				with:
					input_text: "texto de prueba"
					num_of_repeats: "4"

			- name: Print docker output
				run: echo ${{ steps.docker-action.outputs.output_text }}

Este flujo se ejecuta cada vez que hagamos push en el repositorio y ejecuta las acción que hemos creado para luego imprimir su contenido en la consola. Una vez tengamos todo, podemos hacer push al repositorio con todos los archivos para que se ejecute la acción. El resultado de este workflow lo podemos ver en la pestaña «Actions» del repositorio. En esta pestaña veremos, bajo la parte de «Print docker output» el resultado de la acción.

captura consola acción docker

Como podemos ver, la aplicación se ha ejecutado dentro de un contenedor de Docker que hemos definido en un Dockerfile. Aunque este ha sido un ejemplo muy sencillo, podemos configurar el contenedor con todos los requisitos que tenga nuestro proyecto para poder probarlo en el entorno adecuado.

Crear una acción con JavaScript

Para crear una acción utilizando JavaScript, tenemos que configurar el archivo de la acción para que se ajuste a este tipo de lenguaje. Este tipo de acciones hace uso de Node.js para poder empaquetar el proyecto e instalar las dependencias que tenga el proyecto y poder probarlo siempre en el mismo entorno.

Por lo tanto, nuestro proyecto tendrá un archivo package.json que será el encargado de registrar los paquetes que utilicemos. Esto es importante ya que necesitaremos incluir en el proyecto paquetes que serán los que nos permitan conectar con el flujo de las acciones para, por ejemplo, obtener las variables de entrada y escribir en la de salida.

El primer paso es crear el archivo de metadatos, por lo tanto, vamos a ver los elementos que se pueden añadir:

  • runs: obligatorio, indica que se comienza a especificar cómo se va a ejecutar la acción. El resto de valores tienen un nivel mayor de tabulación.
  • using: obligatorio, la tecnología que se va a utilizar para ejecutar el proyecto.
  • main: obligatorio, el archivo que contiene el código de la acción.
  • pre: opcional, permite ejecutar código antes de main. En este proyecto no se va a configurar este parámetro. Se especificaría como pre: ‘pre.js’ .
  • pre-if: opcional, añade una condición para que se ejecute el código de pre. En este proyecto no se va a configurar este parámetro. Se especificaría como pre-if: ‘runner.os == linux’ .
  • post: opcional, permite ejecutar código después de main. En este proyecto no se va a configurar este parámetro. Se especificaría como post: ‘post.js’ .
  • post-if: opcional, añade una condición para que se ejecute el código de post. En este proyecto no se va a configurar este parámetro. Se especificaría como post-if: ‘runner.os == linux’ .

Crearemos el archivo action.yml  en la ruta .github/actions/js-repeat , donde incluiremos también el resto de archivos. El contenido del fichero de metadatos es el siguiente:

name: 'Acción de repetición con JavaScript'
author: 'Julen'
description: 'Repite un número de veces el texto indicado'

inputs:
  input_text:
    description: 'El texto que queremos repetir varias veces'
    required: true
  num_of_repeats:
    description: 'Número de veces que queremos que aparezca el texto'
    required: false
    default: '1'

outputs:
  output_text:
    description: 'El texto repetido el número de veces indicado'
  
runs:
  using: 'node12'
  main: 'src/main.js'

branding:
  icon: 'rotate-cw'
  color: 'yellow'

El siguiente paso es el de crear el archivo que ejecute la acción que, como hemos especificado, debe estar en la ruta src  dentro del directorio donde estamos trabajando. Esta ruta podría ser diferente y el archivo con el código JavaScript podría estar en, por ejemplo, la raíz de la acción.

Para continuar con el proceso debemos instalar en el proyecto @actions/core, que nos permite acceder a a las variables de entrada y escribir en las de salida. También existen otros tipos de herramientas que, por ejemplo, permiten obtener información sobre los contextos de acciones de GitHub (@actions/github). Se pueden ver en el siguiente repositorio: https://github.com/actions/toolkit.

Debemos ir con la terminal a la carpeta donde está el fichero action.yml  y ejecutar el siguiente comando:

npm install @actions/core

Esto creará una una carpeta node_modules  y un archivo package-lock.json , que serán los que informen de las dependencias que tiene que instalar a la acción. A continuación procedemos a escribir el código JavaScript que será encargado de implementar la funcionalidad de la acción. Creamos el archivo src/main.js  con el siguiente contenido:

const core = require('@actions/core')

const inputText = core.getInput('input_text');
const numOfRepeats = parseInt(core.getInput('num_of_repeats'));

let outputText = ""
let i;
for (i = 0; i < numOfRepeats; i++) {
    outputText += inputText;
}

core.setOutput('output_text', outputText)

Con esto finalizamos la configuración de la acción. A continuación debemos configurar el flujo de trabajo para que llame a esta acción. Partiremos de la configuración del workflow anterior en el que se llamaba a la acción en Docker para añadir la llamada a la nueva acción en JavaScript. Si queremos quitar la parte de Docker, bastaría con quitar la parte de run-docker-action. En este caso, se ha separado la ejecución en dos trabajos, pero se podría llamar a las dos acciones dentro del mismo trabajo.

name: Workflow for our actions

on: [push]

jobs:
	run-docker-action:
		runs-on: ubuntu-latest

		steps:
			- uses: actions/checkout@v1

			- name: Docker repeat action
				uses: ./.github/actions/docker-repeat
				id: docker-action
				with:
					input_text: "texto de prueba"
					num_of_repeats: "4"

			- name: Print docker output
				run: echo ${{ steps.docker-action.outputs.output_text }}
	
	run-javascript-action:
		runs-on: ubuntu-latest

		steps:
			- uses: actions/checkout@v1

			- name: JavaScript repeat action
				uses: ./.github/actions/js-repeat
				id: js-action
				with:
					input_text: "texto de prueba"
					num_of_repeats: "4"

			- name: Print JavaScript output
				run: echo ${{ steps.js-action.outputs.output_text }}

Con estos cambios, podemos hacer push al repositorio para ver cómo se ejecutan las acciones. Ahora vemos que hay dos trabajos y que la acción de JavaScript se ha ejecutado correctamente:

captura acción consola javascript

Publicar nuestra acción en GitHub Marketplace

Las acciones que nosotros desarrollamos se pueden publicar en GitHub Marketplace, lo que hará que otros desarrolladores puedan utilizarlos sin problemas. Se recomienda desarrollar la acción en su propio repositorio para que se pueda encontrar y usar por terceros de forma sencilla, esto quiere decir que todos los archivos de la acción, como por ejemplo el archivo de metadatos actions.yml , estará en la raíz del repositorio.

Cuando tengamos un repositorio únicamente para la acción, GitHub lo detectará y nos mostrará un aviso al entrar al repositorio que nos permitirá publicar la acción en el Marketplace. Para ello, pulsaremos sobre «Draft a release». Cuando nos salga el aviso, tenemos que seleccionar «Publish this Action to the GitHub Marketplace» y comprobar que se han detectado todos los datos necesarios. Si faltara información, como podría ser algún campo en el metadata o que no hay un archivo README, esta ventana nos avisará.

A continuación debemos seleccionar la categoría de nuestra acción y, opcionalmente, podemos asignarle una segunda categoría. Después debemos etiquetar la acción con un número de versión y, finalmente, pulsar sobre «Publish release».

Conclusiones

Las acciones nos permiten ejecutar código para realizar tareas automáticamente que pueden ser desde muy sencillas hasta muy complejas. Nos podrían servir, por ejemplo, para conectarnos a una API y darle datos que necesite a nuestro sistema para que funcione correctamente el flujo de integración continua.

Otro caso de uso posible sería el de revisar automáticamente nuestro repositorio, ejecutando acciones cuando hay un pull request, buscando que pasen los tests de dicho pull request y que el código llegue a un nivel de calidad suficiente. Después de eso, una acción nuestra podría añadir una marca al pull request para indicar que es válida.

En el marketplace de GitHub hay muchas acciones que están disponibles para los desarrolladores, como la acción Checkout, muy utilizada para que nuestra imagen tenga los archivos del repositorio, u otras acciones que permiten subir artefactos para que queden disponibles para su descarga.

Recursos

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad