From 124b796a769106b9283fa01dfa72fb5ccbdfefb3 Mon Sep 17 00:00:00 2001 From: Herve Labas Date: Tue, 12 May 2026 20:42:11 +0200 Subject: [PATCH] skip incomplete API reference generations --- .github/scripts/detect-new-endpoints.mjs | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.github/scripts/detect-new-endpoints.mjs b/.github/scripts/detect-new-endpoints.mjs index 27ec8c39..8e303485 100644 --- a/.github/scripts/detect-new-endpoints.mjs +++ b/.github/scripts/detect-new-endpoints.mjs @@ -193,6 +193,29 @@ function getUniqueFilename(ep) { return `${baseFilename}-${Date.now()}`; } +function getDocumentabilityIssues(ep, details) { + const issues = []; + const responseCodes = Object.keys(details.responses ?? {}); + const nonDefaultResponses = responseCodes.filter(code => code !== 'default'); + + if (nonDefaultResponses.length === 0) { + issues.push('only has a default response'); + } + + const pathParams = [...ep.path.matchAll(/\{([^}]+)\}/g)].map(match => match[1]); + const documentedPathParams = new Set( + (details.parameters ?? []) + .filter(param => param?.in === 'path') + .map(param => param.name) + ); + const missingPathParams = pathParams.filter(param => !documentedPathParams.has(param)); + if (missingPathParams.length > 0) { + issues.push(`missing path parameter metadata: ${missingPathParams.join(', ')}`); + } + + return issues; +} + function openPrExistsForBranchBase(branchBaseName) { try { const result = run( @@ -382,6 +405,7 @@ async function main() { // 2. Find undocumented endpoints const undocumented = []; + const skippedPoorSpec = []; for (const [path, methods] of Object.entries(spec.paths)) { for (const [method, details] of Object.entries(methods)) { if (!['get', 'post', 'put', 'delete', 'patch'].includes(method)) continue; @@ -398,10 +422,24 @@ async function main() { const { dir, group, subgroup } = resolveMapping(tag, summary); const ep = { key, method: method.toUpperCase(), path, tag, summary, dir, group, subgroup }; + const documentabilityIssues = getDocumentabilityIssues(ep, details); + if (documentabilityIssues.length > 0) { + skippedPoorSpec.push({ ...ep, issues: documentabilityIssues }); + continue; + } + undocumented.push({ ...ep, filename: getUniqueFilename(ep) }); } } + if (skippedPoorSpec.length > 0) { + console.log(`\n⚠️ Skipping ${skippedPoorSpec.length} endpoint(s) with incomplete OpenAPI metadata:\n`); + for (const ep of skippedPoorSpec) { + console.log(` ${ep.key} — ${ep.issues.join('; ')}`); + } + console.log('\n Fix the upstream OpenAPI metadata before generating API reference pages for these endpoints.'); + } + if (undocumented.length === 0) { console.log('\n✅ All endpoints are documented (or excluded). Nothing to do.'); return;