Chapitre 14.7 — CI avec GitHub Actions
Partie 14 : Tests & qualité — Chapitre 7/7 Version de référence : GitHub Actions / Symfony 7.4.
⏱️ TL;DR
- Une pipeline CI (intégration continue) exécute automatiquement, à chaque push/PR, l’ensemble des vérifications : tests, PHPStan, CS Fixer (dry-run),
composer audit,schema:validate.- Si une étape échoue, la CI bloque le merge — rien de cassé n’entre dans
main.- On utilise
shivammathur/setup-phppour PHP, un service PostgreSQL pour les tests, et le cache Composer.- C’est la porte de qualité : elle transforme les bonnes intentions (tester, analyser) en garanties appliquées.
- Pour un dev Next.js : c’est votre workflow GitHub Actions habituel — même fichier YAML, mais avec les outils PHP.
🎯 Objectifs
- Écrire un workflow GitHub Actions pour un projet Symfony.
- Enchaîner tests, analyse statique, style et audit.
- Fournir une base de données de test.
- Faire de la CI une porte de qualité bloquante.
1. Pourquoi une CI
Écrire des tests et configurer PHPStan/CS Fixer ne sert à rien s’ils ne sont pas exécutés. La CI les lance automatiquement à chaque contribution, avant le merge. Résultat : une PR ne peut être fusionnée que si tout passe — le code de main reste toujours vert.
2. Le workflow
# .github/workflows/ci.yml
name: CI
on:
push: { branches: [main] }
pull_request: ~
jobs:
quality:
runs-on: ubuntu-latest
services:
database:
image: postgres:16-alpine
env:
POSTGRES_DB: app_test
POSTGRES_USER: app
POSTGRES_PASSWORD: '!ChangeMe!'
ports: ['5432:5432']
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: ctype, iconv, intl, pdo_pgsql
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-progress --prefer-dist
- name: Analyse statique (PHPStan)
run: vendor/bin/phpstan analyse --no-progress
- name: Style (PHP CS Fixer)
run: vendor/bin/php-cs-fixer fix --dry-run --diff
- name: Vérifier le schéma Doctrine
run: php bin/console doctrine:schema:validate --skip-sync
- name: Migrations + tests
env:
DATABASE_URL: "postgresql://app:!ChangeMe!@127.0.0.1:5432/app_test?serverVersion=16"
run: |
php bin/console doctrine:migrations:migrate --no-interaction --env=test
php bin/phpunit
- name: Audit de sécurité des dépendances
run: composer audit3. Décryptage des étapes
| Étape | Rôle |
|---|---|
| checkout | récupère le code |
| setup-php | installe PHP 8.4 + extensions |
| composer install | dépendances (avec cache) |
| PHPStan | analyse statique (14.5) |
| CS Fixer —dry-run | vérifie le style (14.6) |
| schema:validate | mapping ↔ base cohérents (6.4) |
| migrations + phpunit | applique les migrations sur la base de test, lance les tests |
| composer audit | vulnérabilités connues des dépendances (10.6) |
Le service PostgreSQL fournit une base éphémère pour les tests fonctionnels/API (14.2-14.3). Chaque étape qui échoue fait échouer le job → la PR est bloquée.
4. Aller plus loin
- Matrice : tester sur plusieurs versions de PHP (
8.3,8.4) pour la compatibilité. - Cache Composer :
actions/cachepour accélérer les installs. - Couverture de code : générer un rapport (Codecov) — utile, mais viser un taux n’est pas une fin en soi (mieux vaut de bons tests que 100 % de couverture creuse).
- Déploiement : un job supplémentaire qui déploie si la CI passe sur
main(CD — Partie 15).
⚠️ Piège : une CI lente (plusieurs minutes) décourage et se fait contourner. Optimisez : cache des dépendances, jobs parallèles (PHPStan et tests en même temps),
--prefer-dist. Et protégez la branchemain(dans les réglages GitHub) pour exiger que la CI passe avant tout merge — sinon la porte de qualité est optionnelle, donc inutile.
💡 Pour un dev Next.js : c’est exactement votre
ci.ymlGitHub Actions, avec des étapes PHP au lieu denpm test/tsc/eslint. La philosophie est identique : bloquer le merge tant que tests + analyse + lint + audit ne passent pas. Sur un projet combiné (API Symfony + front Next.js), vous auriez deux jobs (ou deux workflows) : un pour le back (ce chapitre), un pour le front (vos habitudes). La qualité de bout en bout est ainsi garantie des deux côtés.
✏️ Exercices
Exercice 1. Quelles étapes minimales une CI Symfony sérieuse doit-elle enchaîner ?
✅ Solution
Au minimum : checkout, setup PHP, composer install, tests (PHPUnit, avec une base de test), PHPStan (analyse statique), CS Fixer —dry-run (style), et composer audit (dépendances vulnérables). Souvent aussi doctrine:schema:validate et l’application des migrations sur la base de test. Chaque échec bloque le merge.
Exercice 2. Pourquoi lancer composer audit en CI ?
✅ Solution
Pour détecter automatiquement les vulnérabilités connues dans vos dépendances (une faille dans une lib tierce est aussi dangereuse qu’une faille dans votre code, Partie 10.6). En CI, composer audit alerte (et peut bloquer) dès qu’une dépendance vulnérable est présente, à chaque PR — plutôt que de le découvrir en prod.
Exercice 3. La CI passe, mais des développeurs mergent quand même des PR rouges. Que manque-t-il ?
✅ Solution
La protection de branche : dans les réglages GitHub, il faut exiger que les checks de CI passent (« Require status checks to pass before merging ») sur main. Sans cela, la CI n’est qu’informative et peut être contournée. La protection de branche rend la porte de qualité bloquante (impossible de merger une PR rouge), ce qui est le but.
🧠 Quiz de révision
1. Que fait une CI, et quand ?
Elle exécute automatiquement tests + analyse + style + audit à chaque push/PR, et bloque le merge si quelque chose échoue.
2. Comment fournit-on une base de données aux tests en CI ?
Via un service (ex. postgres:16-alpine) déclaré dans le job, avec un DATABASE_URL de test.
3. Quel outil installe PHP dans GitHub Actions ?
shivammathur/setup-php (version + extensions).
4. Que faut-il configurer pour que la CI soit vraiment bloquante ?
La protection de branche GitHub (exiger que les checks passent avant merge). Sinon la CI est optionnelle.
5. Comment garder la CI rapide ?
Cache des dépendances Composer, jobs parallèles, --prefer-dist — une CI lente se fait contourner.
Fin de la Partie 14. BookLab est testé (unitaire, fonctionnel, API), analysé (PHPStan), formaté (CS Fixer), modernisable (Rector) et gardé par une CI bloquante. On refactore et on déploie sans peur.
Prochaine étape : Partie 15 — Expert : perf, prod, architecture, industrialisation — passer BookLab en production, à l’échelle.