Files
mabibli/docs/publier-une-version.md
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

14 KiB

Publier une version de MaBibli

Pour vous, qui sortez les versions. Pour installer, voir installer.md ; pour comprendre le code, architecture.md.

Avant de publier ailleurs l'URL de dépôt, à configurer une fois
Compiler en développement, et le publish self-contained
La chaîne de publication ce que publier.sh fait, et ce qu'il refuse
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 :

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 :

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.

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

dotnet build
dotnet test

Pour lancer l'application en local (l'API sert aussi le client Blazor compilé) :

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 :

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 aarch64file 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 :

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é.

./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 : 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 — 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.01.0.1~ynh1 oui
Seulement le paquet (conf systemd/nginx, scripts) 1.0.0~ynh11.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 » 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é.

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 :

./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

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 :

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

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 :

sudo yunohost backup create --apps mabibli
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

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 :

sudo yunohost backup list
sudo yunohost app remove mabibli --purge
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.