Aller au contenu
CI/CD & Automatisation medium

extends et anchors YAML GitLab CI/CD

11 min de lecture

logo gitlab

Vous répétez les mêmes lignes dans plusieurs jobs ? extends et les anchors YAML permettent de factoriser votre configuration. Définissez une fois, réutilisez partout.

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

Héritage avec extends : le job enfant hérite des propriétés du parent et peut les surcharger

Un job peut hériter d’un autre job avec extends. Le job parent est généralement caché (préfixé par .) :

# Job caché (ne s'exécute pas)
.base_job:
image: python:3.11
before_script:
- pip install -r requirements.txt
# Job qui hérite
test:
extends: .base_job
script:
- pytest

Le job test hérite de :

  • image: python:3.11
  • before_script: [pip install -r requirements.txt]

Et définit son propre script.

Les jobs dont le nom commence par . ne s’exécutent pas. Ils servent uniquement de modèles :

.template: # Ne s'exécute pas
image: alpine
my_job: # S'exécute
extends: .template
script: echo "Hello"

Un job peut hériter de plusieurs templates (le dernier gagne en cas de conflit) :

.base:
image: node:18
variables:
ENV: production
.with_cache:
cache:
paths:
- node_modules/
build:
extends:
- .base
- .with_cache
script: npm run build

build hérite de .base ET .with_cache.

Le job enfant peut surcharger n’importe quelle propriété du parent :

.node_base:
image: node:18
script:
- npm test
variables:
NODE_ENV: development
# Surcharge l'image et les variables
build_prod:
extends: .node_base
image: node:20 # Surcharge
script:
- npm run build # Surcharge
variables:
NODE_ENV: production # Surcharge
# Garde tout sauf le script
test:
extends: .node_base
script:
- npm run lint
- npm test

Avec extends, les mappings (dictionnaires) fusionnent, mais les scalaires et tableaux sont écrasés par la définition la plus prioritaire :

.base:
script:
- echo "step 1"
- echo "step 2"
job:
extends: .base
script:
- echo "only this" # Remplace complètement !

Pour ajouter des étapes, utilisez before_script et after_script :

.base:
before_script:
- echo "setup"
script:
- echo "main"
job:
extends: .base
after_script:
- echo "cleanup" # Ajoute sans remplacer

Les dictionnaires fusionnent en profondeur :

.base:
variables:
VAR1: "value1"
VAR2: "value2"
job:
extends: .base
variables:
VAR2: "overridden" # Surcharge VAR2
VAR3: "value3" # Ajoute VAR3
# Résultat : VAR1=value1, VAR2=overridden, VAR3=value3

Les anchors sont une fonctionnalité native de YAML, pas spécifique à GitLab.

SymboleSignification
&nameDéfinit une ancre nommée
*nameRéférence l’ancre
<<:Fusionne le contenu de l’ancre
# Définir une ancre
.job_template: &job_config
image: ruby:3.0
services:
- postgres:14
# Utiliser l'ancre
test1:
<<: *job_config
script: ruby test1.rb
test2:
<<: *job_config
script: ruby test2.rb
variables:
DATABASE_URL: &db_url "postgres://localhost:5432/app"
job1:
variables:
DB: *db_url
job2:
variables:
DATABASE: *db_url
.base_config: &base
image: node:18
.cache_config: &cache
cache:
paths:
- node_modules/
build:
<<: [*base, *cache] # Fusionne les deux
script: npm run build
variables: &global_vars
VAR1: "value1"
VAR2: "value2"
job:
variables:
<<: *global_vars
VAR3: "value3" # Ajoute une variable
AspectextendsAnchors!reference
Lisibilité✅ Plus clair❌ Syntaxe cryptique✅ Explicite
Merge mappings✅ Oui⚠️ Shallow❌ Non (insertion)
Réutiliser des listes❌ Écrase❌ Écrase✅ Oui
Multi-fichiers✅ Avec include❌ Même fichier✅ Avec include
Spécifique GitLabOuiNon (YAML)Oui
Recommandé pourJobs completsValeurs simplesFragments (rules, script)

GitLab propose !reference pour réutiliser des fragments de configuration (listes, mappings) sans les limitations des anchors :

.security_rules:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
.test_script:
script:
- npm test
- npm run coverage
build:
script:
- npm run build
rules:
- !reference [.security_rules, rules] # Réutilise les rules
test:
script:
- !reference [.test_script, script] # Réutilise le script
- npm run e2e # Ajoute une commande
rules:
- !reference [.security_rules, rules]
variables:
NODE_VERSION: "18" # Valeur par défaut, surchargeable
.node_base:
image: "node:${NODE_VERSION}"
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
before_script:
- npm ci
build:
extends: .node_base
script: npm run build
artifacts:
paths:
- dist/
test:
extends: .node_base
script: npm test
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
lint:
extends: .node_base
script: npm run lint
allow_failure: true
.deploy_base:
image: alpine:3.18
before_script:
- apk add --no-cache curl
script:
- ./deploy.sh "$ENVIRONMENT"
deploy_staging:
extends: .deploy_base
variables:
ENVIRONMENT: staging
environment:
name: staging
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
deploy_production:
extends: .deploy_base
variables:
ENVIRONMENT: production
environment:
name: production
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
ErreurCauseSolution
Job ne s’exécute pasNom commence par .Retirer le . ou créer un job qui extends
Script remplacé au lieu d’étenduLes tableaux ne fusionnent pasUtiliser before_script/after_script
extends: unknown jobJob parent non trouvéVérifier le nom exact
Anchor non trouvéeOrdre de définitionDéfinir l’ancre avant de l’utiliser
  1. extends permet l’héritage de jobs — préférez-le aux anchors
  2. Jobs cachés (.name) ne s’exécutent pas, servent de templates
  3. Mappings fusionnent, scalaires et tableaux sont écrasés
  4. Héritage multiple : le dernier gagne en cas de conflit
  5. Anchors (&, *, <<:) pour les cas avancés dans le même fichier
  6. !reference pour réutiliser des fragments (rules, script) entre jobs
  7. Combinez avec include pour partager entre projets

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