feat(docs): OAS circular reference check shall fail openapi:generate (#3269)
### 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
This commit is contained in:
1 parent
aefe5aa133
commit
3e274edb9e
2 files changed
+26
-7
No files matched your search
@@ -2,6 +2,7 @@ name: OAS Comments Format Validation
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
- packages/medusa/oas/**
|
||||||
- packages/medusa/src/api/**
|
- packages/medusa/src/api/**
|
||||||
- packages/medusa/src/models/**
|
- packages/medusa/src/models/**
|
||||||
- packages/medusa/src/types/**
|
- packages/medusa/src/types/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const fs = require("fs/promises")
|
const fs = require("fs/promises")
|
||||||
|
const os = require("os")
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const execa = require("execa")
|
const execa = require("execa")
|
||||||
const yaml = require("js-yaml")
|
const yaml = require("js-yaml")
|
||||||
@@ -11,21 +12,22 @@ const basePath = path.resolve(__dirname, `../`)
|
|||||||
const docsApiPath = path.resolve(basePath, "docs/api/")
|
const docsApiPath = path.resolve(basePath, "docs/api/")
|
||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
await generateOASSources(docsApiPath, isDryRun)
|
const outputPath = isDryRun ? await getTmpDirectory() : docsApiPath
|
||||||
if (isDryRun) {
|
|
||||||
return
|
await generateOASSources(outputPath)
|
||||||
}
|
|
||||||
|
|
||||||
for (const apiType of ["store", "admin"]) {
|
for (const apiType of ["store", "admin"]) {
|
||||||
const inputJsonFile = path.resolve(docsApiPath, `${apiType}.oas.json`)
|
const inputJsonFile = path.resolve(outputPath, `${apiType}.oas.json`)
|
||||||
const outputYamlFile = path.resolve(docsApiPath, `${apiType}.oas.yaml`)
|
const outputYamlFile = path.resolve(outputPath, `${apiType}.oas.yaml`)
|
||||||
|
|
||||||
await jsonFileToYamlFile(inputJsonFile, outputYamlFile)
|
await jsonFileToYamlFile(inputJsonFile, outputYamlFile)
|
||||||
await sanitizeOAS(outputYamlFile)
|
await sanitizeOAS(outputYamlFile)
|
||||||
await circularReferenceCheck(outputYamlFile)
|
await circularReferenceCheck(outputYamlFile)
|
||||||
|
if (!isDryRun) {
|
||||||
await generateReference(outputYamlFile, apiType)
|
await generateReference(outputYamlFile, apiType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const generateOASSources = async (outDir, isDryRun) => {
|
const generateOASSources = async (outDir, isDryRun) => {
|
||||||
const params = ["oas", `--out-dir=${outDir}`]
|
const params = ["oas", `--out-dir=${outDir}`]
|
||||||
@@ -68,10 +70,13 @@ const circularReferenceCheck = async (srcFile) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (parser.$refs.circular) {
|
if (parser.$refs.circular) {
|
||||||
console.log(`🔴 Unhandled circular references - ${srcFile}`)
|
const fileName = path.basename(srcFile)
|
||||||
const circularRefs = [...parser.$refs.circularRefs]
|
const circularRefs = [...parser.$refs.circularRefs]
|
||||||
circularRefs.sort()
|
circularRefs.sort()
|
||||||
console.log(circularRefs)
|
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)
|
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 () => {
|
void (async () => {
|
||||||
|
try {
|
||||||
await run()
|
await run()
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
})()
|
})()
|
||||||
Reference in new issue
Block a user