Documente qu'il n'y a plus qu'un script, et pourquoi il refuse

La chaîne de publication n'a plus qu'un point d'entrée. README.md décrit
`publier.sh` seul, ses deux refus (tag déjà pris, dépôt du code sale) et
le mode `--archive-seule` pour la marche à pied ; CLAUDE.md acte la fusion
et ce qu'elle empêche de refaire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-21 23:12:52 +02:00
co-authored by Claude Opus 5
parent 323b50676b
commit 63bf6be3e1
2 changed files with 91 additions and 27 deletions
+35 -4
View File
@@ -1934,15 +1934,18 @@ appris, pas ce qu'on en attendait.
### La chaîne, telle qu'elle tourne ### La chaîne, telle qu'elle tourne
``` ```
publier-release.sh → archive tar.gz (69 Mo, self-contained) → release Gitea publier.sh → archive tar.gz (69 Mo, self-contained) → release Gitea
→ manifest.toml (amd64.url + amd64.sha256) → manifest.toml (amd64.url + amd64.sha256) → commit + push
→ yunohost app install <url du dépôt _ynh> → tag v<version> + push → yunohost app upgrade
``` ```
Le script est la seule source des trois valeurs qui doivent rester cohérentes : Le script est la seule source des trois valeurs qui doivent rester cohérentes :
version, URL, sha256. ⚠️ Il ne réécrit **que** `manifest.toml` — les autres mentions version, URL, sha256. ⚠️ Il ne réécrit **que** `manifest.toml` — les autres mentions
de l'URL (`README.md`, `Documentation=` de l'unité systemd) sont à traiter à la main. de l'URL (`README.md`, `Documentation=` de l'unité systemd) sont à traiter à la main.
⚠️ **Il n'y a qu'UN script, depuis le 2026-08-21 — voir « Un seul script de
publication » ci-dessous.** Ne pas réintroduire d'étape appelable séparément.
⚠️ **Le dépôt du code doit être public.** `ynh_setup_source` télécharge sans jeton. ⚠️ **Le dépôt du code doit être public.** `ynh_setup_source` télécharge sans jeton.
Gitea répond **404 et non 403** à un anonyme sur un dépôt privé : le symptôme est Gitea répond **404 et non 403** à un anonyme sur un dépôt privé : le symptôme est
rigoureusement identique à « la release n'existe pas », ce qui envoie chercher au rigoureusement identique à « la release n'existe pas », ce qui envoie chercher au
@@ -1952,6 +1955,34 @@ mauvais endroit. Contrôle qui tranche, hors session authentifiée :
⚠️ **YunoHost lit le manifeste depuis Gitea**, jamais la copie locale. Une correction ⚠️ **YunoHost lit le manifeste depuis Gitea**, jamais la copie locale. Une correction
non poussée est une correction qui n'existe pas — constaté deux fois. non poussée est une correction qui n'existe pas — constaté deux fois.
### Un seul script de publication — fusion du 2026-08-21
Il y en avait deux : `publier.sh` (l'enchaînement complet) et `publier-release.sh`
(compiler, archiver, réécrire le manifeste). ⚠️ **Le mauvais des deux portait le nom le
plus convaincant** — « publier-release » sonne plus précis que « publier », et les deux
se ressemblent dans la complétion du shell.
Lancé seul, il produisait les **deux moitiés** de la panne constatée ce jour-là :
| Ce qu'il faisait | Conséquence |
|---|---|
| réécrire `manifest.toml` **sans committer** | `yunohost app upgrade` échoue sur le sha256 — et son **retour arrière échoue pour la même raison**, puisqu'il retélécharge la même source |
| accepter de recompiler une version dont le **tag existe déjà** | la release `v0.4.0` contenait en réalité **six commits de plus** que son tag, donc une application qui se déclare « 0.4.0 » sans l'être |
Le second est le plus grave, et le plus silencieux : rien ne le signale, et c'est
précisément le numéro qu'on ira chercher dans « À propos » pour diagnostiquer un
appareil dépareillé (voir le lot Y). **Une release qui ment sur son contenu ruine le
seul repère dont on dispose.**
Les deux scripts sont fondus dans `build/publier.sh`, qui refuse maintenant de publier
**avant de compiler** si le tag existe déjà (en nommant le commit du tag et celui de
HEAD) ou si le dépôt du code a des modifications non committées.
⚠️ Le mode `--archive-seule` conserve la brique réutilisable en CI, mais **sous le même
nom** : il compile et archive sans toucher ni au manifeste ni à git, donc il ne peut
rien laisser à moitié publié. Ne pas recréer de second script — c'est la coexistence de
deux commandes voisines qui était le défaut, pas leur contenu.
### Deux pièges systemd, tous deux invisibles hors d'un vrai serveur ### Deux pièges systemd, tous deux invisibles hors d'un vrai serveur
Ni l'un ni l'autre ne peut sortir d'un `dotnet run` ou d'un lancement du publish à la Ni l'un ni l'autre ne peut sortir d'un `dotnet run` ou d'un lancement du publish à la
@@ -3016,7 +3047,7 @@ utilisateurs d'un service en réseau puissent en obtenir la source** : ce lien n
ornement, c'est ce que la licence demande. ornement, c'est ce que la licence demande.
L'application ne connaissait pas sa version : elle vivait dans le `manifest.toml` du dépôt L'application ne connaissait pas sa version : elle vivait dans le `manifest.toml` du dépôt
`mabibli_ynh` et dans les tags git, **jamais dans le binaire**. `build/publier-release.sh` pose `mabibli_ynh` et dans les tags git, **jamais dans le binaire**. `build/publier.sh` pose
désormais `-p:Version` et `-p:MaBibliDateBuild` (en respectant `SOURCE_DATE_EPOCH`), et l'API rend désormais `-p:Version` et `-p:MaBibliDateBuild` (en respectant `SOURCE_DATE_EPOCH`), et l'API rend
les deux par `GET /api/version`. les deux par `GET /api/version`.
+56 -23
View File
@@ -91,8 +91,7 @@ fichier est le point d'entrée unique du projet.
| `conf/nginx.conf` | Reverse proxy et intégration SSOwat | | `conf/nginx.conf` | Reverse proxy et intégration SSOwat |
| `scripts/_common.sh` | Variables partagées et sauvegarde/restauration cohérente de la base SQLite | | `scripts/_common.sh` | Variables partagées et sauvegarde/restauration cohérente de la base SQLite |
| `scripts/install` `remove` `upgrade` `backup` `restore` | Cycle de vie de l'application | | `scripts/install` `remove` `upgrade` `backup` `restore` | Cycle de vie de l'application |
| `build/publier.sh` | Publie une version de bout en bout : version, archive, manifeste, commits, tag, push | | `build/publier.sh` | **Seul script de publication** : version, archive, manifeste, commit et push du paquet, tag et push du code. `--archive-seule` compile sans rien publier |
| `build/publier-release.sh` | Compile, archive, calcule le `sha256` et met à jour `manifest.toml` |
| `doc/DESCRIPTION.md` `doc/ADMIN.md` | Textes affichés par YunoHost lui-même (catalogue et interface d'administration) — ils doivent rester dans ce dépôt | | `doc/DESCRIPTION.md` `doc/ADMIN.md` | Textes affichés par YunoHost lui-même (catalogue et interface d'administration) — ils doivent rester dans ce dépôt |
### Points de conception ### Points de conception
@@ -128,19 +127,27 @@ propose l'incrément, puis enchaîne tout ce qui suit : archive, manifeste, comm
du paquet, tag et push du code, avec vérification côté distant. Il ne reste qu'à créer du paquet, tag et push du code, avec vérification côté distant. Il ne reste qu'à créer
la release dans Gitea et y téléverser l'archive — le script en rappelle l'URL. la release dans Gitea et y téléverser l'archive — le script en rappelle l'URL.
Sous le capot, c'est `build/publier-release.sh` qui produit l'artefact ; il s'utilise ⚠️ **Il n'y a qu'un seul script, et c'est délibéré.** Un second, `publier-release.sh`,
seul quand on veut une archive sans rien publier : a existé jusqu'au 2026-08-21 : il compilait, archivait et réécrivait le manifeste, à
charge pour l'appelant de committer. Son nom inspirait plus confiance que celui du vrai
point d'entrée, et lancé seul il produisait exactement la panne du 2026-08-21 — un
`manifest.toml` corrigé mais non poussé, et une release `v0.4.0` contenant en réalité six
commits de plus que son tag. Les deux scripts sont fondus ; la brique réutilisable
subsiste sous la même commande :
```bash ```bash
./build/publier-release.sh --version 0.4.0 --no-manifest-update ./build/publier.sh --archive-seule
``` ```
Ce mode compile et archive, **sans toucher ni au manifeste ni à git** : il ne peut donc
rien laisser à moitié publié.
Ce script compile ce dépôt (`mabibli`) en `Release` self-contained, **vérifie** le Ce script compile ce dépôt (`mabibli`) en `Release` self-contained, **vérifie** le
résultat (binaire présent, `wwwroot/` embarqué, toutes les ressources d'`index.html` résultat (binaire présent, `wwwroot/` embarqué, toutes les ressources d'`index.html`
réellement sur disque, aucun placeholder d'empreinte non substitué), produit une réellement sur disque, aucun placeholder d'empreinte non substitué), produit une
archive `.tar.gz` reproductible, calcule son `sha256`, et met à jour `version`, archive `.tar.gz` reproductible, calcule son `sha256`, et met à jour `version`,
`amd64.url` et `amd64.sha256` dans `mabibli_ynh/manifest.toml` — sauf avec `amd64.url` et `amd64.sha256` dans `mabibli_ynh/manifest.toml` — sauf en
`--no-manifest-update`. `--archive-seule`.
Il injecte au passage, dans l'assembly, la **version** (`-p:Version`) et un Il injecte au passage, dans l'assembly, la **version** (`-p:Version`) et un
**horodatage de build** (`-p:MaBibliDateBuild`), que la page « À propos » de **horodatage de build** (`-p:MaBibliDateBuild`), que la page « À propos » de
@@ -157,6 +164,15 @@ voulu.
corrigé mais non poussé n'existe pas pour le serveur. C'est précisément ce que corrigé mais non poussé n'existe pas pour le serveur. C'est précisément ce que
`publier.sh` empêche d'oublier. `publier.sh` empêche d'oublier.
Il refuse par ailleurs de publier dans deux cas, **avant de compiler** :
| Refus | Ce qu'il évite |
|---|---|
| le tag `vX.Y.Z` existe déjà | une release qui ne contient pas le code que son tag désigne — arrivé le 2026-08-21, six commits d'écart, sans que rien ne le signale |
| le dépôt du code a des modifications non committées | une archive contenant du travail que le tag, lui, ne contient pas |
Dans les deux cas il nomme le commit en cause et rappelle `--patch` ou `--archive-seule`.
**La marche à suivre complète et éprouvée**, pour les cas que `publier.sh` ne couvre **La marche à suivre complète et éprouvée**, pour les cas que `publier.sh` ne couvre
pas — première mise en production, montée de version pas à pas, retour arrière, pas — première mise en production, montée de version pas à pas, retour arrière,
désinstallation — est en « Mettre en production » ci-dessous. désinstallation — est en « Mettre en production » ci-dessous.
@@ -193,30 +209,34 @@ sudo yunohost domain add mabibli.mondomaine.tld
- Le SDK .NET est installé sur la machine de développement (`dotnet --version`). - Le SDK .NET est installé sur la machine de développement (`dotnet --version`).
#### A.2 Produire l'archive #### A.2 Produire l'archive, le manifeste et le tag
Depuis `mabibli_ynh`, avec le dépôt du code à côté (`../mabibli`) : Depuis `mabibli_ynh`, avec le dépôt du code à côté (`../mabibli`) :
```bash ```bash
./build/publier-release.sh ./build/publier.sh --version 0.1.0
``` ```
Le script compile en `Release` self-contained, **vérifie le publish** (binaire présent, Le script compile en `Release` self-contained, **vérifie le publish** (binaire présent,
`wwwroot/` embarqué, toutes les ressources d'`index.html` réellement sur disque, aucun `wwwroot/` embarqué, toutes les ressources d'`index.html` réellement sur disque, aucun
placeholder d'empreinte non substitué), produit l'archive de façon reproductible, en placeholder d'empreinte non substitué), produit l'archive de façon reproductible, en
calcule le `sha256`, et réécrit `version`, `amd64.url` et `amd64.sha256` dans calcule le `sha256`, réécrit `version`, `amd64.url` et `amd64.sha256` dans
`manifest.toml`. `manifest.toml`, **commite et pousse le paquet**, puis **tague et pousse le code**.
À contrôler dans sa sortie : la ligne `binaire, wwwroot et ressources d'index.html : OK`, À contrôler dans sa sortie : la ligne `binaire, wwwroot et ressources d'index.html : OK`,
et le `sha256` affiché — c'est celui que le manifeste porte désormais. le `sha256` affiché — c'est celui que le manifeste porte désormais — et les deux `✓` de
la vérification côté distant.
Il ne reste alors que A.3. Les étapes A.4 et suivantes décrivent ce que le script vient
de faire, pour le cas où l'on reprend à la main après un échec en cours de route
(`--archive-seule` s'arrête après l'archive, sans toucher au manifeste ni à git).
#### A.3 Déposer la release #### A.3 Déposer la release
```bash Le tag `v0.1.0` est déjà poussé par A.2 (`git tag v0.1.0 && git push origin main --tags`
cd ../mabibli && git tag v0.1.0 && git push origin main --tags si l'on reprend à la main).
```
Puis, **dans l'interface Gitea** : créer la release `v0.1.0` sur le dépôt `mabibli`, et y **Dans l'interface Gitea** : créer la release `v0.1.0` sur le dépôt `mabibli`, et y
téléverser `build/dist/mabibli-0.1.0-linux-x64.tar.gz`. téléverser `build/dist/mabibli-0.1.0-linux-x64.tar.gz`.
Vérification, à faire **sans être authentifié** (autre navigateur, ou `curl` comme Vérification, à faire **sans être authentifié** (autre navigateur, ou `curl` comme
@@ -229,16 +249,25 @@ curl -fsSLI "https://git.akbar.nohost.me/mathieu/mabibli/releases/download/v0.1.
Attendu : `HTTP/2 200`. Un 404 signifie soit que la release n'est pas déposée, soit que Attendu : `HTTP/2 200`. Un 404 signifie soit que la release n'est pas déposée, soit que
le dépôt est privé — les deux se ressemblent, commencer par vérifier la visibilité. le dépôt est privé — les deux se ressemblent, commencer par vérifier la visibilité.
#### A.4 Pousser le paquet #### A.4 Le paquet, sur Gitea
⚠️ **L'étape la plus facile à oublier.** `yunohost app install <url>` lit le manifeste ⚠️ **L'étape la plus facile à oublier quand elle est manuelle** — et celle qui a fait
échouer la mise à jour du 2026-08-21. `yunohost app install <url>` lit le manifeste
**depuis Gitea**, jamais la copie locale : un manifeste corrigé mais non poussé n'existe **depuis Gitea**, jamais la copie locale : un manifeste corrigé mais non poussé n'existe
pas pour le serveur. pas pour le serveur. A.2 s'en charge et vérifie l'arrivée par `git ls-remote` ; en
reprise à la main :
```bash ```bash
cd ../mabibli_ynh && git add -A && git commit -m "Publier la version 0.1.0" && git push cd ../mabibli_ynh && git add -A && git commit -m "Publier la version 0.1.0" && git push
``` ```
Le contrôle qui tranche, quel que soit le chemin suivi — c'est le manifeste **tel que le
serveur le lira** :
```bash
curl -fsSL "https://git.akbar.nohost.me/mathieu/mabibli_ynh/raw/branch/main/manifest.toml" | grep amd64
```
#### A.5 Installer #### A.5 Installer
```bash ```bash
@@ -310,12 +339,16 @@ cours de route.
Le code est prêt et committé dans `mabibli`. Depuis `mabibli_ynh` : Le code est prêt et committé dans `mabibli`. Depuis `mabibli_ynh` :
```bash ```bash
./build/publier-release.sh --version 0.1.1 ./build/publier.sh --archive-seule --version 0.1.1
``` ```
⚠️ **`--version` est obligatoire ici.** Sans lui, le script déduit la version de ⚠️ **`--version` est obligatoire ici.** En `--archive-seule`, sans lui, le script déduit
`manifest.toml` et reproduirait 0.1.0. Il remet aussi le suffixe à `~ynh1` : une la version de `manifest.toml` et reproduirait 0.1.0.
nouvelle version applicative repart toujours de 1.
⚠️ **`--archive-seule` ne touche pas au manifeste** : `version` (avec son suffixe
`~ynh1` — une nouvelle version applicative repart toujours de 1), `amd64.url` et
`amd64.sha256` sont alors à réécrire à la main. C'est le prix de la marche à pied ;
`publier.sh` sans option le fait, et ne peut pas l'oublier.
Note le `sha256` affiché — il ne sera plus jamais le même, même à code identique si les Note le `sha256` affiché — il ne sera plus jamais le même, même à code identique si les
dépendances bougent. dépendances bougent.