From cfb074b3f02dda652a97215f3738dbd855a7b843 Mon Sep 17 00:00:00 2001 From: mrbobbytables Date: Fri, 30 Oct 2026 10:12:46 -0500 Subject: [PATCH] fix: regenerate members.json after the catalog ExternalDNS fix The catalog normalisation that listed ExternalDNS once on /architectures did not regenerate data/members.json, so /members still spelled the project External-dns for SNCF: the project filter offered two options for one project, selecting ExternalDNS omitted SNCF, and the SNCF profile disagreed with /architectures/sncf-onprem. Regenerate the artifact and add a test that reconciles each member's projects and industries with the catalog entries behind its architectures, so a catalog edit that skips regeneration fails the required check instead of shipping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: mrbobbytables --- data/members.json | 2 +- tests/members-data.test.mjs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/data/members.json b/data/members.json index 088fe7ab..65b93989 100644 --- a/data/members.json +++ b/data/members.json @@ -2343,7 +2343,7 @@ "ArgoCD", "Cluster API", "External Secrets Operator", - "External-dns", + "ExternalDNS", "Harbor", "Kubernetes", "OpenStack", diff --git a/tests/members-data.test.mjs b/tests/members-data.test.mjs index ac2ce79c..22fd86f3 100644 --- a/tests/members-data.test.mjs +++ b/tests/members-data.test.mjs @@ -13,6 +13,7 @@ function readJson(relativePath) { const membersData = readJson('data/members.json'); const awardsData = readJson('data/awards.json'); const landscapeData = readJson('data/enduser-landscape.json'); +const catalogData = readJson('data/architectures/catalog.json'); const members = membersData.members; // src/components/MemberDirectory/index.js dereferences these without guards @@ -212,6 +213,35 @@ test('members are sorted by display name', () => { ); }); +test('member projects and industries match the committed architecture catalog', () => { + // generate-members.mjs derives these two arrays from the catalog entries it + // attaches as member.architectures. Nothing else reconciles the committed + // artifact with its committed input, so a catalog edit that skips + // regeneration leaves /members filtering on a stale project name. + const catalogById = new Map(catalogData.map((entry) => [entry.id, entry])); + for (const member of members) { + if (member.architectures.length === 0) continue; + const entries = member.architectures.map((architecture) => { + const entry = catalogById.get(architecture.id); + assert.ok( + entry, + `${member.id} lists architecture ${architecture.id} that data/architectures/catalog.json does not contain`, + ); + return entry; + }); + for (const field of ['projects', 'industries']) { + const expected = [ + ...new Set(entries.flatMap((entry) => entry[field] || [])), + ].sort(); + assert.deepEqual( + [...member[field]].sort(), + expected, + `${member.id} ${field} drifted from data/architectures/catalog.json; run npm run generate:members`, + ); + } + } +}); + test('member logos live under /img/ and exist in the repository', () => { for (const member of members) { if (!member.logo) continue;