# GitLab CI pour WordPress : un pipeline complet, du lint au déploiement

> Sur les projets hébergés sur GitLab, on a construit un pipeline en quatre étapes qui couvre lint, tests, build et déploiement. Voici sa structure complète.

- Auteur : Clément Hadrot
- Publié le : 2023-05-11
- Mis à jour le : 2023-05-11
- Catégorie : Outils &amp; workflow
- URL : https://wpmoderne.dev.wordpress-developpement.fr/outils/gitlab-ci-wordpress-pipeline-complet/

## L’essentiel

- Quatre étapes distinctes, chacune avec sa propre responsabilité
- Les artefacts de build passent d'une étape à l'autre sans recompilation
- Le déploiement en production reste une étape manuelle déclenchée volontairement

Certains de nos projets sont hébergés sur GitLab plutôt que GitHub, notamment ceux de clients qui disposent déjà d'une instance GitLab interne. GitLab CI fonctionne différemment de GitHub Actions dans sa syntaxe, mais répond au même besoin : automatiser la vérification et le déploiement du code à chaque changement. Voici le pipeline qu'on a construit, pensé pour un projet Bedrock avec des blocs Gutenberg personnalisés.

## La structure en étapes (stages)

GitLab CI organise le pipeline en *stages* exécutés séquentiellement, chaque stage pouvant contenir plusieurs jobs exécutés en parallèle. On sépare volontairement lint, tests, build et déploiement, pour que l'échec d'une étape bloque clairement les suivantes sans ambiguïté :

```
stages:
  - lint
  - test
  - build
  - deploy

variables:
  COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
```

## Lint : PHP et JavaScript en parallèle

```
lint:php:
  stage: lint
  image: php:8.1-cli
  before_script:
    - curl -sS https://getcomposer.org/installer | php
    - php composer.phar install --no-progress
  script:
    - vendor/bin/phpcs --standard=WordPress web/app/themes/mon-theme

lint:js:
  stage: lint
  image: node:18
  script:
    - npm ci
    - npm run lint:js
    - npm run lint:css
```

Ces deux jobs tournent en parallèle car ils appartiennent au même stage et n'ont aucune dépendance déclarée entre eux. Le pipeline attend qu'ils réussissent tous les deux avant de passer au stage suivant.

## Tests et build

> L'essentiel à retenir : Quatre étapes distinctes, chacune avec sa propre responsabilité ; Les artefacts de build passent d'une étape à l'autre sans recompilation ; Le déploiement en production reste une étape manuelle déclenchée volontairement

```
test:phpunit:
  stage: test
  image: php:8.1-cli
  services:
    - mysql:5.7
  variables:
    MYSQL_DATABASE: wordpress_test
    MYSQL_ROOT_PASSWORD: root
  script:
    - bash bin/install-wp-tests.sh wordpress_test root root mysql
    - vendor/bin/phpunit

build:assets:
  stage: build
  image: node:18
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - web/app/themes/mon-theme/build/
    expire_in: 1 hour
```

Le mot-clé `services` lance un conteneur MySQL dédié, accessible depuis le job sous le nom d'hôte `mysql`, indispensable pour les tests PHPUnit qui nécessitent une vraie base de données. Les `artifacts` du job de build conservent le résultat de la compilation JavaScript pendant une heure, pour que le job de déploiement suivant n'ait pas à recompiler les mêmes fichiers.

## Déploiement, avec validation manuelle en production

```
deploy:staging:
  stage: deploy
  image: alpine:latest
  only:
    - develop
  before_script:
    - apk add --no-cache openssh-client rsync
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - rsync -avz --delete web/app/themes/mon-theme/
      deploy@staging.exemple.fr:/var/www/site/web/app/themes/mon-theme/

deploy:production:
  stage: deploy
  image: alpine:latest
  only:
    - main
  when: manual
  before_script:
    - apk add --no-cache openssh-client rsync
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - rsync -avz --delete web/app/themes/mon-theme/
      deploy@production.exemple.fr:/var/www/site/web/app/themes/mon-theme/
```

La ligne `when: manual` sur le déploiement en production est un choix délibéré : le pipeline vérifie automatiquement tout ce qui peut l'être, mais la bascule finale en production reste un acte volontaire d'un humain, déclenché depuis l'interface GitLab. Le déploiement vers staging, lui, reste entièrement automatique sur chaque push de la branche `develop`.

## Les variables sensibles

La clé `SSH_PRIVATE_KEY` et les autres secrets sont déclarés dans les paramètres CI/CD du projet GitLab (menu Settings puis CI/CD, section Variables), avec l'option « masquée » activée pour qu'ils n'apparaissent jamais dans les journaux d'exécution, même en cas d'erreur de script qui les afficherait par accident.

| Stage | Rôle | Déclenchement |
| --- | --- | --- |
| lint | Vérifie le style de code PHP et JS | Automatique, à chaque push |
| test | Exécute les tests PHPUnit | Automatique, si lint réussit |
| build | Compile les assets JavaScript et CSS | Automatique, si test réussit |
| deploy | Déploie vers staging ou production | Auto (staging) / manuel (production) |

> Le déploiement manuel en production n'est pas un manque de confiance envers le pipeline. C'est la reconnaissance qu'un humain doit choisir le moment de la bascule — après une fenêtre de maintenance annoncée, par exemple — même quand tout le reste est automatisé.

## En résumé

Un pipeline GitLab CI bien structuré pour WordPress repose sur une séparation claire des responsabilités entre lint, tests, build et déploiement, avec des artefacts qui évitent le travail redondant entre étapes. Garder le déploiement en production comme geste manuel, tout en automatisant le reste, offre un bon équilibre entre rapidité et contrôle sur les projets les plus sensibles.
