Aller au contenu
CI/CD & Automatisation medium

Lab 10 — Rapports qualité

10 min de lecture

logo gitlab

Un pipeline vert rassure, mais ne dit pas tout. Sans rapports qualité visibles dans la MR, les reviewers ne savent pas quels tests échouent, ni si la couverture monte ou baisse. Ce lab vous apprend à rendre les résultats lisibles directement dans GitLab pour améliorer la décision de merge.

  • Générer un rapport JUnit depuis pytest
  • Publier ce rapport comme artifact reconnu par GitLab
  • Extraire une couverture avec coverage:
  • Lire ces informations dans les widgets de Merge Request

Ce lab suit le Lab 09. Si votre pipeline publie déjà correctement les images, vous pouvez démarrer ici avec starter/lab-10.

Dans un flux d'équipe, la MR est le point de vérité pour décider un merge. Si les infos qualité sont cachées dans des logs longs, elles sont peu consultées. En affichant les résultats au bon endroit, vous rendez la qualité visible et actionnable.

Ce lab répond à des besoins réels :

  • repérer immédiatement un test cassé dans une MR
  • suivre l'évolution de la couverture
  • éviter les merges "à l'aveugle"
  1. Basculez sur la branche du lab

    Fenêtre de terminal
    cd pipeline-craft
    git checkout starter/lab-10
  2. Ouvrez le job pytest dans .gitlab-ci.yml

    Vous allez y ajouter la production de rapport et l'extraction de couverture.

Sans configuration explicite, GitLab ne sait pas interpréter vos résultats de test. Vous devez lui fournir :

  • un fichier JUnit via artifacts.reports.junit
  • une expression coverage: pour extraire le pourcentage

Étape 1 — À vous de générer le rapport JUnit

Section intitulée « Étape 1 — À vous de générer le rapport JUnit »
  1. Modifiez le job pytest pour générer un rapport JUnit et une couverture exploitable.

  2. Ajoutez un artifact JUnit conservé même en cas d'échec.

  3. Vérifiez que GitLab peut afficher le rapport dans l'interface MR.

👉 Vérifier votre solution (Étape 1)

1️⃣ Job pytest avec rapport JUnit et couverture

Section intitulée « 1️⃣ Job pytest avec rapport JUnit et couverture »
pytest:
stage: test
image: python:3.12-slim
cache:
key:
files:
- requirements-dev.txt
paths:
- .pip-cache/
before_script:
- pip install -r requirements-dev.txt
script:
- pytest -v --junitxml=report.xml --cov=app --cov-report=term-missing
coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
artifacts:
when: always
paths:
- report.xml
reports:
junit: report.xml
expire_in: 7 days

Points clés :

  • --junitxml=report.xml : génère le XML attendu par GitLab
  • reports.junit: report.xml : indique à GitLab où lire le rapport
  • when: always : upload l'artifact même si les tests échouent (crucial pour le diagnostic)
  • --cov=app : active la couverture sur le module app
  1. Ajoutez une regex coverage: sur le job pytest.

  2. Vérifiez localement que la regex correspond bien à la ligne TOTAL ... XX%.

  3. Ajustez la regex si besoin.

👉 Vérifier votre solution (Étape 2)
pytest:
coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'

Cette regex matche la ligne produite par pytest-cov :

TOTAL 45 3 93%

GitLab extrait 93% et l'affiche comme badge de couverture dans l'interface.

Tester la regex localement avant de pousser :

Fenêtre de terminal
pytest -v --cov=app --cov-report=term-missing | grep TOTAL

Vérifiez que la sortie contient bien TOTAL suivi d'un pourcentage en fin de ligne.

  1. Poussez vos modifications

    Fenêtre de terminal
    git add .gitlab-ci.yml
    git commit -m "ci: publish junit and coverage"
    git push origin starter/lab-10
  2. Ouvrez une Merge Request

  3. Vérifiez l'onglet tests et la couverture affichée

    L'objectif est de lire la qualité sans ouvrir les logs complets.

👉 Vérifier votre solution (Étape 3)

Après un pipeline sur MR, allez dans l'onglet Overview de la MR.

Vous devriez voir :

  • Un widget Test summary indiquant les tests passés / échoués
  • Un badge Coverage avec le pourcentage extrait

En cas d'échec de test, GitLab affiche le test échoué directement dans la MR — sans ouvrir les logs complets.

Cliquez sur View details dans le widget pour voir les tests un par un avec leur stacktrace.

📄 Voir le fichier .gitlab-ci.yml complet
stages:
- lint
- test
- build
- deploy
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "trigger"
- if: $CI_PIPELINE_SOURCE == "api"
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
ruff-lint:
stage: lint
image: python:3.12-slim
cache:
key:
files:
- requirements-dev.txt
paths:
- .pip-cache/
policy: pull
before_script:
- pip install ruff
script:
- ruff check app/ tests/
pytest:
stage: test
image: python:3.12-slim
cache:
key:
files:
- requirements-dev.txt
paths:
- .pip-cache/
before_script:
- pip install -r requirements-dev.txt
script:
- echo "Pipeline source: $CI_PIPELINE_SOURCE"
- pytest -v --junitxml=report.xml --cov=app --cov-report=term-missing
coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
artifacts:
when: always
paths:
- report.xml
reports:
junit: report.xml
expire_in: 7 days
nightly-regression:
stage: test
image: python:3.12-slim
cache:
key:
files:
- requirements-dev.txt
paths:
- .pip-cache/
before_script:
- pip install -r requirements-dev.txt
script:
- echo "Nightly run on source=$CI_PIPELINE_SOURCE"
- pytest -v
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
docker-build:
stage: build
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker build -t $CI_REGISTRY_IMAGE:latest .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
deploy-staging:
stage: deploy
image: alpine:3.20
script:
- echo "Deploying $CI_COMMIT_SHORT_SHA to staging..."
- ./scripts/deploy-demo.sh staging
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy-production:
stage: deploy
image: alpine:3.20
script:
- echo "Deploying $CI_COMMIT_SHORT_SHA to production..."
- ./scripts/deploy-demo.sh production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
  • report.xml est généré et publié
  • GitLab affiche les tests dans la MR
  • Le pourcentage de couverture est extrait
  • Les reviewers peuvent lire les résultats sans parcourir les logs

La couverture peut ne pas apparaître si la regex ne matche pas la sortie réelle. Vérifiez toujours la ligne exacte produite par pytest-cov.

Le rapport JUnit peut être vide si le chemin est incorrect ou si la commande pytest échoue avant génération. Dans ce cas, when: always aide au diagnostic car l'artifact est tout de même uploadé.

  • Les rapports qualité doivent être visibles dans la MR, pas cachés dans les logs
  • JUnit + coverage améliore la revue et la confiance de merge
  • Une bonne regex coverage est essentielle
  • Les artifacts rendent le diagnostic reproductible

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn