ContribuerGuidePour contributeursS'applique de 4.2.0
Publier une release
This page in EnglishCette page sur le wiki GitHub
Comment une version de quest'n'click se fabrique, pour le mainteneur : un candidate run sur main, un tag signé qui le
nomme, une release qui publie les fichiers de ce run sans rien reconstruire, puis une relecture. Les commandes sont
npm run ship -- … (tools/release/ship.mjs) ; chacune écrit son PID dans
.cache/pids/ship-<commande>.pid (SHIP_PIDS choisit le dossier) : pour en arrêter une, on arrête ce PID, pas un
motif.
Ce que vous obtenez
Une release GitHub v<version> publiée et immuable, construite depuis le commit que la CI et le candidat ont testé,
avec ses archives, manifestes, SBOM, sommes et attestations de provenance, relue par ship verify ; à partir de la
4.5.0, sa documentation publiée après cette relecture.
Contexte et versions
Dans le dépôt du moteur, par le mainteneur (il faut l'accès en écriture, la clé de signature et les réglages du dépôt). La chaîne est celle de la 4.1.20 « Last Mile » (plan §11) ; les tags sont signés depuis la 4.2.0. Cette page vaut à partir de la 4.2.0.
Prérequis
- La CLI GitHub
gh, connectée en tant que mainteneur. - Les réglages du dépôt activés une fois (plus bas) : releases immuables et ruleset de tags.
- La clé de signature configurée (plus bas).
- La section du CHANGELOG de la version assemblée depuis les fragments
changes/(le travail de la branche de release, Conventions), et la fiche des passes des personnes commencée (Passes de terrain).
Où lancer les commandes
Dans le dépôt du moteur, sur la machine du mainteneur, sur un main à jour. La release elle-même tourne sur GitHub
Actions (.github/workflows/release.yml), lancée par le run ci du tag.
Étapes
La chaîne
-
Un candidat sur main. On le lance à la main sur main pour le SHA complet :
# dans le dépôt du moteur gh workflow run candidate --ref main -f sha=<full sha>Il joue toutes les familles lourdes sur ce SHA, le profil de qualification complet sur ses propres archives et son image, les trois charges et la répétition de signature. Sa gate (
candidate-gate) écrit et attestecandidate-manifest.json, avec chaque fichier que la release publiera (tools/release/artifacts.mjs). Lire la gate et sa conclusion. Seul un run lancé à la main (workflow_dispatch) sur main peut être nommé par un tag ; une pull request avec le labelfull-cile lance aussi, pour information seulement.
-
Un tag qui le nomme.
# dans le dépôt du moteur npm run ship -- tag <version> <sha> --candidate=<run> --sign --nowLe tag stable précédent doit être un ancêtre du SHA.
--candidate=<run id>est obligatoire depuis la 4.1.17 : le run doit être vert et son manifeste nommer ce SHA et ce run ; l'annotation du tag le nomme, et release.yml publie les fichiers de ce run.--nown'attend pas le runcide main (le runcidu tag, la même suite sur le même commit, est celui que release.yml vérifie).--signsigne le tag avec la clé SSH (plus bas).ship tagrefuse de taguer tant que les releases immuables sont désactivées. Il attend ensuite commeship watch.
- La release, depuis ce run. Le run
cidu tag, une fois vert, lancerelease.yml. Il vérifie que le tag est bien le commit testé par la CI, que le tag stable précédent est un ancêtre, et que le candidat nommé est un run vert decandidatelancé à la main sur main. Il télécharge les fichiers du run et vérifie chaque SHA-256 contre le manifeste. Il rejoue les vérifications de release (npm run release-check:ci), prouve les catalogues Remix, et copie ce que le candidat a fait : il ne reconstruit rien de ce que le candidat a produit (archives, image, SBOM, le site, les surfaces). Il crée alors la release en brouillon, téléverse chaque fichier, la publie et la relit (ship verify). Depuis la 4.1.20, il lui faut aussi la répétition de signature du run : un candidat antérieur à la PR 3b de cette version ne peut pas être publié, il faut en lancer un nouveau. Un seul run de release par tag à la fois : le second attend, puis trouve la release du premier.
-
Relecture.
# dans le dépôt du moteur npm run ship -- verify <version>La commande télécharge la release et vérifie les sommes, chaque attestation de provenance et la liste des fichiers contre le manifeste ; depuis la 4.1.20, elle lance aussi
gh release verifyetgh release verify-assetpour chaque fichier. release.yml la lance comme dernière vérification.
Ce que porte une release
Chaque release est construite depuis le commit que la CI a testé, porte ses licences dans l'archive, et joint : le jeu
construit (dist), son manifeste d'assets, les archives des cinq paquets npm (quest-n-click, create-quest-n-click,
quest-n-click-bridge, quest-n-click-connectors, quest-n-click-studio-server ; Paquets npm),
un SBOM CycloneDX par paquet et un pour l'image du Bridge (cinq SBOM en 4.1.19, six depuis le paquet du Studio Server
en 4.2.1), l'image du Bridge, les preuves des catalogues Remix, un speedrun complet du chapitre de référence vérifié par
speedrun:verify, les runs du candidat, sa baseline, les fichiers de son site, ses surfaces et sa répétition de
signature, le manifeste du candidat, des sommes SHA-256 et une attestation de provenance de build
(gh attestation verify <file> -R wanoo/quest-n-click) ; à partir de la 4.5.0, l'archive de la documentation. Elle
n'est jamais remplacée une fois publiée. Ce que seuls des gens et de vrais appareils vérifient est rapporté dans ses
notes (Passes de terrain).
Une pré-version (4.1.8-rc.1) se tague de la même façon ; release.yml la marque comme pré-release sur GitHub.
S'applique de 4.5.0 à …
La documentation, après la relecture
À partir de la 4.5.0, le job docs-publish de release.yml dépend (needs) du job de release : il ne démarre donc
qu'une fois ship verify passé. Il appelle .github/workflows/docs-publish.yml avec le tag, le SHA, le candidate run et
le sha256 de l'archive de documentation, promeut cette archive (celle du candidat, vérifiée de nouveau), l'inscrit dans
publication.json et pousse le wiki ; une rc ne publie que /docs/<v-rc>/. Il n'est jamais lancé par
release: published, qu'une release publiée avec GITHUB_TOKEN ne déclenche pas. Seule la clé de déploiement du wiki,
WIKI_DEPLOY_KEY, lui est passée. Voir Écrire la documentation.
Ce que le mainteneur active, une fois (après la PR 3b de la 4.1.20)
- Les releases immuables : Settings → General → Releases. Une release publiée garde alors ses fichiers et son tag.
- Un ruleset sur les tags de release : cible
tag,refs/tags/v*, actif. Il réserve la création, refuse la suppression et interdit le force-push. npm run ship -- preflight-stable --candidate=<run>doit alors voir les deux. Avant le premier tag de la 4.1.20,ship tagrefuse de taguer tant que les releases immuables sont désactivées : le jeton de release.yml ne peut pas lire ce réglage (il faut un droit de lecture admin), doncship tagle vérifie avec l'accès du mainteneur.
Signer les tags
Les tags 4.1.x restent annotés (D30). À partir de la 4.2, ils sont signés avec la clé SSH du mainteneur :
# dans le dépôt du moteur
git config gpg.format ssh
git config user.signingkey ~/.ssh/id_ed25519.pub
npm run ship -- tag 4.2.0-rc.2 <sha> --candidate=<run> --sign --now- La clé doit aussi être enregistrée sur GitHub comme clé de signature (Settings → SSH and GPG keys).
- Elle doit figurer dans
.github/allowed_signers, ajouté dans un commit signé par cette clé (8cebea2, fait par Claude à la demande du mainteneur : D37). Ce fichier est aussi la racine de confiance des passes reportées (ADR 0024). --key=<fichier>donne un autre fichier de clé queuser.signingkey.- Chaque candidat répète ce chemin avec une clé éphémère (
signing-rehearsal) : il signe un tag du commit, jamais poussé, le vérifie avecgit verify-tag, puis détruit la clé.
Le préflight stable
# dans le dépôt du moteur
npm run ship -- preflight-stable --candidate=<run> [--version=4.2.0]Il ne signe rien, ne publie rien et ne change aucun réglage
(tools/release/preflight.mjs). Il dit, vérification par vérification, ok,
missing (une étape encore à faire) ou blocked (quelque chose ne va pas) :
- la clé de signature, locale et enregistrée ;
allowed_signers;- l'immuabilité et le ruleset de tags ;
- la provenance du candidat ;
- pour chaque paquet npm : l'archive (
npm publish --dry-run), le nom, le bootstrap, le trusted publisher (en stage-only), une publication OIDC prouvée, et la version pas encore publiée ; - le Node et le npm exacts de l'étape de publication ;
- le GO / NO-GO face aux rapports des personnes (« GO for 4.2 on a reduced scope » se lit avec D38 écrite).
Il ne sort en 1 que sur un blocked.
Toutes les commandes ship
| Commande | Ce qu'elle fait |
|---|---|
ship checks <pr> | Attend les vérifications de la pull request ; relance une fois un job en échec ; sort en 1 s'il échoue encore |
ship merge <pr> | checks, puis fusionne (un commit de fusion, la seule méthode que le ruleset permet) ; affiche le SHA |
ship main <sha> | Attend que le run ci de main sur ce SHA soit vert (relancé une fois) |
ship tag <version> <sha> --candidate=<run> [--now] [--sign [--key=<file>]] | Tague (plus haut), pousse, puis watch |
ship watch <version> | Attend le run ci du tag, puis le run release ; sort selon sa conclusion |
ship verify <version> | La relecture (plus haut) |
ship preflight-stable --candidate=<run> [--version=<x.y.z>] | Le préflight stable (plus haut) |
ship chain <pr> <version> | fusion → tag → watch → verify ; refusée depuis la 4.1.17, dont les tags demandent un candidate run du commit de fusion (fusion, candidat, puis tag) |
Chaque commande est idempotente et dit ce qu'elle attend.
Résultat attendu, et comment le vérifier
ship watch sort en 0 avec le succès du run de release ; ship verify <version> affiche chaque fichier vérifié et
sort en 0 ; la page de la release montre les fichiers et « Immutable » ;
gh attestation verify <file> -R wanoo/quest-n-click passe pour n'importe lequel de ses fichiers.
Erreurs fréquentes
| Symptôme | Cause | Correction |
|---|---|---|
| release.yml : « names no candidate run » | Le tag a été fait sans --candidate | Taguer la version suivante (ou rc.N+1) avec --candidate : le ruleset refuse de supprimer un tag |
| release.yml : « run … is not a green candidate started on main » | Le run est celui d'une pull request, d'une autre branche, ou rouge | Lancer candidate à la main sur main pour ce SHA |
release.yml : « has no candidate-site » (ou -surfaces, -signing, -pack, -sbom, -image) | Un candidat antérieur à l'étape | Lancer un nouveau candidat |
| « is published: a published release is never changed » | Une relance sur un tag publié | Rien à faire ; une nouvelle version est un nouveau tag |
ship tag refuse : releases immuables désactivées | Le réglage n'est pas activé | L'activer (plus haut), puis taguer |
| Une RC ratée | — | Taguer rc.N+1 depuis un nouveau candidat |
Fichiers ou données modifiés
Un tag v<version> (signé), une release GitHub avec ses fichiers et attestations, .cache/pids/ship-*.pid en local ;
à partir de la 4.5.0, le wiki et publication.json (par docs-publish). Avant cela, la branche de release modifie
CHANGELOG.md, docs/dev/LOG.md et docs/dev/passes/<version>.md.
Revenir en arrière
Une release publiée ne peut être ni changée ni retirée : un défaut se corrige dans une nouvelle version. Un brouillon est supprimé par le run de release suivant. Un tag pas encore publié peut rester tel quel, et un nouveau candidat être tagué sous le numéro de pré-version suivant.