Retour au cours

infra / github-actions

Artifacts

Leçon 91 exercice

Explication

Ce que vous allez apprendre

  • Comprendre pourquoi chaque job démarre isolé, sans rien de ce que le job précédent a produit
  • Sauvegarder des fichiers entre jobs avec upload-artifact et download-artifact
  • Distinguer un artifact (résultat unique d'une exécution) d'un cache (réinstallation accélérée)
  • Sauvegarder spécifiquement un artifact en cas d'échec avec if: failure()
  • Éviter le piège d'un upload silencieusement vide avec if-no-files-found: error

Dans quel contexte ?

Un pipeline compile une application dans un job build, puis un job séparé test doit exécuter des tests sur le résultat compilé. Comme ces deux jobs tournent sur des machines totalement différentes par défaut, le job test ne trouve rien : les fichiers compilés par build ont simplement disparu à la fin de son exécution. Les artifacts existent exactement pour ce besoin : transporter un résultat de build d'un job à un autre au sein du même workflow.

Le problème : chaque job démarre isolé

D'abord, un workflow GitHub Actions peut être découpé en plusieurs jobs qui s'exécutent potentiellement sur des machines différentes, par exemple un job qui compile puis un job séparé qui teste le résultat compilé.

Ce que ça implique concrètement

Chaque job démarre sur une machine fraîche, sans rien de ce que le job précédent a produit.

La conséquence sans mécanisme dédié

Sans mécanisme dédié, le résultat d'un job, des fichiers compilés, un rapport, disparaît simplement à la fin de son exécution.

La solution : l'artifact

Un artifact est un ensemble de fichiers explicitement sauvegardé à la fin d'un job, avec upload-artifact, que n'importe quel autre job du même workflow peut ensuite récupérer, avec download-artifact.

ArtifactCache
ContenuRésultat de build unique, propre à cette exécutionDépendances réinstallables à l'identique
ButTransporter un résultat entre jobsAccélérer une réinstallation
Durée de vie typiqueLe temps du workflow (ou plus, configurable)Réutilisé d'une exécution à l'autre

Ce qui distingue un artifact d'un cache

C'est différent du cache de dépendances vu précédemment : le cache sert à accélérer une réinstallation identique, alors qu'un artifact transporte un résultat de build unique et précis, propre à cette exécution.

Prérequis

Cette leçon suppose la coordination entre jobs (needs:) déjà vue en leçon 4 : un artifact uploadé par un job n'est utile que si un autre job, dépendant du premier, sait le télécharger au bon moment.

Un usage souvent oublié : garder une preuve en cas d'échec

Uploader un artifact n'est pas réservé au cas de succès : la condition if: failure() permet de sauvegarder spécifiquement un rapport de test ou des logs détaillés uniquement quand quelque chose s'est mal passé.

Pourquoi c'est utile

C'est extrêmement utile pour diagnostiquer un échec après coup, sans avoir à reproduire le problème localement.

Piège fréquent

Sans if-no-files-found: error, un upload-artifact qui ne trouve aucun fichier correspondant au chemin donné se termine SILENCIEUSEMENT en succès. Ça peut masquer un vrai problème en amont (le build n'a rien produit) derrière un pipeline qui semble pourtant "vert" — un faux sentiment de sécurité à éviter absolument.

Un piège de fiabilité à connaître

Sans if-no-files-found: error, un upload qui ne trouve aucun fichier correspondant au chemin donné se termine silencieusement en succès.

Ce que ce silence peut masquer

Cela peut masquer un vrai problème en amont, le build n'a rien produit, derrière un pipeline qui semble pourtant "vert". Rendre cet échec explicite évite un faux sentiment de sécurité.

La leçon suivante s'attaque à un problème d'un autre ordre : éviter de dupliquer la même configuration entre plusieurs workflows, avec les reusable workflows.

Commandes & code

Artifacts

Les artifacts transportent des fichiers d'un job à un autre, ou les rendent téléchargeables après l'exécution.

yaml
name: Build and Test
on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: dist-files
          path: dist/
          retention-days: 7             # durée de rétention (défaut 90 jours, coûte du stockage)

  test-e2e:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download build artifact
        uses: actions/download-artifact@v4
        with:
          name: dist-files
          path: dist/

      - run: npx playwright test

      - name: Upload rapport de test en cas d'échec
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 14
yaml
# Artifact multi-fichiers avec exclusion de patterns
- uses: actions/upload-artifact@v4
  with:
    name: coverage-report
    path: |
      coverage/
      !coverage/**/*.tmp
    if-no-files-found: error          # échoue explicitement si rien à uploader (évite un faux succès)
bash
# Récupérer un artifact depuis le terminal, sans passer par l'UI
gh run download <run-id> --name dist-files
gh api repos/:owner/:repo/actions/artifacts
yaml
# Publier un artifact comme "release asset" une fois le workflow terminé
- name: Attacher à la release GitHub
  if: startsWith(github.ref, 'refs/tags/')
  uses: softprops/action-gh-release@v2
  with:
    files: dist/app-${{ github.ref_name }}.tar.gz

Résumé

  • upload-artifact/download-artifact font transiter des fichiers entre jobs d'un même workflow.
  • retention-days maîtrise le coût de stockage (défaut 90 jours, souvent excessif).
  • if-no-files-found: error évite un succès silencieux quand rien n'a été généré.
  • gh run download récupère un artifact en ligne de commande, sans ouvrir l'UI GitHub.

Exercices pratiques

1 disponible
1

Mission : un job de tests qui ne trouve jamais les fichiers compilés

Objectif : Diagnostiquer une chaîne artifact incomplète entre deux jobs, et sécuriser l'upload contre un échec silencieux.

Contexte

Le job build compile l'application dans dist/ puis l'uploade avec upload-artifact (name: dist-files, path: dist/). Le step d'upload apparaît pourtant coché vert dans les logs. Le job test-e2e, qui en dépend via needs: build, échoue systématiquement en ne trouvant aucun fichier dans dist/ au moment de lancer Playwright — comme si l'artifact n'avait jamais existé.

Résoudre l’exercice →