Passer au contenu principal

🚀 Qu'est-ce que le CI/CD ?

📖 Définition

CI/CD signifie Continuous Integration (Intégration Continue) et Continuous Deployment (Déploiement Continu), une méthodologie de développement qui teste et déploie automatiquement les modifications de code. CI compile et teste automatiquement le code à chaque fusion, tandis que CD déploie automatiquement le code testé dans les environnements de production. Cela permet de détecter rapidement les bugs et de raccourcir les cycles de déploiement.

🎯 Comprendre par analogies

Ligne d'automatisation d'usine

Développement traditionnel (Manuel)
Développeur 1 → Écrire du code
Développeur 2 → Écrire du code
Développeur 3 → Écrire du code

Une semaine plus tard

Le chef fusionne manuellement

Conflits surviennent ! 😱

Tests manuels

Bugs trouvés ! 😱

Déploiement manuel

Déploiement échoué ! 😱

CI/CD (Automatisé)
Développeur 1 → Push code → Test auto ✅ → Deploy auto 🚀
Développeur 2 → Push code → Test auto ✅ → Deploy auto 🚀
Développeur 3 → Push code → Test auto ❌ → Alerte immédiate !
(Problèmes détectés et corrigés immédiatement)

Livraison de nourriture

Déploiement manuel = Livraison directe
1. Préparer nourriture (Développement)
2. Vérifier emballage (Tests)
3. Confirmer adresse (Configuration)
4. Conduire et livrer (Déploiement)
5. Confirmation client (Vérification)
→ Long et sujet aux erreurs

CI/CD = Système de livraison automatique
1. Préparer nourriture (Développement)
2. Emballage automatique (Build auto)
3. Contrôle qualité auto (Tests auto)
4. Robot livraison auto (Déploiement auto)
5. Suivi en temps réel (Monitoring)
→ Rapide et précis

⚙️ Comment ça fonctionne

1. Pipeline CI/CD

Push de code

┌─────────────────────────────┐
│ CI: Intégration Continue │
│ │
│ 1. Checkout code │
│ 2. Installer dépendances │
│ 3. Vérification lint │
│ 4. Build │
│ 5. Tests unitaires │
│ 6. Tests d'intégration │
│ │
│ ✅ Tout réussi │
│ ❌ Échec quelconque → Stop │
└─────────────────────────────┘

┌─────────────────────────────┐
│ CD: Déploiement Continu │
│ │
│ 1. Déployer en staging │
│ 2. Tests E2E │
│ 3. Déployer en production │
│ 4. Health check │
│ 5. Envoyer notifications │
└─────────────────────────────┘

🎉 Déploiement terminé !

2. Approche traditionnelle vs CI/CD

Approche traditionnelle
┌─────────────────────────────────────┐
│ Lundi │
│ - Développeur A : Fonctionnalité 1 │
│ - Développeur B : Fonctionnalité 2 │
│ - Développeur C : Corriger bug │
├─────────────────────────────────────┤
│ Mardi-Jeudi │
│ - Développement individuel continu │
│ - Risque de conflits augmente 😰 │
├─────────────────────────────────────┤
│ Vendredi (Jour d'intégration) │
│ - Fusionner tout le code │
│ - Toute la journée à résoudre conflits 😱│
│ - Exécuter tests → Beaucoup de bugs │
│ - Heures supplémentaires jusqu'au week-end 😭│
└─────────────────────────────────────┘

Approche CI/CD
┌─────────────────────────────────────┐
│ Chaque jour, chaque commit │
│ │
│ Développeur A : Push code │
│ → Test auto ✅ │
│ → Deploy auto 🚀 │
│ → En production en 3 minutes │
│ │
│ Développeur B : Push code │
│ → Test auto ❌ │
│ → Alerte immédiate │
│ → Corriger immédiatement (5 min) │
│ │
│ - Conflits minimisés │
│ - Détection rapide des bugs │
│ - Sortir à l'heure 😊 │
└─────────────────────────────────────┘

3. Composants CI/CD

┌──────────────────────────────────────┐
│ Contrôle de version │
│ Git, GitHub, GitLab │
└───────────────┬──────────────────────┘
↓ Push
┌──────────────────────────────────────┐
│ Serveur CI │
│ GitHub Actions, Jenkins, CircleCI │
│ - Checkout code │
│ - Build automatique │
│ - Tests automatiques │
└───────────────┬──────────────────────┘
↓ Pass
┌──────────────────────────────────────┐
│ Dépôt d'artefacts │
│ Docker Hub, npm Registry │
└───────────────┬──────────────────────┘
↓ Deploy
┌──────────────────────────────────────┐
│ Déploiement │
│ AWS, Heroku, Vercel, Netlify │
└───────────────┬──────────────────────┘
↓ Monitor
┌──────────────────────────────────────┐
│ Monitoring │
│ Sentry, DataDog, CloudWatch │
└──────────────────────────────────────┘

💡 Exemples pratiques

Exemple de base GitHub Actions

# .github/workflows/ci.yml
# Pipeline CI/CD pour projet Node.js

name: CI/CD Pipeline

# Déclencheur : lors du push vers main ou création PR
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]

# Variables d'environnement
env:
NODE_VERSION: '18'

# Définition des jobs
jobs:
# ========== Job 1 : Tests ==========
test:
name: Tests et lint
runs-on: ubuntu-latest # Exécuter sur Ubuntu

steps:
# 1. Checkout code
- name: Checkout code
uses: actions/checkout@v3

# 2. Configurer Node.js
- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm' # Utiliser le cache npm

# 3. Installer dépendances
- name: Installer dépendances
run: npm ci # Plus rapide et stable que npm install

# 4. Vérification lint
- name: Exécuter lint
run: npm run lint

# 5. Tests unitaires
- name: Exécuter tests
run: npm test

# 6. Couverture du code
- name: Uploader couverture
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}

# ========== Job 2 : Build ==========
build:
name: Build
needs: test # S'exécute seulement si test réussit
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Installer dépendances
run: npm ci

# Build de production
- name: Build de production
run: npm run build
env:
NODE_ENV: production

# Uploader artefacts de build
- name: Uploader artefacts de build
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
retention-days: 7

# ========== Job 3 : Déploiement ==========
deploy:
name: Déploiement en production
needs: build # S'exécute seulement si build réussit
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # Déployer uniquement branche main

steps:
- name: Checkout code
uses: actions/checkout@v3

# Télécharger artefacts de build
- name: Télécharger artefacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/

# Déployer sur Vercel
- name: Déployer sur Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'

# Notification Slack
- name: Notification Slack
if: always() # Exécuter indépendamment du succès/échec
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Déploiement ${{ job.status }} !'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Build et déploiement Docker

# .github/workflows/docker.yml
# Build et déploiement d'image Docker

name: Docker CI/CD

on:
push:
branches: [ main ]
tags:
- 'v*' # Exécuter lors de la création de tags comme v1.0.0

env:
DOCKER_IMAGE: myapp
DOCKER_REGISTRY: docker.io

jobs:
docker:
name: Build et Push Docker
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

# Configurer métadonnées Docker
- name: Extraire métadonnées Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha

# Configurer Docker Buildx (pour build multi-plateforme)
- name: Configurer Docker Buildx
uses: docker/setup-buildx-action@v2

# Se connecter à Docker Hub
- name: Se connecter à Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

# Build et push de l'image Docker
- name: Build et push de l'image Docker
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # Utiliser cache GitHub Actions
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64 # Multi-plateforme

# Déploiement (accès SSH au serveur et redémarrage du conteneur)
- name: Déploiement sur serveur
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker stop myapp || true
docker rm myapp || true
docker run -d \
--name myapp \
-p 3000:3000 \
--restart unless-stopped \
${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker system prune -af

Validation automatique de Pull Request

# .github/workflows/pr.yml
# Valider automatiquement lors de la création de PR

name: Pull Request Check

on:
pull_request:
types: [ opened, synchronize, reopened ]

jobs:
# ========== Vérification qualité du code ==========
lint:
name: Lint et Format Check
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: Installer dépendances
run: npm ci

# ESLint
- name: Exécuter ESLint
run: npm run lint

# Prettier
- name: Vérifier Prettier
run: npm run format:check

# Vérification des types TypeScript
- name: Vérifier types TypeScript
run: npm run type-check

# ========== Tests ==========
test:
name: Tests
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16, 18, 20] # Tester sur plusieurs versions de Node

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Installer dépendances
run: npm ci

- name: Exécuter tests
run: npm test -- --coverage

- name: Uploader résultats de tests
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.node-version }}
path: coverage/

# ========== Vérification sécurité ==========
security:
name: Vérification sécurité
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

# npm audit
- name: Audit sécurité npm
run: npm audit --audit-level=moderate

# Scan sécurité Snyk
- name: Scan sécurité Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# ========== Tests de performance ==========
performance:
name: Tests de performance
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: Installer dépendances
run: npm ci

- name: Build
run: npm run build

# Lighthouse CI
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
http://localhost:3000
uploadArtifacts: true

# ========== Commentaire PR ==========
comment:
name: Commentaire PR
needs: [lint, test, security]
runs-on: ubuntu-latest
if: always()

steps:
- name: Créer commentaire PR
uses: actions/github-script@v6
with:
script: |
const statuses = {
lint: '${{ needs.lint.result }}',
test: '${{ needs.test.result }}',
security: '${{ needs.security.result }}'
};

let message = '## 🤖 Résultat vérification CI\n\n';

for (const [job, status] of Object.entries(statuses)) {
const emoji = status === 'success' ? '✅' : '❌';
message += `${emoji} **${job}**: ${status}\n`;
}

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});

Tâches planifiées

# .github/workflows/scheduled.yml
# Tâches exécutées périodiquement

name: Scheduled Tasks

on:
schedule:
# Exécuter tous les jours à 9h (00:00 UTC)
- cron: '0 0 * * *'
workflow_dispatch: # Autoriser également l'exécution manuelle

jobs:
# ========== Vérification mises à jour dépendances ==========
dependency-check:
name: Vérifier mises à jour dépendances
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

# Vérifier npm outdated
- name: Vérifier paquets obsolètes
run: npm outdated || true

# Alternative à Dependabot
- name: Vérifier paquets modifiables
run: |
npx npm-check-updates

# ========== Backup ==========
backup:
name: Backup base de données
runs-on: ubuntu-latest

steps:
- name: Faire backup base de données
run: |
# En pratique, exécuter script backup base de données
echo "Backup de la base de données en cours..."

# Uploader vers S3
- name: Uploader backup vers S3
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Upload vers S3
run: |
aws s3 cp backup.sql s3://my-backups/$(date +%Y%m%d).sql

# ========== Monitoring performance ==========
performance-monitor:
name: Monitoring performance
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Exécuter Lighthouse
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
https://myapp.com
uploadArtifacts: true

# Notification Slack en cas de dégradation performance
- name: Notification dégradation performance
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
text: '⚠️ Les performances du site web ont diminué !'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Déploiement multi-environnement

# .github/workflows/multi-env.yml
# Déploiement par environnement : développement, staging, production

name: Multi-Environment Deployment

on:
push:
branches:
- develop # Environnement développement
- staging # Environnement staging
- main # Environnement production

jobs:
deploy:
name: Déploiement
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: Installer dépendances
run: npm ci

# Build selon environnement
- name: Build
run: npm run build
env:
NODE_ENV: ${{
github.ref == 'refs/heads/main' && 'production' ||
github.ref == 'refs/heads/staging' && 'staging' ||
'development'
}}

# Déploiement environnement développement
- name: Déploiement développement
if: github.ref == 'refs/heads/develop'
run: |
echo "Déploiement sur environnement développement..."
# Commande déploiement serveur développement
env:
API_URL: https://api-dev.myapp.com

# Déploiement environnement staging
- name: Déploiement staging
if: github.ref == 'refs/heads/staging'
run: |
echo "Déploiement sur environnement staging..."
# Commande déploiement serveur staging
env:
API_URL: https://api-staging.myapp.com

# Déploiement environnement production
- name: Déploiement production
if: github.ref == 'refs/heads/main'
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: task-definition.json
service: myapp-service
cluster: production-cluster
wait-for-service-stability: true
env:
API_URL: https://api.myapp.com

# Health Check après déploiement
- name: Health Check
run: |
sleep 30 # Attendre 30 secondes

URL=${{
github.ref == 'refs/heads/main' && 'https://myapp.com' ||
github.ref == 'refs/heads/staging' && 'https://staging.myapp.com' ||
'https://dev.myapp.com'
}}

STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL/health)

if [ $STATUS -eq 200 ]; then
echo "✅ Health Check réussi"
else
echo "❌ Health Check échoué : $STATUS"
exit 1
fi

# Notification succès déploiement
- name: Notification déploiement
if: success()
uses: 8398a7/action-slack@v3
with:
status: success
text: |
🚀 Déploiement terminé !
Environnement : ${{ github.ref_name }}
Commit : ${{ github.sha }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

🤔 Questions fréquentes

Q1. Quels sont les avantages de l'adoption du CI/CD ?

R:

✅ Principaux avantages :

1. Détection rapide des bugs
Traditionnel : Découverts après une semaine
CI/CD : Découverts en 5 minutes
→ 90% de réduction des coûts de correction

2. Temps de déploiement réduit
Traditionnel : 2 heures de déploiement manuel
CI/CD : 5 minutes de déploiement automatique
→ Plusieurs déploiements par jour possibles

3. Meilleure qualité du code
- Lint et tests automatiques
- Revue de code automatisée
- Moins de bugs

4. Productivité accrue des développeurs
- Éliminer les tâches manuelles
- Automatiser le travail répétitif
- Se concentrer uniquement sur le développement

5. Stabilité accrue
- Tests automatiques
- Rollback automatique
- Processus de déploiement cohérent

6. Meilleure collaboration
- Minimiser les conflits de code
- Retour rapide
- Processus transparent

Cas réel :
Entreprise A : Avant CI/CD
- Déploiement : 1 fois par mois
- Temps de déploiement : 4 heures
- Taux d'échec : 30%
- Temps de détection des bugs : Moyenne 3 jours

Entreprise A : Après CI/CD
- Déploiement : 10 fois par jour
- Temps de déploiement : 5 minutes
- Taux d'échec : 5%
- Temps de détection des bugs : Moyenne 10 minutes

Q2. GitHub Actions vs Jenkins vs CircleCI ?

R:

// ========== GitHub Actions ==========
Avantages :
- Intégration parfaite avec GitHub
- Gratuit (repos publics, 2000 min/mois gratuit)
- Configuration simple (fichiers YAML)
- Diverses actions dans Marketplace

Inconvénients :
- Dépendant de GitHub
- Workflows complexes limités

Idéal pour :
- Utiliser GitHub
- CI/CD simple
- Démarrage rapide nécessaire

Exemple :
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test

// ========== Jenkins ==========
Avantages :
- Le plus ancien et mature
- Écosystème de plugins étendu
- Personnalisation complète
- Auto-hébergé (sans coût)

Inconvénients :
- Configuration complexe
- UI obsolète
- Maintenance requise
- Courbe d'apprentissage abrupte

Idéal pour :
- Environnement sur site
- Pipelines complexes
- Intégration de systèmes legacy

// ========== CircleCI ==========
Avantages :
- Vitesse de build rapide
- Excellent support Docker
- Parallélisation forte
- UI intuitive

Inconvénients :
- Payant (tier gratuit limité)
- Support GitHub/GitLab uniquement

Idéal pour :
- Performance critique
- Utilisation intensive de Docker
- Tests parallèles nécessaires

// ========== Tableau comparatif ==========
Caractéristique| GitHub Actions | Jenkins | CircleCI
---------------|----------------|---------|----------
Prix | Gratuit(limité) | Gratuit | Payant
Configuration | Facile | Difficile| Moyen
Performance | Moyen | Élevé | Élevé
Intégration | GitHub parfait | Générique| Générique
Maintenance | Pas nécessaire | Nécessaire| Pas nécessaire
Docker | Moyen | Bon | Très bon

Recommandation :
- Petite équipe, utilisant GitHubGitHub Actions
- Grande équipe, exigences complexes → Jenkins
- Performance critique, budget disponible → CircleCI

Q3. Comment gérer les clés secrètes (Secrets) ?

R:

# ========== Configuration GitHub Secrets ==========
# Repository → Settings → Secrets and variables → Actions

# Utilisation
- name: Déploiement
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: npm run deploy

# ========== Secrets spécifiques par environnement ==========
# Repository → Settings → Environments

# Environnement production
environment: production
env:
API_URL: ${{ secrets.PROD_API_URL }}

# Environnement staging
environment: staging
env:
API_URL: ${{ secrets.STAGING_API_URL }}

# ========== Meilleures pratiques de sécurité ==========

# ✅ Bon exemple
- name: Déploiement
env:
# Obtenir depuis Secrets
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
run: |
# Utiliser variables d'environnement
aws s3 sync dist/ s3://my-bucket

# ❌ Mauvais exemple
- name: Déploiement
run: |
# Codé en dur dans le code (absolument interdit !)
export AWS_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# ========== Créer fichier .env ==========
- name: Créer fichier .env
run: |
cat << EOF > .env
API_URL=${{ secrets.API_URL }}
DATABASE_URL=${{ secrets.DATABASE_URL }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
EOF

# ========== Docker Secrets ==========
- name: Docker Build
env:
DOCKER_BUILDKIT: 1
run: |
docker build \
--secret id=api_key,env=API_KEY \
--secret id=db_url,env=DATABASE_URL \
-t myapp .

# Dockerfile
# syntax=docker/dockerfile:1
FROM node:18
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) npm install

# ========== Utiliser Vault (avancé) ==========
- name: Obtenir secrets depuis HashiCorp Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.mycompany.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/production api_key | API_KEY ;
secret/data/production db_url | DATABASE_URL

Q4. Que se passe-t-il quand les tests échouent ?

R:

# ========== Comportement par défaut : arrêter le pipeline ==========
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Exécuter tests
run: npm test
# Erreur tests → s'arrête ici
# Les étapes suivantes ne s'exécutent pas

deploy:
needs: test # S'exécute seulement si test réussit
runs-on: ubuntu-latest
steps:
- name: Déploiement
run: npm run deploy
# Cette étape ne s'exécute pas si test échoue ✅

# ========== Continuer malgré l'échec ==========
- name: Exécuter tests
run: npm test
continue-on-error: true # Continuer même si échec
# ⚠️ Non recommandé

# ========== Exécution conditionnelle ==========
- name: Notifier en cas d'échec
if: failure() # Seulement si étape précédente a échoué
uses: 8398a7/action-slack@v3
with:
status: failure
text: '❌ Tests échoués !'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

- name: Déployer en cas de succès
if: success() # Seulement si toutes les étapes réussissent
run: npm run deploy

- name: Toujours exécuter
if: always() # Exécuter indépendamment du succès/échec
run: npm run cleanup

# ========== Réessais ==========
- name: Tests instables (réessayer)
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: npm run test:e2e

# ========== Exemple de gestion d'erreurs ==========
- name: Tests
id: test
run: npm test

- name: Créer issue en cas d'échec tests
if: failure() && steps.test.outcome == 'failure'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '❌ Tests échoués',
body: 'Les tests ont échoué. Vérification nécessaire.',
labels: ['bug', 'ci']
});

# ========== Rollback ==========
- name: Déploiement
id: deploy
run: npm run deploy

- name: Rollback en cas d'échec déploiement
if: failure() && steps.deploy.outcome == 'failure'
run: |
echo "Déploiement échoué ! Rollback vers version précédente..."
npm run rollback

Q5. Comment réduire les coûts ?

R:

# ========== Utiliser le cache ==========
- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm' # Cache npm (50% plus rapide au build)

- name: Cacher dépendances
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

# ========== Exécution conditionnelle ==========
on:
push:
branches: [ main ]
paths: # Exécuter seulement si certains fichiers changent
- 'src/**'
- 'package.json'
# Ne pas exécuter si seulement README.md change → économie de coûts

# ========== Limiter exécutions concurrentes ==========
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # Annuler exécution précédente
# → Empêche duplication d'exécutions inutiles

# ========== Self-hosted runner ==========
# Utiliser serveur propre (gratuit)
jobs:
build:
runs-on: self-hosted # Ne consomme pas minutes GitHub Actions
steps:
- run: npm run build

# ========== Exécuter seulement jobs courts ==========
- name: Vérifier fichiers modifiés
id: changes
uses: dorny/paths-filter@v2
with:
filters: |
frontend:
- 'frontend/**'
backend:
- 'backend/**'

- name: Tests frontend
if: steps.changes.outputs.frontend == 'true'
run: npm run test:frontend
# Exécuter seulement si frontend modifié → économie de temps

- name: Tests backend
if: steps.changes.outputs.backend == 'true'
run: npm run test:backend

# ========== Exemple de coûts ==========
# GitHub Actions Free Tier :
# - Repos publics : Illimité
# - Repos privés : 2000 minutes/mois

# Avant optimisation :
# - Tests complets à chaque commit (20 min)
# - 10x push par jour
# - Utilisation mensuelle : 10 × 20 × 30 = 6000 min
# - Surcoût : (6000 - 2000) × $0.008 = $32

# Après optimisation :
# - 10 min économisés avec cache
# - Tester seulement parties modifiées
# - Temps moyen build 5 min
# - Utilisation mensuelle : 10 × 5 × 30 = 1500 min
# - Coût : $0 (dans Free Tier)
# → $32/mois économisés !

🎓 Prochaines étapes

Une fois que vous comprenez le CI/CD, apprenez ces sujets :

  1. Qu'est-ce que Git ? (Document à écrire) - Fondamentaux du contrôle de version
  2. Qu'est-ce que Docker ? (Document à écrire) - Déploiement conteneurisé
  3. Qu'est-ce que le TDD ? (Document à écrire) - Développement piloté par les tests

Essayez-le

# ========== 1. Commencer avec GitHub Actions ==========

# 1) Créer fichier de workflow dans dépôt
mkdir -p .github/workflows
cat > .github/workflows/ci.yml << 'EOF'
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configurer Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm test
EOF

# 2) Commit et push
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git push

# 3) Voir onglet Actions sur GitHub
# → Voir le workflow s'exécuter automatiquement !

# ========== 2. Tester localement (act) ==========
# Utiliser act pour tester GitHub Actions localement

# Installer act (macOS)
brew install act

# Exécuter workflow
act push

# Exécuter seulement job spécifique
act -j test

# ========== 3. Exemples d'automatisation du déploiement ==========

# Déploiement Vercel
npm install -g vercel
vercel login
vercel --prod

# Déploiement Netlify
npm install -g netlify-cli
netlify login
netlify deploy --prod

# Déploiement Heroku
heroku login
git push heroku main

🎬 Conclusion

Le CI/CD est un outil essentiel dans le développement moderne :

  • CI : Tester et intégrer automatiquement les modifications de code
  • CD : Déployer automatiquement le code testé
  • Avantages : Retour rapide, stabilité améliorée, productivité accrue
  • Outils : GitHub Actions, Jenkins, CircleCI, etc.

Concentrez-vous sur le développement et déployez plus rapidement avec l'automatisation ! 🚀