Patrick Schurig 010a7da0f4 ci: le contrôle de qualité documentaire — écrit, éprouvé, PAS en service
Étape 4 du chantier de documentation. tools/ci-quality.sh porte les trois
vérifications qui se posent au même endroit — elles partagent la même sortie
(doc-generated/) et la même commande de réparation, les séparer ferait trois jobs
qui régénèrent trois fois la même chose :

  1. l'index des règles est VRAI (code de retour de gen-rules.py) ;
  2. la doc Doxygen est complète — 0 avertissement, DoD §5 ;
  3. l'index est REPRODUCTIBLE : deux passes, un seul résultat.

PAS EN SERVICE, et l'extension le garantit : ci/gitea-workflow.yml.disabled ne
déclenche rien tant qu'il n'est pas déplacé dans .gitea/workflows/. La raison est
datée dans le fichier — forge muette, plus de trente commits en attente ici et
plus de soixante côté app ; un job activé à l'aveugle échouerait au moment précis
où tout le monde pousse, et le premier réflexe serait de le désactiver.

CHAQUE ÉCHEC DONNE LA COMMANDE À LANCER. Un job qui annonce « l'index est
périmé » sans dire quoi faire se contourne en le désactivant : c'est le chemin de
moindre effort, et il gagne toujours.

VÉRIFIÉ AVANT D'ÊTRE DÉCLARÉ PRÊT, et ça ne passait pas du premier coup.

— Les 26 avertissements Doxygen de ce matin sont CORRIGÉS, pas contournés par un
  cliquet sur un compte de référence : c'était de la dette DoD-5 (retours et
  paramètres non documentés dans relayrouter.h, energyarbitrator.h, loadconfig.h,
  les trois clearFault(), ILoadAdapter::updateSoftConfig), plus deux que j'avais
  introduits — un \rule{} dans un titre \par, et un \param energyLogs qui ne
  correspond à aucun argument. Le seuil est donc ZÉRO, le seul qui ne rote pas.

— Et le script lui-même échouait sur un dépôt SAIN : `grep -c ... || echo 0`
  affiche 0 PUIS sort en 1 quand il ne trouve rien, si bien que le « || » empile
  un second zéro et que le test entier casse. Corrigé ici et dans gen-doc.sh, qui
  portait le même piège. Une commande de mesure dont l'échec produit une lecture
  fausse — le motif de la semaine, appliqué à l'outil.

CE QUI N'EST PAS VÉRIFIÉ, et pourquoi : « régénérer et refuser si ça diffère de
ce qui est commité » n'a rien à comparer, doc-generated/ étant dans .gitignore.
Le risque qu'un tel diff attraperait — un artefact commité qui dérive de sa
source — a été SUPPRIMÉ en ne le commitant pas, pas déplacé. Ce qui reste à
garantir est que l'index soit vrai (contrôle 1) et déterministe (contrôle 3).

État au 2026-08-29 : ./tools/ci-quality.sh → RC=0, 113 règles, 0 avertissement.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
2026-08-29 11:33:46 +02:00

112 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
#
# Génération reproductible de la documentation — UNE seule commande, le Doxyfile
# du dépôt, épinglé.
#
# ./tools/gen-doc.sh
#
# Pourquoi une commande unique plutôt qu'un « doxygen » lancé à la main : le
# nombre d'avertissements NE VEUT RIEN DIRE hors de sa configuration exacte. Le
# piège a déjà été rencontré — 163 avertissements sans générateur de sortie
# contre 113 avec HTML+XML, sur le même arbre. Un chiffre de référence ne se
# compare qu'à un chiffre produit de la même façon ; ce script est cette façon.
#
# DÉPENDANCES — de la CIBLE DOC uniquement, jamais du build du paquet :
# apt install doxygen graphviz
# Le conteneur build-cross-arm64 n'a rien à faire de Graphviz : il compile, il
# ne dessine pas.
set -u
RACINE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DOXYFILE="$RACINE/Doxyfile"
SORTIE="$RACINE/doc-generated"
VERSION_ATTENDUE="1.9.8"
cd "$RACINE" || exit 1
manquant=0
for outil in doxygen dot; do
if ! command -v "$outil" >/dev/null 2>&1; then
echo "MANQUANT : $outil" >&2
manquant=1
fi
done
if [ "$manquant" -ne 0 ]; then
echo "" >&2
echo "Dépendances de la cible doc : apt install doxygen graphviz" >&2
exit 127
fi
# L'INDEX DES RÈGLES d'abord : le Doxyfile le prend en entrée, et ses ancres {#LM-1105}
# sont ce qui rend \rule{} résoluble. Un index absent produirait des \ref cassés en masse,
# donc un compte d'avertissements incomparable — exactement ce que ce script existe pour
# empêcher.
#
# Son code de retour ne STOPPE pas la génération : un index incomplet reste utile à lire,
# et refuser de produire la doc parce qu'une règle manque punirait le mauvais geste. Il est
# répercuté à la fin, pour que l'appelant — un humain ou la CI — le voie.
VERSION_REELLE="$(doxygen --version | cut -d' ' -f1)"
if [ "$VERSION_REELLE" != "$VERSION_ATTENDUE" ]; then
# Avertissement et non erreur : la génération reste utile, mais le compte
# d'avertissements n'est plus comparable au chiffre de référence.
echo "ATTENTION : doxygen $VERSION_REELLE, référence établie sous $VERSION_ATTENDUE." >&2
echo " Les graphes restent valables ; le COMPTE d'avertissements," >&2
echo " lui, n'est pas comparable d'une version à l'autre." >&2
fi
rm -rf "$SORTIE"
# L'INDEX DES RÈGLES, et il se produit APRÈS le nettoyage — il vit DANS $SORTIE, donc le
# générer avant reviendrait à l'effacer aussitôt. Doxygen le prend en entrée : ses ancres
# {#LM-1105} sont ce qui rend \rule{} résoluble, et un index absent produirait des \ref
# cassés en masse, donc un compte d'avertissements incomparable — exactement ce que ce
# script existe pour empêcher.
#
# Son code de retour ne STOPPE pas la génération : un index incomplet reste utile à lire, et
# refuser de produire la doc parce qu'une règle manque punirait le mauvais geste. Il est
# répercuté à la fin, pour que l'appelant — humain ou CI — le voie.
echo "→ index des règles"
python3 "$RACINE/tools/gen-rules.py"
RC_REGLES=$?
JOURNAL="$(mktemp)"
trap 'rm -f "$JOURNAL"' EXIT
doxygen "$DOXYFILE" 2>"$JOURNAL"
code=$?
# Le Doxyfile écrit déjà ses avertissements dans WARN_LOGFILE ; on compte ici ce
# qui est réellement remonté, quelle que soit la destination.
LOGFILE="$(sed -n 's/^WARN_LOGFILE *= *//p' "$DOXYFILE" | tr -d ' ')"
if [ -n "$LOGFILE" ] && [ -f "$RACINE/$LOGFILE" ]; then
JOURNAL_EFFECTIF="$RACINE/$LOGFILE"
else
JOURNAL_EFFECTIF="$JOURNAL"
fi
# `wc -l`, jamais `grep -c ... || echo 0` : grep -c affiche 0 PUIS sort en 1 quand il ne
# trouve rien, et le « || » empile alors un second zéro dans la variable.
AVERTISSEMENTS="$(grep -i "warning" "$JOURNAL_EFFECTIF" 2>/dev/null | wc -l)"
echo ""
echo " doxygen $VERSION_REELLE (référence $VERSION_ATTENDUE)"
echo " graphviz $(dot -V 2>&1 | sed 's/^dot - graphviz version //; s/ .*//')"
echo " configuration $DOXYFILE"
echo " sortie $SORTIE (html/ + xml/)"
echo " avertissements $AVERTISSEMENTS"
echo ""
echo " Rappel : ce compte n'est comparable qu'à un compte produit par CE script."
echo " Rappel : le graphe d'héritage est tronqué par construction — la classe de"
echo " base amont SmartChargingManager est hors INPUT. Voir l'en-tête du"
echo " Doxyfile ; ne pas « réparer » en élargissant le périmètre."
if [ "$RC_REGLES" -ne 0 ]; then
echo ""
echo " ⚠ L'INDEX DES RÈGLES est incomplet — voir la sortie d'erreur ci-dessus."
echo " La documentation est produite quand même ; le code de retour, lui, le dit."
[ "$code" -eq 0 ] && code="$RC_REGLES"
fi
exit $code