Aller au contenu
CI/CD & Automatisation medium

Conditions d'exécution GitLab CI/CD (rules)

15 min de lecture

logo gitlab

Votre pipeline lance tous les jobs à chaque commit, même quand ce n’est pas nécessaire ? Les rules permettent de contrôler précisément quand un job s’exécute — sur quelle branche, pour quel type de changement, avec quelle approbation.

Ce guide vous montre comment optimiser vos pipelines en exécutant uniquement ce qui est nécessaire, et comment éviter le piège classique des pipelines qui “skip” sans raison apparente.

Avant de continuer, assurez-vous de maîtriser :

Sans rules, tous les jobs s’exécutent à chaque pipeline. C’est un gaspillage de ressources et de temps :

  • Tests complets alors que seul le README a changé
  • Build Docker alors que le code n’a pas bougé
  • Déploiement automatique sans validation humaine

Les rules permettent d’exécuter uniquement ce qui est nécessaire, quand c’est nécessaire.

La règle la plus utilisée. Teste une expression qui renvoie vrai ou faux.

job:
script: echo "Déploiement"
rules:
- if: '$CI_COMMIT_BRANCH == "main"'

Opérateurs disponibles :

OpérateurSignificationExemple
==Égal à$VAR == "value"
!=Différent de$VAR != "skip"
=~Match regex$VAR =~ /^feature-/
!~Ne match pas regex$VAR !~ /wip/
&&ET logique$A == "x" && $B == "y"
``

Variables les plus utilisées dans les rules :

VariableValeurCas d’usage
$CI_COMMIT_BRANCHNom de la brancheLimiter à main, develop
$CI_COMMIT_TAGNom du tag (si tag)Déployer uniquement les releases
$CI_PIPELINE_SOURCESource du pipelinepush, merge_request_event, schedule
$CI_MERGE_REQUEST_IDID de la MRJobs spécifiques aux MRs
# Exemples pratiques
rules:
# Sur la branche main uniquement
- if: '$CI_COMMIT_BRANCH == "main"'
# Sur un tag de release (v1.0.0, v2.3.4...)
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
# Uniquement pour les merge requests
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# Pipeline planifié (cron)
- if: '$CI_PIPELINE_SOURCE == "schedule"'

Exécute le job uniquement si certains fichiers ont été modifiés dans le commit.

build_frontend:
script: npm run build
rules:
- changes:
- "frontend/**/*"
- "package.json"
- "package-lock.json"

Patterns supportés :

PatternSignification
src/*.jsFichiers .js dans src/
src/**/*.jsFichiers .js dans src/ et sous-dossiers
*.mdFichiers .md à la racine
**/*.mdTous les fichiers .md du projet

exists : condition sur l’existence d’un fichier

Section intitulée « exists : condition sur l’existence d’un fichier »

Exécute le job si un fichier existe dans le repository.

docker_build:
script: docker build -t myapp .
rules:
- exists:
- Dockerfile

Utile pour les monorepos où tous les projets n’ont pas les mêmes fichiers.

Vous pouvez combiner if, changes et exists dans une même règle :

deploy_docs:
script: ./deploy-docs.sh
rules:
# Sur main ET si des fichiers docs ont changé
- if: '$CI_COMMIT_BRANCH == "main"'
changes:
- "docs/**/*"
- "mkdocs.yml"

Attention : dans une règle, les conditions sont en ET. Pour un OU, utilisez plusieurs règles :

job:
rules:
# Sur main OU sur un tag de release
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG =~ /^v\d+/'

when définit comment le job démarre si la règle matche.

ValeurComportement
on_successDémarre automatiquement si les jobs précédents ont réussi (défaut)
on_failureDémarre uniquement si un job précédent a échoué
alwaysDémarre toujours, quel que soit le résultat des jobs précédents
manualAttend un clic dans l’interface pour démarrer
delayedDémarre automatiquement après un délai
neverNe démarre jamais (exclut le job)

Déploiement manuel en production :

deploy_prod:
script: ./deploy.sh production
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual

Notification en cas d’échec :

notify_failure:
script: ./send-slack-alert.sh
rules:
# Condition explicite + when: on_failure
- if: '$CI_PIPELINE_SOURCE'
when: on_failure

Déploiement différé (canary) :

deploy_canary:
script: ./deploy.sh canary
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: delayed
start_in: 30 minutes

Exclure explicitement :

heavy_tests:
script: ./run-all-tests.sh
rules:
# Pas sur les branches WIP
- if: '$CI_COMMIT_BRANCH =~ /^wip-/'
when: never
# Sinon, exécuter normalement
- when: on_success

workflow:rules détermine si le pipeline lui-même doit être créé. C’est différent des rules au niveau des jobs qui contrôlent chaque job individuellement.

Sans workflow:rules, GitLab crée un pipeline pour chaque push, même si aucun job ne doit s’exécuter. Cela crée du bruit dans l’interface.

Avec workflow:rules, vous pouvez empêcher la création du pipeline dans certains cas.

workflow:
rules:
# Pas de pipeline si c'est un tag (on déploie via autre workflow)
- if: '$CI_COMMIT_TAG'
when: never
# Pas de pipeline si la branche a une MR ouverte
# (le pipeline MR suffit)
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
# Pour les merge requests
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# Pour les pushs sur les branches
- if: '$CI_COMMIT_BRANCH'

Symptôme : vous poussez du code, le pipeline apparaît comme “skipped” ou ne démarre pas du tout.

Cause probable : workflow:rules empêche la création du pipeline.

Diagnostic :

  1. Vérifiez votre section workflow:rules
  2. Identifiez quelle règle matche avec vos conditions actuelles
  3. Si aucune règle ne matche, le pipeline est skipped
# ❌ Problème : ce workflow ne matche jamais pour les pushs simples
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# ✅ Solution : ajouter les autres cas
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
stages:
- lint
- build
- test
- deploy
# Lint : toujours (rapide, peu coûteux)
lint:
stage: lint
script: npm run lint
# Build : seulement si le code a changé
build:
stage: build
script: npm run build
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- "src/**/*"
- "package*.json"
# Tests : seulement si le code a changé
test:
stage: test
script: npm test
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- "src/**/*"
- "tests/**/*"
- "package*.json"
# Deploy staging : auto sur main
deploy_staging:
stage: deploy
script: ./deploy.sh staging
environment:
name: staging
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
# Deploy prod : manuel sur tags
deploy_prod:
stage: deploy
script: ./deploy.sh production
environment:
name: production
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+/'
when: manual
workflow:
rules:
# Un tag déclenche son propre pipeline, pas besoin du push
- if: '$CI_COMMIT_TAG'
# Pour les MRs, utiliser le pipeline MR
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# Pour les pushs sur branches sans MR ouverte
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
- if: '$CI_COMMIT_BRANCH'
SymptômeCause probableSolution
Pipeline entier “skipped”workflow:rules ne matche pasAjouter une règle pour votre cas
Job jamais exécutéOrdre des règles (never en dernier)Mettre les exclusions en premier
Job toujours exécutéPas de règle, comportement par défautAjouter rules: explicites
changes toujours vraiPipeline schedule ou webchanges ne fonctionne qu’avec push/MR
Variables non définies dans rulesVariable inexistanteTester avec $VAR (vide = faux)

Si vous avez des pipelines avec only/except, migrez vers rules (plus flexible et plus clair).

# ❌ Ancien style (deprecated)
deploy:
script: ./deploy.sh
only:
- main
except:
- schedules
# ✅ Nouveau style
deploy:
script: ./deploy.sh
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: never
- if: '$CI_COMMIT_BRANCH == "main"'
  1. rules contrôle quand un job s’exécute, workflow:rules contrôle quand le pipeline est créé.
  2. Première règle qui matche gagne — ordonnez vos règles du plus spécifique au plus général.
  3. if teste des variables, changes teste les fichiers modifiés, exists teste l’existence.
  4. when: never en premier pour exclure, when: on_success en dernier par défaut.
  5. changes ne fonctionne pas avec les pipelines schedule ou web.
  6. Pipeline “skipped” = vérifier workflow:rules en premier.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

10 questions
5 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre