Contribuer
Releases et stabilité
À lire avant : Flux de contribution (le gate de version) et Publier la documentation (ce qu'une release régénère).
Cette page traite de l'autre moitié d'une release : ce que promet le version dans
Cargo.toml, ce qui se passe quand on demande une release, et ce que le moteur garantit de ne pas
casser sans une version majeure. Publier la documentation couvre déjà le
côté documentation d'une release (ce qui est régénéré, ce que vérifie la CI) ; cette page
couvre le numéro de version lui-même et le contrat CLI/manifeste qu'il soutient.
Le gate de version#
scripts/version_gate.py (job de CI version, fetch-depth: 0 car il a besoin de tous les
tags) autorise le version du workspace, dans le Cargo.toml racine, à être exactement l'une
de deux choses :
- Égal au tag le plus récent que ce commit contient. Travail ordinaire entre les releases.
Deux builds avec le même numéro de version se distinguent par
delonix --version, qui affiche la distance depuis ce tag :commit: <hash> (+N commits since vX.Y.Z). - Supérieur au tag contenu le plus récent, seulement dans le commit de release — et alors
docs/releases/v<version>.mddoit exister, car le workflow de release le publie comme corps de la GitHub Release.
Tout le reste échoue, chacun avec une raison liée à un vrai mode de défaillance :
| Ce que voit le gate | Pourquoi ça échoue |
|---|---|
| Un tag plus récent existe que ce commit ne contient pas | La branche a commencé avant cette release ; la fusionner telle quelle annule ce que la release a déjà publié. Fusionnez d'abord origin/main. |
Cargo.toml est inférieur au tag contenu le plus récent |
Un numéro de version plus ancien serait publié par-dessus un plus récent. |
Cargo.toml est supérieur au tag contenu le plus récent, sans docs/ |
Un bump sans tag correspondant — envoie le téléchargement de delonix-cri (résolu depuis la propre version du binaire en cours d'exécution, voir vmimage.rs) vers une release qui n'existera jamais. |
La version n'est pas de la décoration : outre le téléchargement de delonix-cri, c'est le
ServerVersion de l'API Docker, le delonix_version enregistré dans chaque sauvegarde de
ressource, et ce que le workflow de release (ci-dessous) vérifie contre le binaire construit
avant de publier quoi que ce soit.
N'incrémentez pas la version dans une PR de fonctionnalité, et n'utilisez pas de suffixe -dev
— la première règle du gate couvre déjà le travail ordinaire, et un suffixe -dev enverrait le
téléchargement du CRI vers une release qui n'existe pas.
Ce que fait la publication d'une release#
Pousser le tag ne publie rien. Depuis le 2026-09-23, le workflow de release est
workflow_dispatch et rien d'autre : le tag et la release sont deux décisions distinctes, donc un
tag qui arrive sur le remote par accident (git push --tags, push.followTags=true) ne met plus
un binaire devant tout le monde. Ici, un tag sans release est un état intermédiaire normal.
git tag -a v4.4.0 -m "v4.4.0" && git push origin v4.4.0 # coupe la version
gh workflow run release.yml -f tag=v4.4.0 # la publie
Un job guard s'exécute d'abord et coûte quelques secondes : il refuse un tag qui n'a pas la
forme vX.Y.Z, un qui n'existe pas sur le remote, et un qui a déjà une release — l'entrée
choisit le commit à construire et donne son nom à la release, donc un tag: main non vérifié
aurait publié une release appelée « main ». Ensuite seulement, en un seul job :
- Construit
delonix,delonix-cri,delonix-mcpetdelonix-mgmtdeux fois — une fois générique x86-64, une fois avec-C target-cpu=x86-64-v3(AVX2/BMI2/FMA) — spécifiquement surubuntu-22.04, afin que la base glibc (2.35) reste compatible avec RHEL 9 et Debian 12, pas seulement avec le dernier Ubuntu.scripts/install.shchoisit automatiquement le build-v3quand le CPU de l'hôte le prend en charge. Un jobbuild-arm64distinct construit nativement les quatre mêmes binaires sur un runner aarch64 (un par composant, sans variante-v3), et ils sont publiés sous le nom<name>-aarch64-linuxavec le mêmeSHA256SUMS.install.shles installe sur un hôte aarch64 (#447). Le job ne s'exécute qu'au moment de la release, donc sa première exécution a été la release v4.2.0 elle-même ; la CI exécute la suite de tests nativement sur arm64 dans le jobtest (arm64)à chaque PR. - Régénère le site utilisateur contre ce build de release exact et échoue si
docs/diffère. Ce gate existe parce qu'il n'a pas toujours existé : un trou du site est parti en direct dans la v0.48.0, cachant une nouvelle commande pendant des heures pendant qu'un job de CI parallèle était déjà rouge à ce sujet — les deux workflows ne se regardaient tout simplement pas l'un l'autre. Exécuterdocs/gen.pyici, avant de publier, referme cela. - Construit un
SHA256SUMSavec somme de contrôle, un SBOM SPDX 2.3 (scripts/sbom.py, à partir deCargo.lock, lui-même haché dansSHA256SUMS), et — quand le secretMINISIGN_SECRET_KEYest configuré — une signature minisign surSHA256SUMS.SHA256SUMSseul ne prouve que l'intégrité du transfert (il vient de la même URL que le binaire) ; la signature prouve que la release vient bien de ce projet, puisqueinstall.shembarque la clé publique et refuse d'installer une release non signée sans--insecure-skip-signature. Échouer à signer quand une clé est configurée est une erreur bloquante — cela casserait d'un coup la vérification de signature de tous les installateurs. - Vérifie que son propre binaire rapporte la version du tag (
delonix --version | grep <tag>) avant de publier quoi que ce soit — la même classe de vérification queversion_gate.pya déjà exécutée plus tôt, contre l'artefact qui est réellement sur le point d'être publié. - Attache la provenance de build SLSA (
actions/attest-build-provenance, l'action propre à GitHub, gardée volontairement séparée de minisign : la provenance prouve où et depuis quel commit quelque chose a été construit, pour qui ne fait pas confiance au projet d'emblée ; minisign prouve que la release est bien de ce projet, pour qui fait déjà confiance à sa clé publique embarquée). - Publie la GitHub Release, avec
docs/releases/<tag>.mdcomme notes quand ce fichier existe, ou--generate-notessinon. - Fait un checkout de
mainet régénèredocs/RELEASES.md(scripts/gen-releases.sh) et les faits générés du manuel (scripts/dev_docs.py) et, séparément, le site du manuel (scripts/dev_docs_site.py) — en commitant ce qui a changé,[skip ci], pour que la documentation ne soit jamais en retard de plus d'un commit sur une release. Un échec du générateur ici est un avertissement fort, pas une release échouée : la release elle-même n'en dépend pas.
La moitié narrative du manuel — la prose de ces pages — n'est pas régénérée par la CI. Après la publication d'une release, une revue menée par un mainteneur lit ce qui a changé depuis le tag précédent (commits, notes de release) et ne met à jour que les pages que ce changement affecte, exactement comme décrit dans Publier la documentation § Ce qui se passe au moment de la release.
Ce qui est stable, et où vit cette promesse#
docs/cli-stability.md est le contrat réel, dans le même dépôt, lu aussi bien par delonix
explain que par les pages générées — cette section ne fait que vous y orienter, car dupliquer
son contenu ici lui donnerait une seconde copie susceptible de se désynchroniser du code. Elle
s'applique depuis la v0.42.3 et, depuis la v1.0.0, se lit comme la véritable promesse de semver
du projet plutôt que comme une note interne au 0.x.
Stable — ne casse pas sans une version majeure :
- Les verbes de cycle de vie container/image (
container run,ps,stop,exec, …) et les verbes d'image, avec les noms et l'ordre des arguments propres à Docker/Podman, et les options courtes/longues précises quedocs/cli-stability.mdliste pourrun/exec. - Les codes de sortie (
0succès,4non trouvé,5conflit,69capacité de l'hôte manquante,124délai dépassé, …) et le numéro de dictionnaireDX-CDNNque porte chaque échec (ADR-0043) — le numéro identifie quel échec et ne change jamais de signification ni n'est réutilisé ;delonix explain DX-4501en cherche un. -o jsonsur chaque commande de listage : des champs peuvent être ajoutés, jamais retirés ni retypés (ADR-0005).- Le schéma du manifeste pour les Kinds à spec typée (
Container,Pod,Volume,Network, et les autres que listedelonix manifest schema) : un champ n'est jamais retiré, retypé ou réaffecté ; un nouveau champ est toujours optionnel avec une valeur par défaut qui préserve l'ancien comportement ; un champ renommé garde l'ancienne orthographe comme alias ;apiVersion: delonix.io/v1continue de se charger même après que les groupes par domaine (compute.delonix.io/v1alpha1, …) sont devenus canoniques. C'est la promesse qui compte le plus en pratique — elle protège ce que les gens mettent dans git et relisent dans une PR, pas seulement ce qu'ils tapent à une invite.
Pas stable — peut changer à n'importe quelle version : serve cri/serve api/serve
docker-api (l'API de gestion locale en particulier n'a aucun contrat publié et n'est
explicitement pas quelque chose contre quoi automatiser — voir Les crates §
delonix-mgmt et les ADR-0040/0041) ; les surfaces impératives
cluster/vm/pod/workload/net (leur schéma de manifeste, quand il existe, est couvert
ci-dessus — seuls les verbes et les options autour ne le sont pas) ; compose ; backup ;
mcp ; system/dashboard/completion/init/man/config/explain ; le format de l'état
sur disque sous $DELONIX_ROOT ; et stack history/stack rollback (ADR-0019 — rien ne lit
cet historique pour décider ce qui existe, donc le perdre ne change rien à ce que fait le
réconciliateur).
Comment un changement incompatible est fait, quand il le faut#
Le précédent, déjà appliqué plus d'une fois (la réorganisation de la CLI en v0.30.0, l'inversion
image list→image ls en v2.0.0) : une coupure nette, sans alias de compatibilité.
L'ancienne orthographe échoue avec unrecognized subcommand, bruyamment, dans chaque version à
partir de la coupure — jamais un alias silencieux qui change discrètement de comportement plus
tard. docs/cli-stability.md § Como uma quebra é feita consigne une vraie leçon tirée de cette
pratique : un renommage peut laisser un appelant interne derrière lui (le serveur CRI
lui-même a continué à invoquer un delonix netns attach déjà retiré pendant des mois après la
réorganisation de la v0.30.0, cassant la création de pods rootless) — grepper tout le workspace
pour l'ancienne orthographe, pas seulement la documentation et les tests, fait partie de la
coupure.
Un changement incompatible sur quelque chose que cette page ou docs/cli-stability.md marque
comme stable a besoin d'un ADR au préalable (Flux de contribution § Quand écrire un
ADR), parce que cela déplace une frontière
structurelle par définition — le même raisonnement qui s'applique à un nouveau backend ou à une
nouvelle frontière de privilège s'applique aussi ici.
Ensuite : Publier la documentation — comment le site et ce manuel sont générés, contrôlés par gate et publiés, et ce que votre PR doit régénérer.