Pourquoi GitHub Actions (et pas Jenkins)
Après 8 ans avec Jenkins, j’ai migré tous mes projets vers GitHub Actions en 2023. Voici pourquoi.
Jenkins
- Configuration en XML/Groovy (complexe)
- Serveur à maintenir
- Plugins cassés à chaque update
- 2-3h/mois de maintenance
GitHub Actions
- Configuration en YAML (simple)
- Infrastructure managée
- Marketplace avec 10,000+ actions
- 0h de maintenance
Cas réel : startup avec 4 apps Next.js
- Avant (Jenkins) : 2 jours pour setup CI/CD
- Après (GitHub Actions) : 3 heures
Pipeline complet : de git push à production
Architecture cible
git push
↓
[GitHub Actions]
↓
┌─────────────┬─────────────┬─────────────┐
│ Tests │ Build │ Deploy │
│ - Lint │ - Docker │ - Staging │
│ - Unit │ - Optimize │ - Prod │
│ - E2E │ │ │
└─────────────┴─────────────┴─────────────┘
Étape 1 : Tests & Lint
.github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${"$"}{"{"}"{"{"} matrix.node-version {"}"}"}"}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run type-check
- name: Unit tests
run: npm run test:unit -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
flags: unittests
Temps d’exécution : 2-3 minutes
Étape 2 : Build Docker
name: Build
on:
push:
branches: [main]
tags: ['v*']
jobs:
build:
runs-on: ubuntu- latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${"$"}{"{"}"{"{"} github.actor {"}"}"}"}
password: ${"$"}{"{"}"{"{"} secrets.GITHUB_TOKEN {"}"}"}"}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${"$"}{"{"}"{"{"} github.repository {"}"}"}"}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={"{"}{"{"}version{"}"}"}
type=sha
- name: Build and push
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
Optimisation : cache Docker layers → build en 45s au lieu de 5 minutes
Étape 3 : Deploy automatique
Staging (automatique sur develop)
name: Deploy Staging
on:
push:
branches: [develop]
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.votreapp.ch
steps:
- name: Deploy to 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'
working-directory: ./
Production (manuel avec approbation)
name: Deploy Production
on:
workflow_dispatch: # Déclenchement manuel
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://votreapp.ch
steps:
- uses: actions/checkout@v4
- 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-1
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster production \
--service app-service \
--force-new-deployment
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{"{"}
"text": "✅ Deployed to production: ${"$"}{"{"}"{"{"} github.sha {"}"}"}"}",
"blocks": [
{"{"}
"type": "section",
"text": {"{"}
"type": "mrkdwn",
"text": "*Deployment successful*\n\nCommit: ${"$"}{"{"}"{"{"} github.sha {"}"}"}"}"
{"}"}
{"}"}
]
{"}"}
env:
SLACK_WEBHOOK_URL: ${"$"}{"{"}"{"{"} secrets.SLACK_WEBHOOK {"}"}"}"}
Patterns avancés
1. Tests E2E parallélisés
e2e:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4] # 4 workers parallèles
steps:
- uses: actions/checkout@v4
- name: Run Playwright
run: npx playwright test --shard=${"$"}{"{"}"{"{"} matrix.shard {"}"}"}"}/4
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report-${"$"}{"{"}"{"{"} matrix.shard {"}"}"}"}
path: playwright-report/
Gain : tests E2E en 3 minutes au lieu de 12
2. Matrix builds multi-plateforme
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20]
runs-on: ${"$"}{"{"}"{"{"} matrix.os {"}"}"}"}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${"$"}{"{"}"{"{"} matrix.node {"}"}"}"}
- run: npm ci && npm test
3. Déploiement conditionnel
deploy:
if: |
github.ref == 'refs/heads/main' &&
!contains(github.event.head_commit.message, '[skip ci]')
steps:
- name: Deploy
run: npm run deploy
4. Cache intelligent
- name: Cache node modules
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
.next/cache
key: ${"$"}{"{"}"{"{"} runner.os {"}"}"}"}-node-${"$"}{"{"}"{"{"} hashFiles('**/package-lock.json') {"}"}"}"}
restore-keys: |
${"$"}{"{"}"{"{"} runner.os {"}"}"}"}-node-
Gain : npm install en 15s au lieu de 90s
5. Secrets par environnement
Settings → Environments → Create environment
deploy-staging:
environment: staging
steps:
- run: echo ${"$"}{"{"}"{"{"} secrets.DATABASE_URL {"}"}"}"}
# DATABASE_URL différent pour staging
deploy-prod:
environment: production
steps:
- run: echo ${"$"}{"{"}"{"{"} secrets.DATABASE_URL {"}"}"}"}
# DATABASE_URL différent pour production
Actions réutilisables (DRY)
.github/workflows/reusable-test.yml
name: Reusable Test
on:
workflow_call:
inputs:
node-version:
required: true
type: string
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${"$"}{"{"}"{"{"} inputs.node-version {"}"}"}"}
- run: npm ci && npm test
Utilisation
jobs:
test-node-18:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '18'
test-node-20:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
Monitoring & Alertes
1. Slack notifications
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"{"}
"text": "❌ Build failed: ${"$"}{"{"}"{"{"} github.workflow {"}"}"}"}",
"blocks": [
{"{"}
"type": "section",
"text": {"{"}
"type": "mrkdwn",
"text": "*Build Failed*\n\nWorkflow: ${"$"}{"{"}"{"{"} github.workflow {"}"}"}"}\nCommit: ${"$"}{"{"}"{"{"} github.sha {"}"}"}"}\nActor: @${"$"}{"{"}"{"{"} github.actor {"}"}"}"}"
{"}"}
{"}"},
{"{"}
"type": "actions",
"elements": [
{"{"}
"type": "button",
"text": {"{"}"type": "plain_text", "text": "View Logs"{"}"},
"url": "${"$"}{"{"}"{"{"} github.server_url {"}"}"}"}/$ {"$"}{"{"}"{"{"} github.repository {"}"}"}"}/actions/runs/${"$"}{"{"}"{"{"} github.run_id {"}"}"}"}"
{"}"}
]
{"}"}
]
{"}"}
env:
SLACK_WEBHOOK_URL: ${"$"}{"{"}"{"{"} secrets.SLACK_WEBHOOK {"}"}"}"}
2. Métriques de performance
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
https://staging.votreapp.ch
https://staging.votreapp.ch/pricing
uploadArtifacts: true
temporaryPublicStorage: true
Exemples réels d’optimisation
Avant
# 12 minutes pour tout le pipeline
jobs:
test:
- npm install # 2 min
- npm test # 8 min
build:
- npm install # 2 min (re-download!)
- npm build # 3 min
Après
# 5 minutes avec cache + parallelisation
jobs:
test:
- cache restore # 10s
- npm ci # 20s
- npm test --shard # 3 min (4 workers)
build:
needs: test
- cache restore # 10s
- npm build # 2 min (cache)
Gain : -58% de temps d’exécution
Coûts
GitHub Actions pricing
- Public repos : gratuit illimité
- Private repos : 2,000 minutes/mois gratuites
- Au-delà : $0.008/minute
Exemple : 50 deploys/mois × 5 min = 250 min → gratuit
vs Jenkins : serveur $80/mois + maintenance → GitHub Actions est moins cher.
Checklist migration Jenkins → GitHub Actions
Préparation
[ ] Inventaire des jobs Jenkins
[ ] Identifier les dépendances
[ ] Documenter les secrets/credentials
Migration
[ ] Créer .github/workflows/ci.yml
[ ] Tester sur feature branch
[ ] Configurer environments (staging/prod)
[ ] Migrer secrets vers GitHub Secrets
Validation
[ ] Tests passent ✓
[ ] Build fonctionne ✓
[ ] Deploy automatique ✓
[ ] Notifications configurées ✓
Cleanup
[ ] Désactiver Jenkins jobs
[ ] Archiver configuration Jenkins
Ressources
- GitHub Actions Marketplace : https://github.com/marketplace
- Workflow syntax : https://docs.github.com/actions
- Awesome Actions : https://github.com/sdras/awesome-actions
Besoin d’aide pour setup votre CI/CD avec GitHub Actions ? Contactez-moi.