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 titreMerge branch 'release/...'dans le cas du commit de merge. - Toujours
git remote set-url --push originvers une URLgitlab-ci-token:${RELEASE_TOKEN}avant d'appelertag. - Utiliser
eval $(... tag)pour capturer le dotenv. Ne pas le remplacer par ungit tagfait 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 plageHEAD^1..HEAD^2de la MR.
Deux saveurs à choisir :
- Paquet npm :
npm publish --tag $DIST_TAGaprèseval $(release-util tag).DIST_TAGvautstagingpour les releases staging etlatestpour la prod. - Image Docker : build, tag, push.
latestetstaging-latestsont 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)
| Variable | Portée | Rôle |
|---|---|---|
RELEASE_TOKEN | Protégée + Masquée | Project 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_TOKEN | Protégée + Masquée | Token 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=publishLe 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
prepare:
script:
- VER=$(npx --yes @spektrum/release-util@latest next-version --env prod)
- echo "RELEASE_VERSION=$VER" > version.env
artifacts:
reports:
dotenv: version.envnext-version écrit sur stdout ; tout le reste va sur stderr, donc la capture est propre.
Évaluer le dotenv du tagger
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
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.shPublier 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 source | Tag git | Tags d'image poussés |
|---|---|---|
release/X.Y.Z | X.Y.Z | ${REGISTRY}/${IMAGE}:X.Y.Z et ${REGISTRY}/${IMAGE}:latest |
release/X.Y.Z-staging.N | X.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.

