Créer une action GitHub pour tester avec des services

Écrire un workflow GitHub Actions qui lance les tests d'une application Django avec une base PostgreSQL en service, du déclencheur au health check.

Portrait de Abderrahim ELBAHI

Abderrahim ELBAHI

Fondateur et Directeur Général

Profil LinkedIn

Publié le , mis à jour le · 4 min de lecture

GitHub Actions, qu’est-ce que c’est ?

GitHub Actions est une solution d’intégration continue et de déploiement automatisé (CI/CD). C’est une extension de GitHub. Son fonctionnement repose sur des événements GitHub, tels qu’un push de commits.

On écrit un processus à lancer en rapport avec son projet. Il sera exécuté en fonction des critères définis dans l’action à réaliser. Cela a été conçu de manière à effectuer des processus en continu, en fonction du travail collaboratif sur Git. Il faut savoir que GitHub Actions se base sur Docker : il est donc recommandé d’avoir des notions dessus pour l’utiliser assez simplement.

Écrire son action

Une action comporte plusieurs éléments nécessaires pour effectuer un processus. Le premier est l’événement on, qui correspond à l’événement GitHub : push, pull request, etc.

on: [push, pull_request]

Il est bien évidemment possible de définir plus précisément le cadre de votre action sur certaines branches de votre dépôt, pour l’effectuer dans des cas précis — uniquement sur la branche master, par exemple :

on:
  push:
    - master

Ensuite, nous avons les jobs. Concrètement, un job est une suite d’étapes effectuées de manière ordonnée. Il comporte deux éléments importants : l’environnement et les étapes à effectuer.

Le paramètre runs-on définit l’environnement dans lequel l’action est effectuée :

runs-on: ubuntu-latest

Il existe plusieurs environnements virtuels possibles pour l’exécution de votre action ; cela peut être utile pour correspondre aux spécificités de chacun. Du dernier Ubuntu à Windows, vous avez le choix.

Il est à noter que chaque job est effectué dans une nouvelle instance de l’environnement virtuel. Donc si vous voulez faire une suite d’actions avec un lien entre elles, il faudra penser à le faire dans le même job. Mais il est possible de créer des dépendances entre jobs avec le paramètre needs :

jobs:
  job1:
  job2:
    needs: job1

Dans ce cas, job2 ne s’exécutera que lorsque job1 aura été effectué.

Vient ensuite l’ensemble des étapes à réaliser lors du processus. Dans une optique d’intégration continue, le but est de lancer les tests automatiquement. Néanmoins, il faut définir un certain nombre d’éléments avant de pouvoir les exécuter. Cet ensemble est défini par le mot-clé steps.

Chaque étape requiert au minimum un élément à exécuter, c’est-à-dire l’un de ces deux mots-clés :

  • uses, pour utiliser un élément spécifique :
    • une action publique
    • une action dans le même dépôt
    • une action sur le Docker Hub ou sur le registre public Docker
  • run, pour lancer une commande en bash — sachant qu’il y a plusieurs moyens d’exécuter une commande si nécessaire

Enfin, on associe le paramètre name pour savoir quelle étape cela représente. Un exemple étant toujours plus parlant, voici un job pour tester un projet Django :

jobs:
  tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: Set up Python 3.5.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.5.7
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run tests
        run: python manage.py test

Ici, le job tests consiste à :

  • installer Python 3.5.7 sur l’environnement Ubuntu
  • installer les dépendances
  • lancer les tests

Pour les tests en conditions réelles, on a besoin d’une base de données, d’où la mise en place de services.

Ajouter un service à son action

Comment fait-on ? Très simple : cela se rapproche de la définition d’un service dans un docker-compose.yml, mais avec beaucoup moins de paramètres. On utilise le mot-clé services avec :

  • la définition de l’image Docker à utiliser
  • la liste des ports à exposer du service
  • une liste de variables d’environnement
  • une liste de volumes

L’ensemble de ces éléments ne sont pas tous requis, mais bon à savoir. Concrètement, cela ressemble à cela, pour un service PostgreSQL :

services:
  image: postgres
  env:
    - POSTGRES_USER: postgres
    - POSTGRES_PASSWORD: postgres
    - POSTGRES_DB: postgres
  ports:
    - 5432/tcp
  options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

On a besoin de l’image Docker à lancer, du port à exposer et du nom du service. Il existe un moyen de transmettre des valeurs d’environnement ou des options Docker, comme on peut le voir dans l’exemple ci-dessus. Les valeurs sensibles peuvent être définies avec les secrets.

De plus, il est parfois nécessaire d’avoir un retour de l’état du service pour établir une connexion. Par conséquent, on définit un élément qui vérifie la santé du service pour savoir lorsqu’il est opérationnel — également appelé health check. J’ai repris l’exemple fait par Chris Patterson et Mike Coutermash pour PostgreSQL.

Pour le cas où vous n’avez pas de health check à disposition, on met en pause l’exécution du processus avec la commande sleep. Oui, ce n’est pas terrible, je vous l’accorde.

Tout cela c’est très bien, mais il faut faire le lien entre le service et notre application. Nous allons le faire grâce au port ; pour l’hôte, ce sera localhost, étant donné que le service est exécuté directement dans la machine Ubuntu dans notre exemple. Sinon, cela aurait été le nom du service.

Dans l’exemple précédent, on attribue un port libre de manière aléatoire au port 5432 de la machine, et on y accède de la manière suivante :

${{ job.services.postgres.ports[5432] }}

Néanmoins, on peut l’attribuer de manière fixe :

ports:
  - 5432:5432

Ici, nous avons le port 5432 du service lié au port 5432 de la machine définie dans l’action.

On obtient le workflow suivant :

name: Test Workflow

on: push

jobs:
  tests:
    runs-on: ubuntu-latest

    services:
      image: postgres
      env:
        - POSTGRES_USER: postgres
        - POSTGRES_PASSWORD: postgres
        - POSTGRES_DB: postgres
      ports:
        - 5432:5432
      options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      - uses: actions/checkout@v1
      - name: Set up Python 3.5.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.5.7
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run tests
        run: python manage.py test

Il reste à bien changer les valeurs du service dans le fichier settings.py de Django, pour la connexion à la base de données PostgreSQL dans le cadre de notre exemple.

Puis le tour est joué : plus qu’à pousser du code et espérer que le tout fonctionne.

Version anglaise

Une traduction anglaise de cet article est publiée sur HackerNoon : How to Create GitHub Actions to Run Tests with Docker Services.

Partager

À lire ensuite

Démarrer

Exposez votre besoin