← Retour au blog

GitHub Actions : CI/CD moderne sans Jenkins ni GitLab CI

Pipeline complet de 0 à production en 30 minutes. Tests, build, deploy multi-environnement avec GitHub Actions.

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

GitHub Actions

Cas réel : startup avec 4 apps Next.js

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

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


Besoin d’aide pour setup votre CI/CD avec GitHub Actions ? Contactez-moi.