Configura la integración continua


Configurar la integración continua (CI) para tu track es muy importante, ya que ayuda a detectar errores.

GitHub Actions

Los repositorios de Exercism (incluidos los repositorios de los tracks) usan GitHub Actions para ejecutar su CI. GitHub Actions se basa en flujos de trabajo, que definen scripts que se ejecutan automáticamente cada vez que ocurre un evento concreto (p. ej., al hacer push de un commit). Para obtener más información sobre los flujos de trabajo de GitHub Actions, consulta la documentación de flujos de trabajo.

Flujos de trabajo preinstalados

Los tracks vienen con una serie de flujos de trabajo preinstalados, la mayoría de los cuales no deberías modificar (se llaman flujos de trabajo compartidos). Sin embargo, hay un flujo de trabajo que sí deberías cambiar: el flujo de trabajo test.yml.

Flujo de trabajo de pruebas

El objetivo del flujo de trabajo test.yml es verificar que los ejercicios del track estén en buen estado. El flujo de trabajo está configurado para ejecutarse automáticamente (en terminología de GitHub Actions: se activa) cuando se hace un push a la rama main o a la rama de un pull request.

El flujo de trabajo en sí no debería hacer gran cosa, salvo:

  • Hacer checkout del código (ya implementado)
  • Instalar dependencias (p. ej., instalar paquetes; opcional)
  • Instalar las herramientas (p. ej., instalar un SDK; opcional)
  • Ejecutar el script de verificación de ejercicios (ya implementado)

Implementar el script de verificación de ejercicios

Como se ha mencionado, los ejercicios se verifican mediante un script, en concreto el script bin/verify-exercises (bash). Este script está casi terminado y hace lo siguiente:

  • Recorre todos los directorios de ejercicios
  • Para cada directorio de ejercicio, a continuación:
    • Copia la solución de ejemplo/ejemplar a los archivos de solución (stub) (ya implementado)
    • Llama a la función unskip_tests, en la que puedes reactivar las pruebas de tus archivos de prueba (opcional)
    • Llama a la función run_tests, en la que debes ejecutar las pruebas (obligatorio)

Las funciones run_tests y unskip_tests son lo único que necesitas implementar.

Reactivar las pruebas

Si tu track admite omitir pruebas, debemos asegurarnos de que no se omita ninguna prueba al verificar la solución de ejemplo/ejemplar de un ejercicio. En general, hay dos formas en que los tracks permiten «reactivar» las pruebas:

  1. Eliminar anotaciones/código/texto de los archivos de prueba. Por ejemplo, cambiar test.skip por test.
  2. Proporcionar una variable de entorno. Por ejemplo, establecer SKIP_TESTS=false.

Eliminar anotaciones/código/texto de los archivos de prueba

Si la omisión de pruebas se basa en archivos (la primera opción mencionada antes), edita la función unskip_tests para modificar los archivos de prueba (el código existente ya se encarga de recorrer los archivos de prueba).

Note

La función unskip_test se ejecuta sobre una copia del directorio de un ejercicio, así que no dudes en modificar los archivos como mejor te parezca.

Ejemplo

El archivo bin/verify-exercises del track de Arturo usa sed para reactivar las pruebas dentro de los archivos de prueba:

unskip_tests() {
    jq -r '.files.test[]' .meta/config.json | while read -r test_file; do
        sed -i 's/test.skip/test/g' "${test_file}"
    done
}

Proporcionar una variable de entorno

Caution

Si para reactivar las pruebas se requiere establecer una variable de entorno, asegúrate de establecerla en la función run_tests.

Ejecutar las pruebas

La función run_tests se encarga de ejecutar las pruebas de un ejercicio. Cuando se llama a la función, los archivos de ejemplo/ejemplar ya se habrán copiado a los archivos de solución (stub), así que solo tienes que llamar al comando adecuado para ejecutar las pruebas.

La función debe devolver cero como código de salida si se superan todas las pruebas; de lo contrario, debe devolver un código de salida distinto de cero.

Note

La función run_tests se ejecuta sobre una copia del directorio de un ejercicio, así que no dudes en modificar los archivos como mejor te parezca.

Opción 1: usar las herramientas del lenguaje

La opción predeterminada para el script de verificación de ejercicios es usar las herramientas del lenguaje (SDK/binario/etc.), que es lo que usan la mayoría de los tracks. Cada track tendrá su propia forma de ejecutar las pruebas, pero normalmente se trata de un solo comando.

Ejemplo

El archivo bin/verify-exercises del track de Arturo modifica la función run_tests para que simplemente llame al comando arturo sobre el archivo de prueba:

run_tests() {
    arturo tester.art
}

Opción 2: usar la imagen de Docker del ejecutor de pruebas

La segunda opción es verificar los ejercicios ejecutando el ejecutor de pruebas del track. Esto, por supuesto, depende de que el track tenga un ejecutor de pruebas que funcione.

Si tu track todavía no tiene un ejecutor de pruebas, puedes:

  • crear un ejecutor de pruebas que funcione, o
  • usar la opción 1 y utilizar directamente las herramientas del lenguaje

Hay que hacer las siguientes modificaciones en el script bin/verify-exercises file predeterminado:

  1. Comprobar que el comando docker está disponible
  2. Descargar la imagen de Docker del ejecutor de pruebas
  3. Usar docker run para ejecutar la imagen de Docker del ejecutor de pruebas en cada ejercicio
  4. Usar jq para comprobar que el archivo results.json devuelto por el contenedor de Docker indica que se han superado todas las pruebas
  5. Eliminar la función unskip_test y la llamada a esa función
Note

La principal ventaja de este enfoque es que imita mejor cómo se ejecutan las pruebas en producción (en el sitio web). Con este enfoque, es menos probable que fallen en producción cosas que pasaron en CI. La desventaja de este enfoque es que normalmente es más lento, debido a que hay que descargar la imagen de Docker y a la sobrecarga de Docker.

Ejemplo

El archivo bin/verify-exercises file del track de Unison añade la comprobación de que el comando docker también está instalado:

required_tool docker

Después, descarga la imagen del ejecutor de pruebas del track:

docker pull exercism/unison-test-runner

Luego modifica la función run_tests para usar docker run y ejecutar el ejecutor de pruebas sobre el ejercicio actual (que está en el directorio de trabajo), seguido de un comando jq para comprobar el estado correcto:

run_tests() {
    local slug

    slug="${1}"

    docker run \
        --rm \
        --network none \
        --mount type=bind,src="${PWD}",dst=/solution \
        --mount type=bind,src="${PWD}",dst=/output \
        --tmpfs /tmp:rw \
        exercism/unison-test-runner "${slug}" "/solution" "/output"
    jq -e '.status == "pass"' "${PWD}/results.json" >/dev/null 2>&1
}

Por último, tenemos que modificar la llamada al comando run_tests, ya que ahora requiere el slug:

run_tests "${slug}"

Implementar el flujo de trabajo de pruebas

Ahora que el script verify-exercises está terminado, es el momento de finalizar el flujo de trabajo test.yml. Cómo hacerlo depende de la opción que hayas elegido para implementar el script verify-exercises.

Opción 1: usar las herramientas del lenguaje

Si el script verify-exercises usa directamente las herramientas del lenguaje, el flujo de trabajo de pruebas tendrá que instalar:

  • Las dependencias de las herramientas del lenguaje, como openssh o un compilador de C/C++.
  • Las herramientas del lenguaje, como un SDK o un binario. Si la instalación de las herramientas del lenguaje no añade el binario o los binarios instalados a la ruta, asegúrate de añadirlo a la ruta del sistema de GitHub Actions.

Una vez hecho esto, el script verify-exercises debería funcionar como se espera, ¡y habrás configurado la CI con éxito!

Para ver un ejemplo, consulta el flujo de trabajo test.yml del track de Arturo:

name: Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

jobs:
  ci:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev libmpfr-dev

      - name: Install Arturo
        run: bin/install-arturo
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Verify all exercises
        run: bin/verify-exercises

Opción 2: usar la imagen de Docker del ejecutor de pruebas

La segunda opción es verificar los ejercicios ejecutando el ejecutor de pruebas del track. Esta opción requiere que se cumplan dos cosas:

  1. El track tiene un ejecutor de pruebas que funciona
  2. El script verify-exercises usa la imagen de Docker del ejecutor de pruebas para ejecutar las pruebas de un ejercicio

Si tu track todavía no tiene un ejecutor de pruebas, puedes:

  • crear un ejecutor de pruebas que funcione, o
  • usar la opción 1 y utilizar directamente las herramientas del lenguaje

Este enfoque tiene un par de ventajas:

  1. No necesitas instalar ninguna dependencia ni herramienta dentro del flujo de trabajo de pruebas (ya que se habrán instalado dentro de la imagen de Docker)
  2. El enfoque imita mejor cómo se ejecutan las pruebas en producción (en el sitio web), lo que reduce la probabilidad de problemas en producción.

La principal desventaja es que probablemente sea más lento, debido a que hay que descargar la imagen de Docker y a la sobrecarga de Docker.

Hay un par de formas de descargar la imagen de Docker del ejecutor de pruebas:

  1. Descargar la imagen dentro del archivo verify-exercises. Este es el enfoque que sigue el track de Unison.
  2. Descargar la imagen dentro del flujo de trabajo. Este es el enfoque que sigue el track de Standard ML.
  3. Crear la imagen dentro del flujo de trabajo. Este es el enfoque que sigue el track de 8th.

¿Y qué enfoque usar? Recomendamos implementar al menos la opción número 1, para que el script verify-exercises sea autónomo. Si tu imagen es especialmente grande, podría ser beneficioso implementar también la opción 3, que almacenará la imagen de Docker creada en la caché de GitHub Actions. Las ejecuciones posteriores podrán entonces simplemente leer la imagen de Docker de la caché en lugar de descargarla, lo que podría ser mejor para el rendimiento (mide para asegurarte).

Opción 3: ejecutar el script de verificación de ejercicios dentro de la imagen de Docker del ejecutor de pruebas

Una tercera opción alternativa es un híbrido de las dos opciones anteriores. Aquí también usamos la imagen de Docker del ejecutor de pruebas, solo que esta vez ejecutamos el script verify-exercises dentro de esa imagen de Docker. Para habilitar esta opción, tenemos que establecer el contenedor del flujo de trabajo en el ejecutor de pruebas:

container:
  image: exercism/vimscript-test-runner

Entonces podemos omitir los pasos de instalación de dependencias y herramientas (ya que se habrán instalado dentro de la imagen de Docker del ejecutor de pruebas) y proceder a ejecutar el script bin/verify-exercises file.

Ejemplo

El flujo de trabajo test.yml del track de vimscript usa esta opción:

name: Verify Exercises

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

jobs:
  ci:
    runs-on: ubuntu-24.04
    container:
      image: exercism/vimscript-test-runner

    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

      - name: Verify all exercises
        run: bin/verify-exercises