dev-resources.site
for different kinds of informations.
Tester c'est tricher, compiler c'est douter
Dans cet article, nous allons voir le concept de Continuous Integration (CI), son intĂ©rĂȘt et ses inconvĂ©nients et une dĂ©monstration.
Histoire
Mais d'abord, comme Ă mon habitude, un petit point histoire.
En 1999, Kent Beck a approfondi le sujet dans son premier livre sur l'Extreme Programming. En 2001, CruiseControl, l'un des premiers outils open-source de CI, a vu le jour.
Mais why ?
Le but d'une CI est de faire des tests automatisés à chaque commit. Cela garantit que le code reste fonctionnel en permanence. On appelle cela une Continuous Integration car, à chaque modification, le code est vérifié pour s'assurer qu'il n'y a pas de régressions.
Avantages
- Détection précoce des erreurs : Les problÚmes sont identifiés rapidement, ce qui permet de réagir sans attendre.
- Amélioration de la qualité : En testant systématiquement, on garantit un code plus robuste.
- Gain de temps : Les pipelines automatisés réduisent la nécessité de tests manuels répétitifs.
Inconvénients
- Coût initial : Mettre en place une CI peut demander des efforts et des compétences initiales importantes.
- Temps dâexĂ©cution : Les pipelines complexes peuvent rallonger le temps avant qu'un dĂ©veloppeur puisse valider son code.
Fonctionnement
Avant de voir le fonctionnement, un petit lexique :
-
Jobs : Une instance d'un conteneur (souvent Docker) qui exécute un script. Cela peut inclure des commandes, des tests ou des actions simples comme un
echo
. - Pipeline : Une série de jobs organisés de maniÚre séquentielle ou parallÚle. Chaque commit déclenche cette série pour valider les changements.
Le principe est simple : chaque job retourne un code de statut (succĂšs ou Ă©chec). Si un job Ă©choue, la pipeline sâarrĂȘte ou ignore les Ă©tapes suivantes selon la configuration.
TrĂȘve de blabla
Nous allons utiliser un exemple basé sur GitLab CI. On la configure via un fichier .gitlab-ci.yml
.
Basique, simple, simple, basique
image: bookworm-slim:latest
myjobname:
script:
- make
Les flags
Pour ajouter des flags de compilation, deux approches sont possibles :
- Via une rĂšgle dans le Makefile.
- En passant les flags directement dans la commande CI.
myjobname_hard:
script:
- CFLAGS="-Wall -Werror" make
# ou
- make compile_flags
Tests avec Criterion et flags
Criterion est une bibliothĂšque de tests unitaires en C.
OĂč est passĂ© Criterion ?
Avant dâexĂ©cuter des tests avec Criterion, il est souvent nĂ©cessaire d'installer Criterion, eh oui !
before_script:
- apt-get update && apt-get install -y libcriterion-dev
script:
- ./configure
- make test
Multistaging
Diviser les tests unitaires et fonctionnels en plusieurs stages garantit :
- une bonne organisation
- une meilleure visibilité des résultats
stages:
- build
- test
build:
stage: build
script:
- make all
test-unit:
stage: test
script:
- make unit-test
test-functional:
stage: test
script:
- make functional-test
Tu t'es fait clang ?
Le formatage du code est super important pour maintenir une base de code propre.
clang_format:
stage: format
before_script:
- apt-get -qq update && apt-get -qq install -y clang-format autotools-dev autoconf-archive gcovr libcriterion-dev
script:
- clang-format -i $(find src/ -type f -name "*.c") --dry-run --Werror
Cache
Dans certains cas, c'est utile de mettre en cache des fichiers ou dossiers pour Ă©viter de les recharger Ă chaque pipeline.
Un exemple courant est le dossier node_modules/
en JavaScript.
cache:
paths:
- node_modules/
install:
script:
- npm install
Bien entendu, vous pouvez nettoyer le cache au besoin avec une option supplémentaire dans la configuration de pipeline.
Artefacts
Les artefacts sont les fichiers gĂ©nĂ©rĂ©s par la CI qui peuvent ĂȘtre partagĂ©s entre jobs ou tĂ©lĂ©chargĂ©s.
Par exemple, les rapports de tests ou de couverture.
artifacts:
paths:
- build/
- reports/
Coverage de tests
On peut mesurer la couverture de tests en intégrant des outils comme gcovr ou Cobertura dans votre pipeline CI.
test-coverage:
stage: test
script:
- gcovr --html --html-details -o coverage.html
artifacts:
paths:
- coverage.html
Rapporteur
Ce bloc vous permet d'intégrer le coverage report dans votre Merge Request, vous pourrez ainsi voir le code qui n'est pas couvert mais aussi votre pourcentage de coverage.
coverage-report:
script:
# do coverage
coverage: /^TOTAL.*\s+(\d+\%)$/
artifacts:
name: coverage.xml
expire_in: 2 days
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
Environnement custom
Vous pouvez prĂ©ciser lâenvironnement de base pour votre CI en sĂ©lectionnant une image Docker spĂ©cifique.
image: gcc:latest
En utilisant un peu ce que l'on vient de voir, ça donnerait quelque chose comme ça :
image: gcc
stages:
- format
- build
- test
- clean
clang-format:
stage: format
script:
- clang-format -i $(find src/ -type f -name "*.c") --dry-run --Werror
build:
stage: build
script:
- autoreconf --install
- ./configure
- make all
test-unit:
stage: test
script:
- autoreconf --install
- ./configure
- make unit-test
Attention aux
.h
et il manque desbefore_script
.
Petit Bonus
On peut aussi vĂ©rifier les trash-files pour sâassurer que le make clean
fait bien son travail.
trash-file:
stage: clean
needs: []
before_script:
- apt-get -qq update && apt-get -qq install -y tree
script:
- tree > /tmp/REF
- make && make clean
- tree > /tmp/TEST
- diff /tmp/REF /tmp/TEST
Conclusion
La Continuous Integration est un outil extrĂȘmement puissant. Il peut parfois ĂȘtre difficile Ă mettre en place, mais les gains sont immenses.
Featured ones: