Besoin
Le besoin avec la publication d’une feature branche en mode staging est simple:
Il s’agit de voir si le nouvel article de blog fonctionne correctement.
Les problèmes du passé qui me poussent à faire cela sont
le fait d’oublier de mettre draft à
false
, ce qui entraîne la non-publication en prod (en dev,hugo serve -D
fait du rendering sur tous les articles, brouillons ou non)le fait de rater les liens internes et/ou d’oublier de commiter les images du blog. En dev, l’image est initialement au bon endroit et donc le processus de publication la copie bien dans public/ Une fois sur le repo, ce n’est plus le cas si on oublie de commiter !
Je vais donc voir comment faire pour publier le blog en ‘staging’ sur les branches de feature.
Je reprends l’idée de C Chaudier pour cet hébergement, qui lui accédait aux artefacts du build hugo.
Théorie
On peut repartir d’accéder aux artefacts issus du “build” hugo. On pourrait alors définir notre environnement comme lié à l’artefact et à son stockage. A l’époque de la création de la vidéo de C.Chaudier, il y avait un souci au niveau des accès de fichier index.html plutôt que sur les noms de pages.
L’autre option sera de tester les déploiements parallèles.
Pratique
Par artefact
Je vais d’abord tester d’utiliser l’artefact créé pendant l’étape de build.
Lors de ma dernière publication, le job ‘pages’ a créé un artefact. Je peux accéder au index.html du site buildé à l’adresse https://watysay.gitlab.io/-/watysay.gitlab.io/-/jobs/11319071008/artifacts/public/index.html.
Par contre les liens de navigations sont KO. Cliquer sur “Posts” nous renvoie vers https://watysay.gitlab.io/posts/, ce qui est la prod. Dans le cadre d’une vérification article par article, on pourrait se satisfaire du index.html spécifique.
Par exemple, pour l’article de prod https://watysay.gitlab.io/posts/2025/03/installation-par-netboot/ on peut retrouver pour le job l’adresse https://watysay.gitlab.io/-/watysay.gitlab.io/-/jobs/11319071008/artifacts/public/posts/2025/03/installation-par-netboot/index.html.
Il y a quand même plusieurs inconvénients :
- la navigation reste KO vers d’autres liens internes
- la récupération de la page en question pour publier le lien n’est pas simple
C’est surtout ce dernier point qui pose problème en fait. Je pourrais choisir le dernier .md (les index.html sont tous recréés lors du rendering), mais le dernier .md n’est pas forcément le bon. Il pourrait y avoir des commits sans .md (par exemple, quand on oublie de commiter une image …)
Pour l’instant trop d’inconvénients dans ce fonctionnement, je vais essayer autre chose.
Déploiements parallèles
Au travers des déploiements parallèles, gitlab propose de publier plusieurs versions de son site en parallèle.
La clé ici consiste à utiliser pages.path_prefix
afin d’ajouter ce préfixe dans le chemin d’accès aux fichiers.
Ce préfixe peut être défini à l’avance (“staging” ou “uat” par exemple) ou variabilité (pour prendre le nom de la branche en cours de MR par exemple).
Cette nouveauté est disponible depuis la version 17.4 de Gitlab (la version en cours à l’heure de l’écriture est 18.4).
Le seul problème dans notre cas, c’est que cette feature n’est disponible qu’à partir du Tier Premium de Gitlab…
Chou blanc donc. Retour à la case départ.
Solution ‘close enough’
On va tenter de partir sur une approche qui sera approximative.
Approche
Je vais essayer de récupérer, dans la MR, le nom d’un fichier markdown. Le cas le plus courant, dans notre blog, sera l’ajout ou la modification d’un fichier .md dans la branche, qui sera donc différent de la prod (branche main).
Donc dans le pipeline de la MR, on va ajouter une étape qui va nous lister la liste des fichiers modifiés et contenu dans la MR (ce qui correspond aux fichiers dans l’onglet ‘Modifications’ de la MR sur gitlab.com).
Astuce pour tester une MR via gitlab-ci-local : ajouter l’option --variable
afin de déclencher le job.
J’ai comme règle sur le job :
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
et donc en lançant :
gitlab-ci-local --variable CI_PIPELINE_SOURCE="merge_request_event"
J’ai le job qui se lance.
J’ai réussi à récupérer le fichier html, en partant du nom de fichier .md.
Je passe par git diff --name-only
pour récupérer la liste, puis je grep le premier fichier .md trouvé sous posts/
Ensuite je transforme le nom de ce fichier en variable de recherche pour find une fois le build fait.
J’ai donc le chemin du fichier index.html.
Il me reste donc à compléter le chemin avec les variables CI_* prédéfinies.
Le chemin :
https://watysay.gitlab.io/-/watysay.gitlab.io/-/jobs/11319071008/artifacts/public/posts/2025/03/installation-par-netboot/index.html
devient
https://${CI_PAGES_HOSTNAME}/-/${CI_PAGES_HOSTNAME}/-/jobs/${CI_JOB_ID}/artifacts/<html path>
Il reste alors à créer dynamiquement un environnement lié à cette adresse et à la MR :
environment:
name: "${CI_MERGE_REQUEST_TITLE}"
url: "https://${CI_PAGES_HOSTNAME}/-/${CI_PAGES_HOSTNAME}/-/jobs/${CI_JOB_ID}/artifacts/<html path>"
Correction
Là-dessus j’ai 2 erreurs:
- Le job qui créerait l’environnement pour la MR ne se lance pas car la variable HTMLINDEX n’existe pas
- mon job pour trouver mon fichier est KO. Il semble avoir un problème sur
git diff
Pour résoudre le problème de git diff
, il suffit de récupérer la branche main
pour faire la diff et ensuite on peut trouver le fichier.
Le job de création d’environnement ne voulait pas se lancer, non pas que HTMLINDEX soit problématique mais en fait c’était le nom de l’environnement.
En effet CI_MERGE_REQUEST_TITLE contient toutes sortes de caractères, dont ici “:”, qui n’est pas acceptable. Je modifie pour avoir un nom associé au IID de la merge request.
Fait étrange, mon fichier .md est dans la liste des fichiers sous git, en mode brouillon et son fichier .html est réalisé via hugo
.
Cette commande hugo
ainsi appelée ne publie pas les articles en brouillons (draft: true
).
En fait, l’article est publié mais non présenté dans le menu des articles (“posts”). On peut voir la différence entre artifacts/public/posts/index.html pour le job build-site (qui build les drafts) et staging-pages (qui n’est pas censé les builder). Le premier contient le lien vers l’article mais pas le second.
Par contre cela voudrait dire que les fichiers drafts seraient accessible en prod, non pas par le menu “posts” mais en tapant le nom directement.
Limites
A ce stade, le pipeline est fonctionnel et la modification est publiée, le lien fonctionne. Par contre, que se passe-t-il s’il n’y a pas de fichier .md dans la MR ? Dans le cas d’un simple bug sur la CI, ou d’un changement de configuration, il est possible qu’il n’y ait qu’un seul fichier non Markdown de commité.
Si mon git diff
suivi du grep
ne trouve pas de fichier alors on a une erreur dans le job.
Il me faut un mécanisme plus robuste.
Je rajoute || echo ""
après le grep.
Ainsi, soit on trouve un fichier et on stocke son nom dans la variable MDFILE, soit cette variable sera initialisée à vide.
Passée à find
, soit la recherche du chemin sera basée sur le nom de fichier,
soit sur du vide (le pattern à rechercher devenant “**.html”). Dans ce dernier cas,
tout les .html de public/ remonteront et on se limitera au premier.
Dans mon test c’est le chemin public/posts/index.html qui apparaît, ce qui devrait mettre la puce à l’oreille quand on accédera à l’espace de staging.
Bilan
Ce travail de publication d’autre chose que la production s’avère complexe. Avec de la méthode et quelques itérations on arrive à une solution un peu bancale mais qui permet une première approche.
On ne résous pas le problème du brouillon cependant. Il reste lisible quand bien même il ne serait pas publié sur la prod.
Pour une solution satisfaisante il faudra je pense passer par upgrader son abonnement Gitlab. Une future possibilité, à envisager un jour, serait de considérer l’actuelle production sur Gitlab comme un futur staging, c’est-à-dire qu’il faudrait migrer le blog ailleurs sur un autre hébergement.