The product page of la-compagnie-maximus copies the edition matrix into a comparison table (la-compagnie-maximus#180). Step 0 of the release skill now says to prepare the site PR before the tag and deploy it only after the release is published. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
15 KiB
| name | description | user-invocable | updated |
|---|---|---|---|
| release | Release a new version of Simpl-Resultat (bump, changelog, tag, push) | true | 2026-10-11 |
/release — Release Simpl-Resultat
Context injection
- Lire version dans
src-tauri/Cargo.tomletpackage.json - Lister les derniers tags :
git tag --sort=-v:refname | head -10 - Lire
CHANGELOG.mdetCHANGELOG.fr.md(dernieres entrees)
Workflow
-
Pré-vol — revalider le tip localement. Les workflows
check-rust.yml/check-frontend.ymlne tournent pas surmain: le tip mergé n'a jamais été vu par le CI (le dernier run vert portait sur la branche d'issue avant merge), et le tag grave ce tip exact dans des binaires distribués. Lancernpm run build && npm test(vitest) +cd src-tauri && cargo check && cargo test. Vérifier aussi que.claude/worktrees/est vide (worktrees leftover → vitest récurse et gonfle le compteur). Ne tagger que sur un tip vert. Accès des testeurs. Si[Unreleased]toucheFEATURE_TIERS, le gating par édition ouauto-update: vérifier que chaque testeur (Max, Michel) a une clé Base+ saisie avant le tag, émise via/issue-licenseau besoin — la clé s'entre dans la version installée et survit à la mise à jour ; une installation sans clé reçoit cette version, puis plus rien. Cas réel v0.15.0 : deux clés Premium émises le jour même, juste avant le tag. Tableau des éditions du site. Si[Unreleased]change la matrice des éditions (ENTITLEMENTSdesrc/shared/entitlements.ts,FEATURE_TIERSdesrc-tauri/src/commands/entitlements.rs, ou un module Free qui passe sous verrou, comme le fractionnement de #369) : la page produit du site en a une copie (la-compagnie-maximus/src/data/editions.ts, tableau comparatif et phrasesimplresultat_detail_desc). Préparer la PR du site avant le tag en suivant la section « Matrice des éditions — Simpl-Résultat » de sonCLAUDE.md, et ne la déployer qu'après la publication de la release : avant, le tableau promettrait un verrou absent des binaires. -
Determiner la nouvelle version (argument utilisateur ou demander)
-
Bump version dans les 5 fichiers :
src-tauri/Cargo.toml(ligneversion = "...")src-tauri/Cargo.lock(bloc[[package]] name = "simpl-result"+ sa ligneversion = "..."; ne PAS regenerer avec cargo)src-tauri/tauri.conf.json(champ"version")package.json(champ"version")package-lock.json(deux champs"version"— root ~ligne 3 et le package racine""~ligne 9)- Si
package-lock.jsonest stale (hygiene warningpackage-lock.json plus ancien que package.json) :npm install --package-lock-only --no-audit --no-fundpour resync. Note : peut ajouter des entrees bundled optionnelles (tailwindcss oxide wasm etc.) — cosmetique, pas d'install effective.
- Si
- Puis rejouer le garde
windows-sysdecheck-rust.ymlsur le lock édité : le commit de release toucheCargo.lockdirectement surmain, sans PR, etcheck-rustne le verrait qu'au lundi suivant, après le build du tag (ADR 0023). Depuis la racine du dépôt, le texte exact de l'étape avec les options du runner :
Attendu : code de sortie 0 et dernière lignepython3 -c 'import sys, yaml; steps = yaml.safe_load(open(".forgejo/workflows/check-rust.yml"))["jobs"]["rust"]["steps"]; sys.stdout.write(next(s["run"] for s in steps if s.get("name") == "Verify windows-sys pinning"))' \ | bash --noprofile --norc -e -o pipefailwindows-sys pinning: N checks, exit 0. Une ligneFAIL:arrête la release : suivre la procédure de l'ADR 0023 avant de tagger.
-
Mettre a jour les 2 changelogs — format Keep a Changelog :
CHANGELOG.md(EN) : header## [Unreleased]CHANGELOG.fr.md(FR) : header## [Non publié](PAS[Unreleased]— ne pas le confondre avec un changelog vide)- Pattern de migration : transformer le header « non publié » de chaque fichier en
## [X.Y.Z] - YYYY-MM-DD, puis recreer la section « non publié » vide au-dessus pour accueillir les prochaines entrees. Le header differe selon la langue. Ne pas deplacer le contenu — les sections sont laissees en place.
-
Si changement d'architecture : mettre a jour
docs/architecture.md -
Commit :
chore: release vX.Y.Z(ajouter les 7 fichiers : 5 bumps + 2 changelogs) -
Tag annote (permet une release notes par tag, lisible via
git show vX.Y.Z) :git tag -a vX.Y.Z -m "Release X.Y.Z - <bullet highlights>" -
Push :
git push origin main && git push origin vX.Y.Z -
Forgejo CI build automatique (Windows + Linux) via
release.ymlsuron: push: tags: v* -
Post-CI — vérifier la release publiée. Surveiller
release.yml(outilMonitorsur le run), puis vérifier la release réellement attachée —status=successdu workflow ne suffit pas :bash .claude/skills/release/scripts/verify-release.sh vX.Y.ZLe script (token
~/.forgejo-token) lit la release par tag, compte les 7 artefacts par suffixe (.exeNSIS,.deb,.rpm, leurs 3 signatures.sig,latest.json— les noms exacts varient selon la version de Tauri), puis téléchargelatest.json(il pilote l'auto-update des installations existantes) et vérifieversion(il affichepub_dateet la longueur des notes), puis exige exactement trois clés (#320) :linux-x86_64-deb,linux-x86_64-rpmetwindows-x86_64, sans clé génériquelinux-x86_64depuis le 2026-10-11 (docs/qa-update-cycle.md). Pour chacune : l'extension de l'URL (.deb,.rpm,.exe), une signature non vide dont lefile:(commentaire de confiance minisign, signature décodée du base64) est le nom de fichier de l'URL, décodé, et la version dans l'URL. Il sort en 1 sur tout écart (MANQUANT,VIDE,MAUVAISE VERSION,MAUVAISE EXTENSION,DIFFÉRENT,INATTENDUE) et finit parVERDICT : OKouVERDICT : ÉCHEC: pas d'annonce de la release ni d'étape 10 avant un verdict OK. Un second argument (verify-release.sh vX.Y.Z fichier.json) contrôle unlatest.jsonlocal au lieu de l'asset, pour éprouver les contrôles sur un fichier fabriqué. Lire aussi l'étape « Generate latest.json » du journal du run (même route web que ci-dessous) :scripts/build-latest-json.shy nomme le paquet retenu pour chaque type (build-latest-json: .rpm <- …), puis lelatest.jsongénéré est affiché. Le script, le filtrescripts/check-latest-json.jqet le texte de l'étape « Publish » (avec uncurlfactice) passent par les tests decheck-frontendà chaque PR ; l'appel du script par l'étape « Generate latest.json », le délimiteur aléatoire des notes et les vrais appels au registre ne s'exercent qu'au tag. Un manifeste refusé par le filtre arrête le job surERROR: release-assets/latest.json failed scripts/check-latest-json.jq, avant leDELETE: registre intact, et la release Forgejo reste créée sans mise à jour servie. Durée observée du run : 22 à 30 min sur les 12 dernières releases — poser leMonitorpuis passer à autre chose. Lire aussi le Node.js du run.release.ymln'est exercé qu'au tag : une montée de Node (Node 20 → 24 par #376) ne se prouve que dans ce journal. Il passe par la route web (l'API v1 des journaux répond 404). Lerun_numbervient de/actions/tasks: sans paramètrepage, la route rend toute la liste, la plus récente en tête, et ignorelimit(avecpage, elle pagine par 30 ou parlimit, mesuré le 2026-10-12) :TAG=vX.Y.Z RUN=$(curl -s -H "Authorization: token $(cat ~/.forgejo-token)" \ "https://git.lacompagniemaximus.com/api/v1/repos/maximus/simpl-resultat/actions/tasks" \ | python3 -c "import json,sys; print(next(t['run_number'] for t in json.load(sys.stdin)['workflow_runs'] if t['workflow_id']=='release.yml' and t['head_branch']==sys.argv[1]))" "$TAG") curl -sL -H "Authorization: token $(cat ~/.forgejo-token)" \ "https://git.lacompagniemaximus.com/maximus/Simpl-Resultat/actions/runs/$RUN/jobs/0/logs" \ | grep -m1 -E 'Z v[0-9]+\.[0-9]+\.[0-9]+\s*$'Attendu :
v24.x. C'est la sortie denode --versiondans l'étape « Install base tools and runtimes », seule ligne de ce format dans le journal (la v0.17.1, run 508, affichaitv20.20.2). Toute autre majeure est à expliquer avant l'étape 10. -
Post-CI — dérouler un vrai cycle de mise à jour si la release touche
tauri-plugin-updater, ses dépendances (reqwest/rustls/rustls-webpki),release.yml, ou la configupdaterdetauri.conf.json:docs/qa-update-cycle.md.Inspecter
latest.jsonprouve qu'il est bien formé, pas qu'il installe. Le reste de la chaîne — téléchargement TLS, vérification de signature, exécution de l'installeur, redémarrage — n'est exercé par aucun test :cargo check/cargo testprouvent que ce code compile, rien de plus. Une régression s'y voit chez l'utilisateur, au moment de la mise à jour.Deux pièges qui font cocher la checklist sans rien vérifier, détaillés dans la doc : tester depuis une machine déjà à la nouvelle version (
check()répond « à jour ») et tester sans clé Base+ (l'auto-update est verrouillé par édition, l'app bascule ennotEntitledavant même d'interroger le serveur).Si la checklist n'est pas déroulée, l'écrire avec la raison sur la release plutôt que de laisser le silence.
Regles
- JAMAIS
git push --tags— toujours push le tag individuellement - Toujours mettre a jour les 2 changelogs (EN + FR)
- Format Keep a Changelog :
## [X.Y.Z] - YYYY-MM-DD - Les changelogs sont bundles dans
public/pour l'affichage in-app - Tag annote (
-a), pas lightweight : les artefacts CI reference le tag pour les release notes - Tagger publie vers l'extérieur :
release.ymlpousse le JSON d'updater, donc les utilisateurs installés reçoivent la mise à jour automatiquement. Confirmer avec Max avant de tagger.
Changelog
- 2026-04-19 — Added Cargo.lock + package-lock.json to bump list,
npm install --package-lock-onlyfallback when lockfile stale, explicit[Unreleased]migration pattern, annotated tags (#102/#112 release cycle) - 2026-07-01 — Documenter que le header FR est
## [Non publié](≠[Unreleased]), pour éviter le faux diagnostic « changelog FR vide » lors de la migration. Source : session 5466da98. - 2026-07-13 — Étape 0 (pré-vol) : revalider le tip localement avant de tagger —
check.ymlne tourne pas surmain, le tip mergé n'a jamais été vu par le CI ; vérifier.claude/worktrees/vide (vitest récurse sinon). Étape 9 (post-CI) : vérifier la release publiée — 7 artefacts attendus + contenu delatest.json(pilote l'auto-update) ;status=successne suffit pas. Règle : tagger publie vers l'extérieur (updater automatique) → confirmer avec Max avant de tagger. Source : session fdda84cb (release v0.13.0). - 2026-07-27 — Étape 10 (post-CI) : dérouler un vrai cycle de mise à jour via
docs/qa-update-cycle.mdquand la release touche l'updater. Inspecterlatest.jsonprouve qu'il est bien formé, pas qu'il installe : le téléchargement TLS, la vérification de signature, l'exécution de l'installeur et le redémarrage ne sont exercés par aucun test. Deux pièges qui font cocher sans vérifier — tester depuis la machine déjà à jour (check()répond « à jour ») et tester sans clé Base+ (auto-update verrouillé par édition,notEntitledavant toute requête). Source : session 50ac88d9 (#315, découvert en traitant les advisoriestar/rustls-webpkide #310). - 2026-09-13 — Étape 0 (pré-vol) : cross-référence vers
/issue-licensequand la release modifieFEATURE_TIERSou verrouille une fonctionnalité Free — émettre et distribuer les clés testeurs avant de tagger, sinon ils perdent l'auto-update. Source : session 690a6129 via /skills-review-inbox (draft 2026-09-06). - 2026-09-13 — Étape 0 : prérequis « clés testeurs saisies avant le tag » précisé (déclencheurs
FEATURE_TIERS, gating,auto-update; cas réel v0.15.0, deux clés Premium émises le jour même). Étape 9 : scriptscripts/verify-release.sh(7 artefacts par suffixe + contenu delatest.json) au lieu d'un script réécrit à chaque release ; durée de run observée 22-30 min. Source : session 690a6129 (release v0.15.0, run 402) via /skills-review-inbox (draft 2026-09-12). - 2026-10-10 — Étape 9 (post-CI) : lire
node --versiondans le journal du run de release (route web, seule lignevX.Y.Zdu journal).release.ymln'est exercé qu'au tag, donc la montée Node 20 → 24 de #376 ne se prouve qu'à la release suivante. Source : caveat de planification de #376 (milestoneplanned-2026-10-10-release-deps). - 2026-10-10 — Étape 9 (post-CI) :
verify-release.shexige les quatre clés delatest.json(linux-x86_64,linux-x86_64-deb,linux-x86_64-rpm,windows-x86_64), l'extension de chaque URL et lefile:minisign de chaque signature, et sort en 1 sur tout écart (verdict en dernière ligne) ; lire l'étape « Generate latest.json » du journal. Source : #320 (milestoneplanned-2026-10-10-release-deps). - 2026-10-11 — Étape 9 (post-CI) :
latest.jsonà trois clés, la clé génériquelinux-x86_64étant retirée (décision de Max sur #320 : ses derniers lecteurs, AppImage v0.4.3 à v0.4.5 et binaires hors paquet, ne savaient pas installer le.debqu'elle servait). Le filtre d'avant leDELETEvit dansscripts/check-latest-json.jq, que les tests decheck-frontendexercent à chaque PR, avec la comparaison des trois listes de clés. Source : revue de la PR #416. - 2026-10-11 — Étape 2 : rejouer le garde
windows-sysdecheck-rust.yml(ADR 0023) juste après l'édition deCargo.lock, puisque le commit de release n'a pas de PR et quecheck-rustne le verrait qu'au lundi suivant. Commande éprouvée sur le lock de la pile (exit 0) et sur une arête dérivée (exit 1). Source : revue de la PR #415. - 2026-10-16 — Étape 0 : report d'un changement de matrice des éditions vers le tableau comparatif du site (
la-compagnie-maximus/src/data/editions.ts), PR du site préparée avant le tag et déployée après la publication. Source : la-compagnie-maximus#180. - 2026-10-18 — Étape 9 (post-CI) : le filtre de
latest.jsonest appelé avec-s(fichier vide ou à deux documents refusé sous jq 1.6, celle du conteneur), et le texte de l'étape « Publish » derelease.ymlest exécuté parscripts/build-latest-json.test.mjs;check-frontendne saute plus les PR qui ne touchent que.claude/**ourelease.yml. Source : #419 (suivis de la revue de la PR #418).