DEV Community

Ulrich (Houngbe)
Ulrich (Houngbe)

Posted on

CI/CD avec GitHub Actions

CI/CD avec GitHub Actions : Guide Complet

GitHub Actions révolutionne l'intégration et le déploiement continus en intégrant directement ces fonctionnalités dans votre repository GitHub. Ce guide vous accompagne dans la mise en place d'une pipeline CI/CD robuste.

Qu'est-ce que GitHub Actions ?

GitHub Actions est une plateforme d'automatisation qui permet de :

  • Exécuter des workflows basés sur des événements
  • Automatiser les tests, builds et déploiements
  • Créer des actions personnalisées réutilisables
  • S'intégrer parfaitement avec l'écosystème GitHub

Concepts Fondamentaux

1. Composants Clés

  • Workflow : Processus automatisé défini dans un fichier YAML
  • Job : Ensemble de steps qui s'exécutent sur un runner
  • Step : Action individuelle (commande ou action)
  • Runner : Machine virtuelle qui exécute les jobs
  • Action : Application réutilisable qui effectue une tâche

2. Structure d'un Workflow

name: CI/CD Pipeline

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm ci
      - name: Run tests
        run: npm test
Enter fullscreen mode Exit fullscreen mode

Pipeline CI Complète

1. Workflow Python avec Tests

name: Python CI

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

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Cache pip dependencies
        uses: actions/cache@v3
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
          restore-keys: |
            ${{ runner.os }}-pip-

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install flake8 black mypy
          pip install -r requirements.txt

      - name: Lint with flake8
        run: |
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics

      - name: Format check with black
        run: black --check .

      - name: Type check with mypy
        run: mypy src/

  test:
    needs: lint
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest pytest-cov
          pip install -r requirements.txt

      - name: Run tests with coverage
        run: |
          pytest --cov=src --cov-report=xml --cov-report=html

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
          flags: unittests
          name: codecov-umbrella

  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run security scan
        uses: pypa/gh-action-pip-audit@v1.0.8
        with:
          inputs: requirements.txt

      - name: Run Bandit security check
        run: |
          pip install bandit
          bandit -r src/ -f json -o bandit-report.json

      - name: Upload security report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: security-report
          path: bandit-report.json
Enter fullscreen mode Exit fullscreen mode

2. Workflow Node.js/React

name: Node.js CI/CD

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

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16, 18, 20]

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

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

      - name: Install dependencies
        run: npm ci

      - name: Run linting
        run: npm run lint

      - name: Run type checking
        run: npm run type-check

      - name: Run unit tests
        run: npm test -- --coverage --watchAll=false

      - name: Run integration tests
        run: npm run test:integration

      - name: Build application
        run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-files-${{ matrix.node-version }}
          path: dist/

  e2e-tests:
    needs: test
    runs-on: ubuntu-latest

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

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

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Start application
        run: |
          npm run build
          npm run start &
          sleep 30

      - name: Run Playwright tests
        run: npx playwright test

      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
Enter fullscreen mode Exit fullscreen mode

Pipeline CD avec Déploiement

1. Déploiement sur AWS

name: Deploy to AWS

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Checkout code
        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: us-east-1

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

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build
        env:
          REACT_APP_API_URL: ${{ secrets.API_URL }}
          REACT_APP_ENV: production

      - name: Deploy to S3
        run: |
          aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete

      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

      - name: Notify Slack
        if: always()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          channel: '#deployments'
          webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
Enter fullscreen mode Exit fullscreen mode

2. Déploiement Docker

name: Docker Build and Deploy

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - name: Build and push Docker image
        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

      - name: Deploy to staging
        if: github.ref == 'refs/heads/main'
        run: |
          echo "Deploying to staging environment"
          # Commandes de déploiement ici
Enter fullscreen mode Exit fullscreen mode

Workflows Avancés

1. Matrix Strategy avec Conditions

name: Cross-platform Testing

on: [push, pull_request]

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.9', '3.10', '3.11']
        exclude:
          - os: windows-latest
            python-version: '3.9'

    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies (Unix)
        if: runner.os != 'Windows'
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: Install dependencies (Windows)
        if: runner.os == 'Windows'
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
        shell: cmd

      - name: Run tests
        run: pytest
Enter fullscreen mode Exit fullscreen mode

2. Déploiement Multi-Environnement

name: Multi-Environment Deploy

on:
  push:
    branches: [main, develop]

jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.example.com

    steps:
      - name: Deploy to Staging
        run: |
          echo "Deploying to staging"
          # Logique de déploiement staging

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com

    steps:
      - name: Deploy to Production
        run: |
          echo "Deploying to production"
          # Logique de déploiement production
Enter fullscreen mode Exit fullscreen mode

Actions Personnalisées

1. Action Composite

# .github/actions/setup-node-cache/action.yml
name: 'Setup Node with Cache'
description: 'Setup Node.js with dependency caching'

inputs:
  node-version:
    description: 'Node.js version'
    required: false
    default: '18'
  working-directory:
    description: 'Working directory'
    required: false
    default: '.'

runs:
  using: 'composite'
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'
        cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json

    - name: Install dependencies
      working-directory: ${{ inputs.working-directory }}
      run: npm ci
      shell: bash
Enter fullscreen mode Exit fullscreen mode

2. Usage de l'Action

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js with cache
        uses: ./.github/actions/setup-node-cache
        with:
          node-version: '18'
          working-directory: './frontend'
Enter fullscreen mode Exit fullscreen mode

Bonnes Pratiques

1. Sécurité

# Utilisation des secrets
steps:
  - name: Deploy with secrets
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
    run: |
      echo "API_KEY is set: ${API_KEY:+yes}"
      # Utiliser les secrets de manière sécurisée
Enter fullscreen mode Exit fullscreen mode

2. Optimisation des Performances

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

# Parallélisation des jobs
jobs:
  lint:
    runs-on: ubuntu-latest
  test:
    runs-on: ubuntu-latest
  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
Enter fullscreen mode Exit fullscreen mode

3. Monitoring et Notifications

  - name: Notify on failure
    if: failure()
    uses: actions/github-script@v7
    with:
      script: |
        github.rest.issues.createComment({
          issue_number: context.issue.number,
          owner: context.repo.owner,
          repo: context.repo.repo,
          body: '❌ Pipeline failed! Please check the logs.'
        })
Enter fullscreen mode Exit fullscreen mode

Conclusion

GitHub Actions offre une solution puissante et flexible pour l'automatisation :

  • Intégration native avec GitHub
  • Écosystème riche d'actions réutilisables
  • Scaling automatique des runners
  • Support multi-plateforme
  • Gestion fine des permissions

Une pipeline bien conçue améliore la qualité du code, réduit les risques de déploiement et accélère le cycle de développement. L'investissement initial en configuration est rapidement rentabilisé par la réduction des erreurs et l'automatisation des tâches répétitives.

Top comments (0)