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:
parent
0166436000
commit
ad1f459659
2 changed files with 53 additions and 21 deletions
|
|
@ -198,7 +198,20 @@ choses à savoir :
|
||||||
- **Seules les pages de la navigation sont annoncées.** Une page hors `nav` — typiquement
|
- **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.
|
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 ;
|
- **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
|
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
|
à lire ce seul fichier JSON (`Access-Control-Allow-Origin`). Sans lui, le navigateur
|
||||||
|
|
|
||||||
|
|
@ -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 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).
|
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
|
from __future__ import annotations
|
||||||
|
|
@ -62,6 +66,14 @@ def _git(depot: Path, *args: str) -> str:
|
||||||
).stdout
|
).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]:
|
def _historique(depot: Path, dossier: str) -> tuple[dict, dict]:
|
||||||
"""Retourne (dernière modification, date de création) par chemin actuel.
|
"""Retourne (dernière modification, date de création) par chemin actuel.
|
||||||
|
|
||||||
|
|
@ -115,9 +127,12 @@ def on_post_build(config):
|
||||||
try:
|
try:
|
||||||
modifiees, creees = _historique(depot, dossier)
|
modifiees, creees = _historique(depot, dossier)
|
||||||
except (OSError, subprocess.SubprocessError) as erreur:
|
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
|
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)
|
limite = datetime.now(timezone.utc) - timedelta(days=JOURS_NOUVEAU)
|
||||||
articles = []
|
articles = []
|
||||||
|
|
||||||
|
|
@ -141,12 +156,13 @@ def on_post_build(config):
|
||||||
})
|
})
|
||||||
|
|
||||||
if not articles:
|
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
|
return
|
||||||
|
|
||||||
articles.sort(key=lambda a: a["date"], reverse=True)
|
articles.sort(key=lambda a: a["date"], reverse=True)
|
||||||
articles = articles[:NB_MAX]
|
articles = articles[:NB_MAX]
|
||||||
|
|
||||||
|
try:
|
||||||
(site_dir / FICHIER).write_text(
|
(site_dir / FICHIER).write_text(
|
||||||
json.dumps(
|
json.dumps(
|
||||||
{"genere": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
{"genere": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||||
|
|
@ -166,5 +182,8 @@ def on_post_build(config):
|
||||||
"</IfModule>\n",
|
"</IfModule>\n",
|
||||||
encoding="utf-8",
|
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)
|
log.info("derniers-articles : %d article(s) publié(s) dans %s", len(articles), FICHIER)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue