Skip to content

Commit

Permalink
feat: rewrite api generation to support older versions; configure v8.…
Browse files Browse the repository at this point in the history
…6 of operate API generation
  • Loading branch information
pepopowitz committed Dec 20, 2024
1 parent 237c326 commit 8116292
Show file tree
Hide file tree
Showing 4 changed files with 2,134 additions and 25 deletions.
134 changes: 117 additions & 17 deletions api/generate-api-docs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
//sjhsjhsjh:
// 0. [x] collect version from args
// 1. [x] pull in version config from docusaurusconfig
// 2. [x] protect against nonexisting versions
// 3. Call correct drex commands given version info
// 4. pass config into pre/postGenerateDocs

const { execSync } = require("child_process");

// More strategies to come, for other APIs.
// Each API has a custom strategy, for modifying the schema or generated docs.
const operate = require("./operate/generation-strategy");
const tasklist = require("./tasklist/generation-strategy");
const adminsm = require("./administration-sm/generation-strategy");
Expand All @@ -12,49 +19,142 @@ const apiStrategies = {
camunda,
};

// Execute a command as if we were in the terminal
function runCommand(command) {
const result = execSync(command, { stdio: "inherit" });
return result;
}

// API name must be passed in as an arg.
const api = process.argv[2];
if (api === undefined) {
const requestedAPI = process.argv[2];
if (requestedAPI === undefined) {
const validAPIs = Object.keys(apiStrategies).join(", ");
console.log(`Please specify an API name. Valid names: ${validAPIs}`);
process.exit();
}

// The API name must be recognized.
const strategy = apiStrategies[api];
const strategy = apiStrategies[requestedAPI];
if (strategy === undefined) {
const validAPIs = Object.keys(apiStrategies).join(", ");
console.error(`Invalid API name ${api}. Valid names: ${validAPIs}`);
console.error(`Invalid API name ${requestedAPI}. Valid names: ${validAPIs}`);
process.exit();
}

// Version is an optional argument. If not provided, we assume "vNext".
const requestedVersion = process.argv[3];

// Find the corresponding configuration in docusaurus.config.js.
const configs = loadAPIConfigs();
const apiConfig = buildAPIConfig(configs, requestedAPI, requestedVersion);

// All APIs will execute these same steps, with custom-per-API steps
// implemented by each API's generation-strategy.js.
const steps = [
// Remove old docs
() => runCommand(`docusaurus clean-api-docs ${api} -p api-${api}-openapi`),
() => runCommand(buildCleanCommand(apiConfig)),

// Run any custom steps before generation
strategy.preGenerateDocs,
() => strategy.preGenerateDocs(apiConfig),

// Generate the docs
() => runCommand(`docusaurus gen-api-docs ${api} -p api-${api}-openapi`),
() => runCommand(buildGenerateCommand(apiConfig)),

// Run any custom steps after generation
strategy.postGenerateDocs,
() => strategy.postGenerateDocs(apiConfig),

// Run prettier against the generated docs. Twice. Yes, twice.
// I don't know why, but the first run always leaves an extra blank line,
// which the second execution removes.
() => runCommand(`prettier --write ${strategy.outputDir}`),
() => runCommand(`prettier --write ${strategy.outputDir}`),
() => runCommand(`prettier --write ${apiConfig.outputDir}`),
() => runCommand(`prettier --write ${apiConfig.outputDir}`),
];

// Run the steps!
steps.forEach((step) => step());

// ---------- vvvvvvv helper functions vvvvvvv ----------

// Execute a command as if we were in the terminal
function runCommand(command) {
const result = execSync(command, { stdio: "inherit" });
return result;
}

// Load the API configs from the docusaurus.config.js file.
function loadAPIConfigs() {
const config = require("../docusaurus.config");
const apiConfigs = config.plugins
.filter(
(plugin) =>
Array.isArray(plugin) && plugin[0] === "docusaurus-plugin-openapi-docs"
)
.reduce((acc, plugin) => {
const [_, options] = plugin;
configObject = options.config;
const apiName = Object.keys(configObject)[0];
acc[apiName] = configObject[apiName];
return acc;
}, {});

// Reduce should give a shape like this:
// {
// "operate": {
// "specPath": "api/operate/operate-openapi.yaml",
// "outputDir": "docs/apis-tools/operate-api/specifications",
// ...
// "versions": {
// "8.6": {
// "specPath": "api/operate/version-8.6/operate-openapi.yaml",
// "outputDir": "versioned_docs/version-8.6/apis-tools/operate-api/specifications",
// ...
// }
// }
// },
// "tasklist": {
// ....

return apiConfigs;
}

// Find the API config for the given API and version.
function buildAPIConfig(apiConfigs, requestedAPI, requestedVersion) {
const apiConfig = apiConfigs[requestedAPI];
if (apiConfig === undefined) {
console.error(
`No configuration found for API ${requestedAPI}. Check docusaurus.config.js.`
);
process.exit();
}

let matchingConfig = apiConfig;

if (requestedVersion !== undefined) {
matchingConfig = apiConfig.versions[requestedVersion];
if (matchingConfig === undefined) {
console.error(
`No config found for API ${requestedAPI} version ${requestedVersion}. Check docusaurus.config.js.`
);
process.exit();
}
}

return {
apiName: requestedAPI,
specPath: matchingConfig.specPath,
outputDir: matchingConfig.outputDir,
version: requestedVersion || "next",
};
}

// Build the command to clean the API docs.
function buildCleanCommand(apiConfig) {
const { apiName, version } = apiConfig;
if (version === "next") {
return `docusaurus clean-api-docs ${apiName} -p api-${apiName}-openapi`;
}
return `docusaurus clean-api-docs:version ${apiName}:${version} -p api-${apiName}-openapi`;
}

// Build the command to generate the API docs.
function buildGenerateCommand(apiConfig) {
const { apiName, version } = apiConfig;
if (version === "next") {
return `docusaurus gen-api-docs ${apiName} -p api-${apiName}-openapi`;
}
return `docusaurus gen-api-docs:version ${apiName}:${version} -p api-${apiName}-openapi`;
}
14 changes: 6 additions & 8 deletions api/operate/generation-strategy.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
const { makeServerDynamic } = require("../make-server-dynamic");
const removeDuplicateVersionBadge = require("../remove-duplicate-version-badge");

const outputDir = "docs/apis-tools/operate-api/specifications";
const specFile = "api/operate/operate-openapi.yaml";

function preGenerateDocs() {
makeServerDynamic(specFile);
function preGenerateDocs(config) {
makeServerDynamic(config.specPath);
}

function postGenerateDocs() {
removeDuplicateVersionBadge(`${outputDir}/operate-public-api.info.mdx`);
function postGenerateDocs(config) {
removeDuplicateVersionBadge(
`${config.outputDir}/operate-public-api.info.mdx`
);
}

module.exports = {
outputDir,
preGenerateDocs,
postGenerateDocs,
};
Loading

0 comments on commit 8116292

Please sign in to comment.