Problème rencontré chez un client dont la suite de tests end-to-end tournait sur GitLab CI, historique du prestataire précédent, alors que le déploiement WordPress avait été migré vers GitHub Actions par la nouvelle équipe. Deux systèmes distincts, deux fournisseurs, et pourtant une exigence non négociable : ne jamais déployer en production tant que la suite de tests fonctionnels n’avait pas validé la version.
Fusionner les deux pipelines dans un seul système n’était pas envisageable à court terme, la suite de tests dépendant d’une infrastructure GitLab spécifique difficile à déplacer. La solution retenue a consisté à faire communiquer les deux systèmes par un mécanisme de statut de commit, standard et supporté par les deux plateformes.
Le principe : le statut de commit comme langage commun
GitHub et GitLab exposent tous deux une API de statuts de commit (commit statuses ou check runs) qui permet à un système tiers de signaler l’état d’un traitement externe sur un SHA de commit donné. N’importe quel outil, indépendamment de la plateforme qui l’a créé, peut consulter et poser ce statut via une simple requête HTTP authentifiée. C’est exactement ce mécanisme qu’utilisent déjà les outils de revue de code tiers pour signaler leurs résultats.
Le pipeline de déploiement WordPress, hébergé sur GitHub Actions, n’a donc pas besoin de connaître les détails internes de la suite de tests GitLab. Il lui suffit d’interroger périodiquement le statut posé sur le commit à déployer, et d’attendre qu’il passe à success.
Côté GitLab : poser le statut sur GitHub
Le pipeline GitLab, à la fin de sa suite de tests, appelle l’API GitHub pour poser un statut sur le commit correspondant :

tests_fonctionnels:
stage: test
script:
- npm run test:e2e
after_script:
- |
if [ "$CI_JOB_STATUS" = "success" ]; then
ETAT="success"
else
ETAT="failure"
fi
curl -s -X POST \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/agence/site-client/statuses/${CI_COMMIT_SHA}" \
-d "{\"state\":\"${ETAT}\",\"context\":\"tests-fonctionnels-gitlab\",\"description\":\"Suite e2e GitLab\"}"
Le champ context identifie ce statut particulier parmi d’éventuels autres statuts posés sur le même commit, ce qui permet au pipeline de déploiement de cibler précisément celui qui l’intéresse.
Côté GitHub Actions : attendre avant de déployer
Le pipeline de déploiement inclut une étape d’attente active, qui interroge l’API GitHub par intervalles réguliers jusqu’à obtenir le statut attendu, ou jusqu’à expiration d’un délai maximal :
- name: Attendre les tests fonctionnels GitLab
run: |
SHA="${{ github.sha }}"
DELAI_MAX=900
ECOULE=0
while [ "$ECOULE" -lt "$DELAI_MAX" ]; do
ETAT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/commits/${SHA}/statuses" \
| jq -r '.[] | select(.context=="tests-fonctionnels-gitlab") | .state' | head -n1)
if [ "$ETAT" = "success" ]; then
echo "Tests fonctionnels validés, déploiement autorisé."
exit 0
elif [ "$ETAT" = "failure" ]; then
echo "Tests fonctionnels en échec, déploiement annulé."
exit 1
fi
echo "En attente du statut GitLab... (${ECOULE}s écoulées)"
sleep 20
ECOULE=$((ECOULE + 20))
done
echo "Délai d'attente dépassé, déploiement annulé par sécurité."
exit 1
Le job de déploiement suivant, celui qui pousse effectivement le code en production via rsync ou une commande WP-CLI de mise à jour, ne se déclenche que si cette étape se termine avec succès, grâce à un simple enchaînement séquentiel des jobs dans le fichier de workflow.
Pourquoi un délai d’expiration est indispensable
Sans limite de temps, une panne côté GitLab, une suite de tests bloquée sur un test qui ne se termine jamais, ou un webhook mal configuré laisserait le pipeline GitHub tourner indéfiniment, consommant des minutes de CI facturées sans jamais aboutir. Le délai fixé à quinze minutes correspond, chez ce client, à la durée maximale observée pour la suite de tests en conditions normales, avec une marge confortable.
Gérer le cas où GitLab ne répond jamais
Un abandon après expiration du délai ne doit jamais déployer par défaut : le code ci-dessus choisit explicitement d’échouer plutôt que de continuer, ce qui correspond à l’exigence initiale du client. En cas de doute sur l’état des tests, mieux vaut un déploiement bloqué qu’un déploiement non validé.
Une alternative plus réactive : le webhook entrant
La boucle d’attente active consomme des minutes de CI même quand rien ne se passe. Une alternative plus économe consiste à déclencher directement le pipeline de déploiement via un événement repository_dispatch envoyé par GitLab à la fin de sa suite de tests, plutôt que de faire sonder GitHub Actions. Cette approche demande un peu plus de configuration côté sécurité, avec un jeton d’API à portée restreinte, mais élimine complètement le temps d’attente passif.
Deux systèmes CI qui ne se parlent pas nativement peuvent toujours se coordonner par un contrat minimal : un statut, un SHA, un état attendu.
En résumé
Faire dépendre un déploiement WordPress d’une suite de tests hébergée ailleurs ne demande pas de fusionner les deux systèmes CI. Le mécanisme de statut de commit, standard sur GitHub comme sur GitLab, suffit à établir un contrat clair entre deux outils qui s’ignorent par ailleurs. La construction de la suite de tests elle-même, avec ses scénarios et ses assertions, relève d’un tout autre sujet, déjà traité côté tests.