Skip to content

Intégration CI

Comment le pipeline GitLab consomme l'outil, quels réglages projet sont requis, et les recettes d'intégration courantes. Le .gitlab-ci.yml du dépôt de l'outil est la forme canonique que les consommateurs copient. La skill agent .claude/skills/spektrum-release-pipeline/SKILL.md détient le YAML de référence pour câbler un nouveau dépôt.

Mécanique d'authentification

Rien dans l'ensemble local ne requiert de token GitLab — les MR sont ouvertes via les push options GitLab, portées par l'auth git existante. Côté CI, tout est agnostique vis-à-vis de l'auth : le YAML configure git remote set-url --push origin <url-auth> avant d'appeler le binaire.

Les pushs CI sur des refs protégées nécessitent un Project Access Token au scope write_repository, exposé en RELEASE_TOKEN (variable protégée + masquée). CI_JOB_TOKEN ne peut pas pousser sur des refs protégées.

Forme du pipeline

Étapes canoniques : lint, test, publish, tag-pipeline. Le job publish est conditionné au passage d'un commit chore(release): sur le trunk.

Invariants clés quand on câble le job publish soi-même :

  • Le rules: doit matcher à la fois ^chore\(release\): et ^Merge.*release\/ — GitLab synthétise un titre Merge branch 'release/...' dans le cas du commit de merge.
  • Toujours git remote set-url --push origin vers une URL gitlab-ci-token:${RELEASE_TOKEN} avant d'appeler tag.
  • Utiliser eval $(... tag) pour capturer le dotenv. Ne pas le remplacer par un git tag fait main — la CLI gère l'idempotence, le choix du dist-tag et l'incrément du suffixe staging.
  • Régler GIT_DEPTH: "0" — commitlint et le tagger parcourent l'historique ; le tagger lit les sujets sur toute la plage HEAD^1..HEAD^2 de la MR.

Deux saveurs à choisir :

  • Paquet npm : npm publish --tag $DIST_TAG après eval $(release-util tag). DIST_TAG vaut staging pour les releases staging et latest pour la prod.
  • Image Docker : build, tag, push. latest et staging-latest sont des tags flottants indépendants.

Réglages projet GitLab

Ces réglages vivent dans l'UI GitLab, pas dans le YAML, et le workflow déraille silencieusement si l'un d'eux est faux. À régler une fois par projet.

Merge requests → Méthode de merge

  • Autoriser : « Merge commit » ou « Fast-forward ».
  • Désactiver : « Squash commits when merging » pour les MR release/*.

Le squash réécrit le sujet chore(release): en un style Merge branch 'release/...' que release-util tag ne reconnaît pas — et un sujet squashé perd entièrement la chaîne de version, sans récupération possible.

Repository → Push rules

Exiger des sujets de commit conventionnels sur le trunk. Le motif dépend de la config commitlint du projet ; un point de départ permissif :

^(feat|fix|perf|refactor|docs|test|build|ci|chore|revert)(\(.+\))?!?: .+

CI/CD → Variables (Protégée + Masquée)

VariablePortéeRôle
RELEASE_TOKENProtégée + MasquéeProject Access Token au scope write_repository. Sert à pousser le tag annoté dans le job publish. Requis. CI_JOB_TOKEN ne peut pas pousser sur des refs protégées.
NPM_TOKENProtégée + MasquéeToken du registre interne avec scope publish. Requis pour les dépôts qui publient sur npm uniquement.

Pour créer le RELEASE_TOKEN : Settings → Access Tokens → nom release-token, rôle Maintainer, scope write_repository. Le token peut tourner ; la variable est le nom stable que les scripts CI utilisent.

General → Badges (optionnel mais recommandé)

Après la première publication réussie produisant badges/production.svg et badges/staging.svg, ajouter des badges projet pointant vers les URLs d'artefacts stables :

https://gitlab.spektrum-suisse.ch/<groupe>/<projet>/-/jobs/artifacts/<branche-defaut>/raw/badges/production.svg?job=publish
https://gitlab.spektrum-suisse.ch/<groupe>/<projet>/-/jobs/artifacts/<branche-defaut>/raw/badges/staging.svg?job=publish

Le expire_in: never sur l'artefact garde ces liens stables entre les releases. Ces deux fichiers sont produits par release-util badges --out badges/ (mode hérité, les deux d'un coup) ou par deux appels release-util badge --env prod / --env staging si on veut personnaliser un badge (label, message, couleur, style).

Recettes d'intégration

Capturer la prochaine version pour des jobs en aval

yaml
prepare:
  script:
    - VER=$(npx --yes @spektrum/release-util@latest next-version --env prod)
    - echo "RELEASE_VERSION=$VER" > version.env
  artifacts:
    reports:
      dotenv: version.env

next-version écrit sur stdout ; tout le reste va sur stderr, donc la capture est propre.

Évaluer le dotenv du tagger

yaml
publish:
  script:
    - git remote set-url --push origin "https://gitlab-ci-token:${RELEASE_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
    - eval $(npx --yes @spektrum/release-util@latest tag)
    - echo "Tagué $RELEASE_TAG, canal=$RELEASE_ENV"

Faire diverger un pipeline de tag selon le type de release

yaml
detect:
  stage: tag-pipeline
  script:
    - npx --yes @spektrum/release-util@latest detect --out release.env
  artifacts:
    reports:
      dotenv: release.env
  rules:
    - if: $CI_COMMIT_TAG

deploy-major:
  needs: [detect]
  rules:
    - if: $CI_COMMIT_TAG && $RELEASE_TYPE == "major"
  script:
    - ./deploy.sh --extra-approval

deploy-routine:
  needs: [detect]
  rules:
    - if: $CI_COMMIT_TAG && $RELEASE_TYPE == "minor_patch"
  script:
    - ./deploy.sh

Publier une image Docker au lieu de npm

Remplacer le bloc npm publish du job publish par build/tag/push. Les espaces de tags d'image reflètent la séparation des dist-tags npm :

Branche sourceTag gitTags d'image poussés
release/X.Y.ZX.Y.Z${REGISTRY}/${IMAGE}:X.Y.Z et ${REGISTRY}/${IMAGE}:latest
release/X.Y.Z-staging.NX.Y.Z-staging.N${REGISTRY}/${IMAGE}:X.Y.Z-staging.N et ${REGISTRY}/${IMAGE}:staging-latest

latest et staging-latest sont disjoints — promouvoir latest ne touche pas staging-latest. Les déploiements prod et staging tirent depuis des espaces de tags indépendants.

Contributors

No contributors

Changelog

No recent changes