Utiliser les services d’intégration continue

Introduction

Les services d’intégration continue sont des outils permettant au système de développement de valider la non-régression du code source sans la nécessité d’imposer l’exécution manuelle des tests aux développeurs.

Il est à noter qu’en plus des tests, les services d’intégration continue moderne peuvent automatiser un grand nombre de tâches. Par exemple les tâches de compilation, de livraison, de déploiement et d’inspection (monitoring) peuvent être faites à l’aide de ces outils.

Pourquoi utiliser les services d’intégration continue dans le logiciel libre

Il est d’autant plus important de bien tester la non-régression des logiciels libres puisque ces derniers encouragent la participation du plus grand nombre au développement du logiciel. Sans service d’intégration continue, les administrateurs de dépôt d’un logiciel ayant une grande popularité se verront rapidement dépassés par les événements.

Ainsi, en instaurant une politique de « merge/pull » request basée sur le résultat d’un service d’intégration continue, les administrateurs de dépôt peuvent diminuer au maximum les tâches à effectuer durant le « merge/pull ».

Types de tests à implanter

En général, le minimum qu’un service de développement continu devrait avoir à faire est:

  • La compilation du projet (si nécessaire);
  • L’exécution des tests unitaires;
  • L’exécution des tests de non-régression.

Si le langage le permet, il est également possible (et souhaitable) d’exécuter:

  • Un « linter » afin de valider le standard du projet;
  • Les systèmes de métriques permettant de valider le projet.

Il est bien entendu possible d’en faire plus.

Les logiciels d’intégration continue

Voici une liste de service libre d’intégration continue non exhaustive pouvant être utilisée dans un projet de logiciel libre.

  • Gitlab CI/CD
  • Github Action
  • Jenkins
  • Travis CI
  • Azure Pipelines

La procédure de configuration d’un logiciel d’intégration continue

Il est important de comprendre que chaque logiciel d’intégration continue a une procédure de configuration différente et il est impossible de toutes les montrer ici.

Par contre, ces procédures sont tout de même relativement semblables. Nous allons donc utiliser le logiciel Gitlab CI/CD pour cette présentation.

Afin d’utiliser Gitlab CI/CD, il est nécessaire d’avoir un dépôt (ou un clone du dépôt) du projet sur Gitlab.

Créer le fichier de configuration

Gitlab CI/CD utilise des fichiers Yaml afin de configurer le « pipeline » d’intégration continue. Afin de créer un nouveau fichier de configuration Yaml, il suffit de se rendre dans la section « CI/CD » dans le dépôt Gitlab.

Gitlab CI/CD

Ensuite, pour générer initialement le script, vous pouvez soit utiliser un script modèle (« template ») fourni par Gitlab, ou bien utiliser le bouton « use template » pour avoir un modèle de base.

Templates spécifiques

Template générique

Il est également possible de créer manuellement le fichier Yaml à la racine du projet. Le fichier doit s’appeler exactement « .gitlab-ci.yml » (ne pas oublier le « . »).

Les configurations de bases

En fonction du type de langage à utiliser, on utilise des configurations différentes (avec ou sans compilation, linter, etc.) Nous ne les montrerons pas toutes ici. Nous n’allons que montrer la base. La documentation complète est accessible (en anglais seulement) ici. Donc, la première section du script est la section « stages » indiquant les différentes étapes à utiliser. Par exemple, la section « stage » suivante a trois (3) étapes: la compilation, les tests) et le déploiement:

stages:
  - compilation
  - test
  - deploiement

Ensuite, nous pouvons créer autant de sections que nous souhaitons, mais pour que ces sections soient exécutées, nous devons spécifier dans quel « stage » ils doivent être utilisés. Par exemple:

stages:
  - compilation
  - test
  - deploiement

compilation-job:
  stage: compilation
  script:
    - echo Compilation
    - ...
    - echo Compilation terminé

unit-test-job:
  stage: test
  script:
    - echo Exécution des tests
    - ...
    - echo Fin des tests

lint-test-job:
  stage: test
  script:
    - echo Exécution du Linter
    - ...
    - echo Fin d'exécution du Linter

deploiement-job:
  stage: deploiement
  script:
    - echo Déploiement
    - ...
    - echo Fin du déploiement

Il est à noter que les « … » dans les sections « script » représentent les lignes de commande à exécuter pour effectuer les étapes correspondantes.

Parfois, il est nécessaire de garder certaines informations entre les « stages » (par exemple, des fichiers compilés). Pour se faire, on utilise des « artifacts ». De plus, pour s’assurer que le « Gitlab Runner » exécute les « stages » dans le bon ordre, on peut utiliser des « dependencies ». Voici un exemple:

stages:
  - compilation
  - test
  - deploiement

compilation-job:
  stage: compilation
  script:
    - echo Compilation
    - ...
    - echo Compilation terminé
  artifacts:
    paths:
      - build

unit-test-job:
  stage: test
  dependencies:
    - compilation-job
  script:
    - echo Exécution des tests
    - ...
    - echo Fin des tests

lint-test-job:
  stage: test
  script:
    - echo Exécution du Linter
    - ...
    - echo Fin d'exécution du Linter

deploiement-job:
  stage: deploiement
  dependencies:
    - compilation-job
  script:
    - echo Déploiement
    - ...
    - echo Fin du déploiement

Utilisation de docker

L’exécution de la configuration du Gitlab CI/CD de base peut être suffisant pour des tâches simples ne nécessitant pas de logiciel (compilateur, interpréteur, etc.) ou librairie particulière. Par contre, si un système plus précis est nécessaire, il est possible d’exécuter les scripts dans des « dockers ». Tous les « dockers » accessibles gratuitement sur le site de DockerHub peuvent être utilisés. Également, il est possible de fournir l’image docker directement dans le dépôt ou bien utiliser un lien afin de télécharger l’image. Pour utiliser un « docker », il faut utiliser une information « image ».

Il est à noter qu’une nouvelle image de « docker » sera générée à chaque « stage » du « pipeline ». Il est donc nécessaire de configurer à nouveau le « docker ».

Voici un exemple:

stages:
  - compilation
  - test

compilation-job:
  image: debian:latest
  stage: compilation
  script:
    - echo "Préparation de l'image..."
    - apt-get update
    - apt-get install -y build-essential
    - apt-get clean
    - rm -rf /var/lib/apt/lists/*
    - echo "Préparation terminé."
    - echo "Compilation de la librairie..."
    - make clean
    - make all
    - echo "Compilation terminée"
  artifacts:
    paths:
      - bin

test-job:
  image: debian:latest
  stage: test
  dependencies:
    - compilation-job
  script:
    - echo "Préparation de l'image..."
    - apt-get update
    - apt-get install -y build-essential
    - apt-get clean
    - rm -rf /var/lib/apt/lists/*
    - echo "Préparation terminé."
    - echo "Compilation des tests..."
    - cd test
    - make clean
    - make all
    - echo "Exécution des tests..."
    - bin/Release/test
    - echo "Fin des tests."

Si la même image est utilisée pour tous les « stage », on peut spécifier l’image une seule fois. De plus, afin de ne pas dupliquer inutilement la préparation du docker, on peut utiliser l’information « extends » et mettre les instructions dans un « before_script » commun.

Voici un exemple:

image: debian:latest

stages:
  - compilation
  - test

.prepare-image:
  before_script:
    - echo "Préparation de l'image..."
    - apt-get update
    - apt-get install -y build-essential
    - apt-get clean
    - rm -rf /var/lib/apt/lists/*
    - echo "Préparation terminé."

compilation-job:
  stage: compilation
  extends: .prepare-image
  script:
    - echo "Compilation de la librairie..."
    - make clean
    - make all
    - echo "Compilation terminée"
  artifacts:
    paths:
      - bin

test-job:
  stage: test
  extends: .prepare-image
  dependencies:
    - compilation-job
  script:
    - echo "Compilation des tests..."
    - cd test
    - make clean
    - make all
    - echo "Exécution des tests..."
    - bin/Release/test
    - echo "Fin des tests."

Les variables

Il y a trois types de variables utilisables dans un script Yaml de gitlab CI/CD:

  • Variable prédéfinie
  • Variable publique
  • Variable cachée

Les variables prédéfinies sont des variables qui sont définies par le Gitlab Runner directement. Il y en a une grande quantité et on peut avoir leur documentation ici.

Les variables publiques sont généralement indiquées directement dans le fichier « .gitlab-ci.yml »; dans une section « variables » (soit dans un « stage » ou dans une section en tant que telle).

Voici un exemple utilisant des variables:

variables:
  VARIABLE_GOLBALE: "Valeur de la variable globale"

stages:
  - jobs

job_1:
  stage: jobs
  variables:
    VARIABLE_LOCALE: "Valeur de la variable locale"
  script:
    - echo "Nom du stage courrant:" "$CI_JOB_STAGE"
    - echo "La variable globale:" "$VARIABLE_GOLBALE"
    - echo "La variable locale:" "$VARIABLE_LOCALE"

Les derniers types de variables sont les variables cachées. Ce type de variable nécessite de placer la valeur de ces variables directement dans les configurations privées du dépôt Gitlab. Il est généralement utile de créer ce type de variable lorsque certaines informations nécessaires à la compilation et aux tests ne peuvent pas être publiques. Le meilleur exemple de ce type de variables est les clés d’API Web.

Afin de déclarer une variable cachée il faut aller dans les configurations CI/CD du dépôt.

Ensuite, il faut se rendre dans la section « Variables »

Enfin, on peut ajouter des variables en utilisant le bouton « Add variable »

Les variables sont représentées de manière « Clé->Valeur » ou la clé est le nom de la variable et la valeur est sa valeur.

Il est important de noter que pour s’assurer que la valeur de la variable n’apparaisse pas dans les « logs » des exécutions de « pipeline », il faut cocher le « Mask ». Noter également que les variables « Mask » doivent respecter les critères suivants:

  • Être sur une seule ligne,
  • Être d’au moins 8 caractères,
  • Être des caractères compatibles avec le standard Base64, en plus des caractères:
    • « @ », « : », « . » et « ~ »

Retour


Auteur: Louis Marchand
Creative Commons License
Sauf pour les sections spécifiées autrement, ce travail est sous licence Creative Commons Attribution 4.0 International.