PUBLICATION.md donne les gestes pas à pas, avec le contrôle attendu à chaque étape : première mise en production, montée de version (0.1.0 → 0.1.1), retour arrière si la mise à jour échoue, désinstallation. Deux points qui se paient cher s'ils sont oubliés y sont explicites : `--version` est obligatoire pour une nouvelle version applicative (sans lui le script reproduit celle du manifeste), et la sauvegarde de sécurité pré-upgrade ne contient PAS le répertoire de données. README et A_FAIRE renvoient au fichier plutôt que de tripler la procédure. Dernière URL fictive éliminée : gitea.exemple.org subsistait dans l'exemple CI de publier-release.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
273 lines
9.1 KiB
Bash
Executable File
273 lines
9.1 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Produit l'archive de release de MaBibli et met à jour manifest.toml.
|
|
#
|
|
# Pourquoi ce script vit dans `mabibli_ynh` et non dans `mabibli` :
|
|
# sa sortie utile n'est pas l'archive, c'est le couple (url, sha256) que le
|
|
# manifeste doit porter. Le garder ici permet de compiler, d'archiver et de mettre à
|
|
# jour le manifeste en une commande, puis de committer le tout d'un bloc — le
|
|
# manifeste ne peut pas se désynchroniser de l'archive qu'il décrit.
|
|
#
|
|
# Réutilisable en CI (Gitea Actions) sans modification : aucune interaction, aucune
|
|
# variable propre à un environnement d'intégration, tout passe par des options ou des
|
|
# variables d'environnement, et le script échoue au premier problème.
|
|
#
|
|
# Exemple d'usage en CI :
|
|
# ./build/publier-release.sh \
|
|
# --source-dir "$GITHUB_WORKSPACE/mabibli" \
|
|
# --version 0.2.0 \
|
|
# --base-url "https://git.akbar.nohost.me/mathieu/mabibli/releases/download"
|
|
#
|
|
set -euo pipefail
|
|
|
|
#=================================================
|
|
# VALEURS PAR DÉFAUT
|
|
#=================================================
|
|
|
|
racine_paquet="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
source_dir="${MABIBLI_SOURCE_DIR:-$(cd "$racine_paquet/../mabibli" 2>/dev/null && pwd || true)}"
|
|
version="${MABIBLI_VERSION:-}"
|
|
base_url="${MABIBLI_BASE_URL:-https://git.akbar.nohost.me/mathieu/mabibli/releases/download}"
|
|
output_dir="${MABIBLI_OUTPUT_DIR:-$racine_paquet/build/dist}"
|
|
maj_manifeste=1
|
|
runtime="linux-x64"
|
|
projet="MaBibli.Api"
|
|
|
|
#=================================================
|
|
# OPTIONS
|
|
#=================================================
|
|
|
|
usage() {
|
|
cat <<'FIN'
|
|
Usage : publier-release.sh [options]
|
|
|
|
--source-dir CHEMIN Dépôt du code C# (défaut : ../mabibli)
|
|
--version X.Y.Z Version de la release (défaut : déduite de manifest.toml)
|
|
--base-url URL Racine des URL de release, sans le tag ni le fichier
|
|
--output-dir CHEMIN Où déposer l'archive (défaut : build/dist)
|
|
--no-manifest-update Ne pas réécrire manifest.toml
|
|
-h, --help Cette aide
|
|
|
|
Variables d'environnement équivalentes : MABIBLI_SOURCE_DIR, MABIBLI_VERSION,
|
|
MABIBLI_BASE_URL, MABIBLI_OUTPUT_DIR.
|
|
FIN
|
|
}
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--source-dir) source_dir="$2"; shift 2 ;;
|
|
--version) version="$2"; shift 2 ;;
|
|
--base-url) base_url="$2"; shift 2 ;;
|
|
--output-dir) output_dir="$2"; shift 2 ;;
|
|
--no-manifest-update) maj_manifeste=0; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Option inconnue : $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
manifeste="$racine_paquet/manifest.toml"
|
|
|
|
#=================================================
|
|
# CONTRÔLES PRÉALABLES
|
|
#=================================================
|
|
|
|
echoerr() { echo "$@" >&2; }
|
|
|
|
if [ -z "$source_dir" ] || [ ! -d "$source_dir" ]; then
|
|
echoerr "Dépôt du code introuvable : '${source_dir:-<vide>}'"
|
|
echoerr "Précisez-le avec --source-dir."
|
|
exit 1
|
|
fi
|
|
source_dir="$(cd "$source_dir" && pwd)"
|
|
|
|
if [ ! -d "$source_dir/$projet" ]; then
|
|
echoerr "'$source_dir' ne contient pas de projet $projet."
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v dotnet >/dev/null; then
|
|
echoerr "Le SDK .NET est introuvable. Il n'est nécessaire QUE sur cette machine :"
|
|
echoerr "le serveur YunoHost reçoit un publish self-contained et n'a pas de SDK."
|
|
exit 1
|
|
fi
|
|
|
|
# La version par défaut se lit dans le manifeste, en retirant le suffixe ~ynhN :
|
|
# le tag et le nom de fichier portent la version applicative, pas celle du paquet.
|
|
if [ -z "$version" ]; then
|
|
version="$(sed -n 's/^version *= *"\([^"~]*\).*"/\1/p' "$manifeste" | head -1)"
|
|
if [ -z "$version" ]; then
|
|
echoerr "Impossible de déduire la version depuis $manifeste ; utilisez --version."
|
|
exit 1
|
|
fi
|
|
echo "Version déduite de manifest.toml : $version"
|
|
fi
|
|
|
|
#=================================================
|
|
# COMPILATION
|
|
#=================================================
|
|
|
|
travail="$(mktemp -d)"
|
|
# shellcheck disable=SC2064
|
|
trap "rm -rf '$travail'" EXIT
|
|
|
|
publish="$travail/publish"
|
|
|
|
echo
|
|
echo "=== Compilation self-contained $runtime ==="
|
|
echo " source : $source_dir"
|
|
echo " version: $version"
|
|
|
|
# `--self-contained` embarque le runtime .NET dans le dossier publié : c'est ce qui
|
|
# permet au paquet YunoHost de ne dépendre d'aucun `dotnet-runtime` côté serveur.
|
|
#
|
|
# `MaBibli.Api` référence `MaBibli.Client` : le client Blazor WebAssembly est compilé
|
|
# au passage et atterrit dans `wwwroot/`. Un seul publish suffit donc pour les trois
|
|
# projets.
|
|
dotnet publish "$source_dir/$projet" \
|
|
--configuration Release \
|
|
--runtime "$runtime" \
|
|
--self-contained \
|
|
--output "$publish" \
|
|
-p:Version="$version"
|
|
|
|
#=================================================
|
|
# CONTRÔLES SUR LE RÉSULTAT
|
|
#=================================================
|
|
|
|
echo
|
|
echo "=== Vérification du publish ==="
|
|
|
|
if [ ! -x "$publish/$projet" ]; then
|
|
echoerr "Binaire '$projet' absent ou non exécutable dans le publish."
|
|
exit 1
|
|
fi
|
|
|
|
# Sans `wwwroot`, le service démarrerait et répondrait — en ne servant aucune page.
|
|
# C'est le défaut qui est passé inaperçu pendant trois phases du projet, faute de
|
|
# regarder ailleurs que la racine. On le vérifie donc ici, à la source.
|
|
if [ ! -f "$publish/wwwroot/index.html" ]; then
|
|
echoerr "wwwroot/index.html absent : le client Blazor n'a pas été embarqué."
|
|
exit 1
|
|
fi
|
|
|
|
# `index.html` doit référencer un script réellement présent. Un placeholder non
|
|
# substitué (`blazor.webassembly#[.{fingerprint}].js`) donnerait une page blanche
|
|
# alors que `/` répondrait 200.
|
|
if grep -q '#\[\.{fingerprint}\]' "$publish/wwwroot/index.html"; then
|
|
echoerr "index.html contient des placeholders d'empreinte non substitués."
|
|
echoerr "Voir CLAUDE.md, « Empreintes WASM désactivées »."
|
|
exit 1
|
|
fi
|
|
|
|
for ressource in $(grep -oE '(src|href)="[^"]+"' "$publish/wwwroot/index.html" \
|
|
| sed -E 's/^(src|href)="//; s/"$//' \
|
|
| grep -vE '^(https?:|data:|#|/$|\.$)'); do
|
|
if [ ! -f "$publish/wwwroot/$ressource" ]; then
|
|
echoerr "index.html référence '$ressource', absent du publish."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo " binaire, wwwroot et ressources d'index.html : OK"
|
|
|
|
#=================================================
|
|
# ARCHIVE
|
|
#=================================================
|
|
|
|
archive_nom="mabibli-$version-$runtime.tar.gz"
|
|
mkdir -p "$output_dir"
|
|
archive="$output_dir/$archive_nom"
|
|
|
|
echo
|
|
echo "=== Archive ==="
|
|
|
|
# Fichiers à la racine de l'archive, sans dossier intermédiaire : cohérent avec
|
|
# `in_subdir = false` dans manifest.toml.
|
|
#
|
|
# Options de reproductibilité : sans elles, deux compilations identiques donneraient
|
|
# deux sha256 différents (dates, ordre de parcours, uid/gid). En CI comme en local,
|
|
# on veut pouvoir vérifier qu'une archive correspond bien à un commit.
|
|
tar --create --gzip \
|
|
--file="$archive" \
|
|
--directory="$publish" \
|
|
--owner=0 --group=0 --numeric-owner \
|
|
--mtime="@${SOURCE_DATE_EPOCH:-0}" \
|
|
--sort=name \
|
|
.
|
|
|
|
somme="$(sha256sum "$archive" | cut -d' ' -f1)"
|
|
taille="$(du -h "$archive" | cut -f1)"
|
|
taille_octets="$(stat -c%s "$archive")"
|
|
|
|
echo " fichier : $archive"
|
|
echo " taille : $taille ($taille_octets octets)"
|
|
echo " sha256 : $somme"
|
|
|
|
#=================================================
|
|
# MISE À JOUR DU MANIFESTE
|
|
#=================================================
|
|
|
|
url="$base_url/v$version/$archive_nom"
|
|
|
|
if [ "$maj_manifeste" -eq 1 ]; then
|
|
echo
|
|
echo "=== Mise à jour de manifest.toml ==="
|
|
|
|
# Le suffixe ~ynhN est conservé s'il existe déjà pour cette version, sinon
|
|
# remis à ~ynh1 : un changement de version applicative repart toujours de 1.
|
|
version_actuelle="$(sed -n 's/^version *= *"\([^"]*\)".*/\1/p' "$manifeste" | head -1)"
|
|
if [[ "$version_actuelle" == "$version~ynh"* ]]; then
|
|
version_paquet="$version_actuelle"
|
|
echo " version : $version_paquet (inchangée)"
|
|
else
|
|
version_paquet="$version~ynh1"
|
|
echo " version : $version_actuelle -> $version_paquet"
|
|
fi
|
|
|
|
python3 - "$manifeste" "$version_paquet" "$url" "$somme" <<'PY'
|
|
import re, sys
|
|
|
|
chemin, version, url, somme = sys.argv[1:5]
|
|
with open(chemin, encoding="utf-8") as f:
|
|
texte = f.read()
|
|
|
|
remplacements = [
|
|
(r'^version = ".*"$', f'version = "{version}"'),
|
|
(r'^ amd64\.url = ".*"$', f' amd64.url = "{url}"'),
|
|
(r'^ amd64\.sha256 = ".*"$', f' amd64.sha256 = "{somme}"'),
|
|
]
|
|
|
|
for motif, valeur in remplacements:
|
|
texte, n = re.subn(motif, valeur, texte, count=1, flags=re.MULTILINE)
|
|
if n != 1:
|
|
sys.exit(f"Motif introuvable dans le manifeste : {motif}")
|
|
|
|
with open(chemin, "w", encoding="utf-8") as f:
|
|
f.write(texte)
|
|
PY
|
|
|
|
echo " url : $url"
|
|
echo " sha256 : $somme"
|
|
fi
|
|
|
|
#=================================================
|
|
# SUITE À DONNER
|
|
#=================================================
|
|
|
|
cat <<FIN
|
|
|
|
=== Terminé ===
|
|
|
|
Archive prête : $archive
|
|
|
|
Il reste à faire, à la main (le dépôt Gitea et la release ne sont pas automatisés) :
|
|
|
|
1. Créer le tag v$version sur le dépôt du code, puis la release correspondante.
|
|
2. Y téléverser $archive_nom.
|
|
3. Vérifier que l'URL du manifeste répond :
|
|
curl -fsSLI "$url"
|
|
4. Committer manifest.toml dans mabibli_ynh.
|
|
|
|
FIN
|