Aller au contenu
CI/CD & Automatisation medium

Lab 08, Déclencher un pipeline

17 min de lecture

logo gitlab

Dans un projet réel, un pipeline ne doit pas dépendre uniquement d'un git push. Vous avez souvent besoin de lancer des tests chaque nuit, de déclencher un rebuild depuis un outil externe, ou de relancer un pipeline à la demande après une alerte monitoring. Ce lab vous montre comment faire avec les déclencheurs GitLab natifs.

Ce lab se fait sur un projet GitLab réel, pas en simulation : la création d'un schedule et la génération d'un trigger token passent par l'interface du projet, et le pipeline déclenché consomme des minutes de runner.

  • Déclencher un pipeline via un schedule GitLab
  • Déclencher un pipeline via API et trigger token
  • Comprendre les valeurs de $CI_PIPELINE_SOURCE
  • Écrire des rules spécifiques au type de déclenchement

Ce lab vient après Lab 07. Si vous êtes déjà à l'aise avec la validation de pipeline, vous pouvez commencer directement depuis starter/lab-08.

Les équipes DevOps utilisent plusieurs sources de déclenchement selon le besoin :

  • push et merge request pour la validation continue
  • schedule pour les tests de régression nocturnes
  • API/trigger pour orchestrer des pipelines depuis d'autres systèmes

Sans cette maîtrise, vous limitez l'automatisation et vous ratez des scénarios importants.

La branche starter/lab-08 contient un .gitlab-ci.yml déjà fonctionnel sur push et merge request. Vous ne partez donc pas d'une page blanche : le travail consiste à ouvrir les sources de déclenchement manquantes, pas à réécrire le pipeline. Gardez cette branche telle quelle et travaillez dessus, la branche solution/lab-08 sert uniquement de point de comparaison.

  1. Basculez sur la branche du lab

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

    Vous allez ajouter des règles basées sur la source du pipeline.

Le pipeline gère déjà les runs MR, main et tags, mais il ne traite pas correctement les déclenchements schedule, trigger et api. Le but de ce lab est de rendre ces sources explicites dans workflow et dans les rules des jobs.

Vous allez faire évoluer le pipeline pour distinguer clairement :

  • push
  • schedule
  • trigger
  • api

Étape 1, À vous d'ajouter des règles basées sur la source

Section intitulée « Étape 1, À vous d'ajouter des règles basées sur la source »

Cette première étape se joue entièrement dans le fichier .gitlab-ci.yml, sans toucher à l'interface GitLab. Le point clé : le bloc workflow:rules décide si un pipeline existe, les rules d'un job décident s'il s'exécute dans ce pipeline. Une source absente de workflow ne créera jamais de pipeline, même si tous les jobs l'autorisent. Commencez donc par workflow, puis descendez vers les jobs.

  1. Ajoutez un job dédié aux runs planifiés (schedule).

  2. Remplacez les règles MR basées sur $CI_MERGE_REQUEST_IID par des règles basées sur la source du pipeline.

  3. Ajoutez des règles explicites sur les jobs de validation pour distinguer :

    • merge_request_event
    • trigger
    • api
  4. Vérifiez que la logique dépend bien de CI_PIPELINE_SOURCE.

Vérifier votre solution (Étape 1)

Remplacez la règle MR historique par une règle source explicite et ajoutez les sources externes :

workflow:
rules:
- 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"

La règle unique if: $CI_PIPELINE_SOURCE == "schedule" isole ce job : il n'apparaît dans aucun pipeline de push ni de merge request. C'est ce qui permet d'y mettre une suite pytest complète, plus lente, sans pénaliser la boucle de développement. Notez l'absence de --junitxml ici, contrairement au job pytest : la régression nocturne sert d'alerte, pas de rapport de merge request.

nightly-regression:
stage: test
image: python:3.12-slim@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
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"

Les six valeurs ci-dessous sont celles que vous rencontrerez dans ce lab. La distinction la plus piégeuse est celle entre trigger et api : les deux passent par l'API REST, mais trigger désigne un appel authentifié par un trigger token sur l'endpoint /trigger/pipeline, alors que api désigne un appel à /pipeline authentifié par un jeton d'accès. Une règle qui n'autorise que api ne verra donc jamais passer un trigger token.

ValeurDéclencheur
pushgit push
merge_request_eventOuverture / mise à jour MR
scheduleTâche planifiée GitLab
triggerTrigger token
apiAPI REST GitLab
webBouton « Run pipeline » dans l'UI

Exemple sur un job existant (ruff-lint/pytest) :

ruff-lint:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "api"
- if: $CI_PIPELINE_SOURCE == "trigger"

Étape 2, À vous de créer un schedule dans GitLab

Section intitulée « Étape 2, À vous de créer un schedule dans GitLab »

On quitte le fichier YAML pour l'interface : un schedule est un objet du projet, pas une directive du pipeline. Conséquence pratique, il survit aux modifications du .gitlab-ci.yml et s'exécute avec les droits de l'utilisateur qui l'a créé, ce qui compte si ce compte perd son accès au projet. Le schedule ne produira un pipeline que si la source schedule est acceptée par le bloc workflow de l'étape 1.

  1. Allez dans Build > Pipeline schedules

  2. Créez un schedule quotidien

  3. Choisissez la branche cible, l'horaire et le fuseau

    Le champ Cron timezone vaut UTC par défaut. Si vous raisonnez en heure locale, changez ce champ ou compensez le décalage dans l'expression cron.

Vérifier votre solution (Étape 2)

Le formulaire tient en quatre champs. Le seul qui demande réflexion est Interval Pattern : GitLab accepte une expression cron standard à cinq champs, et propose aussi des raccourcis (Every day, Every week). Prenez l'expression explicite pour ce lab, elle rend le fuseau et la minute d'exécution visibles.

  1. Allez dans Build > Pipeline schedules
  2. Cliquez New schedule
  3. Remplissez les champs :
ChampValeur exemple
DescriptionRégression nocturne
Interval Pattern0 2 * * * (chaque nuit à 02:00 UTC)
Target branchmain
Active
  1. Cliquez Save pipeline schedule

Pour déclencher immédiatement en test, utilisez le bouton de lancement à droite du schedule dans la liste. Le pipeline créé porte bien CI_PIPELINE_SOURCE == "schedule", vous n'avez pas à attendre l'heure programmée pour valider vos règles.

Le formulaire propose un champ Cron timezone, positionné sur UTC par défaut. Laissé tel quel, 0 2 * * * correspond à 02:00 UTC, soit 04:00 à Paris en heure d'été (CEST, UTC+2) et 03:00 en heure d'hiver (CET, UTC+1). L'horaire réel se décale donc d'une heure deux fois par an. Pour figer l'heure locale, sélectionnez explicitement Paris dans ce champ plutôt que de compenser à la main dans l'expression cron.

Étape 3, À vous de déclencher via API avec trigger token

Section intitulée « Étape 3, À vous de déclencher via API avec trigger token »

Le trigger token est un secret de projet à portée volontairement étroite : il ne sert qu'à créer un pipeline, il ne donne accès ni au code, ni aux variables, ni au reste de l'API. C'est ce qui le rend acceptable dans un système tiers (outil de supervision, ordonnanceur maison) auquel vous ne confieriez jamais un jeton d'accès personnel. Traitez-le malgré tout comme un mot de passe : quiconque le détient peut consommer vos minutes de runner et exécuter votre pipeline sur la branche de son choix.

  1. Générez un token dans Settings > CI/CD > Pipeline trigger tokens.

  2. Déclenchez un pipeline via l'API GitLab avec ce token.

  3. Vérifiez dans GitLab que la source du pipeline est trigger.

Vérifier votre solution (Étape 3)

Un détail de visibilité mérite d'être connu : vous pouvez relire en clair les tokens que vous avez créés, mais des tokens créés par un autre membre du projet ne vous montrent que leurs quatre premiers caractères. Un token perdu par son créateur se révoque et se recrée, il ne se récupère pas auprès d'un collègue. La description sert au moment de la révocation, donnez-lui le nom du système qui va l'utiliser plutôt qu'un libellé générique.

  1. Allez dans Settings > CI/CD > Pipeline trigger tokens
  2. Saisissez une description : test external trigger
  3. Cliquez Add trigger token et copiez le token généré

Le token transite en paramètre de formulaire, pas en en-tête. Passez-le par une variable d'environnement plutôt qu'en clair sur la ligne de commande : un argument curl finit dans l'historique du shell et reste visible dans la liste des processus le temps de l'appel. Le --fail fait renvoyer un code non nul à curl sur une réponse HTTP d'erreur, sans quoi un token invalide passerait pour un succès.

Fenêtre de terminal
read -rs -p "Trigger token : " TRIGGER_TOKEN
export TRIGGER_TOKEN
curl -X POST \
--fail \
-F "token=${TRIGGER_TOKEN}" \
-F ref=main \
"https://gitlab.com/api/v4/projects/<PROJECT_ID>/trigger/pipeline"

Récupérez <PROJECT_ID> dans Settings > General > Project ID.

La réponse JSON confirme le déclenchement :

{
"id": 12345,
"status": "created",
"source": "trigger"
}

Étape 4, À vous de vérifier la source dans les logs

Section intitulée « Étape 4, À vous de vérifier la source dans les logs »

Vos règles peuvent être syntaxiquement correctes et malgré tout ne jamais matcher : GitLab n'affiche aucun avertissement quand une condition rules:if est fausse, le job disparaît simplement du pipeline. La seule preuve fiable est la valeur réellement injectée dans le job. Un echo dans le script la rend visible dans les logs et transforme un doute en constat.

  1. Ajoutez temporairement une ligne de debug qui affiche la valeur de CI_PIPELINE_SOURCE.

  2. Lancez un pipeline de chaque type et comparez les valeurs observées.

    Cette étape vous aide à valider vos règles sans ambiguïté.

Vérifier votre solution (Étape 4)

La ligne d'echo se place en tête du script, avant toute commande susceptible d'échouer : si pytest plante, vous voulez quand même avoir lu la source du pipeline. Le job pytest est un bon porteur pour cette trace parce que ses rules couvrent quatre sources sur six, il s'exécutera donc dans presque tous vos essais.

pytest:
script:
- 'echo "Pipeline source: $CI_PIPELINE_SOURCE"'
- pytest -v --junitxml=report.xml

Les logs affichent la valeur exacte selon le déclencheur :

  • MR → Pipeline source: merge_request_event
  • schedule → Pipeline source: schedule
  • trigger API → Pipeline source: trigger
  • API REST → Pipeline source: api

Vous pouvez garder cette ligne echo le temps du lab pour observer le routage des règles, puis la retirer ensuite.

Voici le .gitlab-ci.yml obtenu à l'issue des quatre étapes. Comparez-le au vôtre en regardant d'abord les blocs rules : c'est là que se concentre tout le travail du lab, le reste (stages, cache, images) est identique à la branche de départ. Les jobs docker-build, deploy-staging et deploy-production conservent volontairement une règle sur la seule branche par défaut : on ne veut ni construire ni déployer depuis un déclenchement externe.

Voir le fichier .gitlab-ci.yml complet
stages:
- lint
- test
- build
- deploy
workflow:
rules:
- 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@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
cache:
key:
files:
- requirements-dev.txt
paths:
- .pip-cache/
policy: pull
before_script:
- pip install ruff
script:
- ruff check app/ tests/
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "api"
- if: $CI_PIPELINE_SOURCE == "trigger"
pytest:
stage: test
image: python:3.12-slim@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
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
artifacts:
when: always
paths:
- report.xml
reports:
junit: report.xml
expire_in: 7 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "api"
- if: $CI_PIPELINE_SOURCE == "trigger"
nightly-regression:
stage: test
image: python:3.12-slim@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
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@sha256:aa3df78ecf320f5fafdce71c659f1629e96e9de0968305fe1de670e0ca9176ce
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
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy-staging:
stage: deploy
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
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@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
script:
- echo "Deploying $CI_COMMIT_SHORT_SHA to production..."
- ./scripts/deploy-demo.sh production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual

Le lab est réussi quand vous obtenez quatre pipelines de sources différentes sur le même dépôt et que la composition des jobs change d'un pipeline à l'autre. Un pipeline qui contient exactement les mêmes jobs quelle que soit la source signale des rules qui ne discriminent rien.

  • Un schedule déclenche bien un pipeline
  • Un trigger API déclenche bien un pipeline
  • Les jobs s'exécutent selon la valeur de CI_PIPELINE_SOURCE
  • Vous savez expliquer la différence entre trigger token et personal access token

Le trigger token sert à déclencher un pipeline, pas à accéder à toute l'API GitLab. Le personal access token a un autre usage. Mélanger les deux est une erreur classique.

Autre point : un cron mal calé en UTC donne l'impression que le schedule ne fonctionne pas. Vérifiez toujours le fuseau horaire avant de conclure.

  • Un pipeline GitLab peut être déclenché sans push
  • $CI_PIPELINE_SOURCE permet d'adapter les jobs au contexte
  • Schedule et API couvrent des besoins complémentaires
  • Tester vos règles par source évite les surprises en production

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn