Pipeline CI GitHub Actions : construire build et tests automatisés de zéro

Le téléphone vibre. Un collègue écrit : « La prod est tombée, le code que tu as mergé hier pose problème. »
La tête tourne. Pourtant, les tests passaient en local. En fouillant les logs, on découvre que le poste local tourne en Node 20 alors que l’environnement de test est en Node 18 — un bug lié à un comportement d’API différent. À ce moment-là, on aurait aimé qu’un pipeline CI lance les tests avant le merge.
Lancer les tests à la main, neuf développeurs sur dix l’oublient. Le dixième, c’est souvent celui qui a déjà pris une claque. GitHub Actions règle ça : après un push, build, tests et déploiement tournent dans le cloud. Pas besoin d’y penser, la machine s’en charge.
Cet article vous guide pour construire de zéro un pipeline CI complet : un modèle de workflow prêt à copier, la stratégie Matrix pour des tests multi-versions en parallèle (plus de la moitié du temps de build en moins), plus les pièges et retours d’expérience. Prêt ? C’est parti.
Chapitre 1 : Prise en main rapide de GitHub Actions
Qu’est-ce que GitHub Actions
En bref, GitHub Actions est la plateforme d’automatisation intégrée à GitHub. Vous poussez du code en local, elle exécute tests, build et déploiement dans le cloud — en automatique.
Avant, le CI/CD passait souvent par un serveur Jenkins à installer, configurer et maintenir. Avec GitHub Actions, pas de serveur à gérer : un fichier YAML dans le dépôt suffit. Et vous disposez de 2 000 minutes gratuites par mois (illimité sur les dépôts publics), largement suffisant pour les projets perso et les petites équipes.
Par rapport à Jenkins ou Travis CI, les atouts sont nets : intégration profonde au dépôt GitHub, statut de build visible dans les PR ; configuration simple, sans Groovy ; écosystème riche avec des milliers d’Actions sur le Marketplace officiel. Les limites existent aussi : dépendance à GitHub, migration vers GitLab implique de réécrire la config ; pour des pipelines enterprise très complexes, Jenkins reste parfois plus souple. Pour la majorité des projets, GitHub Actions suffit.
Concepts clés en deux minutes
Au début, Workflow, Job, Step et Runner peuvent sembler confus. Voici une explication directe :
Workflow : un fichier YAML qui décrit tout un flux d’automatisation. Par exemple « à chaque push sur main, lancer les tests ». Il vit dans .github/workflows/.
Job : un ensemble d’étapes dans le workflow. Plusieurs jobs peuvent tourner en parallèle ou avec des dépendances. Par exemple un job « test », puis un job « deploy ».
Step : une action concrète dans un job, exécutée dans l’ordre. Ça peut être une commande (npm test) ou une Action réutilisable (actions/checkout@v4).
Runner : la machine virtuelle qui exécute le job. GitHub propose ubuntu-latest (Linux), windows-latest (Windows) et macos-latest (macOS). Vous pouvez aussi utiliser vos propres serveurs ; dans la plupart des cas, les runners officiels suffisent.
Image simple : le Workflow est le scénario, le Job une scène, le Step un geste dans la scène, le Runner l’acteur.
Votre premier workflow CI
Ne compliquez pas : faites tourner quelque chose. À la racine du projet, créez .github/workflows/ci.yml et collez-y ce code :
name: CI Pipeline # nom affiché dans l'onglet Actions
on:
push:
branches: [main] # déclenché au push sur main
pull_request:
branches: [main] # déclenché pour les PR vers main
permissions:
contents: read # moindre privilège : lecture seule
jobs:
build:
runs-on: ubuntu-latest # environnement Ubuntu récent
timeout-minutes: 15 # timeout anti-blocage
steps:
- name: Checkout code
uses: actions/checkout@v4 # récupère le code
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20 # Node.js 20
cache: 'npm' # cache npm activé
- name: Install dependencies
run: npm ci # install fiable via lockfile
- name: Run tests
run: npm test # exécute les tests
- name: Build
run: npm run build # build
Que fait ce fichier ?
La section on définit les déclencheurs : push sur main ou PR vers main. permissions déclare les droits selon le principe du moindre privilège — ici contents: read uniquement, pour éviter qu’un workflow modifie le dépôt par accident. Le cœur : un job build sur Ubuntu qui enchaîne checkout, installation de Node, dépendances, tests et build.
Commitez, poussez sur GitHub, ouvrez l’onglet Actions du dépôt. Un cercle vert tourne : le runner exécute votre workflow. Après quelques minutes, si tout est vert, votre premier pipeline CI est en service.
Croix rouge ? Ouvrez les logs : chaque étape est détaillée. Dans 90 % des cas, c’est l’installation des dépendances ou les tests eux-mêmes qui échouent, pas la config CI.
Chapitre 2 : Configuration cœur du pipeline CI
Le workflow du chapitre 1 tourne, mais il n’est pas encore « production-ready ». Ce chapitre couvre quatre piliers : déclencheurs, permissions, variables d’environnement et cache des dépendances. Bien réglés, le workflow est plus sûr et plus rapide.
Déclencheurs : quand exécuter
Les déclencheurs fixent le moment où le workflow démarre. Les plus courants : push et pull_request.
on:
push:
branches: [main, dev] # push sur main ou dev
paths:
- 'src/**' # uniquement si src/ change
- 'package.json' # ou si les dépendances changent
pull_request:
branches: [main] # PR ciblant main
Le filtre paths est très utile. Si le projet a un dossier docs/, modifier la doc ne devrait pas lancer le CI. Avec paths, seuls les changements de code déclenchent le build — moins de ressources, moins d’attente.
Autres déclencheurs possibles :
schedule : tâche planifiée en cron. Par exemple un build chaque nuit :
on:
schedule:
- cron: '0 0 * * *' # chaque jour à minuit UTC
Sur un projet, je l’utilise pour vérifier les dépendances obsolètes chaque jour avec npm outdated et recevoir un rappel par e-mail.
workflow_dispatch : déclenchement manuel. Utile pour tester une config sans push. L’onglet Actions affiche un bouton « Run workflow ».
on:
workflow_dispatch: # déclenchement manuel
Gestion des permissions : la sécurité d’abord
Par défaut, GitHub Actions fournit un GITHUB_TOKEN capable de lire/écrire le dépôt, créer des PR, voire pousser du code. Pratique, mais risqué : un workflow compromis peut donner des droits d’écriture sur le dépôt.
En 2021, un incident de sécurité a montré qu’un workflow CI pouvait être détourné via une PR forgée. Depuis, GitHub recommande : déclarer explicitement le minimum de permissions.
permissions:
contents: read # lecture du dépôt uniquement
pull-requests: write # écriture PR si nécessaire
Pour un CI pur (tests + build), contents: read suffit. Release, commentaires sur PR, etc. : ajoutez les permissions au cas par cas.
Astuce : dans les paramètres du dépôt, passez la permission par défaut en « Read repository contents ». Tous les workflows n’ont alors que la lecture ; l’écriture se déclare explicitement. Une barrière de plus.
Variables d’environnement : gestion par niveaux
Trois niveaux : workflow, job, step. Plus le niveau est bas, plus la portée est étroite, avec possibilité d’écraser la valeur du niveau supérieur.
env:
NODE_ENV: production # niveau workflow, tous les jobs
CI: true # outils CI détectent souvent cette variable
jobs:
build:
env:
BUILD_TARGET: web # niveau job, job build uniquement
steps:
- name: Run custom script
env:
MY_VAR: hello # niveau step, cette étape seulement
run: echo $MY_VAR
Pourquoi plusieurs niveaux ? Exemple : jobs build et deploy. NODE_ENV sert aux deux → niveau workflow. BUILD_TARGET ne concerne que build → niveau job. Un paramètre ponctuel pour un script → niveau step.
Données sensibles : ne les mettez jamais en clair dans le YAML. Utilisez Secrets : ajoutez la clé dans les paramètres du dépôt (ex. API_KEY), référencez-la avec ${{ secrets.API_KEY }}. Les Secrets sont masqués dans les logs.
steps:
- name: Deploy to server
env:
SSH_KEY: ${{ secrets.SSH_KEY }} # depuis Secrets
run: |
echo "$SSH_KEY" > private.key
ssh -i private.key user@server 'deploy.sh'
Cache des dépendances : accélérer le build
Avec des centaines de paquets npm, réinstaller à chaque run CI coûte cher. Sur un projet, l’installation prenait 3 minutes pour 1 minute de tests — 75 % du temps perdu à l’install.
GitHub Actions peut stocker les dépendances déjà installées. Le plus simple : le cache intégré de setup-node.
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm' # cache npm automatique
Une ligne cache: 'npm' : au premier run, installation normale + mise en cache de node_modules. Aux runs suivants, si package-lock.json est inchangé, restauration depuis le cache — de 3 minutes à environ 10 secondes.
Avec pnpm ou yarn : cache: 'pnpm' ou cache: 'yarn'.
Pour un contrôle fin, actions/cache :
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm # cache global npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
key identifie le cache de façon unique — ici le hash de package-lock.json : si le lock change, le cache est invalidé. restore-keys sert de repli pour retrouver un cache proche.
Avec un bon taux de hit, le gain est net. Mesure sur un projet : 4 minutes sans cache, 1,5 minute avec cache. À 20 builds par jour, le temps économisé vaut bien un article.
Chapitre 3 : Stratégie Matrix — tests en parallèle
C’est la fonctionnalité GitHub Actions que je préfère, et le cœur de cet article. Matrix transforme un job en plusieurs jobs parallèles pour tester versions, OS, etc. Un push peut lancer une dizaine de builds en quelques secondes ; le temps total reste proche du job le plus lent, pas de la somme — souvent plus de 60 % de gain par rapport au séquentiel.
Qu’est-ce que Matrix
Vous devez vérifier le projet sur Node 16, 18 et 20. L’approche classique : trois jobs dupliqués, ou un seul job qui change de version l’une après l’autre — config lourde ou temps long.
Matrix, c’est un tableau : en colonne les versions Node, en ligne les OS ; chaque case est un job de test indépendant. GitHub Actions génère toutes les combinaisons et les exécute en parallèle.
strategy:
matrix:
node: [16, 18, 20]
os: [ubuntu-latest, windows-latest]
Cette config produit 6 jobs : Node 16 sur Ubuntu, Node 16 sur Windows, Node 18 sur Ubuntu, etc. La durée totale dépend du job le plus lent, pas de la somme.
Matrice de versions : tester plusieurs Node
J’ai déjà vu ce cas : développement en Node 20, un utilisateur signale un échec en Node 18 — une API se comporte différemment. Des tests multi-versions en amont auraient évité la mise en prod du bug.
Avec Matrix, c’est simple :
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false # un échec n'arrête pas les autres versions
matrix:
node-version: [16, 18, 20, 22] # quatre versions à tester
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }} # version depuis la matrix
cache: 'npm'
- run: npm ci
- run: npm test
Points clés :
matrix.node-versionliste les versions à tester${{ matrix.node-version }}dans les steps : chaque job reçoit sa valeurfail-fast: false: un échec n’arrête pas les autres versions (défauttrue). Pour la compatibilité, gardezfalsepour voir tous les résultats.
include et exclude : exclure des combinaisons inutiles ou en ajouter.
strategy:
matrix:
node-version: [16, 18, 20]
os: [ubuntu-latest, windows-latest]
exclude:
- node-version: 16 # exclut Node 16 + Windows
os: windows-latest
include:
- node-version: 20 # Node 20 aussi sur macOS
os: macos-latest
exclude retire des combinaisons ; include en ajoute. Contrôle fin de la couverture.
Matrice OS : tests multi-plateformes
Pour un outil CLI ou tout code qui tourne sur plusieurs OS, la matrice OS est pertinente.
jobs:
test:
runs-on: ${{ matrix.os }} # OS depuis la matrix
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
À garder en tête :
Différences de plateforme : chemins \ vs / sous Windows, comportements d’outils CLI différents. Les tests cross-OS détectent ces problèmes tôt.
Coût : la facturation varie selon l’OS. Linux : quota gratuit de base ; Windows ×2 ; macOS ×10. Des runs macOS épuisent vite le quota mensuel.
Stratégies d’économie :
- macOS seulement si le produit tourne vraiment sur Mac
- workflow séparé avec
workflow_dispatchpour les tests macOS - dépôt public si possible : minutes illimitées
Astuces de performance
Matrix parallélise, mais pas sans limite. GitHub plafonne le parallélisme par défaut. Vous pouvez le régler :
strategy:
max-parallel: 4 # au plus 4 jobs en parallèle
matrix:
node-version: [16, 18, 20, 22]
Avec beaucoup de combinaisons (10+ jobs), max-parallel évite de tout lancer d’un coup et de grignoter le quota gratuit.
Cache par job Matrix : chaque job a son cache ; setup-node avec cache le gère. Avec package-lock.json et node-version stables, le taux de hit reste élevé.
Éviter les étapes redondantes : le lint n’a pas besoin de tourner sur chaque version :
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint # lint une seule fois sur Node 20
test:
needs: lint # tests après lint OK
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
Le lint une fois sur Node 20, les tests sur trois versions — plus efficace.
Mesure : sans Matrix, 3 versions en série ≈ 12 minutes ; avec Matrix parallèle ≈ 4 minutes (version la plus lente). 8 minutes gagnées ; à 10 builds par jour, ça fait une différence visible.
Chapitre 4 : Retours d’expérience et dépannage
Les trois chapitres précédents couvrent la configuration. Celui-ci regroupe une checklist sécurité, performance et dépannage — à garder sous la main quand quelque chose bloque.
Checklist sécurité
| Pratique | Description | Exemple |
|---|---|---|
| Déclarer explicitement permissions | Ne pas compter sur les droits par défaut | permissions: { contents: read } |
| Secrets pour les données sensibles | Pas de clés API ou SSH en dur | ${{ secrets.API_KEY }} |
| Limiter les branches déclenchées | CI seulement où c’est nécessaire | branches: [main] |
| Référencer les Actions par SHA | Commit précis plutôt qu’une étiquette modifiable | actions/checkout@b4ffde65f46336ab88eb53be808477a39b6bc2b1 |
| Définir un timeout | Éviter les runs bloqués qui consomment le quota | timeout-minutes: 15 |
Souvent oublié : la version des Actions. @v4 est pratique pour les mises à jour, mais une étiquette peut être déplacée — en théorie vers du code malveillant. Le SHA (@b4ffde65f...) est plus sûr pour la prod, même si les upgrades demandent plus de travail.
Checklist performance
| Astuce | Effet | Configuration |
|---|---|---|
| Cache des dépendances | −50 % ou plus sur l’install | cache: 'npm' |
| npm ci plutôt que install | Plus rapide et déterministe | run: npm ci |
| timeout-minutes | Limite les runs bloqués | timeout-minutes: 15 |
| Matrix en parallèle | −60 %+ sur le temps total | strategy.matrix |
| concurrency pour annuler les doublons | Une seule build active par branche | concurrency.group: ${{ github.ref }} |
concurrency est pratique : cinq push d’affilée sur la même branche lancent cinq builds par défaut. Avec concurrency, les quatre premières sont annulées ; seule la dernière tourne.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # annule les builds en cours obsolètes
Table de dépannage rapide
| Message d’erreur | Cause | Solution |
|---|---|---|
Permission denied | Droits insuffisants | Vérifier permissions, ajouter ce qui manque |
Cache not found | Clé de cache non trouvée | Vérifier la key, package-lock.json inchangé |
npm ERR! network | Timeout réseau | Augmenter le timeout ou miroir registry |
Out of memory | Mémoire Node insuffisante | NODE_OPTIONS=--max_old_space_size=4096 |
EACCES permission denied | Droits fichier | chmod +x script.sh en tête de script |
Error: Cannot find module | Dépendances incomplètes | Vérifier que npm ci a réussi dans les logs |
Scénarios fréquents :
Timeout réseau : parfois le runner accède lentement au registry npm. Miroir dans .npmrc :
- name: Configure npm registry
run: echo "registry=https://registry.npmmirror.com" > .npmrc
Mémoire insuffisante : gros build Node → OOM. Variable d’environnement :
env:
NODE_OPTIONS: --max_old_space_size=4096 # alloue 4 Go de mémoire à Node
Cache absent : normal au premier run. Vérifiez que package-lock.json existe (npm ci en a besoin) et que cache sur setup-node correspond au gestionnaire (npm/pnpm/yarn).
Conclusion
En résumé : un YAML suffit pour un pipeline CI ; permissions au minimum ; variables d’environnement par niveaux ; le cache peut diviser par deux le temps d’install ; Matrix simplifie les tests multi-versions en parallèle.
Copiez le modèle du chapitre 1, adaptez la version Node et vos commandes, et votre projet a un CI. Lancez d’abord, affinez ensuite. Essayez Matrix même avec deux versions Node — voir plusieurs coches vertes apparaître en parallèle, c’est satisfaisant.
Si vous bloquez sur GitHub Actions, laissez un commentaire. J’ajouterai les cas récurrents au tableau du chapitre 4 pour que d’autres évitent les mêmes pièges.
Mettre en place un pipeline CI GitHub Actions
Construire de zéro un pipeline CI complet pour automatiser build et tests
⏱️ Estimated time: 30 min
- 1
Step 1: Créer le répertoire des workflows
À la racine du projet, créez le répertoire `.github/workflows/` pour y placer tous les fichiers de workflow. - 2
Step 2: Rédiger la configuration CI de base
Créez le fichier `ci.yml` avec les déclencheurs (push/PR), les permissions (principe du moindre privilège) et les étapes du job (checkout, setup-node, install, test, build). - 3
Step 3: Activer le cache des dépendances
Ajoutez le paramètre `cache: 'npm'` à l'étape `setup-node` pour mettre en cache automatiquement les dépendances npm et accélérer les builds suivants. - 4
Step 4: Configurer les tests Matrix multi-versions
Ajoutez `strategy.matrix` avec la liste des versions Node à tester (par ex. [16, 18, 20]) pour exécuter les tests en parallèle. - 5
Step 5: Commit et vérification des résultats
Commitez la configuration, poussez sur GitHub, puis ouvrez l'onglet Actions pour suivre l'état du build et les logs.
FAQ
Quel est le quota gratuit mensuel de GitHub Actions ?
Sur quelles branches le workflow CI doit-il se déclencher ?
Pourquoi privilégier npm ci plutôt que npm install ?
Combien de temps la stratégie Matrix peut-elle faire gagner ?
Pourquoi le cache ne fonctionne-t-il parfois pas ?
Comment utiliser des informations sensibles (clé API, clé SSH) dans le CI ?
13 min de lecture · Publié le: 6 avr. 2026 · Mis à jour le: 30 juil. 2026
Guide complet GitHub Actions
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
GitHub Actions pour débutants : bases des workflows YAML et configuration des déclencheurs
Tutoriel d'introduction aux workflows YAML GitHub Actions : les quatre champs clés name, on, jobs et steps, 8 méthodes de configuration des déclencheurs, avec modèles YAML prêts à copier et checklist de dépannage.
Partie 1 sur 10
Suivant
Stratégie de cache GitHub Actions : accélérer le pipeline CI/CD par 5
Guide pratique de la stratégie de cache GitHub Actions : exemples complets de npm à Docker, bonnes pratiques de conception des clés de cache, comparaison des gains de performance. Maîtrisez le mécanisme de cache pour accélérer votre pipeline CI/CD par 5 et réduire les coûts de build.
Partie 3 sur 10



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire