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
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
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/
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 }}
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
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
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
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
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'
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
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
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.'
})
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)