Retour au cours

infra / github-actions

Jobs et steps : dépendances, sorties, conditions

Leçon 41 exercice

Explication

Ce que vous allez apprendre

  • Comprendre pourquoi les jobs d'un workflow s'exécutent en parallèle et isolés par défaut
  • Coordonner explicitement des jobs dépendants les uns des autres avec needs:
  • Faire communiquer deux jobs isolés via des outputs
  • Ajuster le comportement par défaut en cas d'échec avec continue-on-error et if: always()
  • Distinguer $GITHUB_ENV (même job) de $GITHUB_OUTPUT (inter-jobs via needs)

Dans quel contexte ?

Un pipeline a deux jobs : build, qui compile l'application, et deploy, qui la met en production. Sans coordination explicite entre les deux, GitHub Actions les lance en parallèle par défaut — et il est déjà arrivé qu'un déploiement parte alors que le build venait tout juste d'échouer, les deux jobs ayant démarré au même instant sur des machines totalement isolées l'une de l'autre. Cette leçon montre comment forcer un ordre logique entre jobs, et comment leur faire échanger des informations malgré leur isolement.

Un rappel important : les jobs s'ignorent par défaut

D'abord, rappelle-toi de la première leçon : les jobs d'un même workflow s'exécutent en parallèle par défaut, chacun sur une machine isolée qui ne partage rien avec les autres.

Le problème que ça pose

C'est très bien pour la rapidité, mais problématique dès qu'un job dépend logiquement d'un autre : on ne veut pas déployer une application dont le build vient d'échouer.

La solution : une coordination explicite

needs: introduit cette coordination explicite entre jobs par ailleurs isolés.

MécanismePortéeRôle
needs:Entre jobsForce un ordre d'exécution et attend le succès du job précédent
outputs + needs.<job>.outputs.<cle>Entre jobsTransmet une valeur calculée d'un job à un autre
$GITHUB_ENVÀ l'intérieur d'un même jobPropage une variable aux steps suivants du même job
continue-on-error / if: always()Au sein d'un step/jobAjuste le comportement par défaut en cas d'échec

Un nouveau problème : comment communiquer entre jobs

Puisque les jobs ne partagent pas de mémoire ni de système de fichiers, comment un job "déploiement" peut-il savoir ce qui s'est passé dans le job "test" qui l'a précédé ?

La solution : les outputs

Les outputs résolvent ce problème : un job peut explicitement exposer une valeur calculée pendant son exécution, que les jobs suivants pourront lire via needs.<job>.outputs.<clé>.

Prérequis

Cette leçon suppose la première leçon du cours acquise (vocabulaire workflow/job/step) : elle approfondit spécifiquement la coordination entre plusieurs jobs d'un même workflow.

Le comportement par défaut en cas d'échec

Par défaut, l'échec d'un step interrompt immédiatement tout le reste du job : les steps suivants ne s'exécutent pas. C'est un comportement protecteur, mais parfois trop strict.

Deux façons d'ajuster ce comportement

On veut parfois continuer malgré un échec ponctuel, avec continue-on-error, ou au contraire garantir qu'une étape de nettoyage s'exécute toujours, même après un échec, avec if: always().

Ce que ça change pour ton pipeline

Savoir manier ces conditions transforme un pipeline rigide en un pipeline qui réagit intelligemment à ce qui se passe réellement.

Piège fréquent

$GITHUB_ENV et $GITHUB_OUTPUT se ressemblent mais ne servent pas au même besoin : le premier propage une variable aux steps suivants À L'INTÉRIEUR du même job, le second expose une valeur consultable depuis d'autres jobs via needs. Utiliser l'un à la place de l'autre fait échouer silencieusement la transmission de données attendue.

Une confusion fréquente à éviter

$GITHUB_ENV et $GITHUB_OUTPUT répondent à deux besoins différents malgré leur ressemblance.

La distinction précise entre les deux

Le premier propage une variable aux steps suivants à l'intérieur du même job, le second expose une valeur consultable depuis d'autres jobs via needs.

La leçon suivante s'attaque à un problème différent : éviter de dupliquer un même job pour tester plusieurs combinaisons, avec les matrix builds.

Commandes & code

Jobs & steps

yaml
name: Build and Deploy
on: push

jobs:
  test:
    runs-on: ubuntu-latest
    outputs:
      coverage: ${{ steps.tests.outputs.coverage_pct }}
    steps:
      - uses: actions/checkout@v4
      - id: tests
        run: |
          npm ci
          npm test
          echo "coverage_pct=87" >> "$GITHUB_OUTPUT"

  build:
    needs: test                       # attend que "test" réussisse avant de démarrer
    runs-on: ubuntu-latest
    if: needs.test.outputs.coverage >= 80
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

  deploy:
    needs: [test, build]               # dépend de PLUSIEURS jobs
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
      - run: echo "Déploiement en production"
yaml
# Steps : gestion des échecs et conditions fines
jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Tests unitaires
        id: unit
        run: npm run test:unit
        continue-on-error: true          # n'interrompt pas le job en cas d'échec

      - name: Notifier si les tests unitaires ont échoué
        if: steps.unit.outcome == 'failure'
        run: echo "::warning::Les tests unitaires ont échoué, voir les logs"

      - name: Étape toujours exécutée (cleanup, notif)
        if: always()
        run: echo "Nettoyage final"

      - name: Étape seulement si tout a réussi
        if: success()
        run: echo "Tout est vert"
bash
# GITHUB_OUTPUT, GITHUB_ENV : fichiers spéciaux pour faire circuler des données entre steps/jobs
echo "build_id=$(date +%s)" >> "$GITHUB_ENV"      # dispo dans les steps SUIVANTS du même job via $build_id
echo "artifact_name=app-${{ github.sha }}" >> "$GITHUB_OUTPUT"

Résumé

  • needs: ordonne les jobs et permet de lire leurs outputs (transmis via $GITHUB_OUTPUT).
  • Par défaut, un échec de step arrête le job ; continue-on-error: true change ce comportement.
  • if: always() exécute un step même après un échec (nettoyage, notification).
  • $GITHUB_ENV propage une variable aux steps suivants DANS le même job.

Exercices pratiques

1 disponible
1

Mission : un déploiement qui démarre avant la fin du build

Objectif : Corriger un workflow à deux jobs parallèles pour que le déploiement attende le succès du build et récupère sa sortie.

Contexte

Un pipeline a deux jobs, build et deploy, sans coordination entre eux. Comme les jobs s'exécutent en parallèle par défaut, il est déjà arrivé que deploy démarre alors que build venait tout juste d'échouer. De plus, build calcule un identifiant de build (build_id) que deploy a besoin de connaître pour nommer l'artefact déployé, mais ne dispose actuellement d'aucun moyen de le récupérer.

Résoudre l’exercice →