From 5176099c798dd06d2edbd9d917adeb99920231c8 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 12 Jul 2021 16:41:39 +0200 Subject: [PATCH] Allow either out-of-the-box or recommended configurations in TechDocs createRouter Signed-off-by: Eric Peterson --- .../techdocs-backend/src/service/router.ts | 141 +++++++++++------- 1 file changed, 87 insertions(+), 54 deletions(-) diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index eceae2e3d3..7563dfa2f9 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -31,7 +31,11 @@ import { Logger } from 'winston'; import { DocsBuilder } from '../DocsBuilder'; import { shouldCheckForUpdate } from '../DocsBuilder/BuildMetadataStorage'; -type RouterOptions = { +/** + * All of the required dependencies for running TechDocs in the "out-of-the-box" + * deployment configuration (prepare/generate/publish all in the Backend). + */ +type OutOfTheBoxDeploymentOptions = { preparers: PreparerBuilder; generators: GeneratorBuilder; publisher: PublisherBase; @@ -41,15 +45,39 @@ type RouterOptions = { config: Config; }; -export async function createRouter({ - preparers, - generators, - publisher, - config, - logger, - discovery, -}: RouterOptions): Promise { +/** + * Required dependencies for running TechDocs in the "recommended" deployment + * configuration (prepare/generate handled externally in CI/CD). + */ +type RecommendedDeploymentOptions = { + publisher: PublisherBase; + logger: Logger; + discovery: PluginEndpointDiscovery; + config: Config; +}; + +/** + * One of the two deployment configurations must be provided. + */ +type RouterOptions = + | RecommendedDeploymentOptions + | OutOfTheBoxDeploymentOptions; + +/** + * Typeguard to help createRouter() understand when we are in a "recommended" + * deployment vs. when we are in an out-of-the-box deployment configuration. + */ +function isOutOfTheBoxOption( + opt: RouterOptions, +): opt is OutOfTheBoxDeploymentOptions { + return (opt as OutOfTheBoxDeploymentOptions).preparers !== undefined; +} + +export async function createRouter( + options: RouterOptions, +): Promise { const router = Router(); + const { publisher, config, logger, discovery } = options; router.get('/metadata/techdocs/:namespace/:kind/:name', async (req, res) => { const { kind, namespace, name } = req.params; @@ -158,58 +186,63 @@ export async function createRouter({ }); return; } - const docsBuilder = new DocsBuilder({ - preparers, - generators, - publisher, - logger, - entity, - config, - }); - let foundDocs = false; - switch (publisherType) { - case 'local': - case 'awsS3': - case 'azureBlobStorage': - case 'openStackSwift': - case 'googleGcs': { - // This block should be valid for all storage implementations. So no need to duplicate in future, - // add the publisher type in the list here. - const updated = await docsBuilder.build(); - if (!updated) { - throw new NotModifiedError(); - } + // Set up a DocsBuilder if "out-of-the-box" configuration is provided. + if (isOutOfTheBoxOption(options)) { + const { preparers, generators } = options; + const docsBuilder = new DocsBuilder({ + preparers, + generators, + publisher, + logger, + entity, + config, + }); + let foundDocs = false; + switch (publisherType) { + case 'local': + case 'awsS3': + case 'azureBlobStorage': + case 'openStackSwift': + case 'googleGcs': { + // This block should be valid for all storage implementations. So no need to duplicate in future, + // add the publisher type in the list here. + const updated = await docsBuilder.build(); - // With a maximum of ~5 seconds wait, check if the files got published and if docs will be fetched - // on the user's page. If not, respond with a message asking them to check back later. - // The delay here is to make sure GCS/AWS/etc. registers newly uploaded files which is usually <1 second - for (let attempt = 0; attempt < 5; attempt++) { - if (await publisher.hasDocsBeenGenerated(entity)) { - foundDocs = true; - break; + if (!updated) { + throw new NotModifiedError(); } - await new Promise(r => setTimeout(r, 1000)); + + // With a maximum of ~5 seconds wait, check if the files got published and if docs will be fetched + // on the user's page. If not, respond with a message asking them to check back later. + // The delay here is to make sure GCS/AWS/etc. registers newly uploaded files which is usually <1 second + for (let attempt = 0; attempt < 5; attempt++) { + if (await publisher.hasDocsBeenGenerated(entity)) { + foundDocs = true; + break; + } + await new Promise(r => setTimeout(r, 1000)); + } + if (!foundDocs) { + logger.error( + 'Published files are taking longer to show up in storage. Something went wrong.', + ); + throw new NotFoundError( + 'Sorry! It took too long for the generated docs to show up in storage. Check back later.', + ); + } + + res + .status(201) + .json({ message: 'Docs updated or did not need updating' }); + break; } - if (!foundDocs) { - logger.error( - 'Published files are taking longer to show up in storage. Something went wrong.', - ); + + default: throw new NotFoundError( - 'Sorry! It took too long for the generated docs to show up in storage. Check back later.', + `Publisher type ${publisherType} is not supported by techdocs-backend docs builder.`, ); - } - - res - .status(201) - .json({ message: 'Docs updated or did not need updating' }); - break; } - - default: - throw new NotFoundError( - `Publisher type ${publisherType} is not supported by techdocs-backend docs builder.`, - ); } });