Aller au contenu
quest'n'click

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

  1. 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 atteste candidate-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 label full-ci le lance aussi, pour information seulement.

  1. Un tag qui le nomme.

    # dans le dépôt du moteur
    npm run ship -- tag <version> <sha> --candidate=<run> --sign --now

    Le 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. --now n'attend pas le run ci de main (le run ci du tag, la même suite sur le même commit, est celui que release.yml vérifie). --sign signe le tag avec la clé SSH (plus bas). ship tag refuse de taguer tant que les releases immuables sont désactivées. Il attend ensuite comme ship watch.

  1. La release, depuis ce run. Le run ci du tag, une fois vert, lance release.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 de candidate lancé à 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.
  1. 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 verify et gh release verify-asset pour 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 tag refuse 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), donc ship tag le 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é que user.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 avec git 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

CommandeCe 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ômeCauseCorrection
release.yml : « names no candidate run »Le tag a été fait sans --candidateTaguer 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 rougeLancer 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'étapeLancer 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éesLe 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.

Références