L’intégration continue (CI) consiste à vérifier automatiquement chaque modification poussée sur le dépôt : installation, analyse statique, tests. Le déploiement continu (CD) prolonge la chaîne : une modification validée est livrée automatiquement, en préproduction puis en production. L’ensemble forme un pipeline. L’objectif n’est pas la vitesse pour elle-même, mais la confiance : un problème est détecté quelques minutes après son introduction, par une machine qui ne se lasse jamais de relancer les tests.
Dans ce cours, nous utilisons GitHub Actions, intégré à GitHub. Les notions (déclencheur, job, étape, artefact, environnement, secret) se retrouvent presque à l’identique dans GitLab CI, Azure Pipelines ou Jenkins.
Un premier workflow
Un workflow est un fichier YAML placé dans le dossier .github/workflows/ du dépôt. Le nom du fichier est libre (ci.yml, deploy.yml).
# .github/workflows/ci.yml
name: CI # nom affiché dans l'onglet Actions
on: # quand le workflow se déclenche
push:
branches: [main]
pull_request:
jobs:
test: # identifiant du job
runs-on: ubuntu-latest # machine virtuelle fournie par GitHub
steps:
- uses: actions/checkout@v4 # récupère le code du dépôt
- uses: actions/setup-node@v4 # installe Node.js
with:
node-version: 22
- run: npm ci # commande shell
- run: npm test
Lisons-le de haut en bas :
onliste les déclencheurs : ici, chaque push surmainet chaque pull request.jobscontient un ou plusieurs jobs. Chaque job démarre sur un runner neuf, une machine vierge : rien n’est conservé d’un job à l’autre, sauf ce que vous transmettez explicitement (artefacts, sorties).stepsest la liste ordonnée des étapes. Une étape fait soituses:(une action réutilisable, publiée dans un dépôt, avec sa version après@), soitrun:(une commande shell, exécutée par bash sur un runner Linux).with:passe des paramètres à une action.
Si une étape échoue (code de sortie différent de 0), les étapes suivantes sont sautées et le job est marqué en échec. C’est exactement ce que l’on veut : npm test qui échoue rend le pipeline rouge.
Les déclencheurs
on:
push:
branches: [main]
paths-ignore: ["docs/**", "**.md"] # ne pas relancer pour la doc
pull_request:
branches: [main] # PR qui visent main
workflow_dispatch: # bouton « Run workflow »
inputs:
environnement:
type: choice
options: [staging, production]
schedule:
- cron: "0 3 * * 1" # chaque lundi à 3 h UTC
push: à chaque push, filtrable parbranches,tagsetpaths.pull_request: à l’ouverture et à chaque nouveau commit d’une pull request. Le code testé est celui de la PR fusionné avec la branche cible.workflow_dispatch: lancement manuel depuis l’onglet Actions, avec des paramètres (inputs) lus via${{ inputs.environnement }}.schedule: exécution planifiée, au format cron, en UTC.
Enchaîner des jobs avec needs
Par défaut, les jobs d’un workflow tournent en parallèle. Le mot-clé needs crée une dépendance :
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
build:
needs: [lint, test] # attend que lint ET test réussissent
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
lint et test démarrent ensemble ; build ne démarre que si les deux sont verts. Si l’un échoue, build est marqué « skipped ». L’onglet Actions du dépôt affiche ce graphe, le statut de chaque job et le journal de chaque étape, que l’on déplie pour lire l’erreur.
Rendre la CI obligatoire
Un pipeline rouge n’empêche rien tant qu’on peut fusionner malgré lui. Dans Settings > Branches (règle de protection) ou Settings > Rules > Rulesets, on protège main :
- exiger une pull request avant de fusionner (plus de push direct) ;
- exiger que les status checks sélectionnés soient verts, par exemple les jobs
lintettest; - éventuellement exiger que la branche soit à jour avec
main.
Les noms proposés pour les checks sont ceux des jobs : choisissez des noms stables, car renommer un job requis bloque les pull requests jusqu’à la mise à jour de la règle.
Bonnes habitudes dès le départ
- Gardez le pipeline rapide (quelques minutes) : sinon on cesse d’attendre son verdict.
- Utilisez
npm ci(oupip install -r requirements.txt,composer install) : installation reproductible depuis le fichier de verrouillage. - Ajoutez
timeout-minutesà un job susceptible de rester bloqué. - Vérifiez la syntaxe localement avec un linter de workflows comme
actionlintavant de pousser.
Exercices
Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.
Premier workflow vert
Dans un dépôt GitHub contenant un projet Node.js avec un script
testdanspackage.json, créez le fichier.github/workflows/ci.ymlavecname: CI, les déclencheurspushsurmainetpull_request, et un job nommétestsurubuntu-latestqui exécuteactions/checkout@v4,actions/setup-node@v4(Node 22),npm cipuisnpm test. Poussez surmain.- Le fichier se trouve exactement à `.github/workflows/ci.yml`
- L'onglet Actions affiche une exécution du workflow « CI » déclenchée par le push
- Le job `test` contient les étapes checkout, setup-node, `npm ci` et `npm test`
- L'exécution se termine avec le statut vert (Success)
Chaîner lint, test et build
Modifiez
ci.ymlpour obtenir trois jobs :lint(npm run lint),test(npm test) etbuild(npm run build) avecneeds: [lint, test]. Introduisez ensuite volontairement une erreur de lint dans une brancheessai-lint, ouvrez une pull request versmain, observez, puis corrigez.- Sur main, le graphe de l'exécution montre `lint` et `test` en parallèle puis `build`
- Sur la pull request avec l'erreur, `lint` est rouge et `build` est marqué « skipped »
- Après correction et nouveau push sur la branche, les trois jobs sont verts
- Aucune étape n'est dupliquée inutilement entre les jobs hormis checkout, setup-node et `npm ci`
Rendre la CI obligatoire sur main
Dans les paramètres du dépôt, créez une règle de protection (ou un ruleset) pour
mainqui exige une pull request et les status checkslintettest. Vérifiez qu’une pull request donttestéchoue ne peut pas être fusionnée.- La règle cible la branche `main`
- Les checks requis sont exactement `lint` et `test`
- Sur une pull request avec un test cassé, le bouton de fusion est désactivé avec la mention que des checks requis ont échoué
- Un push direct sur main est refusé (ou soumis à la pull request)
Ordre d'exécution des jobs
Un workflow définit trois jobs
a,betc, sans aucunneeds. Comment s’exécutent-ils ?- Dans l'ordre a, b, c
- En parallèle, chacun sur son propre runner
- Sur le même runner, en partageant les fichiers
Quiz de fin de leçon
Où doit se trouver un fichier de workflow GitHub Actions ?
- À la racine du dépôt
- Dans .github/workflows/
- Dans .actions/
Quelle est la différence entre
usesetrundans une étape ?- Aucune
- uses appelle une action réutilisable, run exécute une commande shell
- run appelle une action, uses une commande
Quel déclencheur ajoute un bouton de lancement manuel ?
- push
- workflow_dispatch
- schedule
Si le job
testéchoue, que devient un jobbuildqui aneeds: test?- Il s'exécute quand même
- Il est sauté (skipped)
- Il est relancé automatiquement
La suite du cours
- Tests et qualité dans la CI20 min
- Artefacts, sorties de jobs et releases15 min
- Déploiement automatique et environnements20 min
- Secrets et sécurité du pipeline20 min