GitHub Actions et CI/CD
Configurez des workflows d'intégration et de déploiement continus directement dans vos dépôts GitHub.
GitHub Actions et CI/CD
GitHub Actions révolutionne l’automatisation du développement logiciel en intégrant directement CI/CD dans vos dépôts. Ce tutoriel vous apprendra à créer des workflows puissants pour automatiser tests, builds et déploiements.
Introduction à GitHub Actions
Qu’est-ce que GitHub Actions ?
GitHub Actions est une plateforme d’automatisation qui permet de :
- Exécuter des workflows sur des événements Git
- Automatiser les tests et la validation
- Déployer automatiquement vos applications
- Gérer les releases et notifications
graph LR
A[Push/PR] --> B[GitHub Actions]
B --> C[Tests]
B --> D[Build]
B --> E[Deploy]
C --> F[Notifications]
D --> F
E --> F
Concepts clés
Workflow : Processus automatisé défini en YAML Job : Ensemble d’étapes exécutées sur un runner Step : Action individuelle dans un job Action : Composant réutilisable Runner : Machine virtuelle qui exécute les jobs
Structure d’un workflow
Fichier de base
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
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'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
Déclencheurs (Triggers)
# Événements Git
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
release:
types: [published]
# Événements programmés
on:
schedule:
- cron: '0 2 * * 1' # Tous les lundis à 2h
# Déclenchement manuel
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy'
required: true
default: 'staging'
Workflows essentiels
CI basique pour Node.js
# .github/workflows/node-ci.yml
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- 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 linter
run: npm run lint
- name: Run tests
run: npm test
- name: Run build
run: npm run build
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
CI pour Python
# .github/workflows/python-ci.yml
name: Python CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 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 -r requirements.txt
pip install -r requirements-dev.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=127
- name: Test with pytest
run: |
pytest --cov=./ --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
Déploiement automatique
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install and build
run: |
npm ci
npm run build
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.ORG_ID }}
vercel-project-id: ${{ secrets.PROJECT_ID }}
vercel-args: '--prod'
Actions avancées
Matrice de tests
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
include:
- os: ubuntu-latest
node-version: 20
coverage: true
exclude:
- os: windows-latest
node-version: 16
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Run tests
run: npm test
- name: Upload coverage
if: matrix.coverage
uses: codecov/codecov-action@v3
Conditions et expressions
jobs:
deploy:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Deploy to staging
if: contains(github.event.head_commit.message, '[staging]')
run: echo "Deploying to staging"
- name: Deploy to production
if: startsWith(github.ref, 'refs/tags/v')
run: echo "Deploying to production"
- name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Artifacts et cache
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install and build
run: |
npm ci
npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- name: Deploy
run: echo "Deploying files from dist/"
Sécurité et secrets
Gestion des secrets
# Configuration des secrets dans GitHub
# Settings > Secrets and variables > Actions
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to AWS
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: |
aws s3 sync ./dist s3://my-bucket
Environnements protégés
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to production
run: echo "Deploying to production environment"
Permissions GITHUB_TOKEN
name: Secure Workflow
on: [push]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run security scan
uses: github/super-linter@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Actions personnalisées
Action JavaScript
// .github/actions/hello-world/index.js
const core = require('@actions/core');
const github = require('@actions/github');
try {
const nameToGreet = core.getInput('who-to-greet');
console.log(`Hello ${nameToGreet}!`);
const time = (new Date()).toTimeString();
core.setOutput("time", time);
const payload = JSON.stringify(github.context.payload, undefined, 2);
console.log(`The event payload: ${payload}`);
} catch (error) {
core.setFailed(error.message);
}
# .github/actions/hello-world/action.yml
name: 'Hello World'
description: 'Greet someone and record the time'
inputs:
who-to-greet:
description: 'Who to greet'
required: true
default: 'World'
outputs:
time:
description: 'The time we greeted you'
runs:
using: 'node20'
main: 'index.js'
Utilisation de l’action
jobs:
hello_world_job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Hello world action step
uses: ./.github/actions/hello-world
id: hello
with:
who-to-greet: 'GitHub Actions'
- name: Get the output time
run: echo "The time was ${{ steps.hello.outputs.time }}"
Workflows complexes
Pipeline multi-environnements
# .github/workflows/multi-env-deploy.yml
name: Multi-Environment Deploy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: npm test
deploy-staging:
needs: test
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
run: echo "Deploying to staging"
deploy-production:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: echo "Deploying to production"
notify:
needs: [deploy-staging, deploy-production]
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify team
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Release automatique
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Generate changelog
id: changelog
uses: metcalfc/changelog-generator@v4.0.1
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: ${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: false
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/app.zip
asset_name: app.zip
asset_content_type: application/zip
Exercices pratiques
Exercice 1 : CI basique
# .github/workflows/basic-ci.yml
name: Basic CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
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'
- name: Install dependencies
run: |
echo '{"name": "test-app", "scripts": {"test": "echo \"Tests passed!\""}}' > package.json
npm install
- name: Run tests
run: npm test
- name: Success message
run: echo "✅ All tests passed!"
Exercice 2 : Déploiement conditionnel
# .github/workflows/conditional-deploy.yml
name: Conditional Deploy
on:
push:
branches: [main, staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
if: github.ref == 'refs/heads/staging'
run: |
echo "🚀 Deploying to staging environment"
echo "Environment: staging"
- name: Deploy to production
if: github.ref == 'refs/heads/main'
run: |
echo "🚀 Deploying to production environment"
echo "Environment: production"
- name: Notify deployment
run: |
echo "📧 Sending notification"
echo "Deployment completed for branch: ${{ github.ref_name }}"
Exercice 3 : Workflow avec artifacts
# .github/workflows/artifacts-demo.yml
name: Artifacts Demo
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create build artifacts
run: |
mkdir -p dist
echo "Built application v1.0.0" > dist/app.txt
echo "Build timestamp: $(date)" > dist/build-info.txt
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: dist/
test:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: build-artifacts
path: ./downloaded/
- name: Test artifacts
run: |
echo "📦 Testing downloaded artifacts:"
ls -la ./downloaded/
cat ./downloaded/app.txt
cat ./downloaded/build-info.txt
Monitoring et debugging
Logs et debugging
jobs:
debug:
runs-on: ubuntu-latest
steps:
- name: Debug information
run: |
echo "🔍 Debug Information:"
echo "Runner OS: ${{ runner.os }}"
echo "GitHub Actor: ${{ github.actor }}"
echo "Repository: ${{ github.repository }}"
echo "Branch: ${{ github.ref_name }}"
echo "Commit SHA: ${{ github.sha }}"
- name: Enable debug logging
run: echo "::debug::This is a debug message"
- name: Set environment variable
run: echo "CUSTOM_VAR=hello-world" >> $GITHUB_ENV
- name: Use environment variable
run: echo "Custom variable: $CUSTOM_VAR"
Notifications
jobs:
notify:
runs-on: ubuntu-latest
if: always()
steps:
- name: Slack notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
- name: Email notification
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: "Build ${{ job.status }}"
body: "Build completed with status: ${{ job.status }}"
to: team@company.com
Bonnes pratiques
Organisation des workflows
.github/
├── workflows/
│ ├── ci.yml # Tests et validation
│ ├── deploy-staging.yml # Déploiement staging
│ ├── deploy-prod.yml # Déploiement production
│ ├── release.yml # Gestion des releases
│ └── security.yml # Scans de sécurité
├── actions/
│ └── custom-action/ # Actions personnalisées
└── ISSUE_TEMPLATE/ # Templates d'issues
Optimisation des performances
jobs:
optimized:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Cache des dépendances
- name: Cache Node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
# Parallélisation
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
# Éviter les étapes inutiles
- name: Run tests
if: github.event_name == 'pull_request'
run: npm test
Sécurité
# Permissions minimales
permissions:
contents: read
jobs:
secure:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Scan de sécurité
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
# Validation des secrets
- name: Check for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
Ressources supplémentaires
Actions populaires
- actions/checkout : Récupérer le code
- actions/setup-node : Configurer Node.js
- actions/cache : Cache des dépendances
- docker/build-push-action : Build et push Docker
- peaceiris/actions-gh-pages : Déploiement GitHub Pages
Marketplace
Documentation
Conclusion
GitHub Actions transforme votre dépôt en une plateforme DevOps complète. En maîtrisant ces concepts, vous pouvez automatiser l’ensemble de votre pipeline de développement, de l’intégration continue au déploiement en production.
Félicitations ! Vous avez terminé ce cours complet sur Git et GitHub. Vous disposez maintenant de toutes les compétences nécessaires pour gérer efficacement vos projets avec Git, collaborer sur GitHub et automatiser vos workflows de développement.
Temps de lecture estimé : 40 minutes
Niveau : Avancé
Étape précédente : Git sous-modules et sous-arbres
🎉 Cours terminé ! Vous maîtrisez maintenant Git et GitHub !