Les conditions (if) permettent de contrôler quand un job ou un step
s'exécute. Vous pouvez exécuter du code uniquement sur certaines branches,
après un échec, ou selon des critères métier.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Placer une condition
ifau bon niveau — job ou step — selon la granularité voulue - Écrire des expressions conditionnelles : comparaisons, opérateurs logiques, échappement
- Utiliser les fonctions de statut
success(),failure(),always()etcancelled() - Conditionner sur le context : branche, événement, acteur, pull request
- Réagir aux outputs et aux résultats de steps et de jobs précédents
- Éviter les trois pièges classiques des conditions
if
Ce guide suppose que vous connaissez la structure d'un workflow. Sinon, commencez par les guides Workflows GitHub Actions et Contexts et expressions.
Syntaxe de base
Section intitulée « Syntaxe de base »Une condition if se place soit sur un job entier, soit sur un step
individuel. Le principe est identique, seule la portée change.
Condition sur un job
Section intitulée « Condition sur un job »Placée au niveau du job, la condition décide si l'ensemble des steps s'exécute ou si le job entier est ignoré.
jobs: deploy: runs-on: ubuntu-24.04 # Ce job ne s'exécute que sur la branche main if: github.ref == 'refs/heads/main' steps: - run: ./deploy.shCondition sur un step
Section intitulée « Condition sur un step »Placée au niveau du step, la condition n'affecte que cette étape — les autres steps du job continuent normalement.
jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run tests run: npm test
# Ce step ne s'exécute qu'en cas d'échec du précédent - name: Upload logs on failure if: failure() run: ./upload-logs.shExpressions conditionnelles
Section intitulée « Expressions conditionnelles »Les conditions utilisent des expressions GitHub Actions avec la syntaxe
${{ }} (optionnelle dans if).
Comparaisons
Section intitulée « Comparaisons »Les opérateurs de comparaison testent l'égalité, l'inégalité ou l'ordre de deux valeurs.
# Égalitéif: github.ref == 'refs/heads/main'if: github.event_name == 'push'if: matrix.os == 'ubuntu-24.04'
# Inégalitéif: github.ref != 'refs/heads/main'
# Comparaisons numériquesif: matrix.node >= 20if: github.run_attempt > 1Opérateurs logiques
Section intitulée « Opérateurs logiques »Les opérateurs &&, || et ! combinent plusieurs conditions en une seule
expression.
# ET logiqueif: github.ref == 'refs/heads/main' && github.event_name == 'push'
# OU logiqueif: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# Négationif: "!contains(github.event.head_commit.message, '[skip ci]')"
# Combinaisonsif: | github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))Fonctions de statut
Section intitulée « Fonctions de statut »Ces fonctions évaluent le résultat des steps ou jobs précédents :
success() (par défaut)
Section intitulée « success() (par défaut) »success() renvoie vrai tant qu'aucun step précédent n'a échoué — c'est la
condition implicite de chaque step.
steps: - run: npm test
# Équivalent à if: success() - name: Deploy (si tests OK) run: ./deploy.sh
# Explicite - name: Notify success if: success() run: echo "All good!"success() est le comportement par défaut : un step ne s'exécute que si tous
les steps précédents ont réussi.
failure()
Section intitulée « failure() »failure() ne s'active que si un step précédent a échoué : idéal pour
remonter des artefacts de diagnostic ou alerter une équipe.
steps: - name: Run tests run: npm test
- name: Upload test artifacts on failure if: failure() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: test-results path: ./test-results/
- name: Notify team on failure if: failure() run: | curl -X POST "$SLACK_WEBHOOK" \ -d '{"text": "Tests failed on ${{ github.repository }}"}' env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}always()
Section intitulée « always() »always() force l'exécution quoi qu'il arrive — succès, échec ou
annulation. À réserver au nettoyage et à la collecte de logs.
steps: - name: Run tests run: npm test
# S'exécute TOUJOURS, même si un step a échoué ou le job est annulé - name: Cleanup if: always() run: ./cleanup.sh
- name: Upload coverage if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coverage path: ./coverage/cancelled()
Section intitulée « cancelled() »cancelled() cible le cas où le workflow a été interrompu — manuellement ou
par une nouvelle exécution qui remplace la précédente.
steps: - name: Long running task run: ./process.sh
- name: Notify cancellation if: cancelled() run: echo "Job was cancelled"Combinaisons de fonctions
Section intitulée « Combinaisons de fonctions »Combiner ces fonctions permet d'exprimer des cas plus fins, comme « toujours sauf si annulé ».
# S'exécute sur succès OU échec (mais pas si annulé)if: success() || failure()
# S'exécute toujours SAUF si annuléif: "!cancelled()"
# S'exécute uniquement si le job précédent a échouéif: always() && needs.build.result == 'failure'Conditions sur les contexts
Section intitulée « Conditions sur les contexts »La plupart des conditions s'appuient sur le context github pour réagir à la
branche, à l'événement ou à l'acteur qui a déclenché le workflow.
Branches et tags
Section intitulée « Branches et tags »La propriété github.ref distingue branches et tags ; la fonction
startsWith() reconnaît les familles de références.
# Branch main uniquementif: github.ref == 'refs/heads/main'
# Branches commençant par "release/"if: startsWith(github.ref, 'refs/heads/release/')
# Tags uniquementif: startsWith(github.ref, 'refs/tags/')
# Tag avec pattern semverif: startsWith(github.ref, 'refs/tags/v')Événements
Section intitulée « Événements »github.event_name indique quel déclencheur a lancé le workflow — utile
quand un même workflow réagit à plusieurs événements.
# Push uniquementif: github.event_name == 'push'
# Pull request uniquementif: github.event_name == 'pull_request'
# Déclenchement manuelif: github.event_name == 'workflow_dispatch'
# Planifié (cron)if: github.event_name == 'schedule'
# Plusieurs événementsif: github.event_name == 'push' || github.event_name == 'workflow_dispatch'github.actor identifie le compte à l'origine de l'exécution, ce qui permet
de traiter les bots à part des contributeurs humains.
# Utilisateur spécifiqueif: github.actor == 'admin-user'
# Bots (Dependabot, Renovate)if: github.actor == 'dependabot[bot]'if: github.actor == 'renovate[bot]'
# Exclure les botsif: "!contains(github.actor, '[bot]')"Pull requests
Section intitulée « Pull requests »Les conditions sur les pull requests filtrent selon la branche cible, l'origine (fork ou non) ou les labels de la PR.
# PR vers mainif: github.event_name == 'pull_request' && github.base_ref == 'main'
# PR depuis un forkif: github.event.pull_request.head.repo.fork == true
# PR non-draftif: github.event.pull_request.draft == false
# PR avec label spécifiqueif: contains(github.event.pull_request.labels.*.name, 'deploy')Conditions sur les outputs
Section intitulée « Conditions sur les outputs »Une condition peut aussi dépendre d'une valeur calculée plus tôt dans le workflow, via les outputs d'un step ou d'un job.
Outputs de steps
Section intitulée « Outputs de steps »Un step écrit une valeur dans $GITHUB_OUTPUT, et un step suivant la lit dans
sa condition if.
steps: - name: Check changes id: changes run: | if git diff --name-only HEAD~1 | grep -q "^src/"; then echo "src_changed=true" >> $GITHUB_OUTPUT else echo "src_changed=false" >> $GITHUB_OUTPUT fi
- name: Build if: steps.changes.outputs.src_changed == 'true' run: npm run buildOutputs de jobs (needs)
Section intitulée « Outputs de jobs (needs) »Un job expose un output ; un job dépendant le lit via needs pour décider s'il
doit s'exécuter.
jobs: check: runs-on: ubuntu-24.04 outputs: should_deploy: ${{ steps.check.outputs.deploy }} steps: - id: check run: | if [ "${{ github.ref }}" == "refs/heads/main" ]; then echo "deploy=true" >> $GITHUB_OUTPUT else echo "deploy=false" >> $GITHUB_OUTPUT fi
deploy: needs: check if: needs.check.outputs.should_deploy == 'true' runs-on: ubuntu-24.04 steps: - run: ./deploy.shRésultat de jobs
Section intitulée « Résultat de jobs »needs.<job>.result donne le verdict d'un job précédent — success,
failure, skipped ou cancelled — à condition de dépendre de ce job.
jobs: build: runs-on: ubuntu-24.04 steps: - run: npm run build
test: runs-on: ubuntu-24.04 steps: - run: npm test
notify: needs: [build, test] if: always() runs-on: ubuntu-24.04 steps: - name: Notify success if: needs.build.result == 'success' && needs.test.result == 'success' run: echo "All good!"
- name: Notify failure if: needs.build.result == 'failure' || needs.test.result == 'failure' run: echo "Something failed!"Patterns courants
Section intitulée « Patterns courants »Voici les conditions que l'on retrouve dans presque tous les pipelines réels — à copier puis adapter à votre contexte.
Ce pattern évite de relancer le pipeline quand le message de commit contient
le marqueur [skip ci].
jobs: build: # Ne pas exécuter si le message de commit contient [skip ci] if: "!contains(github.event.head_commit.message, '[skip ci]')" runs-on: ubuntu-24.04 steps: - run: npm testDéploiement conditionnel
Section intitulée « Déploiement conditionnel »Chaque environnement reçoit son propre job, déclenché par la branche correspondante.
jobs: deploy-staging: if: github.ref == 'refs/heads/develop' environment: staging runs-on: ubuntu-24.04 steps: - run: ./deploy.sh staging
deploy-production: if: github.ref == 'refs/heads/main' && github.event_name == 'push' environment: production runs-on: ubuntu-24.04 steps: - run: ./deploy.sh productionExécution sur schedule vs push
Section intitulée « Exécution sur schedule vs push »Un même job adapte son comportement selon qu'il tourne sur un push ou sur une exécution planifiée — par exemple un scan rapide contre un scan complet.
jobs: scan: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Scan rapide sur push - name: Quick scan if: github.event_name == 'push' run: ./scan.sh --quick
# Scan complet sur schedule - name: Full scan if: github.event_name == 'schedule' run: ./scan.sh --fullIgnorer les bots
Section intitulée « Ignorer les bots »Cette condition empêche de relancer toute la CI à chaque mise à jour automatique de dépendances poussée par Dependabot ou Renovate.
jobs: test: # Ne pas déclencher les tests pour les commits de bots if: | github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]' runs-on: ubuntu-24.04 steps: - run: npm testDry-run vs exécution réelle
Section intitulée « Dry-run vs exécution réelle »Sur une pull request, le déploiement tourne en simulation ; il ne devient réel que sur la branche principale.
jobs: deploy: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Dry-run sur les PRs - name: Deploy (dry-run) if: github.event_name == 'pull_request' run: ./deploy.sh --dry-run
# Déploiement réel sur main - name: Deploy (real) if: github.ref == 'refs/heads/main' && github.event_name == 'push' run: ./deploy.shMatrice avec conditions
Section intitulée « Matrice avec conditions »Dans une matrice, une condition sur matrix.* réserve certains steps à un
système ou à une version donnés.
jobs: test: strategy: matrix: os: [ubuntu-24.04, windows-latest, macos-latest] node: [18, 20, 22] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Step spécifique Windows - name: Setup (Windows) if: matrix.os == 'windows-latest' run: choco install nodejs
# Step spécifique aux anciennes versions - name: Legacy compatibility check if: matrix.node < 20 run: npm run test:legacyErreurs courantes
Section intitulée « Erreurs courantes »Trois pièges reviennent systématiquement avec les conditions if. Les connaître
évite des heures de debug sur un job qui ne se déclenche jamais — ou toujours.
Condition toujours vraie/fausse
Section intitulée « Condition toujours vraie/fausse »L'erreur la plus fréquente : comparer github.ref à un nom de branche nu,
alors que cette propriété contient le préfixe refs/heads/.
# ❌ Toujours faux : github.ref inclut "refs/heads/"if: github.ref == 'main'
# ✅ Correctif: github.ref == 'refs/heads/main'if: github.ref_name == 'main'Oublier les guillemets
Section intitulée « Oublier les guillemets »Une expression qui commence par ! casse le parseur YAML si elle n'est pas
entourée de guillemets.
# ❌ Erreur YAMLif: !contains(...)
# ✅ Correctif: "!contains(...)"Condition au mauvais niveau
Section intitulée « Condition au mauvais niveau »Une condition if: false sur un job rend tous ses steps inatteignables —
placez la condition au bon niveau de granularité.
# ❌ Le job est skipped, les steps ne s'exécutent jamaisjobs: deploy: if: false steps: - if: true # Jamais atteint run: echo "Never runs"
# ✅ Condition au niveau du step pour plus de granularitéjobs: deploy: steps: - if: github.ref == 'refs/heads/main' run: ./deploy.shÀ retenir
Section intitulée « À retenir »- Une condition
ifse place sur un job (tout ou rien) ou sur un step (granularité fine). - Sans
if, chaque step porte une conditionsuccess()implicite : il est ignoré dès qu'un step précédent échoue. failure(),always()etcancelled()débloquent les steps même après un échec — indispensables pour le diagnostic et le nettoyage.- Comparez toujours
github.refà la référence complète (refs/heads/main), ou utilisezgithub.ref_name. - Une expression qui commence par
!doit être entre guillemets, sinon le YAML casse. - Pour réagir au verdict d'un job précédent, lisez
needs.<job>.resultdepuis un job qui en dépend.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour la liste exhaustive des opérateurs et fonctions, gardez sous la main la documentation officielle des expressions.