Introduction
Références
Définition
Le terme DevOps est un mot-valise anglais formé à partir de
development
(développement) et operations
(exploitation).
Il désigne un ensemble de pratiques visant à automatiser et à
industrialiser les processus de production des applications logicielles,
depuis le développement jusqu’à la mise en production.
Historique
Contexte et défis initiaux
Au début des années 2000, l’industrie du logiciel connaissait une révolution rapide avec l’essor d’Internet. Malgré ces avancées, les entreprises se heurtaient à des obstacles structurels majeurs dans la livraison de logiciels :
- Silotage des équipes : Les équipes de développement (Dev) et des opérations (Ops) travaillaient en silos séparés, avec des objectifs opposés — les développeurs cherchaient à livrer de nouvelles fonctionnalités rapidement, tandis que les opérations privilégiaient la stabilité des systèmes.
- Longs cycles de développement : Les méthodologies en cascade (waterfall) impliquaient des cycles longs, des déploiements rares et risqués.
- Problèmes de communication : Le manque de collaboration entre équipes engendrait des erreurs de configuration et des délais dans la résolution des incidents.
- Environnements incohérents : Les environnements de développement, de test et de production différaient souvent, causant des problèmes de compatibilité lors des déploiements.

Émergence de nouvelles pratiques
Au milieu des années 2000, des réponses concrètes à ces défis ont commencé à émerger :
- Agilité et Lean : Les méthodologies agiles ont favorisé des cycles courts et des livraisons itératives. Les principes Lean ont introduit la réduction des gaspillages et l’optimisation des processus.
- Culture de collaboration : Les entreprises ont pris conscience de la nécessité de briser les silos et de faire travailler Dev et Ops ensemble tout au long du cycle de vie du logiciel.
- Automatisation et outillage : Des outils comme Puppet, Chef, Ansible, puis Docker et Kubernetes ont permis d’automatiser les tâches répétitives et d’homogénéiser les environnements.
- Livraison continue (CD) : Les déploiements sont devenus plus fréquents et fiables grâce à l’intégration de tests automatisés et à la mise en production facilitée.
Formalisation du terme
DevOps
Le terme DevOps
a été popularisé en 2009 lors de la conférence
Velocity, où John Allspaw et Paul Hammond de Flickr ont
présenté 10+
Deploys per Day: Dev and Ops Cooperation at Flickr. Leur retour
d’expérience a démontré concrètement comment la collaboration entre Dev
et Ops permet d’améliorer la fréquence et la fiabilité des
déploiements.
Depuis, DevOps est devenu un mouvement mondial, intégrant progressivement de nouvelles pratiques comme l’infrastructure en tant que code (IaC), le monitoring continu, et la sécurité intégrée dès le début du cycle de développement (DevSecOps).


CI/CD
La CI et la CD sont deux pratiques fondamentales du mouvement DevOps.
CI — Intégration Continue (Continuous Integration)
La CI consiste à intégrer fréquemment les modifications de code dans un dépôt partagé. Chaque modification est automatiquement testée et validée, ce qui permet de détecter et corriger les erreurs au plus tôt.
CD — Livraison Continue (Continuous Delivery)
La CD automatise le processus de déploiement des applications. Les modifications de code sont construites, testées et déployées en production de manière automatique, réduisant les délais de mise en production tout en améliorant la qualité du logiciel.
QCM — Introduction à DevOps et CI/CD
1. Que signifie le terme DevOps
?
- Development + Options
- B) Development + Operations
- C) Deployment + Optimization
- D) Design + Operations
2. Quelle méthodologie traditionnelle de développement impliquait de longs cycles et des déploiements rares ?
- Agile
- B) Scrum
- C) Waterfall (en cascade)
- D) Kanban
3. Lors de la conférence Velocity en 2009, qui a présenté le discours fondateur du mouvement DevOps ?
- Linus Torvalds et Ken Thompson
- B) John Allspaw et Paul Hammond
- C) Jeff Sutherland et Ken Schwaber
- D) Patrick Debois et Gene Kim
4. Dans quelle entreprise travaillaient les présentateurs de la conférence Velocity en 2009 ?
- B) Amazon
- C) Flickr
- D) Netflix
5. Quel était le titre du discours présenté à la conférence Velocity en 2009 ?
- Continuous Deployment at Scale
- B) 10+ Deploys per Day: Dev and Ops Cooperation at Flickr
- C) Breaking the Silos: A DevOps Story
- D) Agile meets Operations
6. Lequel de ces outils N’est PAS mentionné comme outil d’automatisation dans le texte ?
- Puppet
- B) Ansible
- C) Jenkins
- D) Kubernetes
7. Qu’est-ce que la CI (Continuous Integration) ?
- Automatiser le déploiement des applications en production
- B) Intégrer fréquemment les modifications de code dans un dépôt partagé avec tests automatiques
- C) Surveiller en continu les performances des applications
- D) Gérer l’infrastructure sous forme de code
8. Quel est le principal bénéfice de la CD (Continuous Delivery) ?
- Réduire le nombre de développeurs nécessaires
- B) Supprimer les tests manuels
- C) Réduire les délais de mise en production et améliorer la qualité du logiciel
- D) Remplacer les équipes des opérations
9. Qu’est-ce que le DevSecOps ?
- Une version de DevOps réservée aux start-ups
- B) L’intégration de la sécurité dès le début du cycle de développement
- C) Un outil de monitoring continu
- D) Un framework de gestion de projet agile
10. Quel problème causaient les environnements incohérents entre développement, test et production ?
- Des coûts de licence plus élevés
- B) Un manque de développeurs qualifiés
- C) Des problèmes de compatibilité et de performance lors des déploiements
- D) Une augmentation du nombre de fonctionnalités livrées
Outils
Il existe de nombreux outils qui peuvent être utilisés pour mettre en œuvre les pratiques DevOps. Voici quelques-uns des outils les plus populaires :
| Termes | Outils |
|---|---|
![]() |
![]() |
Vous ne devrez pas tous les connaître et je ne pense pas qu’il existe une personne qui les maîtrise tous. Nous pratiquerons quelqu’uns de ces outils et vous vous adapterez à ceux de votre futur entreprise.

Automatisation
Connaître des possibilités d’utilisation des outils d’automatisation dans l’environnement de développement (p. ex. linting, build, exécuter, tester, versionner, dépendances/paquets).
Vue d’ensemble
L’automatisation dans un environnement de développement couvre quatre grandes étapes, dans un ordre logique :
- Linting — analyser et garantir la qualité du code avant toute exécution
- Tests unitaires — valider le comportement des composants de manière isolée
- Documentation — générer la documentation à partir du code source
- Build — compiler et packager l’application pour la production
Linting
Le linting est une pratique de développement logiciel qui consiste à analyser le code source pour détecter les erreurs de syntaxe, les problèmes de style et les mauvaises pratiques de programmation. Les outils de linting permettent de garantir la cohérence du code, d’améliorer sa lisibilité et de réduire les erreurs.
ESLint
ESLint est un outil de linting pour JavaScript qui permet de détecter et de corriger les erreurs de syntaxe, les problèmes de style et les mauvaises pratiques de programmation. Il est largement utilisé dans l’industrie du logiciel pour améliorer la qualité du code JavaScript.
Un fichier de configuration standard de linting ressemble à ceci :
{
"rules": {
"no-unused-vars": "error",
"no-undef": "error"
}
}Dans cet exemple, deux règles de linting sont définies :
no-unused-vars et no-undef. La règle
no-unused-vars signale une erreur si une variable est
déclarée mais jamais utilisée, tandis que la règle no-undef
signale une erreur si une variable est utilisée sans être déclarée.
Les niveaux de sévérité peuvent également être exprimés sous forme numérique :
{
"rules": {
"quotes": [2, "double"],
"no-unused-vars": 1,
"no-undef": 0
}
}Les valeurs 0, 1, 2 correspondent respectivement à off,
warn et error :
offor 0 - turn the rule off
warnor 1 - turn the rule on as a warning (doesn’t affect exit code)
erroror 2 - turn the rule on as an error (exit code is 1 when triggered)
Il existe de nombreuses autres règles de linting que vous pouvez configurer en fonction de vos besoins. Vous trouverez des exemples de règles de linting de différentes entreprises sur github.
Exercice ESLint
Pré-requis : Node.js doit être installé sur votre machine.

Pour cet exercice, vous allez installer ESLint et créer un fichier de configuration de linting pour un projet JavaScript. Le travail sera réalisé dans Visual Studio Code.
- Créez un nouveau projet JavaScript dans Visual Studio Code. Placez
ce projet dans un dossier nommé
jseslint. - Créez un fichier
index.jsdans le dossier du projet et ajoutez-y le code suivant :
console.log("Demo ESLint")- Installez l’extension ESLint dans Visual Studio Code en recherchant
ESLint
dans la barre de recherche des extensions. - Ouvrez le terminal dans Visual Studio Code et installez ESLint en exécutant les commandes suivantes :
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (jseslint)
version: (1.0.0)
description: ESLint projet for learning
entry point: (index.js)
test command:
git repository:
keywords:
author: Pierre Ferrari
license: (ISC)
type: (commonjs) module
About to write to /your/path/jseslint/package.json:
{
"name": "jseslint",
"version": "1.0.0",
"description": "ESLint projet for learning",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Pierre Ferrari",
"license": "ISC",
"type": "module"
}
Is this OK? (yes) yes
$ npx eslint --init
Need to install the following packages:
eslint@10.8.1
Ok to proceed? (y)
You can also run this command directly using 'npm init @eslint/config@latest'.
Need to install the following packages:
@eslint/create-config@2.0.0
Ok to proceed? (y)
> jseslint@1.0.0 npx
> create-config
@eslint/create-config: v2.0.0
✔ What do you want to lint? · javascript
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · none
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · node
ℹ The config that you've selected requires the following dependencies:
eslint, @eslint/js, globals
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
☕️Installing...
added 71 packages, and audited 72 packages in 1s
18 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
✔ Successfully created /home/pepito/Téléchargements/jseslint/eslint.config.js file.
$ tree -L 1
.
├── eslint.config.mjs
├── index.js
├── node_modules
├── package.json
└── package-lock.json
2 directories, 4 filesDéclarez une variable non utilisée dans le fichier
index.js et observez comment ESLint signale une erreur.
Vous pouvez voir que la variable est soulignée en rouge et si vous
placez votre curseur dessus, ESLint affiche un message d’erreur.
'i' is assigned a value but never used. eslint (no-unused-vars)On peut également voir les erreurs dans la console de Visual Studio Code :
$ npx eslint inDex.js
/your/path/jseslint/inDex.js
1:5 error 'i' is assigned a value but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)Dans le fichier de configuration package.json, ajoutez
une commande pour lancer ESLint ainsi qu’une commande pour
démarrer l’exécution du script inDex.js :
{
"name": "jseslint",
"version": "1.0.0",
"description": "ESLint projet for learning",
"main": "inDex.js",
"scripts": {
"start": "node inDex.js",
"lint": "eslint \"**/*.js\" --ignore-pattern node_modules/"
},
"author": "Pierre Ferrari",
"license": "ISC",
"devDependencies": {...}
}Pour ajouter les rules, ça se passe dans le fichier de
configuration d’eslint eslint.config.mjs :
eslint.config.mjs
...
export default defineConfig([
{
...
languageOptions: {
globals: globals.browser
},
rules: {
"no-unused-vars": "error",
"no-undef": "error"
}
},
...
]Et inDex.js sans changer quoi que ce
soit dans un premier temps :
var i = 0
var y
let arr = [
[1, 2],
2,
[3, 4],
4,
[5, 6],
7,
[8, 9],
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
]
console.log("Demo ESLint")
for (y = 0; y < 10; y++) {
console.log(arr[y])
}
if (i == 10) {
console.log('i is 10')
} else {
console.log('i is not 10')
}
const myVariable = 12
myVariable = 13REMARQUE : Le fichier se nomme bien
inDex.js et pas index.js.
Ensuite, démarrez le script avec la commande
npm run start 2>/dev/null et lancez ESLint avec la
commande npm run lint.
Vous pouvez constater que le script fonctionne très bien mais qu’il ne respecte pas les règles de linting.
Exercice 1
Uniquement à l’aide de la documentation officielle, ajoutez les règles suivantes :
- Forcer l’utilisation des guillemets à la place des apostrophes
- Interdire les déclarations de variables ou de fonction dans le scope global
- Interdire la redéfinition de variables constantes
- Interdire l’utilisation du mot clé
var - Forcer l’utilisation des variables constantes si elles ne sont jamais redéfinies
- Forcer l’utilisation d’espaces dans les tableaux
const arr = [ 'foo', 'bar' ] - Interdire les espaces s’il y a des tableaux dans des tableaux
let arr = [[1, 2], [3, 4]]- Résumé :
let arr = [[ 1 ], [ 2 ]]OKlet arr = [ [ 1 ], [ 2 ] ]KOlet tab = [ 1, 2, 3 ]OKlet tab = [1, 2, 3]KO
- Résumé :
- Forcer l’utilisation des comparaisons triples
===,!== - Interdire le
;en fin de ligne - Forcer l’indentation à 2 caractères espace
TIPS : array-bracket-spacing, semi, no-undef, no-unused-vars, no-const-assign, no-var, no-implicit-globals, eqeqeq, indent, prefer-const
Exercice 2
Uniquement à l’aide de la documentation officielle, trouvez et ajoutez les règles de linting permettant de détecter les erreurs suivantes :
- Le code source ne doit pas dépasser une longueur de 80 caractères par ligne
- Les blocs de code doivent être indentés avec une tabulation
- Les noms des variables respectent la notation
snake_case - Les noms des fichiers doivent être en minuscule
(
snake_case) - Les noms des dossiers doivent être en minuscule
(
snake_case) - Les blocs if/else doivent respecter la convention The one true brace style :
if (condition) {
// code
} else {
// code
}Si vous reprenez le code d’exemple fourni plus haut sans faire de modification, vous devriez obtenir les erreurs suivantes :
$ npm run lint
> jseslint@1.0.0 lint
> eslint "**/*.js" --ignore-pattern node_modules/
/your/path/jseslint/inDex.js
1:1 error Filename 'inDex.js' does not match snake_case
1:1 error Unexpected var, use let or const instead
1:10 error Extra semicolon
2:1 error This line has a length of 97. Maximum allowed is 80
2:5 error 'arr' is never reassigned. Use 'const' instead
2:31 error A space is required before ']'
2:35 error A space is required after '['
2:47 error A space is required after '['
2:52 error A space is required before ']'
2:97 error A space is required before ']'
3:13 error Strings must use doublequote
5:5 error 'y' is not defined
5:12 error 'y' is not defined
5:20 error 'y' is not defined
6:1 error Expected indentation of 0 spaces but found 2
6:3 error Opening curly brace does not appear on the same line as controlling statement
7:19 error 'y' is not defined
7:22 error Extra semicolon
10:7 error Expected '===' and instead saw '=='
11:1 error Opening curly brace does not appear on the same line as controlling statement
12:15 error Strings must use doublequote
13:1 error Closing curly brace does not appear on the same line as the subsequent block
15:1 error Opening curly brace does not appear on the same line as controlling statement
16:15 error Strings must use doublequote
19:7 error Identifier 'myVariable' does not match the pattern '^[a-z_]+$'
20:1 error 'myVariable' is constant
20:1 error 'myVariable' is assigned a value but never used
✖ 27 problems (27 errors, 0 warnings)
17 errors and 0 warnings potentially fixable with the `--fix` option.Une fois que vous obtenez toutes les erreurs et que votre fichier de configuration ESLint est correct, corrigez le code pour faire disparaître les messages d’eslint.
Tests unitaires
Les tests unitaires sont une pratique de développement logiciel qui consiste à tester les composants individuels d’une application de manière isolée. Ils permettent de vérifier le bon fonctionnement des fonctions, des classes et des modules, et de détecter les erreurs de manière précoce.
Cela suppose également que le code soit organisé de manière à ce que les composants soient facilement testables. C’est pourquoi il est important de suivre les principes de conception logicielle tels que le découplage, l’encapsulation et la modularité.
Chaque langage possède ses propres outils de test unitaire. Voici quelques-uns des outils les plus populaires :
Vitest

Vitest est un outil de test unitaire pour JavaScript. Il est pensé pour être compatible avec l’outil Vite. Il est compatible avec le framework de test Jest très largement utilisé dans l’industrie.
Vitest possède des atouts par rapport à Jest :
- Plus rapide
- Plus léger
- Compatible avec les standards modernes de JavaScript tels que
l’import dynamique de modules via
importetexport - Fonctionnement interactif continu
L’avantage de Vitest réside dans sa
console interactive. En effet, le développeur peut voir les résultats
des tests en temps réel dans la console de son navigateur. Cela permet
de détecter les erreurs plus rapidement et de faciliter le processus de
débogage. Ainsi, au moment d’envoyer du code à la partie
ops, il est possible de garantir que le code est
fonctionnel.
Exercice Vitest
Pré-requis : Node.js doit être installé sur votre machine.
Pour cet exercice, vous allez installer Vitest et configurer un fichier de test unitaire pour un projet JavaScript. Le travail sera réalisé dans Visual Studio Code.
L’ensemble des instructions pour réaliser cet exercice se trouve dans la vidéo DevTheory.
Jest et
Vitest et donc, il va faire beaucoup de modification en
cours de vidéo
Exercice Vitest en shell
Dans l’optique d’utiliser les tests unitaires dans un pipeline CI/CD, il est important de pouvoir lancer les tests en ligne de commande. On vous demande de réaliser toutes les étapes de mise en place d’un environnement de test permettant de tester un programme réalisé en Javascript.
Le programme sera basique. Il comportera un module mathématique qui contiendra trois fonctions :
- Une fonction
addqui prendra deux paramètres et qui retournera la somme de ces deux paramètres. - Une fonction
subqui prendra deux paramètres et qui retournera la différence de ces deux paramètres. - Une fonction
rotatequi prendra un tableau de nombres et qui retournera un tableau de nombres où le premier élément est devenu le dernier.
math.js
export function add(a, b) {
// Votre code ici
}
export function sub(a, b) {
// Votre code ici
}
export function rotate(arr, n) {
// Votre code ici
}Les tests unitaires seront réalisés avec Vitest.
math.test.js
import { add, sub, rotate } from './math.js'
test('[add] expect the result of 1 + 2 to be 3', () => {
expect(add(1, 2)).toBe(3)
})
// les autres tests
...Les tests seront les suivants :
- Test de la fonction
addavec les paramètres1et2. Le résultat attendu est3. - Test de la fonction
addavec les paramètres-1et-0. Le résultat attendu est-1. - Test de la fonction
addavec les paramètres-1.0et1.0. Le résultat attendu est0. - Test de la fonction
addavec les paramètres1et'a'. Le résultat attendu est une erreur. - Test de la fonction
addavec les paramètres'a'et[1]. Le résultat attendu est une erreur. - Plus généralement, test de la fonction
addavec des paramètres qui ne sont pas des nombres. Le résultat attendu est une erreur. - Tests de la fonction
subidentiques aux tests de la fonctionadd. - Test de la fonction
rotateavec le tableau[1, 2, 3, 4]. Le résultat attendu est[2, 3, 4, 1]. - Test de la fonction
rotateavec le tableau[a, 2, 3, 4]. Le résultat attendu est une erreur. - Test de la fonction
rotateavec le tableau[1, 2, 3, 4, 5]. Le résultat attendu est[2, 3, 4, 5, 1]. - Test de la fonction
rotateavec le tableau[1]. Le résultat attendu est[1]. - Test de la fonction
rotateavec le tableau[]. Le résultat attendu est[]. - Test de la fonction
rotateavec le tableau[[1], 2, 3, 4, 5, 6, 7, 8, 9, 10]. Le résultat attendu est une erreur.
Le résultat attendu est le suivant :
$ npm run vitest
> js-test@1.0.0 vitest
> vitest --globals
DEV v2.0.5 /your/path/js-test
✓ math.test.js (16)
✓ [add] expect the result of 1 + 2 to be 3
✓ [add] expect the result of -1 + -0 to be -1
✓ [add] expect the result of -1.0 + 1.0 to be 0
✓ [add] expect the result of 1 + 'a' to be an error
✓ [add] expect the result of 'a' + [1] to be an error
✓ [sub] expect the result of 1 - 2 to be -1
✓ [sub] expect the result of -1 - -0 to be -1
✓ [sub] expect the result of -1.0 - 1.0 to be -2
✓ [sub] expect the result of 1 + 'a' to be an error
✓ [sub] expect the result of v + [a] to be an error
✓ [rotate] expect the result of [1, 2, 3, 4] to be [2, 3, 4, 1]
✓ [rotate] expect the result of [a, 2, 3, 4] to be an error
✓ [rotate] expect the result of [1, 2, 3, 4, 5] to be [2, 3, 4, 5, 1]
✓ [rotate] expect the result of [1] to be [1]
✓ [rotate] expect the result of [] to be []
✓ [rotate] expect the result of [[1], 2, 3, 4, 5, 6, 7, 8, 9, 10] to be an error
Test Files 1 passed (1)
Tests 16 passed (16)
Start at 13:52:56
Duration 239ms (transform 22ms, setup 0ms, collect 17ms, tests 6ms, environment 0ms, prepare 67ms)Exercice Vitest — coverage et format de sortie
Vitest permet également d’obtenir une information importante lors des
tests unitaires : le code coverage, c’est-à-dire quel
pourcentage du code est couvert par les tests.
Les informations se trouvent ici.
L’objectif de cet exercice est d’obtenir une commande
npm run coverage qui affiche ceci :
$ npm run coverage
> js-test@1.0.0 coverage
> vitest run --coverage
RUN v2.1.9 /your/path/js-test
Coverage enabled with v8
✓ src/math.test.js (16)
✓ [add] expect the result of 1 + 2 to be 3
✓ [add] expect the result of -1 + -0 to be -1
✓ [add] expect the result of -1.0 + 1.0 to be 0
✓ [add] expect the result of 1 + 'a' to be an error
✓ [add] expect the result of 'a' + [1] to be an error
✓ [sub] expect the result of 1 - 2 to be -1
✓ [sub] expect the result of -1 - -0 to be -1
✓ [sub] expect the result of -1.0 - 1.0 to be -2
✓ [sub] expect the result of 1 + 'a' to be an error
✓ [sub] expect the result of v + [a] to be an error
✓ [rotate] expect the result of [1, 2, 3, 4] to be [2, 3, 4, 1]
✓ [rotate] expect the result of [a, 2, 3, 4] to be an error
✓ [rotate] expect the result of [1, 2, 3, 4, 5] to be [2, 3, 4, 5, 1]
✓ [rotate] expect the result of [1] to be [1]
✓ [rotate] expect the result of [] to be []
✓ [rotate] expect the result of [[1], 2, 3, 4, 5, 6, 7, 8, 9, 10] to be an error
Test Files 1 passed (1)
Tests 16 passed (16)
Start at 10:54:40
Duration 492ms (transform 27ms, setup 0ms, collect 19ms, tests 4ms, environment 0ms, prepare 89ms)
% Coverage report from v8
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 98.52 | 85.71 | 100 | 98.52 |
math.js | 98.52 | 85.71 | 100 | 98.52 | 68
----------|---------|----------|---------|---------|-------------------En même temps, la commande doit créer un fichier
coverage-final.json ainsi qu’une page HTML présentant le
coverage. Cette page pourrait directement être affichée sur un
site dédié.

Documentation
La documentation est une partie essentielle du développement logiciel. Elle permet de décrire le fonctionnement d’une application, d’une bibliothèque ou d’un module, et de fournir des informations sur son utilisation, ses fonctionnalités et ses API.
Il existe de nombreux outils de documentation pour les différents langages de programmation. Voici quelques-uns des outils les plus populaires :
- JavaScript : JSDoc, ESDoc
- Python : Sphinx, MkDocs
- Java : Javadoc
- C# : Doxygen
JSDoc
JSDoc est un outil de documentation pour JavaScript qui permet de générer une documentation à partir des commentaires du code source. Il est largement utilisé dans l’industrie du logiciel pour documenter les bibliothèques et les modules JavaScript.
Un exemple de commentaire JSDoc ressemble à ceci :
/**
* Add two numbers.
* @param {number} a - The first number to add.
* @param {number} b - The second number to add.
* @returns {number} The sum of the two numbers.
*/
function add(a, b) {
return a + b
}Dans cet exemple, la fonction add est documentée en
spécifiant le type des paramètres et de la valeur de retour. Cela permet
de générer une documentation claire et précise à partir du code
source.
Pour générer la documentation à partir des commentaires JSDoc, il suffit d’exécuter la commande suivante :
$ npx jsdoc src/math.jsou alors
$ node_modules/.bin/jsdoc src/math.jsCette commande génère un répertoire out contenant les
fichiers HTML de la documentation. Vous pouvez ouvrir le fichier
index.html dans un navigateur pour visualiser la
documentation.

Exercice JSDoc
Reprenez l’exercice précédent des tests unitaires et ajoutez des commentaires JSDoc au code source du module mathématique. Générez ensuite la documentation à partir des commentaires JSDoc.
La documentation doit contenir les informations suivantes pour chaque fonction :
- Une description de la fonction qui indique ce qu’elle permet de faire.
- Une description des paramètres de la fonction qui indique leur utilité et leur type.
- Une description de la valeur de retour de la fonction ainsi que le type.
- Un fichier Markdown
README.mdà la racine du projet qui explique comment installer et utiliser le module mathématique. - Une invitation à consulter le site git de l’école pour plus
d’informations (
see,link). - L’indication que
math.jsest un module ES6. - Le fait que le code est sous licence Apache 2.0 (version standalone).
- L’auteur du code
<email>. - La version du code.
Le résultat doit se trouver dans un répertoire docs à la
racine du projet. La commande pour générer la documentation doit aller
chercher la configuration, notamment du répertoire de sortie, dans le
fichier jsdoc-conf.js.
Build
Le build est une étape du processus de développement logiciel qui consiste à compiler, à transformer et à regrouper les fichiers source en un exécutable ou en un package distribuable.
Chaque environnement de développement possède ses propres outils de
build avec des finalités bien différentes. Si vous écrivez
un programme en C, vous utiliserez make ou
cmake pour obtenir un fichier binaire exécutable tel qu’un
fichier ELF
pour Linux ou PE pour
Windows. Si vous écrivez un programme en Java, vous utiliserez
maven ou gradle pour obtenir un fichier
interprétable par la Java VM.
Si vous écrivez un programme en Javascript, vous utiliserez Webpack, Vite, Parcel ou
Rollup pour fournir un répertoire contenant toutes les
dépendances nécessaires.
Bundler
Un bundler est un outil qui automatise le processus de regroupement qui consiste à combiner plusieurs fichiers, tels que JavaScript, CSS, HTML, des images, des polices et d’autres ressources, en un plus petit nombre de fichiers plus faciles à charger et à gérer.
Programme de démo
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="images/vite.svg" />
<link rel="stylesheet" href="/css/style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo</title>
</head>
<body>
<main id="app"></main>
<script type="text/javascript" src="/js/math.js" defer></script>
<script type="module" src="/js/main.js"></script>
</body>
</html>js/main.js
import { sayHi } from "./module1.js"
import { showMeta } from "./module2.js"
sayHi()
showMeta()js/math.js
js/module1.js
export function sayHi() {
alert("Hello world!")
}
export function UnusedFunction2() {
// This is an unused function
}js/module2.js
export function showMeta() {
console.log(math.sqrt(9))
}
export function UnusedFunction() {
// This is an unused function
}
Installation
$ npm create vite@latest . -- --template vanilla
Need to install the following packages:
create-vite@6.4.1
Ok to proceed? (y) y
> npx
> create-vite . --template vanilla
│
◇ Scaffolding project in /demo...
│
└ Done. Now run:
npm install
npm run dev
$ npm install
added 13 packages, and audited 14 packages in 6s
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ npm install mathjs
$ tree /demo
C:.
│ index.html
│ package-lock.json
│ package.json
├─node_modules
│ ├─ mathjs
│ └─ ...
├─public
│ vite.svg
└─src
main.js
module1.js
module2.js
style.cssBuild
$ npm run build
> demo_editable@0.0.0 build
> vite build
vite v6.3.4 building for production...
✓ 5 modules transformed.
dist/index.html 0.38 kB │ gzip: 0.26 kB
dist/assets/index--E2UjqNH.js 0.79 kB │ gzip: 0.44 kB
✓ built in 152ms
$ tree dist
C:.
└─dist
└─assets
index--E2UjqNH.js
index.html
vite.svgindex–E2UjqNH.js
( ... function de vite js ) ();
function n() {
alert('Hello world!')
}
function c() {
console.log(import.meta)
}
n();
c();Avec le bundler, seules les fonctions utilisées sont
présentes dans le fichier .js final.

Implication ops
À cette étape, il est important de définir les particularités de
l’environnement de production. C’est une étape qui doit être réalisée en
collaboration avec les équipes ops. En effet, les équipes
ops doivent être en mesure de déployer l’application en
production et, comme elles sont responsables de l’infrastructure, elles
doivent être impliquées dans le processus de build.
Prenons un exemple simple. Imaginons le développement d’une application web en JavaScript qui est en mesure de faire des conversions monétaires.

Le développeur travaille avec les import / export de module
Javascript et une API personnelle basée sur l’API fetch
en mode asynchrone.
Dans son environnement, tout se passe à merveille. Cependant, lorsqu’il
envoie son code à l’équipe ops, il reçoit un message qui
l’informe que son application ne fonctionne pas.
vite v5.2.13 building for production...
✓ 5 modules transformed.
x Build failed in 97ms
error during build:
[vite:esbuild-transpile] Transform failed with 2 errors:
assets/index-!~{001}~.js:223:20: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)C’est normal car l’équipe ops utilise, pour ses tests,
un environnement qui ne supporte pas l’utilisation des méthodes
asynchrones directement dans le module de premier niveau.
La différence se résume à la simple ligne suivante de configuration
dans le fichier vite.config.js :
export default {
build: {
target: "esnext",
},
}Malheureusement, le développeur n’a pas fourni ce fichier de
configuration à l’équipe ops et l’a ignoré dans le dépôt
Git, pensant qu’il s’agissait d’un fichier de configuration local. Comme
l’équipe ops utilise la version présente dans le dépôt Git,
elle n’a pas pu déployer l’application.
Inévitablement, les deux équipes seront en conflit pour savoir qui a raison. C’est pourquoi il est important de définir les particularités de l’environnement de production dès le début du projet et de les documenter.
Exercice Build
Pour cet exercice, nous utiliserons vitejs pour construire un site web simple basé sur du Javascript.
L’objectif est de réaliser le site web présenté ci-dessous.

Ce site permet de convertir des devises. Il se base sur l’API ExchangeRate. L’API fournit un service gratuit pour obtenir les taux de change entre différentes devises. Dans sa version gratuite, on ne peut pas directement faire la conversion d’une devise en une autre mais on peut passer par le Dollar US :
€ → CHF revient à faire € ⇢ $ ⇢ CHF.
Particularités
- Le site doit être construit avec vitejs.
- Le site doit être buildé pour la production.
- Les listes déroulantes doivent être construites dynamiquement à partir de l’API.
- Les listes déroulantes doivent contenir les drapeaux correspondant
aux devises. Ils peuvent être obtenus grâce à des emojis dont la liste
est disponible ici.
Il faut prendre le fichier
currency-data.json. - Le site doit être responsive.
- Le site utilise une police de style
hand-writingà choix disponible sur Google Fonts. - L’API se trouve séparée dans un fichier module
api.js. Elle expose au moins les méthodes asynchronesgetLatestRatesetgetSupportedCurrencies. - C’est depuis le module
main.jsque l’on place les comportements (événements) de l’application et qu’on fait appel aux méthodes du moduleapi.js.
Grâce à vitejs, vous pourrez
réaliser la partie build du projet. Le build
fournit un répertoire dist contenant tous les fichiers
nécessaires pour le déploiement en production.
Quelques exemples de contenus de fichier
.env
VITE_API_KEY=b596b2.................ea8d68b
VITE_API_ENDPOINT=https://openexchangerates.org/apiapi.js
/**
* Retrieve latest exchange rates
* @returns {Promise<Object>} The latest exchange rates.
* @throws {Error} If the API request fails.
* VITE_API_KEY and VITE_API_ENDPOINT must be defined in the .env file.
*/
const getLatestRates = async () => {
const response = await fetch(
`${import.meta.env.VITE_API_ENDPOINT}/latest.json?app_id=${
import.meta.env.VITE_API_KEY
}`
)
if (!response.ok) {
throw new Error("Failed to fetch latest exchange rates")
}
return response.json()
}api.test.js
import { describe, it, expect, vi } from "vitest"
import { getLatestRates } from "./api.js"
describe("getLatestRates", () => {
it("should return latest exchange rates", async () => {
const mockResponse = {
rates: {
USD: 1,
EUR: 0.85,
},
}
vi.spyOn(global, "fetch").mockResolvedValueOnce({
ok: true,
json: async () => mockResponse,
})
const rates = await getLatestRates()
expect(rates).toEqual(mockResponse)
})
it("should throw an error if the API request fails", async () => {
vi.spyOn(global, "fetch").mockResolvedValueOnce({
ok: false,
})
await expect(getLatestRates()).rejects.toThrow(
"Failed to fetch latest exchange rates"
)
})
})Au final, l’arborescence de votre projet doit ressembler à ceci :
.
├── dist
│ ├── assets
│ │ ├── index-BKEa98Qj.js
│ │ └── index-Col1SUQS.css
│ ├── favicon.png
│ └── index.html
├── css
│ └── style.css
├── index.html
├── main.js
├── .env
├── package.json
├── package-lock.json
├── public
│ └── favicon.png
├── README.md
├── src
│ ├── api.js
│ └── api.test.js
├── docs
├── coverage
├── vite.config.js
└── eslint.config.mjsVous pouvez remarquer que le répertoire public contient le
favicon du site. Si le fichier favicon se
trouve dans le dossier public, c’est parce que vitejs le
copie automatiquement dans le répertoire dist lors du
build.
Le dossier racine comporte également un fichier .env qui
permet de définir des variables d’environnement utilisables par
vitejs.
Contrôle
Une fois votre build réalisé, vérifiez que le site
fonctionne correctement :
- Placez le contenu de votre répertoire
distdans un serveur web local (par exemple Laragon ou Wamp). - Ouvrez le fichier
index.htmldans un navigateur via le protocole HTTP. - Vérifiez que les listes déroulantes sont bien construites.
- Vérifiez que les drapeaux sont bien affichés.
- Vérifiez que la conversion des devises fonctionne correctement.
- Vérifiez dans la console du navigateur que les appels à l’API se font correctement.
- Vérifiez qu’il n’y a pas d’erreurs dans la console du navigateur.
Par exemple, une erreur de type
404sur lefavicon.icosignifie que le navigateur n’a pas pu trouver ce fichier.
REMARQUES
Vous n’avez pas besoin d’avoir un coverage de 100%. L’idée est de couvrir une partie des cas pour pouvoir générer chaque étape : vitest, coverage, doc et build.
Question Vite
Le fichier .env est ignoré par git et ne doit pas être
versionné. Doit-il être fourni à l’équipe ops lors du
déploiement en production ?
Introduction à git
Gitflow
Connaître des procédures de développement en équipe dont le suivi est compréhensible et traçable (p. ex. liaison des commits et des récits utilisateur, PullRequest/revue par les pairs). Connaître des pratiques de gestion du code source basée fonctionnalités (p. ex. flux de travail GIT, versionnage sémantique, etc.).
La partie Git du cours est entièrement basé sur le livre gratuit et officiel que l’on peut trouver à cette adresse : https://git-scm.com/book/fr/v2.
Cette partie s’articule autour de la lecture de ce livre (pas complètement 😓) et de la réalisation d’exercices pratiques. Voici comment il faut procéder :
Installez-vous confortablement sur votre chaise, téléchargez et ouvrez le livre officiel de Git.
Lisez les 3 premiers chapitres du livre. Au fur et à mesure de votre avancement, mettez en pratique les commandes qui sont présentées. Aucune aide externe ne vous est autorisée pour ces 3 chapitres. Vous devez vous débrouiller seul ou avec votre enseignant. Il ne vous est pas possible de demander à vos camarades de classe ni d’utiliser Internet!
Vous avez bien entendu le droit de créer des dépôts locaux et/ou distant sur GitLab pour vous entraîner. Vous pourrez supprimer ces dépôts une fois que vous n’en aurez plus besoin.
Chapitre Démarrage rapide
Dans cette partie on vous explique les différents gestionnaires de versions, on vous parle de l’origine de Git et de ses prédécesseurs et on vous explique comment installer et configurer Git.
Comme il est indiqué dans ce chapitre:
Dans ce livre, nous utiliserons Git en ligne de commande. Tout d’abord, la ligne de commande est la seule interface qui permet de lancer toutes les commandes Git - la plupart des interfaces graphiques simplifient l’utilisation en ne couvrant qu’un sous-ensemble des fonctionnalités de Git. Si vous savez comment utiliser la version en ligne de commande, vous serez à même de comprendre comment fonctionne la version graphique, tandis que l’inverse n’est pas nécessairement vrai.
Votre objectif est d’installer Git sur votre machine si ce n’est pas
déjà fait, et de passer en revue les différents niveaux de
configuration, system, global et
local.
Déjà que vous y êtes, configurer votre nom et votre adresse email dans la configuration globale.
$ git config --global --list
user.email=pierre.ferrari@rpn.ch
user.name=piferrari
credential.helper=/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
init.defaultbranch=main
pull.rebase=false
alias.last=log -1 HEADLes différentes valeurs de configuration sont expliquées sur la page
de manuel de git-config que vous pouvez consulter avec la
commande man git-config ou en ligne à cette adresse : https://git-scm.com/docs/git-config.
Chapitre Les bases de Git
Dans ce chapitre, vous allez apprendre les bases de Git. Vous allez apprendre à créer un dépôt, à y ajouter des fichiers, à les valider et à les pousser sur un serveur distant. Vous apprendrez également à ignorez des fichiers et à les renommer.
Commandes pratiquées dans ce chapitre :
$ git init
$ git add
$ git status
$ nano .gitignore
$ git clone
$ git commit
$ git status
$ git diff
$ git mv
$ git rm
$ git log
$ git reset
$ git checkout
$ git restore
$ git remote
$ git push
$ git pull
$ git fetch
$ git tag
$ git show
$ git lastChapitre Les branches avec Git
Dans ce chapitre, vous allez apprendre à créer des branches, à les fusionner et à les supprimer. Vous allez également apprendre à gérer les conflits de fusion.
Supplément : Chapitre Commandes Git
Ce chapitre constitue une référence des commandes Git. Vous pouvez le consulter à tout moment pour retrouver une commande ou une option.
Exercices git
GitLab S2
Après avoir pratiqué les exercices précédents, vous devriez être en mesure de réaliser l’exercice ci-dessous. Ce pourrait être un exercice d’examen.
- Créez un dépôt Git locale sur votre machine dans un dossier de votre choix.
- Ajoutez-y un fichier
votreNomcontenant votre nom. Par exempleferraripcontenantPierre Ferrari. - Validez ce changement dans votre dépôt avec un message de commit explicite. Vous trouverez les bonnes pratiques ici
- Créez un lien
originvers le dépôt distant exercice-base. ATTENTION, on ne vous demande pas de le cloner, mais de créer un lien vers ce dépôt. - Rapatriez uniquement le contenu de la branch
maindu dépôt distant dans votre dépôt local. En l’occurrence, un fichierREADME.md. - Mettez à jour le dépôt local pour le faire coïncider avec votre
dépôt distant. C’est-à-dire, faite apparaître le fichier
README.mddans votre dépôt local.
binCraft decoder
Vous trouvez un dépôt binCraft à cette
adresse.
Le dépôt original est différent de ce dépôt pour plusieurs raison mais une des raisons c’est que le dépôt original contient des erreurs dans le décodage des valeurs binaires alors que dans ce dépôt, les erreurs ont étés corrigées. Votre travail consiste à retrouver les erreurs pour être en mesure de proposer des corrections au mainteneur du dépôt original.
Bien entendu, il ne faut pas chercher à lire le code pour trouver les erreurs. Vous devez utiliser Git pour faire le travail.
Une fois les erreurs identifiées, préparez un patch par erreur identifiée comme si vous vouliez soumettre une demande de fusion (merge request) au mainteneur du dépôt original.
Currency converter (le retour)
Reprenez l’exercice du currency converter que vous avez déjà
réalisé précédemment dans la partie build. Durant la
réalisation de cet exercice, on ne vous demandait pas de versionner
votre code. Vous allez maintenant versionner votre code.
- Créez un dépôt Git distant sur GitLab. Créez ce dépôt avec un fichier
README.md. - Cloner ce dépôt sur votre machine.
- Ajouter un fichier
.gitignorespécialisé pour le langage Javascript et le gestionnairevitejs. - Ajouter tous les fichiers nécessaires pour le projet ainsi que votre code.
- Validez les changements avec des messages de commit explicites.
C’est-à-dire, ne faite pas un gros commit avec un message du
genre
mais plusieurs petit commit avec à chaque fois un message qui respect les standards.first commit - Mettez à jour le fichier README.md pour expliquer comment installer et utiliser le projet.
- Validez les changements avec un message de commit explicite.
- Ajouter un tag de version sémantique qui respect les standards. Par exemple,
v1.0.0. - Ajoutez une fonctionnalité permettant à l’utilisateur de changer le
sens de la conversion. Par exemple, si l’utilisateur converti
€ → CHF, il doit pouvoir convertirCHF → €en un clic. - Validez les changements avec un message de commit explicite.
- Ajouter un tag de version sémantique qui respect les standards. Par exemple,
v1.1.0. - Changez votre code pour qu’il utilise une nouvelle API libre et gratuite.
- Validez les changements avec un message de commit explicite en sachant qu’il s’agit d’une modification majeure qui casse la compatibilité avec l’API précédente.
- Ajouter un tag de version sémantique qui respect les standards. Par exemple,
v2.0.0.
$ git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(auto)%d%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
* 1517d42 - (HEAD -> main, tag: v2.0.0, origin/main, origin/HEAD) feat(api)!: changement d'api et adaptation des tests unitaires - piferrari
* 7e5262d - (tag: v1.1.0) feat(app): ajout de la fonctionnalité permettant d'inverser la conversion, par exemple € → CHF par CHF → € en un clic - piferrari
* b9d7042 - (tag: v1.0.0) refactor(readme): mise à jour du fichier readme - piferrari
* 5a369fa - fix(js): suppression de l'event change inutile - piferrari
* c5eae45 - fix(html): correction du titre de la page - piferrari
* 9e758fb - refactor(vite): ajout du dossier public et utilisation de ce dossier pour favicon - piferrari
* 7a9ca98 - feat(js): ajout du programme de conversion, suppression des tests et import css via vite - piferrari
* 79955f1 - feat(html): ajout des formulaires html avec le css - piferrari
* 9ed7492 - feat(api): ajout de l'api exchange ainsi que des tests unitaires - piferrari
* 5e85721 - feat(vite): mise en place de l'environnement vite avec sa config - piferrari
* 3dd38d0 - Initial commit - Ferrari Pierre (PDF)

Exercices supplémentaires
Vous pouvez également pratiquer les exercices suivants chez vous :
Utiliser un processus d’intégration automatisé
Utiliser un processus d’intégration automatisé est essentiel pour optimiser la qualité et la rapidité des cycles de développement logiciel. L’intégration automatisée consiste à déclencher automatiquement une série de tests et de validations à chaque modification du dépôt.
Ce processus permet de détecter rapidement les erreurs de compilation, les conflits de fusion, ou les bugs introduits par des modifications récentes, réduisant ainsi les délais entre la détection d’un problème et sa résolution. De plus, l’automatisation garantit que les tests sont exécutés de manière cohérente et exhaustive, augmentant ainsi la fiabilité du logiciel. Par exemple, dans un environnement DevOps, l’intégration automatisée peut inclure des tests unitaires, des tests d’intégration, des vérifications de la qualité du code, et même le déploiement sur des environnements de staging, permettant ainsi aux équipes de déceler les problèmes potentiels avant que le code n’atteigne la production. Cette approche non seulement accélère le cycle de développement, mais aussi améliore la qualité et la stabilité du produit final, tout en réduisant les risques de régressions et en favorisant une culture de développement itératif et collaboratif.
Principe de l’intégration continue
Il existe plusieurs manières de procéder pour faire de l’intégration continue. Chaque entreprise possède sa propre manière de faire même si elle se base sur des concepts communs. Ce que vous allez mettre en pratique est un exemple parmi d’autres.

Dans cet exemple, on voit un développeur qui va ajouter une fonctionnalité ou corriger un bug.
Il va créer une branche à partir de la branche main pour
réaliser son travail. Il fera des commits réguliers pour sauvegarder son
travail. Une fois qu’il pense être au bout de son travail, il va pousser
sa branche sur le dépôt distant. Cette action va démarrer un pipeline
CI/CD qui va tester le code, le compiler, le valider. Une fois que tous
les tests mis en place seront passés (✔), le code sera proposé à une
revue par un pair, un autre développeur ou un responsable.
Une fois la revue terminée, l’auteur va créer une demande de fusion
(merge request) pour fusionner sa branche avec la branche
main. Cette demande de fusion va déclencher un nouveau
pipeline CI/CD qui va tester le code, le compiler, le valider et le
déployer sur un environnement de staging.
Dans la phase de staging, un groupe de testeur utilisera la nouvelle version proposée pour vérifier que tout fonctionne correctement. Si tout est OK, le code validé sera déployé en production.
GitLab CI/CD
GitLab propose un outil d’intégration continue et de déploiement continu intégré directement dans son outil de gestion de versions. Cet outil s’appelle GitLab CI/CD.
GitLab CI/CD permet de définir des pipelines d’intégration continue et de déploiement continu directement dans le fichier de configuration du dépôt Git. Ces pipelines sont déclenchés automatiquement à chaque modification du dépôt, permettant ainsi de tester, de compiler et de déployer le code de manière automatisée.
Les pipelines GitLab CI/CD sont définis dans un fichier
.gitlab-ci.yml à la racine du dépôt Git. Ce fichier
contient les étapes du pipeline, les tâches à exécuter, les dépendances
entre les tâches, et les conditions de déclenchement du pipeline.
Voici un exemple de fichier .gitlab-ci.yml pour un
pipeline simple :
stages:
- build
- test
- deploy
build:
stage: build
script:
- npm install
- npm run build
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- npm run deploy
only:
- mainDans cet exemple, le pipeline est composé de trois étapes :
build, test et deploy. Chaque
étape contient une ou plusieurs tâches à exécuter, définies dans la
section script. Les tâches sont exécutées dans l’ordre
défini par les stages, et les dépendances entre les étapes
sont gérées automatiquement par GitLab CI/CD.

Exercices basiques GitLab CI/CD
Exercice 1, le plus basique
Créez un dépôt sur le serveur GitLab de l’école. Nommez ce dépôt
cicd-basique.
Dans le menu de gauche, cliquez sur Build puis sur
Pipeline editor. Activez les pipelines GitLab CI/CD pour ce
projet en créant le fichier .gitlab-ci.yml par un simple
appui sur le bouton Configure pipeline. Vous vous trouvez
alors dans l’éditeur de pipeline.
Commiter le fichier .gitlab-ci.yml en cliquant sur le
bouton Commit changes. Rendez-vous ensuite dans l’onglet
Pipelines pour voir le pipeline se déclencher.
Exercice 2, un peu de système
Modifiez votre fichier .gitlab-ci.yml depuis le
Pipeline editor pour:
- Ajouter une partie de commandes systèmes qui s’exécuterons avant
celles contenues dans
script. Dans ce nouveau block:- Faire une mise à jour de la liste des paquets (pas une mise à jour système)
- Installer le paquet
iproute2
Dans la partie script:
- Afficher le contenu de la variable GitLab prédéfinie contenant le nom de la branche du commit
- Afficher le contenu de la variable GitLab prédéfinie contenant le message du commit
- Lister le contenu du dossier courant, y.c. les fichiers cachés
- Obtenir les informations sur l’OS (version, build etc. par exemple:
Linux pifx 6.16.3+deb14-amd64) - Obtenir les informations sur la distribution dans laquelle on se
trouve, par exemple:
PRETTY_NAME="Debian GNU/Linux forky/sid" - Obtenir les adresses ip du conteneur
Exercice 3, l’erreur classique
Dans votre dépôt, créez une branche cicd et dans le
Pipeline Editor mettez ce contenu:
stages:
- learn
learn-job:
stage: learn
rules:
- if: '$CI_COMMIT_BRANCH == "cicd"'
when: never
script:
- echo "Ca tourne en boucle"Au moment de valider votre modification, vous pourrez constatez que:

Pourquoi ?
Exercice 4, on vous prends par la main
Cet exercice est en réalité une vidéo réalisée par M. Droz lors d’un cours en ligne. Vous allez suivre pas à pas les instructions de la vidéo pour réaliser un pipeline GitLab CI/CD.
La vidéo se trouve à cette adresse : Ubicast S2.
Exercice 5, un peu plus complexe
Pour cet exercice, vous allez créer un pipeline GitLab CI/CD pour un projet JavaScript en NodeJS. Le pipeline doit inclure les étapes suivantes :
- Installer les dépendances du projet.
- Lancer les tests unitaires.
- Exécuter le code.
- Déployer le code sur un serveur de staging (simulation pour l’instant).
Le travail sera réalisé dans l’outil de développement Visual Studio Code.
- Créez un nouveau projet sur le serveur GitLab de l’école. Nommez ce
projet
js-cicd. Le projet est vide pour l’instant. - Cloner ce projet localement dans un dossier nommé
js-cicd. - Initialisez un projet JavaScript dans le dossier
js-cicden exécutant la commandenpm init. - Installez les dépendances suivantes dans le projet :
$ npm install dayjs- Créez un fichier
index.jsdans le dossier du projet et ajoutez-y le code suivant :
import dayjs from "dayjs"
const today = dayjs()
const year_end = dayjs("2024-12-31")
console.log(year_end.diff(today, "day"))- Modifier le fichier
package.jsonpour ajouter letypemoduleainsi que les scriptsstartettestsuivants :
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
}- Testez localement vos scripts en exécutant les commandes
npm startetnpm test.
$ npm start
> js-cicd@1.0.0 start
> node index.js
194$ npm test
> js-cicd@1.0.0 test
> echo "Error: no test specified" && exit 1
Error: no test specified- Créez un fichier
.gitlab-ci.ymlà la racine du projet et ajoutez le contenu suivant :
stages:
- run
- test
- deploy
run:
stage: run
before_script:
- placer ici le nécessaire pour installer node ainsi que les dépendances du projet
script:
- placer ici le code nécessaire pour ce stage
test:
stage: test
image: node:trixie-slim
before_script:
- placer ici le nécessaire pour installer les dépendances du projet
script:
- placer ici le code nécessaire pour ce stage
deploy:
stage: deploy
script:
- echo "Deploying to staging server..."
only:
- main- Commitez et poussez le projet sur le dépôt distant.
- Vérifiez que le pipeline est déclenché automatiquement et que les étapes du pipeline sont exécutées avec succès.
Erreurs :
Il y a des erreurs dans l’exécution du pipeline, c’est normal si vous
n’avez rien changé au fichier YAML présent ci-dessus. En effet, dans ce
fichier il n’y a actuellement aucune commande valide. Trouvez-les les
commandes permettant d’effectuer les 3 premiers
stages uniquement.
Runners

Les pipelines GitLab CI/CD sont exécutés par des agents appelés
runners. Les runners sont des machines virtuelles ou
physiques qui exécutent les tâches du pipeline. Ils peuvent être
hébergés sur le cloud, sur site ou sur des machines dédiées. GitLab
propose des runners partagés et des runners spécifiques à chaque projet,
permettant ainsi de personnaliser l’environnement d’exécution des
pipelines en fonction des besoins du projet.
Les runners GitLab CI/CD sont configurés dans les paramètres du projet GitLab. Vous pouvez définir des runners partagés ou spécifiques à chaque projet, en fonction de vos besoins. Les runners peuvent être configurés pour exécuter des tâches spécifiques, utiliser des images Docker personnalisées, ou se connecter à des services externes pour exécuter des tâches spécifiques.
Création d’un runner locale
Pour créer un runner local, il faut installer le logiciel
gitlab-runner sur la machine qui va exécuter les tâches du
pipeline. Le runner peut être installé sur n’importe quelle machine
compatible avec GitLab CI/CD, y compris les machines virtuelles, les
conteneurs Docker, les serveurs physiques, etc.
Nous installerons un runner dans une machine virtuelle Ubuntu 24.04. Pour cela, nous allons suivre les étapes suivantes :
- Créer une machine virtuelle Ubuntu Server ou Debian LTS.
- Installer le logiciel
gitlab-runnersur la machine virtuelle en suivant les instructions de la documentation officielle.
ubuntu@m347:~$ curl -sL "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
[sudo] password for ubuntu:
Detected operating system as Ubuntu/jammy.
Checking for curl...
Detected curl...
Checking for gpg...
Detected gpg...
...
ubuntu@m347:~$ sudo apt install gitlab-runner- Dans le projet précédemment créé
js-cicd, ajoutez un runner spécifique au projet en suivant les instructions de la documentation officielle.

ubuntu@m347:~$ gitlab-runner register --url https://git.s2.rpn.ch --token glrt-ZF_11xZtbP6cJsdaDe5c
ubuntu@m347:~$ gitlab-runner run
Runtime platform arch=amd64 os=linux pid=3420 revision=b92ee590 version=17.4.0
Starting multi-runner from /home/ubuntu/.gitlab-runner/config.toml... builds=0 max_builds=0
WARNING: Running in user-mode.
WARNING: Use sudo for system-mode:
WARNING: $ sudo gitlab-runner...
Configuration loaded builds=0 max_builds=1
listen_address not defined, metrics & debug endpoints disabled builds=0 max_builds=1
[session_server].listen_address not defined, session endpoints disabled builds=0 max_builds=1
Initializing executor providers builds=0 max_builds=1- Vérifiez que votre pipeline sera exécuté par le runner local.

- Exécutez le pipeline sur le runner local et vérifiez que les étapes du pipeline sont exécutées avec succès. Vous pourrez voir les logs évoluer dans la console.
Checking for jobs... received job=6941 repo_url=https://git.s2.rpn.ch/versioning/js-cicd.git runner=ZF_11xZtb
Added job to processing list builds=1 job=6941 max_builds=1 project=5320 repo_url=https://git.s2.rpn.ch/versioning/js-cicd.git time_in_queue_seconds=1
Appending trace to coordinator...ok code=202 job=6941 job-log=0-317 job-status=running runner=ZF_11xZtb sent-log=0-316 status=202 Accepted update-interval=1m0s
Removed job from processing list builds=0 job=6941 max_builds=1 project=5320 repo_url=https://git.s2.rpn.ch/versioning/js-cicd.git time_in_queue_seconds=1
Checking for jobs... received job=6942 repo_url=https://git.s2.rpn.ch/versioning/js-cicd.git runner=ZF_11xZtb
Added job to processing list builds=1 job=6942 max_builds=1 project=5320 repo_url=https://git.s2.rpn.ch/versioning/js-cicd.git time_in_queue_seconds=3
Appending trace to coordinator...ok code=202 job=6942 job-log=0-1524 job-status=running runner=ZF_11xZtb sent-log=0-1523 status=202 Accepted update-interval=1m0sSources :
Remarques
Vous pouvez constater que la commande gitlab-runner run
est lancé en tant qu’utilisateur standard (pas root). Cela
à des conséquences systèmes logiques telles qu’il n’est, par exemple,
pas possible d’utiliser une commande sudo apt update dans
mon fichier .gitlab-ci.yml. En effet, cette commande sera
exécutée par mon runner et il n’y a aucun moyen d’entrer le mot de passe
dans mon runner. On peut contourner ce problème en créant un utilisateur
spécifique qui n’aura pas besoin de mot de passe, un peu comme dans un
Raspberry Pi.
Dans la machine où se trouve le runner
ubuntu@m347:~$ sudo adduser gitlab
Nouveau mot de passe : gitlab
Retapez le nouveau mot de passe : gitlab
passwd : mot de passe mis à jour avec succès
Modifier les informations associées à un utilisateur pour gitlab
Entrer la nouvelle valeur, ou appuyer sur ENTER pour la valeur par défaut
NOM []:
Numéro de chambre []:
Téléphone professionnel []:
Téléphone personnel []:
Autre []:
Is the information correct? [Y/n]
ubuntu@m347:~$ echo "gitlab ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers.d/gitlab
ubuntu@m347:~$ sudo chmod 440 /etc/sudoers.d/gitlab
ubuntu@m347:~$ su gitlab
Mot de passe :
gitlab@m347:$ sudo apt update
Atteint : 1 http://security.debian.org/debian-security trixie-security InRelease
Atteint : 2 http://ftp.ch.debian.org/debian trixie InRelease
Atteint : 3 http://ftp.ch.debian.org/debian trixie-updates InRelease
Atteint : 4 https://packages.gitlab.com/runner/gitlab-runner/debian trixie InRelease
Tous les paquets sont à jour.
## Enregistrement du runner depuis cet utilisateur car le fichier de configuration est crée
## dans son répertoire personnel
gitlab@m347:~$ gitlab-runner register --url https://git.s2.rpn.ch --token glrt-XXXXXXXXXXXXXXXXX
gitlab@m347:~$ ls -la .gitlab-runner/
...
-rw------- 1 gitlab gitlab 477 25 sep 12:36 config.toml
gitlab@m347:~$ gitlab-runner run -c /home/gitlab/.gitlab-runner/config.tomlDans votre runner, une fois que nodejs à
été installé, il n’est pas nécessaire de le réinstaller à chaque fois.
En effet, comme on est en mode shell, si on lance une
commande sudo apt install nodejs elle installera les
paquets en lien avec nodejs directement dans la machine
virtuelle. Donc, il n’est plus nécessaire de le refaire. Dès lors le
fichier .gitlab-ci.yml devient:
stages:
- install
- run
- test
- deploy
install:
stage: install
## Install node in the machine only if it necessary
before_script:
- sudo apt update -y
- |
if ! command -v nodejs &> /dev/null; then
sudo apt install nodejs -y
fi
if ! command -v npm &> /dev/null; then
sudo apt install npm -y
fi
## Test node
script:
- node --version
- npm --version
run:
stage: run
before_script:
- node --version
- npm i
script:
- node index.js
test:
stage: test
before_script:
- export NODE_NB_DAYS_TO_END_OF_YEAR=$(node index.js)
- export BASH_TODAY_NUMBER=$(date +%j)
- export BASH_NB_DAYS_TO_END_OF_YEAR=$(echo "365-$BASH_TODAY_NUMBER" | bc)
- export NB_DAYS_COMPUTED=$(echo "$BASH_NB_DAYS_TO_END_OF_YEAR-$NODE_NB_DAYS_TO_END_OF_YEAR" | bc)
script:
- if [[ $NB_DAYS_COMPUTED -eq 0 ]] ; then echo "Test passed" ; else echo "Test failed" ; exit 1 ; fi
deploy:
stage: deploy
script:
- echo "Deploying to staging server..."
only:
- mainExercice
Pour faire un résumé de ce qui a été vu jusqu’ici, vous allez réaliser un exercice très simple. Le but de l’exercice est d’afficher une page HTML qui nous indique le date de la prochaine fête des vendanges.
Points à respecter:
- L’application est développée avec vitejs
- L’application utilise la librairie
dayjsvue précédemment - La fête des vendanges à toujours lieu le dernier week-end de septembre
- L’application s’adapte automatiquement à la date actuelle pour afficher la prochaine fête
- Il n’y aura que deux jobs CI/CD qui s’exécuteront
- Le job de build s’exécutera sur les runners partagés de gitlab en utilisant une image adéquate
- Le job de publication FTP s’exécutera sur votre runner personnel
avec la commande
lftp
zftpcicd00 le répertoire de
publication sera zftpcicd00 et du coup, la racine de votre
site web sera https://stark.s2dev.ch/zftpcicd00/
Exemple d’interface

Build runner gitlab
Running with gitlab-runner 15.1.0 (76984217)
on Official Docker Runner 3 glrt-t1_
Preparing the "docker" executor
...
$ npm run build
> prochaine-fete-des-vendanges@0.0.0 build
> vite build
vite v7.1.11 building for production...
transforming...
✓ 11 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.73 kB │ gzip: 0.43 kB
dist/assets/index-D7EljR_1.css 0.49 kB │ gzip: 0.31 kB
dist/assets/index-ChczilGb.js 9.48 kB │ gzip: 4.14 kB
✓ built in 257ms
$ echo "Compile complete."
Compile complete.
Uploading artifacts for successful job 00:00
Uploading artifacts...
dist/: found 6 matching files and directories
Uploading artifacts as "archive" to coordinator... 201 Created id=17120 responseStatus=201 Created token=glcbt-64
Cleaning up project directory and file based variables 00:01
Job succeeded
Publish runner local
Running with gitlab-runner 18.5.0 (bda84871)
on debian j2q-TQgQc, system ID: s_ac7de2670f1d
Preparing the "shell" executor
...
$ lftp -u $FTP_USER,$FTP_PASS $FTP_HOST -e "..."
===== Remote directory structure =====
drwxr-xr-x - 2025-10-21 14:04:30 /root/zftpcicd00/
drwxr-xr-x - 2025-10-21 14:04:30 /root/zftpcicd00/assets/
-rw-r--r-- 9480 2025-10-21 14:04:30 /root/zftpcicd00/assets/index-ChczilGb.js
-rw-r--r-- 486 2025-10-21 14:04:30 /root/zftpcicd00/assets/index-D7EljR_1.css
-rw-r--r-- 731 2025-10-21 14:04:30 /root/zftpcicd00/index.html
-rw-r--r-- 1497 2025-10-21 14:04:30 /root/zftpcicd00/vite.svg
$ echo "Application successfully deployed."
Application successfully deployed.
Cleaning up project directory and file based variables 00:01
Job succeeded
Conditions de déclenchement
Cette partie est un copier / coller du blog de Stéphane Robert. Elle est copiée ici au cas où le blog disparaîtrait.
Il s’est lui-même inspiré de la documentation officielle de GitLab.
Tout bon consultant DevOps se doit d’optimiser ses pipelines CI/CD.
GitLab CI/CD, offre une variété de conditions de workflow qui permettent
une personnalisation et une optimisation importantes des pipelines. Ces
conditions, comme if, when, rules
et workflow, sont des instruments clés pour gérer le
comportement des jobs dans vos pipelines.

Pourquoi les Conditions sont-elles essentielles ?
Simplement parce que toutes les étapes d’un pipeline ne doivent pas nécessairement être exécutées à chaque commit ou à chaque modification du code source. C’est pour cette raison que GitLab CI/CD permet l’utilisation de conditions dans le fichier YAML.
Les conditions définissent les règles qui déterminent si une étape du pipeline doit être exécutée ou non. Elles permettent d’optimiser le processus de développement en exécutant uniquement les étapes nécessaires.
Définir des Conditions
Pour définir des conditions sur un job du pipeline, il suffit d’y
ajouter une section rules. Chaque règle spécifie une
condition sous la forme d’une expression conditionnelle et le job sera
exécuté si cette condition est évaluée comme vraie.
job:
script:
- echo "Cette étape s'exécute si la condition est satisfaite"
rules:
- if: '$CI_COMMIT_BRANCH == "main"'Dans cet exemple, le job sera exécuté uniquement si la
branche du commit est main. Cet exemple est très simple
mais les possibilités offertes par les conditions sont vastes. Vous
pouvez créer des conditions complexes en utilisant des opérateurs
logiques ET, OU ainsi que des variables
d’environnement que vous aurez vous-même définies ou qui sont fournies
par GitLab.
Voyons quelques exemples d’utilisation courants de conditions :
rules:
- if: "$CI_COMMIT_TAG"Ici, le job sera exécuté uniquement si le commit est associé à un tag.
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'Ce job s’exécutera seulement si le pipeline a été lancé manuellement depuis l’interface GitLab (bouton Run pipeline).
Utilisation
de when pour Contrôler le Déclenchement
when est utilisé à l’intérieur des règles
rules pour définir le moment où un job doit être exécuté.
GitLab offre plusieurs options pour when afin de
personnaliser le déclenchement de vos jobs en fonction de scénarios
spécifiques.
on_success
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_successDans cet exemple, le job sera exécuté uniquement si la branche du
commit est main et si tous les jobs précédents dans le
pipeline ont été exécutés avec succès.
on_failure
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_failureCe job s’exécutera uniquement si la branche du commit est
main et si au moins l’un des jobs précédents dans le
pipeline a échoué.
always
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: alwaysCe job sera toujours exécuté, quel que soit l’état des jobs
précédents, tant que la branche du commit est main.
manual
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manualCe job ne s’exécute que lorsque l’utilisateur le déclenche manuellement, indépendamment des autres conditions.
delayed
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: delayed
start_in: 30 minutesCe job s’exécute automatiquement, mais il est retardé de 30 minutes à partir du déclenchement du pipeline.
scheduled
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'Ce job s’exécute pour les pipelines planifiés. La planification (par
exemple tous les jours à midi) se configure dans l’interface, sous
Build > Pipeline schedules, avec l’expression cron
0 12 * * *.
Les règles combinées ET / OU
Syntaxe de base
- && signifie toutes les conditions doivent être vraies.
- || signifie au moins une condition doit être vraie.
- if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"
- if: ($CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop") && $CI_PIPELINE_SOURCE == "merge_request_event"Les règles sont évaluées dans l’ordre, et la première qui correspond s’applique. Pour des règles simples sans attributs supplémentaires, l’effet revient à un OU.
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_BRANCH == "develop"'est équivalent à:
rules:
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"Les règles en if / else
Fonctionnement général. Les rules sont évaluées dans l’ordre.
- La première règle dont la condition
if:est vraie détermine le comportement du job. - Si aucune règle n’est vraie, GitLab applique
when: neverpar défaut (le job ne tourne pas).
rules:
# Le tiret ouvre une nouvelle liste contenant le if et le when qui sont alignés
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success # IF
# La première liste se termine et une nouvelle liste commence
- when: manual # ELSE (par défaut, passe en manuel)Les règles sur les
pipelines : workflow
La directive workflow détermine si un pipeline doit être
créé et exécuté. Contrairement aux règles appliquées à des jobs
individuels, workflow permet de contrôler le déclenchement
de l’ensemble du pipeline en se basant sur des critères globaux. Cette
capacité de gestion à un niveau supérieur offre un contrôle précis et
efficace sur l’exécution des pipelines, en particulier dans des projets
complexes avec de multiples branches et conditions.
Un cas d’utilisation courant de workflow est la mise en
place de conditions pour exécuter des pipelines uniquement pour certains
événements ou pour certaines branches. Par exemple, vous pourriez
vouloir déclencher un pipeline seulement sur la branche principale ou
sur des branches de fonctionnalités, mais pas sur des branches de
corrections de bugs. Voici comment cela peut être configuré :
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: "$CI_COMMIT_BRANCH =~ /^feature-/"
- when: neverDans cet exemple, un pipeline est créé pour la branche main ou pour
une branche dont le nom commence par feature-. Tous les
autres cas ne créent pas de pipeline.
On peut raisonner en logique inverse. On bloque
bugfix et hotfix et on autorise tout le reste
:
workflow:
rules:
# Le tiret ouvre une nouvelle liste contenant le if et le when qui sont alignés
- if: '$CI_COMMIT_BRANCH =~ /^(bugfix|hotfix)-/'
when: never
# La première liste se termine et une nouvelle liste commence
- when: alwaysworkflow peut également intégrer des logiques plus
complexes, comme des conditions basées sur des variables
d’environnement, des tags ou des changements spécifiques dans le code.
Cela permet une flexibilité et une personnalisation élevées, adaptant
vos pipelines aux besoins spécifiques de votre projet.
Exemple : Éviter les exécutions redondantes de pipelines
Imaginons un cas où vous souhaitez éviter que le même pipeline soit
déclenché à la fois par un push et par un tag
sur le même commit. En effet, si vous créez un tag avec la
commande git tag <tagname>, le tag sera
créé localement. Vous devrez donc poursuivre votre travail par un
git push origin --tags. Ceci est un scénario courant où des
pipelines redondants peuvent se lancer si les règles ne sont pas bien
configurées. Voici comment workflow peut être utilisé pour
gérer cela :
workflow:
rules:
- if: "$CI_COMMIT_TAG"
when: never
- when: alwaysDans cet exemple, aucun pipeline n’est créé quand on pousse un tag
(when: never). Tous les autres événements continuent de
créer un pipeline. Un commit poussé sur une branche déclenche donc
toujours son pipeline, mais pas le git push origin --tags
correspondant.
Exemple : Gérer les pipelines pour les merge requests
Un autre cas d’usage fréquent est la gestion des pipelines pour les
merge requests. Imaginez que vous avez ouvert une merge request et pour
une raison quelconque, un commit est poussé sur la branche de la merge
request. Vous ne voulez pas que le pipeline se déclenche à la fois pour
le commit et pour la merge request. Voici comment workflow
peut être utilisé pour gérer cela :
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: always
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- if: $CI_COMMIT_BRANCH
when: alwaysDans cette configuration, le pipeline se déclenche uniquement pour les événements de merge requests. Si un commit est poussé sur une branche qui a une merge request ouverte, le pipeline ne se déclenchera pas séparément pour cette branche, évitant ainsi des exécutions en double.
Ces exemples illustrent le fonctionnement de la directive
workflow pour affiner la logique de déclenchement de vos
pipelines dans GitLab CI/CD, vous permettant ainsi de gérer efficacement
les ressources et d’éviter des exécutions inutiles ou redondantes.
Combinaison
stratégique de rules et workflow
L’intégration et l’orchestration efficaces des pipelines dans GitLab
CI/CD peuvent être grandement améliorées en combinant judicieusement les
rules au niveau des jobs avec la directive
workflow pour le pipeline global. Cette combinaison permet
une gestion fine et une optimisation des déclenchements et exécutions
des jobs, adaptant ainsi les pipelines aux exigences spécifiques et aux
conditions de votre projet.
Exemple : Gestion de pipelines en fonction des branches et des événements
Imaginez un scénario où vous souhaitez exécuter des jobs différents en fonction de la branche sur laquelle les commits sont poussés, tout en gérant globalement le déclenchement des pipelines pour éviter les redondances. Voici comment cela peut être configuré :
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH =~ /^release-/)'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
deploy:
script: deploy.sh
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
- if: "$CI_COMMIT_BRANCH =~ /^release-/"
when: on_success
test:
script: test.sh
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'Ici, le job deploy est configuré pour s’exécuter
manuellement sur la branche principale et automatiquement en cas de
succès sur les branches commençant par release-. Le job
test est quant à lui déclenché uniquement pour les merge
requests. Le workflow global est configuré pour déclencher
le pipeline pour les push sur la branche principale, les
événements de planification et les événements de merge requests, tout en
évitant les déclenchements redondants.
En comprenant et en appliquant ces concepts dans vos projets, vous pourrez assurer que vos pipelines ne sont pas seulement fonctionnels, mais qu’ils sont également conçus de manière à répondre efficacement aux changements et exigences de votre environnement de développement. Cela conduira à une intégration et une livraison continues plus robustes, fiables et efficientes, un objectif clé dans toute démarche DevOps.
Exercices 1, comprendre les conditions
En parcourant un dépôt GitLab, vous trouvez le fichier
.gitlab-ci.yml suivant :
stages:
- build
- test
- deploy
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: "$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS"
when: never
- if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"💬 Comment connaître le nom de la branche par défaut
$CI_DEFAULT_BRANCH de ce dépôt ?
💬 Quels sont les autres mots clés utilisables avec la variable
$CI_PIPELINE_SOURCE ?
💬 Quel est le comportement du pipeline si un commit est poussé sur la branche principale ?
💬 Quel est le comportement du pipeline si un commit est poussé sur une branche qui a une merge request ouverte ?
push) n’est pas créé,
car la règle 2 correspond ($CI_COMMIT_BRANCH et
$CI_OPEN_MERGE_REQUESTS sont définies) et applique
when: never. En revanche, ce push génère un
événement de merge request, et le pipeline de merge request est créé
grâce à la règle 1. Il n’y a donc qu’un seul pipeline, pas deux.
Merge request, tag et API GitLab
Objectif
Prendre en main trois opérations :
- créer et fusionner une merge request
- créer et pousser un tag
- interroger l’API GitLab depuis un job exécuté par le runner
L’appel à l’API permettra de récupérer les informations du job en cours d’exécution.
Lisez toute la consigne avant de commencer. La configuration CI/CD doit être enregistrée dans la branche source avant d’ouvrir la merge request.
Environnement
Pour cet exercice, vous travaillerez sur une instance fournie en VM (VMWare). Ce sera la même instance que vous aurez à l’évaluation finale.
- GitLab local : http://192.168.177.129
- Outil de travail : Git Bash.
- Runner disponible : exécuteur Shell utilisant Bash sous Linux.
- Tag du runner :
shell. - Git et curl sont installés sur la machine du runner.
Tous les messages de commit, y compris ceux des commits de fusion, doivent respecter Conventional Commits : https://www.conventionalcommits.org/en/v1.0.0/
Le tag demandé est v0.0.1.
Créer le projet
- Créer dans GitLab un projet vide nommé
preparation324, sans README initial. - Créer le dépôt local correspondant, avec
maincomme branche initiale. - Ajouter le remote
originpointant vers le projet distant. - Créer un fichier
README.mdcontenant :
# Préparation CI/CD
Mon premier exercice avec GitLab (VM).- Committer le fichier et pousser
main. - Vérifier que
mainest la branche par défaut du projet GitLab.
Préparer la branche de travail
Créer une branche nommée exercice depuis
main.
Sur cette branche :
- Ajouter à la fin du README la ligne suivante :
Je prépare ma première merge request.
- Créer un fichier
.gitlab-ci.ymlà la racine du dépôt. - Configurer les deux jobs décrits dans la section suivante.
- Committer les fichiers et pousser la branche.
Configurer les jobs
Les pipelines doivent être créés uniquement pour les merge requests et lors du push d’un tag.
Un push de branche sans MR ne doit pas créer de pipeline. Après la fusion de la MR, le push résultant sur main ne doit pas créer de pipeline supplémentaire.
Les noms imposés sont des noms de jobs. Le nom visible du pipeline est libre.
Job bonjour-mr
Ce job s’exécute uniquement dans un pipeline de merge request.
Il affiche dans les logs :
Bonjour depuis la merge request
Job appel-api
Ce job s’exécute uniquement lors du push d’un tag.
Il doit :
- Afficher le nom du tag dans les logs.
- Effectuer une requête GET avec
curlvers l’API GitLab pour obtenir les informations du job en cours. - Afficher directement la réponse JSON dans les logs.
Informations utiles :
| Élément | Valeur ou utilité |
|---|---|
| Méthode HTTP | GET |
| Point d’entrée | /job, relativement à l’URL de base de l’API |
CI_API_V4_URL |
URL de base de l’API GitLab |
CI_JOB_TOKEN |
Jeton automatiquement fourni par GitLab |
| En-tête d’authentification | JOB-TOKEN |
CI_COMMIT_TAG |
Nom du tag |
Le point d’entrée /job renvoie les informations du job
associé au jeton utilisé. Aucun token personnel n’est nécessaire.
L’appel doit être effectué depuis le script du job. Il suffit d’afficher le JSON : aucun traitement de la réponse n’est demandé.
Documentation : http://192.168.177.129:4000/19.5/api/jobs/#retrieve-a-job-by-job-token
Ne jamais afficher la valeur de CI_JOB_TOKEN dans les
logs ni la placer dans le dépôt.
Créer et fusionner la merge request
Dans GitLab :
- Créer une merge request de
exerciceversmain. - Vérifier qu’un pipeline démarre avec uniquement
bonjour-mr. - Vérifier le message affiché dans les logs.
- Fusionner la merge request avec un message de commit conforme.
Créer et pousser le tag
Dans Git Bash :
- Revenir sur
main. - Récupérer les modifications fusionnées dans GitLab.
- Créer le tag
v0.0.1sur le commit courant. - Pousser ce tag vers GitLab.
Dans GitLab :
- Vérifier qu’un pipeline démarre avec uniquement
appel-api. - Ouvrir les logs.
- Vérifier que le nom du tag et la réponse JSON sont affichés.
- Repérer dans la réponse l’identifiant du job, son nom et la référence Git utilisée.
default:
tags:
- shell
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_TAG'
- when: never
stages:
- preparation
bonjour-mr:
stage: preparation
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
script:
- echo "Bonjour depuis la merge request"
appel-api:
stage: preparation
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_TAG'
script:
- echo "$CI_COMMIT_TAG"
- |
curl --fail-with-body --silent --show-error \
--request GET \
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
"${CI_API_V4_URL}/job"Currency converter, projet complet 😟
Objectif
Être en mesure de créer un pipeline GitLab CI/CD complet pour un projet de conversion de devises en utilisant les conditions de déclenchement et les règles de workflow.
Le travail s’effectue dans des branches séparées. Interdictions de
travailler directement sur la branche main.
Le pipeline doit inclure les étapes suivantes :
- [T] Passer un linter sur le code. Si le linter retourne des erreurs, le pipeline doit s’arrêter.
- [T] Exécuter les tests unitaires. Si un des tests échoue, le pipeline doit s’arrêter.
- [T] Générer un fichier
Changelog.mdcontenant les modifications apportées en se basant sur les messages de commit. - [M] Builder le site web. Si le build échoue, le pipeline doit s’arrêter.
- [M] Créer un artifact
docs.zipcontenant le site web de documentation. Ce fichier zip pourra être téléchargé pendant 1 heure depuis l’interface GitLab, dézippé dans un dossierwwwde Laragon par exemple, et visualisé. - [M] Déployer le site web builder sur un serveur de staging. Le déploiement doit être manuel ⏵.
[T] = Toujours, [M] = Uniquement lors d’un merge request sur main
Pour pouvoir déployer le site web sur un serveur de staging, vous devez disposer d’un accès FTP. Reportez-vous aux exercices précédent.
Pour le nom d’utilisateur et le mot de passe à utiliser avec la connexion FTP, vous devez utiliser les variables CI/CD. L’utilisation est détaillée dans la vidéo de M. Droz.

image: node:20
stages:
- lint
- test
- changelog
- build
- package
- deploy
# Règles du pipeline entier
workflow:
rules:
# Pipeline de merge request : toujours créé
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# Push sur une branche qui a une MR ouverte : pas de doublon
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
# Pas de pipeline sur la branche principale (on ne travaille pas dessus)
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never
# Push sur toutes les autres branches de travail
- if: '$CI_COMMIT_BRANCH'
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
# Règle réutilisable : uniquement lors d'une MR vers main
.only_mr_to_main:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'
# ---------- [T] Toujours ----------
lint:
stage: lint
script:
- npm ci
- npm run lint # code de sortie non nul = job en échec = pipeline arrêté
unit-tests:
stage: test
script:
- npm ci
- npm test # un test qui échoue arrête le pipeline
changelog:
stage: changelog
variables:
GIT_DEPTH: "0" # historique complet pour lire les commits
script:
- git fetch origin "$CI_DEFAULT_BRANCH"
- echo "# Changelog" > Changelog.md
- echo "" >> Changelog.md
- git log --pretty=format:"- %s (%h, %an)" "origin/$CI_DEFAULT_BRANCH..HEAD" >> Changelog.md
artifacts:
paths:
- Changelog.md
expire_in: 1 week
# ---------- [M] Uniquement lors d'une MR vers main ----------
build-site:
stage: build
extends: .only_mr_to_main
script:
- npm ci
- npm run build # échec du build = pipeline arrêté
artifacts:
paths:
- dist/
expire_in: 1 hour
docs-zip:
stage: package
extends: .only_mr_to_main
dependencies: [] # pas besoin des artifacts de build-site
script:
- npm ci
- npm run docs # génère la doc à partir des commentaires du code source
- apt-get update && apt-get install -y zip
- cd docs && zip -r ../docs.zip .
artifacts:
name: docs
paths:
- docs.zip
expire_in: 1 hour # téléchargeable pendant 1 heure
deploy-staging:
stage: deploy
image: alpine:3.20
environment:
name: staging
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'
when: manual # déploiement déclenché à la main
allow_failure: false
needs:
- job: build-site
artifacts: true
script:
- apk add --no-cache lftp
- lftp -u "$FTP_USER","$FTP_PASSWORD" "$FTP_HOST" -e "mirror -R --delete dist/ $FTP_DIR; quit"
