Empêcher le hook des derniers articles de bloquer la publication

Le hook promettait de ne jamais faire échouer le build. En pratique il
journalisait ses échecs en « warning », et le déploiement construit avec
« --strict » : un dépôt sans historique git suffisait à obtenir « Aborted
with 1 warnings in strict mode » — plus aucune publication du wiki, pour
un fichier d'agrément.

Ses messages passent donc en « info », l'écriture des deux fichiers est
protégée à son tour, et un clone superficiel est détecté et signalé : ses
dates seraient toutes identiques.

Vérifié dans les deux cas : avec historique, vingt articles publiés ;
sans dépôt git, build réussi et fichier non écrit.

Documenté au passage que le .htaccess du DocumentRoot est désormais
réécrit à chaque déploiement, rsync --delete recopiant tout le staging.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BE4rvHVETRoWnYNDTGssdo
This commit is contained in:
Alpinux 2026-09-20 00:29:56 +02:00
parent 0166436000
commit ad1f459659
2 changed files with 53 additions and 21 deletions

View file

@ -198,7 +198,20 @@ choses à savoir :
- **Seules les pages de la navigation sont annoncées.** Une page hors `nav` — typiquement
la redirection laissée derrière un article déplacé — n'apparaît jamais dans la liste.
- **Le hook n'échoue jamais.** Sans historique git, il n'écrit rien et le build continue ;
l'accueil d'alpinux.org masque alors simplement sa section wiki.
l'accueil d'alpinux.org masque alors simplement sa section wiki. Ses messages sont pour
cela de niveau *info* et jamais *warning* : le déploiement construit avec `--strict`, où
un seul avertissement suffit à interrompre le build et donc la publication.
!!! warning "Deux conditions côté serveur"
**Le clone doit avoir son historique.** Un clone `--depth 1` ne porte qu'un commit :
toutes les pages sembleraient modifiées le même jour. Le hook le détecte et le
signale dans le journal du build, sans rien casser.
**Le `.htaccess` du DocumentRoot est réécrit à chaque déploiement.** Le hook le
dépose dans le staging, que `rsync --delete` recopie intégralement : un `.htaccess`
qui aurait été posé à la main sur le serveur serait effacé au premier build. S'il
faut d'autres règles Apache, ajoutez-les dans le hook — c'est désormais lui qui fait
foi.
Le même hook dépose un `.htaccess` d'une ligne utile : il autorise les autres sous-domaines
à lire ce seul fichier JSON (`Access-Control-Allow-Origin`). Sans lui, le navigateur

View file

@ -11,6 +11,10 @@ le fait.
Le hook n'échoue jamais : sans git, ou en cas d'erreur, il n'écrit simplement rien et
le build continue (le site reste valide, la page d'accueil garde ses tuiles statiques).
Ses messages sont volontairement de niveau *info* et jamais *warning* : le déploiement
construit le site avec `--strict`, où le moindre avertissement interrompt le build. Un
hook d'agrément ne doit pas pouvoir empêcher la publication du wiki.
"""
from __future__ import annotations
@ -62,6 +66,14 @@ def _git(depot: Path, *args: str) -> str:
).stdout
def _est_superficiel(depot: Path) -> bool:
"""Un clone `--depth 1` n'a pas d'historique : toutes les dates seraient identiques."""
try:
return _git(depot, "rev-parse", "--is-shallow-repository").strip() == "true"
except (OSError, subprocess.SubprocessError):
return False
def _historique(depot: Path, dossier: str) -> tuple[dict, dict]:
"""Retourne (dernière modification, date de création) par chemin actuel.
@ -115,9 +127,12 @@ def on_post_build(config):
try:
modifiees, creees = _historique(depot, dossier)
except (OSError, subprocess.SubprocessError) as erreur:
log.warning("derniers-articles : historique git illisible (%s), fichier non écrit", erreur)
log.info("derniers-articles : historique git illisible (%s), fichier non écrit", erreur)
return
if _est_superficiel(depot):
log.info("derniers-articles : clone superficiel, les dates ne sont pas fiables")
limite = datetime.now(timezone.utc) - timedelta(days=JOURS_NOUVEAU)
articles = []
@ -141,12 +156,13 @@ def on_post_build(config):
})
if not articles:
log.warning("derniers-articles : aucune page datée, fichier non écrit")
log.info("derniers-articles : aucune page datée, fichier non écrit")
return
articles.sort(key=lambda a: a["date"], reverse=True)
articles = articles[:NB_MAX]
try:
(site_dir / FICHIER).write_text(
json.dumps(
{"genere": datetime.now(timezone.utc).isoformat(timespec="seconds"),
@ -166,5 +182,8 @@ def on_post_build(config):
"</IfModule>\n",
encoding="utf-8",
)
except OSError as erreur:
log.info("derniers-articles : écriture impossible (%s), fichier non écrit", erreur)
return
log.info("derniers-articles : %d article(s) publié(s) dans %s", len(articles), FICHIER)