Aller au contenu

Créer un tag de release

Vous êtes mainteneur·se de Kirexo et vous voulez déclencher une release : créer un tag Git qui enchaîne automatiquement le build des images Docker, le déploiement de la documentation sur GitLab Pages et la création de la release GitLab avec changelog. Cette recette explique les deux façons de le faire.

Prérequis

  • Vous avez les droits Maintainer ou Owner sur le projet GitLab.
  • La variable CI/CD GITLAB_TOKEN est configurée (cf. Variables CI/CD GitLab) — un Personal Access Token avec le scope write_repository (les project access tokens sont réservés à GitLab Premium/Ultimate).
  • Les images kirexo-base, kirexo-dev et kirexo-prod ont déjà été buildées au moins une fois — sinon les jobs docker:build-* sur tag échoueraient car il n'y a rien à mettre en cache (et la pipeline qualité, qui dépend de ces images, ne tournerait pas non plus). L'image kirexo-docs ne nécessite pas ce bootstrap : son job docker:build-docs est needs: [] et tourne automatiquement avant pages sur tag.

Pourquoi passer par une pipeline et pas par git tag en local

git push --tags fonctionnerait, mais ça impose d'avoir une clé SSH ou un PAT configurés sur la machine qui pousse, et ça ne marche pas depuis un environnement où le repo n'est pas cloné en écriture (ex. depuis Claude Code en mode bypassPermissions qui n'a pas la clé de la personne). La pipeline tag:create crée le tag côté serveur via l'API GitLab — l'auteur·rice de la release n'a besoin que de son accès UI ou de glab.

Méthode A — Depuis l'UI GitLab

  1. Aller sur Build → Pipelines → Run pipeline (bouton en haut à droite).
  2. Choisir la branche main.
  3. Ajouter une variable :
  4. Key : CREATE_TAG
  5. Value : true
  6. Type : Variable (pas File).
  7. Cliquer sur Run pipeline.

La pipeline créée ne contient que le job tag:create (stage tag). Tous les autres jobs sont filtrés par leurs rules: — la pipeline CREATE_TAG=true est volontairement isolée pour ne pas dédoubler la pipeline qualité.

Garde-fou : une pipeline verte est exigée sur le dernier commit de main

Avant de créer le tag, tag:create vérifie qu'au moins une pipeline success existe pour le dernier commit de main ($CI_COMMIT_SHA) — typiquement la pipeline de validation jouée au merge. Si aucune pipeline verte n'est trouvée, le job échoue et le tag n'est pas créé. Le but : ne jamais figer une release sur un commit dont la CI est rouge ou encore en cours.

Pour outrepasser ce garde-fou dans un cas exceptionnel, ajouter une seconde variable FORCE_TAG à true (en plus de CREATE_TAG) :

Key Value
CREATE_TAG true
FORCE_TAG true

Avec FORCE_TAG=true, le statut de pipeline n'est plus vérifié : le tag est créé inconditionnellement. À réserver aux situations où l'on sait que le commit est sain mais que la pipeline n'a pas (re)tourné.

Méthode B — Depuis le CLI avec glab

glab pipeline run --ref main --variables CREATE_TAG=true

Le retour de glab affiche l'ID et l'URL de la pipeline créée — suivez-la via glab pipeline view <id> ou directement dans l'UI.

Pour outrepasser le garde-fou de pipeline verte (cf. Méthode A), ajouter --variables FORCE_TAG=true :

glab pipeline run --ref main --variables CREATE_TAG=true --variables FORCE_TAG=true

Ce que fait tag:create

Le job tourne sur alpine:3 avec GIT_STRATEGY: none (pas besoin de cloner le code — l'API agit côté serveur GitLab) et exécute :

  1. Garde-fou (sauf si FORCE_TAG=true) : interroge GET /projects/:id/pipelines?sha=$CI_COMMIT_SHA&status=success et refuse de taguer (exit 1) si aucune pipeline success n'existe pour le dernier commit de main. Le contrôle est fail-safe : si l'appel API échoue (token invalide, réseau), le compteur retombe à 0 et le job bloque plutôt que de risquer une release non validée.
  2. Calcule le nom du tag : TAG_NAME=$(date -u +%Y%m%d%H%M) — format YYYYMMDDHHMM en UTC.
  3. Appelle POST /projects/:id/repository/tags avec ${GITLAB_TOKEN} :

    curl --fail \
      --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
      --data "{\"tag_name\": \"${TAG_NAME}\", \"ref\": \"${CI_DEFAULT_BRANCH}\"}" \
      "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/repository/tags"
    
  4. Affiche la réponse JSON via jq '{name, target, message}'.

Le --fail de curl fait échouer le job si l'API renvoie un statut HTTP ≥ 400 — typiquement 403 Forbidden si GITLAB_TOKEN n'a pas le scope write_repository, ou 409 Conflict si un tag du même nom existe déjà (très peu probable avec le format YYYYMMDDHHMM).

Ce qui se déclenche ensuite

Dès que GitLab détecte le tag créé, il démarre automatiquement une nouvelle pipeline $CI_COMMIT_TAG. Cette pipeline ne rejoue ni les vérifications qualité ni les tests : ceux-ci ont déjà tourné sur le même SHA dans la pipeline main que tag:create a exigée verte (cf. Optimisation pipeline de tag). Seuls les jobs qui produisent un livrable ou dont le résultat dépend de l'instant T du tag s'exécutent :

Stage Job Effet
quality quality:composer-audit Filet de sécurité rejoué sur le SHA du tag — capture une CVE Composer éventuellement publiée entre le merge et le tag. Si rouge, la pipeline du tag échoue et les jobs docker:* / release:* ne tournent pas.
docker docker:build-base, docker:build-dev, docker:build-prod Build + push automatique. kirexo-base et kirexo-dev reçoivent :php8.5 + :latest ; kirexo-prod reçoit en plus le tag de version immuable :$CI_COMMIT_TAG (cf. Déployer Kirexo en production).
docker docker:build-docs, docker:build-supply-chain Build + push des images d'outillage CI consommées au stage suivant (mkdocs pour pages, cosign + syft pour docker:sign-prod et release:sbom).
docker docker:sign-prod Signature keyless cosign des trois références poussées par docker:build-prod (cf. Supply chain et signatures).
release pages Build de la documentation mkdocs en mode strict (via l'image kirexo-docs) et déploiement sur GitLab Pages.
release release:sbom Génération du SBOM SPDX + CycloneDX de kirexo-prod:$CI_COMMIT_TAG.
release release:create Création de la release GitLab avec changelog des commits depuis le tag précédent + attachement des SBOM en assets.
maintenance container_scanning + security:container-issue Scan CVE de kirexo-prod:$CI_COMMIT_TAG fraîchement poussée — signal au moment de la release, pas H+24. Ouvre une issue uniquement si au moins une CVE Critical ou High est remontée (cf. Jobs container_scanning et security:container-issue).

Le tout sans intervention manuelle supplémentaire. docker:build-docs étant dans le stage docker (avant release), l'image de build de la doc est toujours fraîche au moment où pages la consomme — aucun bootstrap manuel n'est nécessaire pour la doc (contrairement à kirexo-base / kirexo-dev, cf. prérequis).

Pourquoi la qualité ne rejoue pas

tag:create refuse de poser le tag si aucune pipeline success n'existe pour le commit ciblé. Le code du tag est donc, par construction, strictement le même SHA qu'une pipeline qualité verte. Rejouer cs-fix, phpstan, tests unitaires ou E2E donnerait exactement le même résultat — pure duplication de minutes runner. Seul quality:composer-audit est conservé sur tag, parce que la base de vulnérabilités évolue indépendamment du code et qu'une CVE peut être publiée entre le merge et le tag.

Vérifier qu'une release est partie

  1. La pipeline CREATE_TAG=true doit être verte. Si le job tag:create échoue avec 403, vérifier le scope write_repository du token (cf. Variables CI/CD GitLab).
  2. La pipeline $CI_COMMIT_TAG apparaît dans la liste des pipelines avec le nom du tag (202605231742) — cliquer dessus pour suivre les jobs Docker et release.
  3. La release apparaît dans Deploy → Releases avec le changelog généré.
  4. La doc est mise à jour sur https://doc.kirexo.app/ (cf. Configurer le domaine GitLab Pages).
  5. Les images Docker sont visibles dans Deploy → Container Registry : kirexo-base et kirexo-dev avec les tags :php8.5 et :latest ; kirexo-prod avec :php8.5, :latest et le tag de version :202605231742 (le nom du tag Git) ; kirexo-docs avec le seul tag :latest.

Cas d'erreur

Le job tag:create échoue avec 401 Unauthorized

Le GITLAB_TOKEN est absent ou expiré. Régénérer le token (Settings → Access Tokens), mettre à jour la variable CI/CD (Settings → CI/CD → Variables) et relancer le job.

Le job tag:create échoue avec 403 Forbidden

Le token n'a pas le scope write_repository, ou son rôle est inférieur à Maintainer. Régénérer un token avec les bons droits.

Le job tag:create échoue sans appeler l'API des tags (garde-fou)

Le job s'arrête avant la création du tag parce qu'aucune pipeline success n'existe pour le dernier commit de main. Causes typiques : la pipeline de validation est encore en cours, a échoué, ou n'a jamais tourné sur ce commit. Attendre qu'une pipeline passe au vert sur main, puis relancer CREATE_TAG=true. En cas exceptionnel (commit que l'on sait sain mais sans pipeline rejouée), outrepasser avec FORCE_TAG=true (cf. Méthode A / Méthode B).

Pipeline $CI_COMMIT_TAG jamais déclenchée

Vérifier que le tag a bien été créé : glab repo view --web puis onglet Tags, ou directement via l'API. Si le tag existe mais aucune pipeline n'est partie, vérifier le workflow:rules dans .gitlab-ci.yml — la règle $CI_COMMIT_TAG doit y figurer.

Le job pages échoue en mode strict

mkdocs détecte un lien cassé, un snippet manquant ou un avertissement de plugin. Reproduire localement avec castor docs:build (qui passe les mêmes options) pour identifier la cause exacte avant de retagger.

Voir aussi