a948eed9b6
Auto Tag Develop / tag (push) Successful in 7s
Ticket Lesstime : ERP-67 — `[Convention SQL / Backend / L]` ## Objectif Documenter toutes les colonnes BDD via `COMMENT ON COLUMN` (visible dans DBeaver / DataGrip / pgAdmin sans lire le code Doctrine) et verrouiller la convention par un garde-fou de test architecture. ## Changements ### Convention (CLAUDE.md + rules) - `CLAUDE.md` regle ABSOLUE n°12 : toute migration creant ou modifiant une colonne doit poser un `COMMENT ON COLUMN` (FR, ≤ 200 caracteres). - `.claude/rules/backend.md` § Migrations Doctrine : exemples + helper standardise pour les 4 colonnes du `TimestampableBlamableTrait`. ### Garde-fou architecture - `tests/Architecture/ColumnsHaveSqlCommentTest` : echoue si une colonne `public` n'a pas de `col_description` (hors `doctrine_migration_versions` et `fake_site_aware_entity` fixture de test). - Whitelist metier `EXCLUDED_TABLES` volontairement vide. ### Retrofit des tables existantes - Migration `Version20260528120000` : 64 `COMMENT ON TABLE/COLUMN` sur les 11 tables metier (audit_log, category, category_type, permission, role, role_permission, site, user, user_permission, user_role, user_site). - Source unique de verite : `src/Shared/Infrastructure/Database/ColumnCommentsCatalog.php`. - Commande `app:apply-column-comments` (Module/Core/Infrastructure/Console) : rejoue le catalogue apres `doctrine:schema:update --force` (sinon l'ORM drop les commentaires absents du mapping PHP). Branchee dans `makefile test-db-setup` et `.gitea/workflows/pull-request.yml`. ## Validation - `make db-reset` puis `make test` : 312 tests verts, 0 regression. - `make php-cs-fixer-allow-risky` : 0 fix. - Couverture : 53/53 colonnes documentees sur `starseed` et `starseed_test`. ## Test plan - [ ] `make db-reset` passe sans erreur. - [ ] `make test` passe ; `ColumnsHaveSqlCommentTest` vert sur DB de test. - [ ] Verifier dans DBeaver / pgAdmin que les commentaires apparaissent sur les colonnes de `category`, `user`, `audit_log`. - [ ] Verifier que le workflow CI Gitea (`pull-request.yml`) passe. ## A noter pour la suite La convention `options: ['comment' => '...']` sur chaque `#[ORM\Column]` reste recommandee pour les nouvelles entites — Doctrine genere alors automatiquement le `COMMENT ON COLUMN` dans la migration et `schema:update` le preserve sans avoir a rejouer le catalogue. A discuter si on veut en faire une regle forte. --------- Co-authored-by: admin malio <malio@yuno.malio.fr> Co-authored-by: Matthieu <contact@malio.fr> Co-authored-by: Matthieu <mtholot19@gmail.com> Reviewed-on: #24 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
115 lines
4.2 KiB
PHP
115 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Architecture;
|
|
|
|
use Doctrine\DBAL\ArrayParameterType;
|
|
use Doctrine\DBAL\Connection;
|
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
|
|
|
/**
|
|
* Garde-fou architecture : toute colonne d'une table metier doit porter une
|
|
* description SQL (`COMMENT ON COLUMN`).
|
|
*
|
|
* Postgres stocke la description dans `pg_description`, recuperable via
|
|
* `col_description(table_oid, column_position)`. Une colonne sans description
|
|
* remonte `NULL`. Le test parcourt `information_schema.columns` filtre sur le
|
|
* schema `public` et echoue si une seule colonne metier n'a pas de description.
|
|
*
|
|
* Tables ignorees :
|
|
* - `doctrine_migration_versions` : table system Doctrine, schema fige par la
|
|
* librairie.
|
|
* - Whitelist `EXCLUDED_TABLES` : doit rester vide ou justifiee — toute entree
|
|
* doit avoir un ticket Lesstime ouvert pour le retrofit.
|
|
*
|
|
* @internal
|
|
*/
|
|
final class ColumnsHaveSqlCommentTest extends KernelTestCase
|
|
{
|
|
/**
|
|
* Tables system, gerees par Doctrine — leur schema n'est pas notre.
|
|
*/
|
|
private const EXCLUDED_BUILTINS = [
|
|
'doctrine_migration_versions',
|
|
];
|
|
|
|
/**
|
|
* Entites mappees uniquement en `when@test` (fixtures techniques pour les
|
|
* tests d'integration, jamais en prod). Pas de migration, donc pas de
|
|
* lieu naturel pour poser un COMMENT ON COLUMN.
|
|
*
|
|
* @var list<string>
|
|
*/
|
|
private const EXCLUDED_TEST_FIXTURES = [
|
|
// tests/Fixtures/SiteAware/FakeSiteAwareEntity.php — fixture du module
|
|
// Sites pour couvrir le SiteScopedQueryExtension. Cree via schema:update
|
|
// sur la DB de test uniquement.
|
|
'fake_site_aware_entity',
|
|
];
|
|
|
|
/**
|
|
* Whitelist metier — DOIT rester vide ou justifiee.
|
|
*
|
|
* Chaque entree doit comporter (1) un commentaire expliquant pourquoi la
|
|
* table n'est pas encore documentee et (2) la reference d'un ticket
|
|
* Lesstime ouvert pour le retrofit.
|
|
*
|
|
* @var list<string>
|
|
*/
|
|
private const EXCLUDED_TABLES = [];
|
|
|
|
public function testAllPublicColumnsHaveASqlComment(): void
|
|
{
|
|
/** @var Connection $conn */
|
|
$conn = self::getContainer()->get('doctrine.dbal.default_connection');
|
|
|
|
$excluded = [...self::EXCLUDED_BUILTINS, ...self::EXCLUDED_TEST_FIXTURES, ...self::EXCLUDED_TABLES];
|
|
|
|
$rows = $conn->fetchAllAssociative(
|
|
<<<'SQL'
|
|
SELECT c.table_name, c.column_name
|
|
FROM information_schema.columns c
|
|
WHERE c.table_schema = 'public'
|
|
AND c.table_name NOT IN (:excluded)
|
|
AND col_description(
|
|
(c.table_schema || '.' || c.table_name)::regclass,
|
|
c.ordinal_position
|
|
) IS NULL
|
|
ORDER BY c.table_name, c.ordinal_position
|
|
SQL,
|
|
['excluded' => $excluded],
|
|
['excluded' => ArrayParameterType::STRING],
|
|
);
|
|
|
|
if ([] !== $rows) {
|
|
$missing = array_map(
|
|
static fn (array $row): string => sprintf('%s.%s', $row['table_name'], $row['column_name']),
|
|
$rows,
|
|
);
|
|
|
|
self::fail(sprintf(
|
|
"%d colonne(s) sans COMMENT ON COLUMN — ajouter une description SQL dans la migration qui les cree (cf. .claude/rules/backend.md § Migrations Doctrine) :\n - %s",
|
|
count($missing),
|
|
implode("\n - ", $missing),
|
|
));
|
|
}
|
|
|
|
// Garde : si la requete ne renvoie rien et qu'aucune table publique
|
|
// n'existe (sauf doctrine_migration_versions), le test deviendrait un
|
|
// faux positif vert. On verifie qu'il y a bien des tables a auditer.
|
|
$tableCount = (int) $conn->fetchOne(
|
|
<<<'SQL'
|
|
SELECT COUNT(*)
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name NOT IN (:excluded)
|
|
SQL,
|
|
['excluded' => $excluded],
|
|
['excluded' => ArrayParameterType::STRING],
|
|
);
|
|
|
|
self::assertGreaterThan(0, $tableCount, 'Aucune table publique a auditer : schema vide ou whitelist trop large.');
|
|
}
|
|
}
|