From 3e274edb9e66627a204fe7fd462f368b2e14b8c2 Mon Sep 17 00:00:00 2001 From: Patrick <116003638+patrick-medusajs@users.noreply.github.com> Date: Fri, 17 Feb 2023 07:11:27 -0500 Subject: [PATCH] feat(docs): OAS circular reference check shall fail openapi:generate (#3269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What Unhandled OAS circular references shall fail `openapi:generate` until they have been patched in `docs-util/redocly/config.yaml` ### Why Prevent developers to commit new OAS changes that would cause to API documentation to crash. Our API documentation rendering library will crash and not load if our OAS contains circular references. We have an automated mechanism to patch offending references but they must be identified and configured by hand. ### How Let the `openapi:generate --dry-run` command reach OAS sanitization and circular reference check operations. Fail the build script if unhandled circular references are detected. Output the offending references to the stdout in order to help the developers identify and configure the required patch. Since some the tooling involved only work with files, use the host system's temporary directory mechanism when using the `--dry-run` flag. ### Test * Introduce a bug by removing an entry in `docs-util/redocly/config.yaml` * Run `yarn openapi:generate --dry-run` * Expect the script to exit before completing * Expect the logs to contain `🔴 Unhandled circular references.` * Expect the logs to contain an array of the offending references --- .github/workflows/oas-test.yml | 1 + scripts/build-openapi.js | 36 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/.github/workflows/oas-test.yml b/.github/workflows/oas-test.yml index 7353411894..2c1d83a82a 100644 --- a/.github/workflows/oas-test.yml +++ b/.github/workflows/oas-test.yml @@ -2,6 +2,7 @@ name: OAS Comments Format Validation on: pull_request: paths: + - packages/medusa/oas/** - packages/medusa/src/api/** - packages/medusa/src/models/** - packages/medusa/src/types/** diff --git a/scripts/build-openapi.js b/scripts/build-openapi.js index 644d172aa9..357074c180 100755 --- a/scripts/build-openapi.js +++ b/scripts/build-openapi.js @@ -1,6 +1,7 @@ #!/usr/bin/env node const fs = require("fs/promises") +const os = require("os") const path = require("path") const execa = require("execa") const yaml = require("js-yaml") @@ -11,19 +12,20 @@ const basePath = path.resolve(__dirname, `../`) const docsApiPath = path.resolve(basePath, "docs/api/") const run = async () => { - await generateOASSources(docsApiPath, isDryRun) - if (isDryRun) { - return - } + const outputPath = isDryRun ? await getTmpDirectory() : docsApiPath + + await generateOASSources(outputPath) for (const apiType of ["store", "admin"]) { - const inputJsonFile = path.resolve(docsApiPath, `${apiType}.oas.json`) - const outputYamlFile = path.resolve(docsApiPath, `${apiType}.oas.yaml`) + const inputJsonFile = path.resolve(outputPath, `${apiType}.oas.json`) + const outputYamlFile = path.resolve(outputPath, `${apiType}.oas.yaml`) await jsonFileToYamlFile(inputJsonFile, outputYamlFile) await sanitizeOAS(outputYamlFile) await circularReferenceCheck(outputYamlFile) - await generateReference(outputYamlFile, apiType) + if (!isDryRun) { + await generateReference(outputYamlFile, apiType) + } } } @@ -68,10 +70,13 @@ const circularReferenceCheck = async (srcFile) => { }, }) if (parser.$refs.circular) { - console.log(`🔴 Unhandled circular references - ${srcFile}`) + const fileName = path.basename(srcFile) const circularRefs = [...parser.$refs.circularRefs] circularRefs.sort() console.log(circularRefs) + throw new Error( + `🔴 Unhandled circular references - ${fileName} - Please patch in docs-util/redocly/config.yaml` + ) } } @@ -86,6 +91,19 @@ const generateReference = async (srcFile, apiType) => { console.log(logs) } +const getTmpDirectory = async () => { + /** + * RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner. + */ + const tmpDir = process.env["RUNNER_TEMP"] ?? os.tmpdir() + return await fs.mkdtemp(tmpDir) +} + void (async () => { - await run() + try { + await run() + } catch (err) { + console.log(err) + process.exit(1) + } })()