Utilisation de Gitlab CI avec Drupal et migration sur Gitlab.com

Créé le 04/05/2020

Dernière mise à jour le 04/05/2020

Je m’intéresse régulièrement au sujet des tests automatisés sur Drupal, à chaque grand événement il y a au moins une conférence sur le sujet et les articles sur le sujet sont réguliers dans la communauté Drupal.

De plus l’an passé, j’avais pu avoir une discussion à ce sujet avec Benjamin Rambaud aux Drupal Dev Days 2019 qui m’avait montré son exemple de projet avec des tests PHP Unit sur du code spécifique.

Les tests PHP Unit sur du code spécifique feront l’objet d’un article dédié.

J’ai « profité » du confinement pour me mettre sérieusement à Gitlab CI, en lisant la documentation (juste reprendre des skeletons existants sans comprendre ne m’intéresse pas) et en me lançant dans la mise en place de Gitlab CI sur mon template de projet Drupal. Ça faisait longtemps que j’avais cela en tête, il était grand temps de se lancer.

L’objectif de cet article est de présenter les premières étapes parcourues. Cela me permet de prendre du recul pour faire le point car vous le verrez dans l’article, je me pose beaucoup de questions à chaque étape et le chantier est loin d’être terminé.

Pourquoi cette migration sur Gitlab.com ?

Avec la mise en place de Gitlab CI sur mon skeleton projet, j'allais avoir besoin d’au moins une nouvelle image Docker spéciale CI.

En effet, mes premiers tests (PHPCS, Drupal-check, PHPMD) avec mon image florenttorregrosa/drupal-php-dev:7.3-apache étaient concluants, mais lorsqu'il allait falloir :

  • lancer des commandes NodeJS pour de la compilation d'assets ou des outils nécessitant NodeJS

  • lancer des commandes avec des outils qui n’ont rien à faire sur un environnement de développement, mais uniquement un environnement de CI,

là cela allait être problématique.

Mes fichiers Dockerfile pour créer mes images étant principalement situés sur le dépôt https://github.com/FlorentTorregrosa/docker-drupal-project, j'avais déjà fait une étape de nettoyage il y a presque 2 ans en ne les laissant que sur la branche principale, la 8.x, pour n'avoir qu'un lieu de référence.

Mais j'ai eu envie de les séparer de ce dépôt pour les mettre dans un dépôt dédié, afin de pouvoir reconstruire les images régulièrement sans nécessairement devoir attendre qu'un push soit fait sur le dépôt.

Voulant programmer la construction d'image, j'ai d'abord regardé dans le backoffice du hub.docker.com ce qu'il était possible de faire. Et il n'y avait pas cette option : pas possible de programmer des constructions d'images via hub.docker.com directement. En tout cas, pas en étant utilisateur gratuit.

Il aurait été possible de scripter le déclenchement des builds en utilisant l'API de hub.docker.com, mais j’ai pensé que cela allait très vite être une usine à gaz et surtout où stocker les jetons d’accès de manière sécurisée.

Quitte à se mettre à Gitlab CI et à revoir ma manière de construire mes images, autant les construire via Gitlab CI également. J'ai un peu regardé la documentation des Github Actions avant vu que mes dépôts Git étaient sur Github. Cela m'a moyennement inspiré. J'ai trouvé que Gitlab CI était plus transparent et flexible. Après, j'ai vraiment regardé très vite la documentation des Github Actions.

Même si cela aurait pu être intéressant d’apprendre à utiliser une autre CI que Gitlab CI, il ne fallait pas que je me disperse. Des outils de CI, il y en a des tas : Travis, Circle, Gitlab, Jenkins, Github, etc., et mon but n’est pas de les connaître toutes.

Je me suis posé la question si au passage j'allais regrouper la seule autre image que j’avais https://hub.docker.com/r/florenttorregrosa/pa11y-ci qui n'était pas dans le dépôt. J'ai finalement décidé de séparer les images en différents dépôts afin d'avoir plus de flexibilité. Même les images dépendantes entres elles, drupal-php et drupal-php-dev, au début je voulais les laisser ensemble pour ne pas avoir une complexité supplémentaire à gérer et en pratique mettre en place un déclenchement de build entre images était simple et finalement cela réduisait la complexité.

Vu que j'allais mettre en place Gitlab CI sur mon skeleton Drupal, et même s'il est possible avec Gitlab d’utiliser Gitlab CI sur un dépôt non hébergé sur Gitlab, j'ai décidé de rapatrier le dépôt sur Gitlab.com.

J’ai archivé mes dépôts Github pour ne référencer plus que ceux sur Gitlab.com.

Les étapes accomplies

Pipeline Gitlab CI OK
  1. Tester la création d’images Docker avec Gitlab CI :

    • J’ai commencé en utilisant mon image pa11y-ci.

    • Cela m’a permis de vérifier que même si une image est connectée au build automatique du hub.docker.com, on pouvait quand même envoyer des images construites ailleurs.

  2. Faire des groupes et sous-groupes, plutôt que d’avoir les dépôts en vrac sur mon namespace personnel :

  3. Séparer les images varnish, drupal-php, drupal-php-dev dans des dépôts distincts :

    • utilisation de token pour déclencher le build de drupal-php-dev lorsque drupal-php est construite. Cela inverse le fonctionnement par rapport au build via hub.docker.com où c’était l’image enfant qui réagissait lorsque l’image parente était construite.
  4. Débrancher les builds automatiques hub.docker.com et la connexion à Github.

  5. Récupération des dépôts Github sur Gitlab.com.

  6. Création d’une image ci-php :

    • nommée en m’inspirant de https://github.com/ekino/docker-buildbox, comme ça plus tard, si besoin, il pourra y avoir ci-node, ci-python, etc.

    • basée sur Alpine, je suis parti des images drupal-php, drupal-php-dev pour les fusionner, retirer ce qui n’avait d’intérêt que pour un environnement de développement. Avec le passage à Alpine, j’ai dû m’appuyer sur la variante CLI de l’image officielle PHP, car il n’y a pas de version PHP + Apache pour cette distribution. Ce qui n’est pas plus mal, puisque j’ai aussi dans les cartons, de séparer PHP et Apache de mes images drupal-php.

  7. Nettoyage du skeleton projet des images Docker.

  8. Mise en place de Gitlab CI sur le skeleton :

    1. PHP CS : exécuté avec un fichier de configuration. Jusqu’à présent, j’exécutais PHP CS en mettant uniquement les coding standard Drupal et DrupalPractice. Mais là avec le fichier de configuration, c’est bien pus pratique pour préciser les chemins à scanner et des règles supplémentaires, comme forcer le strict type.

    2. PHP MD : exécuté avec un fichier de configuration. Je n’ai pas trouvé de configuration officielle pour Drupal, j’ai donc repris celle de https://gitlab.com/beram-drupal/drupal-ci avec potentiellement de légers ajustements.

    3. PHP CPD : dommage qu’il n’y ait pas de fichier de configuration comme pour PHP CS, j’ai pour l’instant repris le paramétrage de https://gitlab.com/mog33/gitlab-ci-drupal

    4. Drupal check : par rapport à https://gitlab.com/beram-drupal/drupal-ci, je n’ai pas voulu m’embêter à passer par PHP Stan + un fichier de configuration. Cela permet certes plus de flexibilité, mais pour l’instant je n’en ai pas l’utilité.

    5. Composer normalize : j’ai découvert cet outil quand j’ai regardé GrumPHP (voir plus loin dans l’article). Juste super ! Je n’ai pour l’instant pas trouvé de standard Drupal dans la manière d’organiser un fichier Composer.json et en fait pas besoin, car cela se base sur le schéma JSON officiel de Composer https://getcomposer.org/schema.json. Plus besoin de passer du temps à vérifier que les informations dans le composer.json sont bien organisées, trier par ordre alphabétique, etc. Si vous vous posez la question au sujet de l’indentation standard 2 ou 4, la réponse est dans le noyau Drupal https://git.drupalcode.org/project/drupal/-/blob/HEAD/.editorconfig.

    6. Sensionlabs Security Checker

    7. ShellCheck : pas besoin de le mettre dans l’image ci-php car une image officielle ultra légère existe.

    8. Mise en place de cache entre les jobs Gitlab CI.

  9. Adaptation des images ci-php et drupal-php-dev lorsque nécessaire pour l’ajout d’outils.

  10. Correction des scripts shell par rapport à ShellCheck mis en place.

  11. Suppression des scripts shell pour lancer les outils d’analyse de code, en plus certains ne fonctionnaient pas correctement, pour à la place ajouter des commandes au fichier Makefile.

    • Je verrai plus tard, si je ne pousserai pas le sujet, pour ne plus avoir de script shell et à tout passer par le Makefile.

Désormais, en plus de Gitlab CI initialisé dans le skeleton projet, j’ai mes images mises à jour tous les mois, le 2ème jour à midi UTC. Par défaut Gitlab propose en build mensuel le premier jour du mois, je me suis dit que si tous les builds mensuels choisissaient cette option, ça devait faire goulot d’étranglement donc autant l’éviter. Les images sont également reconstruites lors de commit sur leur branche develop.

Autres avantages de construire les images avec Gitlab CI :

  1. il peut y avoir plusieurs builds en parallèles, car en version gratuite, hub.docker.com ne fait qu’un build à la fois,

  2. les builds sont plus rapides que via hub.docker.com directement. Inférieur à la minute ou de l’ordre de la minute pour construire toutes les images d’un dépôt (https://gitlab.com/florenttorregrosa-docker/images/docker-ci-php/pipelines, https://gitlab.com/florenttorregrosa-docker/images/docker-varnish/pipelines).

Sur le skeleton, j’ai une branche avec du code créé spécialement pour faire échouer les tests et une merge request dédiée à tester que les outils font effectivement leur travail : https://gitlab.com/florenttorregrosa-drupal/docker-drupal-project/-/merge_requests/14.

Pipeline Gitlab CI échec
Légende

Pipeline en échec sur la merge request dédiée à faire échouer les tests.

Prochaines étapes

J’ai listé les points à traiter en tickets sur https://gitlab.com/florenttorregrosa-drupal/docker-drupal-project.

Les points plutôt liés au skeleton et à Gitlab CI :

  • Ajouter des tests PHP Unit :

    • Par rapport à ce qu’il y a https://gitlab.com/beram-drupal/drupal-ci, il faut que je fasse des adaptations car mon dépôt servant de template, je ne veux pas versionner de la configuration Drupal dedans. Mais en même temps, il faut que j’arrive à avoir des tests PHPUnit activés, utilisant la configuration d’un projet pour servir de démo.

  • Ajouter PHP CS Fixer.

  • Ajouter des tests Behat :

    • Je les avais expérimenté il y a presque 3 ans, mais jamais vraiment utilisés. Il faut que je les exécute avec Gitlab CI de manière à m’assurer que les pré-requis, la configuration et les commandes soient opérationnels.

  • Ajouter CSS lint, SASS lint et autres lint utilisant Node JS.

  • Ajouter Eslint :

    • Pas encore ajouté car de ce que j'ai pu voir et essayer du dépôt https://gitlab.com/mog33/gitlab-ci-drupal, c'est qu'il se base sur la configuration du noyau Drupal, ce qui est une bonne chose pour rester iso avec ses standards. Mais le noyau est prévu pour appliquer des standards sur des fichiers « .es6.js ». Or j'aurai aimé pouvoir scanner des fichiers JS "normaux". Même l'utilisation de la configuration .eslintrc.legacy.json du noyau ne fonctionne pas comme je le souhaite, car le noyau embarque Prettier qui ne doit pas prendre en compte le même fichier de configuration et provoque des erreurs de coding standards alors qu’il n’est pas sensé y en avoir. Il faudra que je revois ça, quitte à me mettre également à faire des fichiers JS ES6.

  • Ajouter Pa11y-ci :

  • Ajouter GrumPHP :

    • Je n’ai pas encore mis en place GrumPHP sur le skeleton. Par rapport à l'article dont j'ai pu m'inspirer https://www.famillewallon.com/blog/2019/08/15/presentation-de-grumphp, j'ai choisi de ne pas utiliser le paquet vijaycs85/drupal-quality-checker car il embarque des dépendances que je ne veux pas. Et bien que le côté « hook git » automatique de GrumPHP m'intéresse, car j’avais déjà essayé de le mettre en place de manière plus manuelle, il faut que je vois comment GrumPHP se connecte aux outils qu’il exécute. Car comme expliqué ensuite dans cet article, si les outils (PHP CS, PHP MD, etc.) sont installés globalement, est-ce que GrumPHP pourra les utiliser ? De même il y a des tâches que j'aimerai bien avoir : lint JSON, lint YAML, Twig CS. Je pense que je reviendrai sur GrumPHP une autre fois car les git hooks sont bien pratiques.

  • Ajouter d’autres outils au fur et à mesure.

Les points plutôt liés à Docker :

  • Améliorer la taille des images Docker : en me renseignant sur les options de cache de la commande docker build, je suis tombé sur https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#use-multi-stage-builds.

  • Lancer des tests lors des builds des images pour les tester.

  • Installer les outils de développements dans les images Docker directement :

    • En consultant la documentation d’outils PHP, je suis tombé sur le fil de discussion Twitter https://twitter.com/s_bergmann/status/999635212723212288 qui explique pourquoi les outils de développement ne doivent pas être gérés avec le require-dev de Composer. Je suis d'accord avec les arguments exposés dans le fil Twitter, mais pour des raisons de simplicité je laisse pour l'instant les outils de développement dans le require-dev et je verrai pour les mettre dans mes images Docker directement une autre fois.

Remerciements

Merci beaucoup à Ines Wallon et à Benjamin Rambaud d’avoir répondu à mes questions sur leurs différents dépôts.

Liens

Ressources :

Ajouter un commentaire