Files
mabibli/docs/publier-une-version.md
T
Mathieu LimonierandClaude Opus 5 6a6d745af4 MaBibli 1.0.0
Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts,
scan de code-barres, consultation hors-ligne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 22:36:16 +02:00

326 lines
14 KiB
Markdown

# Publier une version de MaBibli
Pour vous, qui sortez les versions. Pour installer, voir
[installer.md](installer.md) ; pour comprendre le code,
[architecture.md](architecture.md).
| | |
|---|---|
| [Avant de publier ailleurs](#lurl-du-dépôt-et-la-copie-publique) | l'URL de dépôt, à configurer une fois |
| [Compiler](#compilation) | en développement, et le publish self-contained |
| [La chaîne de publication](#publication) | ce que `publier.sh` fait, et ce qu'il refuse |
| [Monter de version](#monter-de-version) | pas à pas |
## L'URL du dépôt, et la copie publique
La documentation de ce dépôt porte une URL de démonstration, `https://forge.example.org/…`.
**Trois valeurs seulement portent la vraie**, et chacune pour une raison :
| Où | Quoi | Pourquoi elle reste réelle |
|---|---|---|
| `build/publier.sh`, `depot_code` | dépôt du code | toutes les URL de release et d'archive en dérivent. `--depot-code URL` fait la même chose sans modifier le fichier, pour un essai ponctuel |
| `manifest.toml`, `code` et `amd64.url` | catalogue YunoHost, archive à télécharger | c'est ce que le serveur va réellement chercher |
| `MaBibli.Client/Pages/APropos.razor` | lien vers la source | l'AGPL attend que les utilisateurs d'un service en réseau puissent obtenir la source. Un lien mort ne la tient pas |
⚠️ **`amd64.url` ne se change JAMAIS à la main** : `publier.sh` la réécrit à chaque
publication. La modifier hors de ce chemin produit un manifeste qui pointe une archive
introuvable — et l'échec survient **bien plus loin**, à l'installation, dans
`ynh_setup_source`, sans rapport apparent avec la cause.
### Produire une copie publique
Pour publier le projet à destination de tiers, on **copie** — on ne transforme pas le dépôt
de travail :
```bash
cd ~/Code && rm -rf mabibli-public && cp -r mabibli mabibli-public
rm -rf mabibli-public/.git
```
⚠️ **Le `rm -rf .git` vient AVANT le `git init`**, et un `git clone` ne conviendrait pas :
la neutralisation ne touche que les fichiers, jamais les commits — l'historique garderait
les URL et l'identité de son auteur.
```bash
cd mabibli-public
grep -rl 'forge\.example\.org' . | xargs sed -i 's|https://forge\.example\.org|<URL DU DÉPÔT>|g'
git init -b main && git add -A && git commit -m "MaBibli"
```
Restent à neutraliser **à la main**, ce sont les trois du tableau ci-dessus plus l'identité :
`depot_code`, `code` et `maintainers` dans `manifest.toml`, et l'adresse de contact, le site
et le dépôt dans `APropos.razor`.
⚠️ **Ne pas toucher à `amd64.url`** : la prochaine exécution de `publier.sh` la réécrira
elle-même, à partir de `depot_code`.
`forge.example.org` est injoignable par construction — `example.org` est réservé à la
documentation par la **RFC 2606**. C'est voulu : `publier.sh` **refuse de publier** tant
qu'une URL en `example.org` est en place, et il refuse **avant de compiler**. Celui qui
reprend le projet doit donc renseigner `depot_code` avant sa première release, plutôt que
de découvrir le problème à l'installation.
## Compilation
Prérequis : le SDK **.NET 10** (`dotnet --version`).
### En développement
```bash
dotnet build
dotnet test
```
Pour lancer l'application en local (l'API sert aussi le client Blazor compilé) :
```bash
dotnet run --project MaBibli.Api
```
### Publication self-contained (ce que le serveur reçoit réellement)
Le serveur YunoHost ne compile jamais : il télécharge une archive déjà publiée et la
déploie telle quelle (voir « Publication » ci-dessous). Pour produire ce même artefact
en local, à des fins de vérification :
```bash
dotnet publish MaBibli.Api --configuration Release --runtime linux-x64 --self-contained
```
⚠️ **`-r linux-x64` désigne le serveur, pas la machine qui compile.** Le SDK télécharge
le runtime pack de la cible : compiler depuis un hôte ARM produit bien un binaire x86-64.
Vérifié depuis un `aarch64``file` rend `ELF 64-bit … x86-64`, `wwwroot/_framework` est
garni et `index.html` ne porte aucun placeholder d'empreinte. Aucune option à changer,
`publier.sh` fixe `runtime="linux-x64"` une fois pour toutes.
`MaBibli.Api` référence `MaBibli.Client` : le client Blazor WebAssembly est compilé au
passage et atterrit dans `wwwroot/` du publish. Un seul projet à publier suffit donc
pour les trois (`MaBibli.Client`, `MaBibli.Shared`, `MaBibli.Api`). `--self-contained`
embarque le runtime .NET dans le dossier produit : aucun `dotnet-runtime` n'est requis
côté serveur.
Pour un hébergement **sans YunoHost** (Synology, VPS), voir « Installer ailleurs que sur
YunoHost » plus bas : le `Dockerfile` de la racine fait ce même publish, mais sans
`--self-contained` — dans un conteneur, l'image `aspnet` fournit déjà le runtime.
⚠️ **Ne jamais compiler sur le serveur YunoHost lui-même** : ce serait imposer le SDK
complet à une machine qui n'en a pas besoin, pour une compilation lente.
## Publication
⚠️ **`build/dist/` est ignoré par git**, et doit le rester : l'archive vit dans la
release du dépôt. Committée, elle ajouterait ~65 Mo d'historique **par version**,
définitivement.
Le geste courant tient en une commande, `build/publier.sh` du dépôt du paquet. Il
compile **les deux architectures** — amd64 et arm64 — et produit une archive pour
chacune :
```bash
cd ../mabibli_ynh
./build/publier.sh
```
Il reprend la version déjà publiée (tag le plus élevé, recoupé avec `manifest.toml`),
propose l'incrément, puis enchaîne tout ce qui suit : archives, manifeste, commit et push
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 les deux archives — le script les rappelle.
⚠️ **Il n'y a pas d'option pour ne compiler qu'une architecture**, et c'est délibéré : le
manifeste déclare les deux, donc publier une seule archive lui ferait promettre une URL
que personne n'a téléversée. Le coût est de ~2 minutes de compilation et ~62 Mo de plus
par release.
⚠️ **Il n'y a qu'un seul script, et c'est délibéré.**
```bash
./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é.
⚠️ **À quoi il sert vraiment** : à **reprendre une publication à la main** quand
`publier.sh` a échoué en cours de route (étape 3 de « Monter de version »).
⚠️ **Les contrôles ne sont PAS désactivés dans ce mode**, ils s'exécutent tous, et **avertissent** au lieu de refuser,
puisque rien n'est publié et que rien ne peut donc mentir. Le dépôt sale, en
particulier, n'était alors pas signalé du tout — l'archive contenait en silence du
travail non committé.
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éellement sur disque, aucun placeholder d'empreinte non substitué), produit une
archive `.tar.gz` reproductible, calcule son `sha256`, et met à jour `version`,
`amd64.url` et `amd64.sha256` dans `mabibli_ynh/manifest.toml` — sauf en
`--archive-seule`.
Il injecte au passage, dans l'assembly, la **version** (`-p:Version`) et un
**horodatage de build** (`-p:MaBibliDateBuild`), que la page « À propos » de
l'application affiche via `GET /api/version`.
⚠️ **L'horodatage est le témoin de l'injection** : sans lui, l'application se déclare
« version de développement » plutôt que d'afficher le `1.0.0` que le SDK .NET pose par
défaut. Ce numéro-là se lirait comme une vraie version alors qu'il ne désigne rien — or
c'est précisément la valeur qu'on va chercher pour diagnostiquer un appareil dont le
cache est dépareillé. Un `dotnet build` local n'annonce donc aucune version, et c'est
voulu.
⚠️ YunoHost lit le manifeste **depuis Gitea**, jamais une copie locale : un manifeste
corrigé mais non poussé n'existe pas pour le serveur. C'est précisément ce que
`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, 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`. ⚠️ En
`--archive-seule`, les mêmes contrôles **avertissent** au lieu de refuser — le constat
s'affiche, le conseil « choisissez un numéro libre » non&nbsp;: en reprise, le tag visé
est justement celui qu'on veut retrouver.
**La première mise en production**, elle, est décrite dans
[installer.md](installer.md#mettre-en-production) — comme la désinstallation.
---
## Monter de version
### 1. Ce qui distingue une version applicative d'une révision de paquet
| Ce qui change | Version | Nouvelle archive ? |
|---|---|---|
| Le code C# | `1.0.0``1.0.1~ynh1` | **oui** |
| Seulement le paquet (conf systemd/nginx, scripts) | `1.0.0~ynh1``1.0.0~ynh2` | non |
Le second cas est le plus simple : bump du suffixe `~ynhN` **à la main** dans
`manifest.toml`, commit, push, puis directement l'étape 5. L'archive et son `sha256`
ne bougent pas.
La suite décrit le premier cas.
### 2. En une commande : `publier.sh`
C'est le geste courant, décrit en « [Publication](#publication) » plus haut : il enchaîne
les étapes 3, 4 et 5 (archive, manifeste, commit et push du paquet, tag et push du code),
et vérifie sur le distant que tout est arrivé.
```bash
cd ../mabibli_ynh && ./build/publier.sh
```
La suite décrit ces mêmes étapes **à la main**, pour comprendre ce que le script fait et
pour les cas qu'il ne couvre pas : révision `~ynhN` seule, reprise après un échec en
cours de route.
### 3. Compiler et vérifier la nouvelle version
Le code est prêt et committé dans `mabibli`. Depuis `mabibli_ynh` :
```bash
./build/publier.sh --archive-seule --patch
```
Les deux modes calculent la version de la même façon : `--patch` propose 1.0.1,
`--minor` et `--major` les autres sauts, et sans option le script la demande.
`--version X.Y.Z` ne sert plus qu'à **viser un numéro précis** — la toute première
publication, où il n'y a rien à incrémenter, ou la reprise sur un tag déjà créé.
⚠️ **`--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 les **deux** `sha256` affichés, un par architecture — ils ne seront plus jamais les
mêmes, même à code identique si les dépendances bougent.
### 4. Tag et release
```bash
cd ../mabibli && git tag v1.0.1 && git push origin main --tags
```
Créer la release `v1.0.1` dans Gitea, y téléverser **les deux** archives de
`build/dist/`, puis vérifier chacune sans authentification :
```bash
curl -fsSLI "https://forge.example.org/mabibli/releases/download/v1.0.1/mabibli-1.0.1-linux-x64.tar.gz" | head -1
curl -fsSLI "https://forge.example.org/mabibli/releases/download/v1.0.1/mabibli-1.0.1-linux-arm64.tar.gz" | head -1
```
### 5. Pousser le paquet
```bash
cd ../mabibli_ynh && git add -A && git commit -m "Publier la version 1.0.1" && git push
```
### 6. Sauvegarder, puis mettre à jour
YunoHost prend **lui-même** une sauvegarde de sécurité avant la mise à jour
(`mabibli-pre-upgrade1`), mais elle **ne contient pas le répertoire de données**
(`BACKUP_CORE_ONLY`) : elle sert à restaurer l'application, pas la bibliothèque. Prendre
une sauvegarde complète reste donc utile avant une version qui touche au schéma :
```bash
sudo yunohost backup create --apps mabibli
```
```bash
sudo yunohost app upgrade mabibli -u https://forge.example.org/mabibli_ynh --debug
```
⚠️ **L'option `-u` n'est pas facultative ici.** MaBibli n'est pas dans le catalogue
officiel : sans elle, YunoHost ne sait pas où retrouver le paquet et refuse d'emblée —
« mabibli is not in the catalog (anymore?) », puis « No apps can be upgraded ». Rien
n'est cassé pour autant, la commande n'a simplement pas commencé. C'est la **même URL**
qu'à l'installation, celle du dépôt `_ynh`, jamais celle de l'archive.
(Ajouter `--force` seulement pour réappliquer une version identique, par exemple en
mise au point du paquet.)
Le script arrête le service **avant** de remplacer les binaires — deux processus sur la
même base SQLite pendant une migration est exactement ce qu'il faut éviter — puis
attend `Application started`, avec un délai de 120 s : une migration sur base remplie
prend plus de temps que la création d'un schéma vide.
### 7. Vérifier après mise à jour
```bash
sudo systemctl status mabibli --no-pager && sudo journalctl -u mabibli -n 30 --no-pager
```
Puis, dans le navigateur, le contrôle qui compte vraiment : **les livres sont toujours
là**. C'est ce qui valide que la base vit bien dans le répertoire de données et non à
côté du binaire — `upgrade` remplace intégralement `/var/www/mabibli`.
Vider le cache du navigateur n'est pas nécessaire : le service worker compare les
empreintes et propose « Mettre à jour ». Sur mobile, un onglet resté ouvert peut
retarder la bascule — c'est précisément ce que le bandeau de mise à jour sert à
débloquer.
### 8. Si la mise à jour échoue
YunoHost restaure automatiquement la sauvegarde de sécurité quand le script échoue. Si
le service démarre mais que l'application se comporte mal, revenir en arrière à la main :
```bash
sudo yunohost backup list
```
```bash
sudo yunohost app remove mabibli --purge
```
```bash
sudo yunohost backup restore <nom-de-l-archive> --apps mabibli
```
⚠️ `--purge` efface le répertoire de données. Ne le faire qu'avec une archive contenant
la bibliothèque sous la main — celle de l'étape 6, pas `mabibli-pre-upgrade1`.
---