Ce que vous saurez faire à la fin
- Construire une pipeline GitHub Actions complète qui build, teste et déploie automatiquement votre application à chaque push.
- Gérer les secrets (mots de passe, clés API, tokens) en sécurité sans jamais les exposer dans le code.
- Tester votre application sur plusieurs versions de Node.js, Python ou PHP en parallèle grâce aux matrices.
- Déployer automatiquement vers Vercel, Netlify ou AWS S3+CloudFront selon votre stack.
- Surveiller la santé de vos pipelines et recevoir des alertes Slack quand un déploiement échoue.
Durée : 4h. Pré-requis : Linux/Mac, Git, dépôt GitHub (gratuit), comptes Vercel/Netlify (gratuits), AWS si déploiement S3 (5 USD soit 3 000 FCFA/mois pour démarrer), budget total : 0 à 8 000 FCFA/mois.
Étape 1 — Comprendre la valeur du CI/CD pour une PME africaine
Sans CI/CD, le déploiement d’une mise à jour ressemble à ceci : le développeur pousse son code, un collègue tire les changements en local, lance les tests à la main, oublie souvent de tester un cas, fait un FTP vers le serveur de production, casse une fonctionnalité, et passe 2 heures à remettre l’ancienne version. Avec GitHub Actions bien configuré : le développeur pousse, 4 minutes plus tard la nouvelle version est en ligne, validée par 280 tests automatiques, et un message Slack confirme tout.
GitHub Actions offre 2 000 minutes gratuites par mois pour les dépôts privés (illimité pour les publics). Pour une PME qui déploie 5 fois par jour, cela couvre largement les besoins sans débourser un FCFA.
Étape 2 — Anatomie d’un workflow GitHub Actions
mkdir -p .github/workflows
cd .github/workflows
touch ci.yml
# La structure d'un fichier YAML d'Actions :
# name: nom lisible
# on: événements déclencheurs (push, pull_request, schedule, workflow_dispatch)
# jobs: groupes d'étapes qui tournent en parallèle ou en chaîne
# steps: actions atomiques (checkout, setup, run)
Chaque workflow vit dans un fichier YAML sous .github/workflows/. GitHub détecte automatiquement les fichiers et propose l’onglet « Actions » sur votre dépôt.
Étape 3 — Premier workflow : tests automatiques
name: CI Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
name: Tests Node.js
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Poussez ce fichier, allez sur GitHub onglet Actions, et observez le workflow tourner en moins de 3 minutes. Chaque commit suivant déclenchera la même validation.
Étape 4 — Tests sur plusieurs versions avec matrice
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
node: [18, 20, 22]
include:
- os: ubuntu-latest
node: 20
coverage: true
exclude:
- os: macos-latest
node: 18
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
- if: matrix.coverage
run: npm run coverage
Cette matrice lance 5 jobs en parallèle (3 versions de Node × 2 OS, moins une exclusion). Vous validez la compatibilité de votre librairie en moins de temps qu’un seul test séquentiel.
Étape 5 — Gérer les secrets correctement
GitHub : Settings > Secrets and variables > Actions > New repository secret
Secrets typiques à créer :
- DATABASE_URL : connexion PostgreSQL production
- VERCEL_TOKEN : token de déploiement Vercel
- AWS_ACCESS_KEY_ID : clé AWS
- AWS_SECRET_ACCESS_KEY : secret AWS
- SLACK_WEBHOOK_URL : webhook Slack pour alertes
- DOCKER_PASSWORD : mot de passe Docker Hub
- SENTRY_AUTH_TOKEN : pour upload sourcemaps
Les secrets sont chiffrés au repos et déchiffrés uniquement pendant l’exécution du workflow. Ils n’apparaissent jamais dans les logs (GitHub les masque automatiquement). Pour les variables non-sensibles (URL de prod, environnement), utilisez plutôt « Variables » dans la même section.
Étape 6 — Pipeline build complète pour une SPA React
name: Build & Deploy SPA
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
outputs:
artifact-id: ${{ steps.upload.outputs.artifact-id }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm run build
env:
VITE_API_URL: ${{ secrets.PROD_API_URL }}
VITE_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- id: upload
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: production
url: https://app.pme-dakar.sn
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- run: ls -la dist/
Le job « deploy » ne démarre qu’après réussite du job « build », grâce au needs. L’artifact (le dossier dist compilé) est partagé entre les jobs sans recompiler.
Étape 7 — Déployer sur Vercel
deploy-vercel:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Install Vercel CLI
run: npm install -g vercel@latest
- name: Pull Vercel env
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy
run: |
DEPLOY_URL=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }})
echo "DEPLOY_URL=$DEPLOY_URL" >> $GITHUB_ENV
- name: Comment URL on commit
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: 'Déployé sur ${{ env.DEPLOY_URL }}'
})
Vercel gratuit couvre 100 Go de bande passante par mois, suffisant pour une PME avec 30 000 visites/mois. Le déploiement complet prend moins de 90 secondes.
Étape 8 — Déployer sur Netlify
deploy-netlify:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: nwtgck/actions-netlify@v3.0
with:
publish-dir: "./dist"
production-branch: main
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: "Deploy from GitHub Actions"
enable-commit-comment: true
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
Netlify offre des previews automatiques pour chaque PR : un lien unique permet à votre client à Lomé de voir la nouvelle version avant le merge. Plan gratuit : 100 Go/mois et formulaires illimités.
Étape 9 — Déployer sur AWS S3 + CloudFront
deploy-aws:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-3
- name: Sync to S3
run: |
aws s3 sync dist/ s3://pme-app-prod \
--delete \
--cache-control "public, max-age=31536000, immutable" \
--exclude "index.html"
aws s3 cp dist/index.html s3://pme-app-prod/index.html \
--cache-control "no-cache, no-store, must-revalidate"
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
--paths "/*"
S3 + CloudFront pour un site statique coûte moins de 3 USD/mois (1 800 FCFA) pour un trafic raisonnable, avec une latence excellente partout en Afrique grâce aux edge locations à Lagos et Le Cap.
Étape 10 — Tableau comparatif des plateformes de déploiement
| Plateforme | Gratuit | Setup | Edge Afrique | Idéal pour |
|---|---|---|---|---|
| Vercel | 100 Go/mois | 5 min | Le Cap, Lagos | Next.js, SPA, JAMstack |
| Netlify | 100 Go/mois | 5 min | Johannesburg | Sites statiques, formulaires |
| Cloudflare Pages | Illimité | 10 min | 10 villes Afrique | Trafic massif gratuit |
| AWS S3+CF | 1 an gratuit | 30 min | Le Cap, Lagos | Contrôle total, gros volumes |
| Hetzner CX22 | Non (4 EUR/mois) | 1h | Falkenstein | Apps full-stack, bases |
| Render | Limité | 10 min | Frankfurt | API Node/Python, Postgres |
Étape 11 — Notifications Slack en cas d’échec
notify-failure:
needs: [build, deploy-vercel]
runs-on: ubuntu-latest
if: failure()
steps:
- name: Send Slack alert
uses: slackapi/slack-github-action@v1.27.0
with:
payload: |
{
"text": "Echec deploiement",
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "Pipeline echouee"}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Repo:* ${{ github.repository }}"},
{"type": "mrkdwn", "text": "*Auteur:* ${{ github.actor }}"},
{"type": "mrkdwn", "text": "*Branche:* ${{ github.ref_name }}"},
{"type": "mrkdwn", "text": "*Commit:* ${{ github.sha }}"}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
Configurez un webhook Slack en 3 minutes via api.slack.com/apps. Votre équipe reçoit l’alerte instantanément, plus besoin de surveiller les emails GitHub.
Étape 12 — Cache pour accélérer les builds
- name: Cache node_modules
uses: actions/cache@v4
with:
path: |
~/.npm
**/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache Cypress binary
uses: actions/cache@v4
with:
path: ~/.cache/Cypress
key: cypress-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- name: Cache build
uses: actions/cache@v4
with:
path: dist
key: build-${{ github.sha }}
Sans cache, npm ci prend 90 secondes. Avec cache, 12 secondes. Sur 50 builds par jour, vous économisez 65 minutes de runner et accélérez le feedback aux développeurs.
Étape 13 — Build Docker et push vers registre
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/metadata-action@v5
id: meta
with:
images: pmedakar/api
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix={{branch}}-
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Cette pipeline construit l’image Docker, génère plusieurs tags (latest, v1.2.3, sha), et la pousse sur Docker Hub. Le cache GHA réduit le build Docker de 5 minutes à 50 secondes.
Étape 14 — Surveillance et métriques de la pipeline
Activez les insights GitHub Actions (gratuit jusqu’à un certain seuil) pour visualiser : durée moyenne par job, taux d’échec, jobs les plus lents, coût en minutes consommées. Pour une PME, surveillez surtout : durée totale (cible < 6 minutes), taux d’échec (cible < 5%), temps de récupération après échec (cible < 30 minutes).
Outils tiers : Datadog CI Visibility (intégration native, à partir de 5 USD/mois soit 3 000 FCFA), ou Trunk.io (gratuit pour petites équipes) qui détecte les tests instables (flaky tests) et propose des correctifs.
Erreurs classiques à éviter
- Mettre les secrets dans le YAML : ils apparaissent en clair dans l’historique Git, scrapés par les bots en moins d’une heure. Toujours via Settings > Secrets.
- Pas de timeout sur les jobs : un job bloqué consomme toutes vos minutes gratuites. Ajoutez timeout-minutes: 15.
- Tester directement en production : définissez des environnements (staging, production) avec approbations manuelles pour la production.
- Oublier needs entre jobs : un déploiement démarre avant la fin des tests et peut pousser du code cassé.
- Utiliser @latest sur les actions : l’auteur peut pousser une mise à jour qui casse votre pipeline. Toujours pinner avec un tag SHA ou version (uses: actions/checkout@v4).
- Pas de cache : chaque build télécharge 200 Mo de dépendances, vous gaspillez 80% de vos minutes mensuelles.
Checklist pipeline GitHub Actions production-ready
✓ Workflow déclenché sur push main + pull_request
✓ Tests, lint et coverage exécutés sur chaque commit
✓ Matrice de versions (Node 18, 20, 22 ou équivalent)
✓ Secrets configurés dans Settings, jamais en dur
✓ Cache npm/pip/gradle activé pour accélérer
✓ Timeout-minutes défini sur chaque job (max 15)
✓ Environnements staging et production séparés
✓ Approbation manuelle requise pour production
✓ Notifications Slack ou Discord en cas d'échec
✓ Build artifacts uploadés et téléchargés entre jobs
✓ Actions pinned avec version (jamais @main ou @latest)
✓ Concurrency group pour annuler les anciens runs
✓ Permissions minimales déclarées (read-only par défaut)
✓ Code coverage minimum 70% requis pour merger
✓ Déploiement reversible (blue-green ou rollback automatique)