Skip to content

Rules et workflow

Tous les jobs n'ont pas à tourner à chaque commit. Il y a deux niveaux pour contrôler ça:

  • rules: dans un job: ce job tourne ou pas
  • workflow: au niveau global: la pipeline entière est créée ou pas

rules

job:
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

  script:
    - echo "tourne si la condition est vraie"

Trois choses à savoir:

  1. les règles sont évaluées dans l'ordre, la première dont le if est vrai décide
  2. si aucune règle ne match, le job ne tourne pas (comme when: never)
  3. une règle sans if match toujours, donc elle sert de "sinon"
rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
    when: on_success    # IF
  - when: manual        # ELSE

when

Valeur Effet
on_success tourne si les jobs d'avant ont réussi (défaut)
on_failure tourne si au moins un job d'avant a échoué
always tourne quoi qu'il arrive
manual il faut cliquer sur ▶️ dans l'interface gitlab
delayed tourne tout seul après un délai (start_in: 30 minutes)
never ne tourne pas

Conditions courantes

# sur la branche par défaut
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

# uniquement quand on pousse un tag
- if: '$CI_COMMIT_TAG != null'

# uniquement dans une merge request vers main
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'

&& = ET, || = OU. Plusieurs - if: à la suite sont combinés avec un OU.

Le dernier when: never

Pattern que j'utilise partout: les règles voulues d'abord, et un when: never à la fin pour être explicite sur le "sinon, ne pas tourner":

rules:
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    when: on_success
  - when: never

Après c'est pas obligatoire hein. Ça revient à faire ça:

rules:
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

Le job qui tourne jamais

stages:
  - learn

learn-job:
  stage: learn
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: never

  script:
    - echo "Ca tourne en boucle"

Sur main, la règle dit never. Sur toute autre branche, aucune règle ne match, donc le job est exclu aussi. Il ne tourne donc jamais, et comme c'est le seul job, la pipeline ne peut même pas être créée.

Pour que ça tourne partout sauf sur main, il faut rajouter une règle "sinon":

rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
    when: never
  - when: on_success

workflow

workflow:rules décide si la pipeline est créée. Même syntaxe que rules, mais écrit une seule fois, en haut du fichier.

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
    - if: '$CI_COMMIT_BRANCH == "main"'

Éviter les pipelines en double

Quand on push sur une branche qui a une merge request ouverte, gitlab peut lancer deux pipelines: une pour le push, une pour la MR. Pour n'en garder qu'une:

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: always

    - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
      when: never

    - if: '$CI_COMMIT_BRANCH'
      when: always

Lecture:

  1. pipeline de MR: ok
  2. push sur une branche qui a une MR ouverte: non (la pipeline de la MR suffit)
  3. tout push sur une branche: ok

Même problème avec les tags: un commit tagué puis push peut lancer une pipeline pour le push et une pour le tag (git tag ne crée le tag qu'en local, il faut ensuite git push origin --tags). Pour ignorer les tags:

workflow:
  rules:
    - if: '$CI_COMMIT_TAG'
      when: never

    - if: '$CI_PIPELINE_SOURCE == "push"'

Exemple du cours

stages:
  - build
  - test
  - deploy

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

    - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
      when: never

    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  • commit poussé sur la branche principale: la pipeline est déclenchée
  • commit poussé sur une branche qui a une MR ouverte: pas de pipeline séparée (celle de la MR tourne)

Jobs spécifiques aux tags

Un job qui ne tourne que lors d'un push de tag (utile pour une release):

release:
  stage: deploy
  rules:
    # $CI_COMMIT_TAG est uniquement set si on est sur un tag push
    - if: '$CI_COMMIT_TAG != null'
      when: on_success

    - when: never

  script: |
    echo "Current tag is: $CI_COMMIT_TAG"

Et un job qui ne tourne que dans une merge request:

check-mr:
  stage: test
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: on_success

    - when: never

  script: |
    echo "Bonjour depuis la merge request"