Pipeline CI/CD

Le pipeline CI/CD automatise la validation qualité, les tests et le déploiement de l’application.

CI/CD : Continuous Integration / Continuous Deployment (Glossaire).

Workflows pratiques : voir fin de page pour exemples concrets.

Infrastructure

Le pipeline CI/CD s’appuie sur l’infrastructure décrite dans Architecture Technique :

  • VM autonome dataia (virsh/KVM) hébergeant l’ensemble

  • 2 containers Docker isolés : preprod (port 8500) et prod (port 8501)

  • Runner GitHub self-hosted orchestrant les déploiements automatiques

Cette architecture permet le déploiement sans connexion VPN manuelle. Le runner exécute git reset --hard SHA + docker-compose restart directement sur la VM.

Architecture Pipeline

Pipeline Parallèle avec Rollback Automatique

Push vers main
     │
     ├──────────────────────────────────────┐
     │                                       │
     ▼                                       ▼
┌─────────────────────────────────┐  ┌──────────────────────────────────┐
│  1. CI Pipeline                 │  │  2. CD Preprod                   │
│  (GitHub-hosted runners)        │  │  (Self-hosted runner)            │
│                                 │  │                                  │
│  - PEP8, Black, Docstrings      │  │  ⚡ DEPLOY FIRST (~40s)          │
│  - Tests unitaires              │  │  - Save rollback point           │
│  - Coverage ≥90%                │  │  - git reset --hard SHA          │
│  - Tests infrastructure         │  │  - docker-compose restart        │
│                                 │  │  - Health check                  │
│  Durée: ~2-3 minutes            │  │  - Launch CI watcher script      │
└────────────┬────────────────────┘  │                                  │
             │                       │  🔍 WATCH CI IN BACKGROUND       │
             │                       │  - Poll CI status (5 min max)    │
             │                       │                                  │
             ├───────────────────────┤                                  │
             │                       │                                  │
             ▼                       ▼                                  │
        ✅ CI SUCCESS          ❌ CI FAILURE                           │
             │                       │                                  │
             │                       ▼                                  │
             │              🔄 ROLLBACK AUTOMATIQUE                    │
             │              - git reset --hard last-validated-sha      │
             │              - docker-compose restart                   │
             │              - Notification Discord avec logs CI        │
             │                                                          │
             ▼                                                          │
        Marquer SHA validé                                             │
        Notification succès                                            │
└──────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  3. CD Production - Manuel avec confirmation            │
│     (Self-hosted runner sur VM dataia)                  │
│     - Backup automatique avant deploy                   │
│     - git reset --hard SHA validé                       │
│     - docker-compose restart                            │
│     - Health checks (3 tentatives)                      │
│     - Notifications Discord                             │
│     - URL: https://backtothefuturekitchen.lafrance.io/  │
└─────────────────────────────────────────────────────────┘

Avantages clés:

  • Déploiement ultra-rapide: 40s au lieu de 3-5 min (pas d’attente CI)

  • 🔒 Sécurité garantie: Rollback automatique si CI échoue

  • 🎯 Traçabilité: Chaque déploiement correspond exactement au SHA testé

  • 🔄 Runner libéré: Self-hosted runner disponible immédiatement

Workflows GitHub Actions

1. CI Pipeline

Fichier: .github/workflows/ci.yml

Déclencheurs:

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

Jobs exécutés:

Job 1: Quality Checks

  • PEP8 compliance (flake8) - ligne max 88 caractères

  • Code formatting (black)

  • Docstrings validation (pydocstyle) - Google style

  • Type checking (mypy) - optionnel, mode warning

Job 2: Tests Preprod

  • Python 3.13.7 avec uv

  • Coverage minimum: 90%

  • Commande: pytest tests/ -v --cov=src --cov-report=html --cov-fail-under=90

  • Artefacts: Rapport HTML coverage (30 jours rétention)

Job 3: Infrastructure Tests

  • Tests S3, DuckDB, SQL (50_test/)

  • Mode: continue-on-error (nécessite credentials)

Job 4: Summary

  • Résumé final tous les jobs

2. CD Preprod

Fichier: .github/workflows/cd-preprod.yml

Architecture innovante: Deploy First, Test in Parallel

Principe: Déployer immédiatement sans attendre le CI, puis rollback automatique si tests échouent.

Avantages:

  • ⚡ Déploiement ultra-rapide (~40 secondes au lieu de 3-5 minutes)

  • 🔄 Runner self-hosted libéré immédiatement

  • 🛡️ Sécurité garantie par rollback automatique

  • 🎯 Chaque déploiement correspond exactement au SHA testé

Phase 1: Déploiement Immédiat (~40s)

  1. 💾 Save rollback point (/var/app-state/last-validated-sha.txt)

  2. 📢 Notification Discord - Déploiement démarré

  3. 📥 Fetch commits - git fetch origin main

  4. 🔄 Deploy exact SHA - git reset --hard ${{ github.sha }}

  5. 🐳 Restart container - docker-compose -f docker-compose-preprod.yml restart

  6. 🔍 Quick health check - 3 tentatives sur https://mangetamain.lafrance.io/

  7. 👀 Launch watcher - Script background qui surveille le CI

  8. ✅ Notification Discord - Déploiement terminé, CI en cours

Phase 2: Surveillance CI en Background

Script watcher (/tmp/watch-ci-SHA.sh) :

  1. ⏳ Wait 30s - Attendre démarrage du CI

  2. 🔍 Poll CI status - Vérifier toutes les 10s pendant 5 minutes max

  3. Si CI réussit ✅ : Marquer SHA validé, notification succès

  4. Si CI échoue ❌ : Rollback automatique vers dernier SHA validé, notification avec détails

Logs du watcher: /tmp/ci-watcher-SHA.log

Pourquoi ``git reset –hard SHA`` au lieu de ``git pull`` ?

# ❌ MAUVAIS: git pull (prend le dernier commit de main)
git pull origin main

# ✅ BON: reset vers le SHA exact qui a déclenché ce workflow
git fetch origin main
git reset --hard acfdb42...  # SHA précis

Garantie: Code déployé = code testé par CI ✅

3. CD Production

Fichier: .github/workflows/cd-prod.yml

Déclenchement: Manuel uniquement (workflow_dispatch)

Confirmation obligatoire: Taper « DEPLOY » pour valider

Workflow:

  1. 📋 Confirmation utilisateur - Input « DEPLOY » requis

  2. 📊 État des environnements - Affiche PREPROD vs PROD SHA

  3. 💾 Backup automatique - Sauvegarde avant déploiement

  4. 📢 Notification Discord - Déploiement PROD démarré

  5. 🔄 Deploy deploy_preprod_to_prod.sh

  6. 🐳 Restart container - docker-compose -f docker-compose-prod.yml restart

  7. 🔍 Health checks - 5 tentatives avec retry

  8. ✅ Notification Discord - Succès ou échec avec instructions rollback

Rollback manuel si nécessaire:

ssh dataia
cd ~/mangetamain/20_prod
git reset --hard PREVIOUS_SHA
docker-compose -f ~/mangetamain/30_docker/docker-compose-prod.yml restart

4. Health Check Monitoring

Fichier: .github/workflows/health-check.yml

Fréquence: Toutes les heures (cron: 0 * * * *)

Vérifications:

Checks effectués:

  1. HTTP status 200

  2. Contenu HTML valide (présence « Mangetamain »)

  3. Timeout: 10 secondes

Notifications Discord: Alertes si service down

5. Documentation Build

Fichier: .github/workflows/documentation.yml

Déclencheurs:

on:
  push:
    branches: [main]
    paths:
      - '90_doc/source/**'
      - '90_doc/requirements.txt'
      - '.github/workflows/documentation.yml'
  workflow_dispatch:

Principe: Workflow complètement isolé du CI/CD preprod/prod. Un échec de build doc n’impacte jamais les déploiements applicatifs.

Workflow:

  1. 📦 Setup Python 3.13.7

  2. 📥 Install Sphinx dependencies (sphinx, sphinx-rtd-theme, myst-parser)

  3. 🔨 Build documentation (sphinx-build -b html source build/html)

  4. 📄 Add .nojekyll file (désactive Jekyll processing)

  5. 🚀 Deploy to GitHub Pages (branche gh-pages)

  6. 📬 Notification Discord (échecs uniquement)

URL Documentation: https://julienlafrance.github.io/backtothefuturekitchen/

Notifications Discord: Échecs uniquement (comme CI Pipeline)

Architecture Documentation:

90_doc/
├── source/         # Fichiers .rst (trackés dans Git)
│   ├── conf.py     # Configuration Sphinx
│   └── *.rst       # Pages documentation
├── build/          # HTML généré (ignoré par Git)
└── Makefile        # Commandes Sphinx

Workflow de mise à jour:

cd 90_doc/source
# Modifier les fichiers .rst
vim installation.rst

# Build local pour tester (optionnel)
cd ..
make html
firefox build/html/index.html

# Commit et push
git add source/
git commit -m "Doc: mise à jour installation"
git push

# → GitHub Actions build automatiquement
# → Doc publiée en 2-3 minutes sur GitHub Pages

Points clés:

  • 💾 HTML retiré du repo main (38 MB économisés)

  • ⚡ Build automatique sur push vers main

  • 🌐 Déploiement sur branche gh-pages séparée

  • 🔒 Workflow isolé: échec doc ≠ impact preprod/prod

  • 📝 Seuls les fichiers .rst sont trackés dans Git

Avantages GitHub Pages vs HTML tracké:

  • Statistiques GitHub correctes (Python au lieu de HTML)

  • Repo plus léger (-38 MB)

  • URL professionnelle et stable

  • Pas de pollution de l’historique Git avec HTML généré

Commandes Pratiques

Vérification Locale Avant Push

# Script de vérification local
./70_scripts/run_ci_checks.sh preprod   # Teste 10_preprod
./70_scripts/run_ci_checks.sh prod      # Teste 20_prod

Déclenchement Manuel Workflows

# Via GitHub CLI

# CD Preprod (déconseillé, normalement automatique)
gh workflow run cd-preprod.yml

# CD Production
gh workflow run cd-prod.yml

# Health Check
gh workflow run health-check.yml

Consulter Status CI/CD

# Liste des runs récents
gh run list --limit 10

# Voir logs d'un run spécifique
gh run view RUN_ID --log

# Watch run en temps réel
gh run watch RUN_ID

Consulter Logs Watcher PREPROD

ssh dataia
ls -lh /tmp/ci-watcher-*.log
tail -f /tmp/ci-watcher-LATEST.log

Runner Self-Hosted

Configuration

Localisation: VM dataia (réseau VPN)

Avantage: Déploiement sans connexion VPN manuelle

Labels: self-hosted, Linux, X64

Services: GitHub Actions Runner service

Vérifier État Runner

ssh dataia
sudo systemctl status actions.runner.*

# Logs du runner
journalctl -u actions.runner.* -f

Notifications Discord

Webhooks Configurés

  • CI Pipeline: Échecs uniquement

  • CD Preprod: Tous déploiements + rollbacks

  • CD Prod: Tous déploiements + rollbacks

  • Health Check: Alertes DOWN uniquement

  • Documentation: Échecs uniquement

Format Message Preprod

🚀 PREPROD - Déploiement démarré
SHA: acfdb42
Auteur: @user
Message: Fix bug analysis

⏳ CI en cours de vérification...

Format Message Prod

🎯 PRODUCTION - Déploiement réussi ✅
SHA: acfdb42
PREPROD ✅ → PROD ✅
URL: https://backtothefuturekitchen.lafrance.io/

Dépannage

Erreur: flake8 not found

Solution: Installer dépendances dev

cd ~/mangetamain/10_preprod
uv pip install -e ".[dev]"

Erreur: Coverage < 90%

Solution: Ajouter tests ou exclure code non-testable

# Dans le code à exclure
def main():  # pragma: no cover
    st.title("Application")

Erreur: Docstring manquante

Solution: Ajouter docstrings Google-style

def my_function():
    """Brief description of the function.

    Detailed description if needed.

    Args:
        param: Description

    Returns:
        Description
    """
    pass

CI échoue mais local fonctionne

Raisons possibles:

  • Versions Python différentes (CI: 3.13.7, Local: autre)

  • Fichiers non commités

  • Dépendances manquantes dans pyproject.toml

Solution:

# Vérifier fichiers non trackés
git status

# Mettre à jour dépendances
git add pyproject.toml
git commit -m "fix: mise à jour dépendances"

CD Preprod bloqué

Cause: Le CI a échoué, rollback automatique effectué

Solution: Corriger les erreurs signalées par le CI, puis push fix

Rollback Manuel Production

Si déploiement PROD échoué:

ssh dataia
cd ~/mangetamain/20_prod

# Trouver dernier SHA validé
git log --oneline -5

# Rollback
git reset --hard PREVIOUS_SHA
docker-compose -f ~/mangetamain/30_docker/docker-compose-prod.yml restart

# Vérifier
curl https://backtothefuturekitchen.lafrance.io/

Configuration Requise

Secrets GitHub

  • DISCORD_WEBHOOK_URL: Webhook Discord pour notifications

Variables Environnement

  • GITHUB_TOKEN: Token automatique GitHub Actions (fourni)

Runner Labels

  • self-hosted: Runner sur VM dataia

Métriques

Performance Pipeline

Phase

Durée

Runner

CI Quality

~2 minutes

GitHub-hosted

CI Tests

~2 minutes

GitHub-hosted

CD Preprod

~40 seconds

Self-hosted

CD Prod

~1 minute

Self-hosted

Health Check

~7 seconds

Self-hosted

Fiabilité

  • Uptime PREPROD: ~99.5%

  • Uptime PROD: ~99.9%

  • Rollbacks automatiques: 100% succès

  • Faux positifs health check: <1%

Exemples Workflows Concrets

Développement Feature

Scénario: Ajouter nouvelle analyse saisonnière

# 1. Créer branche
git checkout -b feature/analyse-mensuelle

# 2. Développer
# Modifier src/visualization/analyse_mensuelle.py
# Ajouter tests dans tests/unit/test_analyse_mensuelle.py

# 3. Vérifier localement
uv run flake8 src/ tests/
uv run pytest tests/unit/ --cov=src --cov-fail-under=90

# 4. Commit et push
git add .
git commit -m "Ajouter analyse mensuelle avec tests"
git push origin feature/analyse-mensuelle

# 5. Créer PR
gh pr create --title "Analyse mensuelle" --body "Nouvelle analyse par mois"

# → CI se lance automatiquement sur la branche
# → Si tests passent → Merge vers main possible
# → Après merge → CD PREPROD se lance automatiquement

Timeline:

Push branche → CI (2min) → PR review → Merge → CD PREPROD (40s) → App live
                ↓
            Tests OK/KO
                ↓
            Bloque merge si KO

Hotfix Production

Scénario: Bug critique en production nécessite fix immédiat

# 1. Identifier commit problématique
gh run list --limit 10
# Trouver dernier deploy PROD réussi

# 2. Créer branche hotfix
git checkout -b hotfix/fix-rating-bug

# 3. Fix rapide + test
# Modifier src/visualization/analyse_ratings.py
# Ajouter test regression

# 4. Push et merge rapide
git add . && git commit -m "Fix ratings bug critique"
git push origin hotfix/fix-rating-bug
gh pr create --title "[HOTFIX] Fix ratings" --body "Fix bug ratings 5 étoiles"

# 5. Après merge → Attendre CD PREPROD (auto)

# 6. Vérifier PREPROD OK puis deploy PROD manuel
gh workflow run cd-prod.yml
# Taper "DEPLOY" dans confirmation

Durée totale: ~5-10 minutes (CI + CD PREPROD + vérif + CD PROD)

Rollback Après Erreur

Scénario: Déploiement PROD casse l’app, besoin rollback immédiat

Option 1 - Rollback via Git :

# Sur VM dataia
ssh dataia
cd ~/mangetamain/20_prod

# Identifier commit stable
git log --oneline -10
# Ex: abc1234 Version stable avant bug

# Rollback
git reset --hard abc1234

# Redémarrer
cd ../30_docker
docker-compose -f docker-compose-prod.yml restart

Durée: ~1 minute

Option 2 - Rollback via Re-deploy :

# Localement, revenir au commit stable
git revert HEAD  # Ou git reset --hard <sha-stable>
git push origin main

# CI/CD PREPROD se lance
# Vérifier PREPROD OK

# Deploy PROD
gh workflow run cd-prod.yml  # Taper DEPLOY

Durée: ~5 minutes (plus sûr, passe par CI/CD)

Monitoring Déploiement

Surveiller en temps réel :

# Option 1: gh CLI
gh run watch

# Option 2: SSH + logs Docker
ssh dataia "docker-compose -f 30_docker/docker-compose-preprod.yml logs -f --tail=50"

# Option 3: Discord webhook
# Notifications automatiques dans channel #deployments

Vérifier health :

# PREPROD
curl -s https://mangetamain.lafrance.io/_stcore/health | jq

# PROD
curl -s https://backtothefuturekitchen.lafrance.io/_stcore/health | jq

Réponse attendue :

{
  "status": "ok",
  "uptime": 12345.67
}

Best Practices

Commits

Format messages :

<type>: <description courte>

<description détaillée optionnelle>

Types: feat, fix, docs, test, refactor, perf, ci

Exemples :

# Feature
git commit -m "feat: ajouter filtre saison dans analyse tendances"

# Bugfix
git commit -m "fix: corriger calcul moyenne ratings"

# Tests
git commit -m "test: ajouter tests analyse weekend (coverage +5%)"

# Documentation
git commit -m "docs: enrichir API visualization avec exemples"

Pull Requests

Template PR :

## Description
Brève description du changement

## Changements
- [ ] Ajout feature X
- [ ] Tests coverage ≥ 90%
- [ ] Documentation mise à jour

## Tests
```bash
pytest tests/unit/test_nouvelle_feature.py -v
```

## Screenshots (si UI)
![Before](url) ![After](url)

Review checklist :

  • Code suit PEP8 (flake8 passe)

  • Tests ajoutés (coverage ≥ 90%)

  • Documentation à jour

  • Pas de credentials committés

  • Branch à jour avec main

CI/CD

Éviter échecs CI :

# Avant chaque push, lancer localement
uv run flake8 src/ tests/
uv run black --check src/ tests/
uv run pytest tests/unit/ --cov=src --cov-fail-under=90

# Script pre-push hook (.git/hooks/pre-push)
#!/bin/bash
echo "Running pre-push checks..."
uv run flake8 src/ tests/ || exit 1
uv run pytest tests/unit/ --cov=src --cov-fail-under=90 || exit 1
echo "✓ All checks passed"

Optimiser CI :

  • Utiliser cache uv pour dépendances

  • Paralléliser tests indépendants

  • Skip CI si [skip ci] dans message commit (docs uniquement)

Déploiement

Checklist avant deploy PROD :

  1. ✅ PREPROD fonctionne correctement

  2. ✅ Tests manuels effectués sur PREPROD

  3. ✅ Pas d’erreurs dans logs PREPROD

  4. ✅ Performance acceptable (load time < 10s)

  5. ✅ Backup automatique effectué (vérifié)

Timing optimal :

  • Éviter : Vendredi soir, juste avant weekend

  • Préférer : Mardi-Jeudi matin (temps pour monitorer)

Communication :

  • Annoncer maintenance si downtime > 1 minute

  • Notifications Discord automatiques

Voir Aussi