From 15b6eaf533169062c79470f87b2a71bf515c3a29 Mon Sep 17 00:00:00 2001 From: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Date: Tue, 27 Dec 2022 10:43:36 -0600 Subject: [PATCH] Large refactor Signed-off-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> --- .changeset/perfect-pears-care.md | 1 + packages/techdocs-cli/cli-report.md | 3 ++ .../src/commands/generate/generate.ts | 1 + packages/techdocs-cli/src/commands/index.ts | 15 ++++++ .../techdocs-cli/src/commands/serve/mkdocs.ts | 4 ++ .../techdocs-cli/src/commands/serve/serve.ts | 3 ++ .../src/DocsBuilder/builder.ts | 2 +- plugins/techdocs-node/api-report.md | 11 ++++- .../generate/__fixtures__/mkdocs_default.yml | 2 +- .../src/stages/generate/helpers.test.ts | 10 ++-- .../src/stages/generate/helpers.ts | 46 +++++++++++++++---- .../src/stages/generate/index.ts | 1 + .../src/stages/generate/techdocs.ts | 4 +- .../src/stages/generate/types.ts | 3 +- 14 files changed, 87 insertions(+), 19 deletions(-) diff --git a/.changeset/perfect-pears-care.md b/.changeset/perfect-pears-care.md index 13db9ad0c1..2ea9f54a7f 100644 --- a/.changeset/perfect-pears-care.md +++ b/.changeset/perfect-pears-care.md @@ -1,6 +1,7 @@ --- '@backstage/plugin-techdocs-backend': patch '@backstage/plugin-techdocs-node': patch +'@techdocs/cli': patch --- Added support for using a default `mkdocs.yml` configuration file when none is provided diff --git a/packages/techdocs-cli/cli-report.md b/packages/techdocs-cli/cli-report.md index 861dad4605..846ccc88ca 100644 --- a/packages/techdocs-cli/cli-report.md +++ b/packages/techdocs-cli/cli-report.md @@ -33,6 +33,7 @@ Options: --no-docker --techdocs-ref --etag + --site-name -v --verbose --omitTechdocsCoreMkdocsPlugin --legacyCopyReadmeMdToIndexMd @@ -98,6 +99,7 @@ Options: --docker-entrypoint --docker-option --no-docker + --site-name --mkdocs-port -v --verbose --preview-app-bundle-path @@ -115,6 +117,7 @@ Options: --docker-entrypoint --docker-option --no-docker + --site-name -p, --port -v --verbose -h, --help diff --git a/packages/techdocs-cli/src/commands/generate/generate.ts b/packages/techdocs-cli/src/commands/generate/generate.ts index 874b904d86..c409992050 100644 --- a/packages/techdocs-cli/src/commands/generate/generate.ts +++ b/packages/techdocs-cli/src/commands/generate/generate.ts @@ -106,6 +106,7 @@ export default async function generate(opts: OptionValues) { logger, etag: opts.etag, ...(process.env.LOG_LEVEL === 'debug' ? { logStream: stdout } : {}), + siteName: opts.siteName, }); logger.info('Done!'); diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index caa7d8efbd..0ff52eee36 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -54,6 +54,11 @@ export function registerCommands(program: Command) { '--etag ', 'A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json.', ) + .option( + '--site-name', + 'Name for site when using default MkDocs config', + 'Table of Contents', + ) .option('-v --verbose', 'Enable verbose output.', false) .option( '--omitTechdocsCoreMkdocsPlugin', @@ -224,6 +229,11 @@ export function registerCommands(program: Command) { '--no-docker', 'Do not use Docker, run `mkdocs serve` in current user environment.', ) + .option( + '--site-name', + 'Name for site when using default MkDocs config', + 'Table of Contents', + ) .option('-p, --port ', 'Port to serve documentation locally', '8000') .option('-v --verbose', 'Enable verbose output.', false) .action(lazy(() => import('./serve/mkdocs').then(m => m.default))); @@ -250,6 +260,11 @@ export function registerCommands(program: Command) { '--no-docker', 'Do not use Docker, use MkDocs executable in current user environment.', ) + .option( + '--site-name', + 'Name for site when using default MkDocs config', + 'Table of Contents', + ) .option('--mkdocs-port ', 'Port for MkDocs server to use', '8000') .option('-v --verbose', 'Enable verbose output.', false) .option( diff --git a/packages/techdocs-cli/src/commands/serve/mkdocs.ts b/packages/techdocs-cli/src/commands/serve/mkdocs.ts index 9cc0aef3be..6c84298c2b 100644 --- a/packages/techdocs-cli/src/commands/serve/mkdocs.ts +++ b/packages/techdocs-cli/src/commands/serve/mkdocs.ts @@ -19,6 +19,7 @@ import openBrowser from 'react-dev-utils/openBrowser'; import { createLogger } from '../../lib/utility'; import { runMkdocsServer } from '../../lib/mkdocsServer'; import { LogFunc, waitForSignal } from '../../lib/run'; +import { getMkdocsYml } from '@backstage/plugin-techdocs-node'; export default async function serveMkdocs(opts: OptionValues) { const logger = createLogger({ verbose: opts.verbose }); @@ -26,6 +27,9 @@ export default async function serveMkdocs(opts: OptionValues) { const dockerAddr = `http://0.0.0.0:${opts.port}`; const localAddr = `http://127.0.0.1:${opts.port}`; const expectedDevAddr = opts.docker ? dockerAddr : localAddr; + + await getMkdocsYml('./', opts.siteName); + // We want to open browser only once based on a log. let boolOpenBrowserTriggered = false; diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index d46c70678a..1e835c2c8d 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -22,6 +22,7 @@ import HTTPServer from '../../lib/httpServer'; import { runMkdocsServer } from '../../lib/mkdocsServer'; import { LogFunc, waitForSignal } from '../../lib/run'; import { createLogger } from '../../lib/utility'; +import { getMkdocsYml } from '@backstage/plugin-techdocs-node'; function findPreviewBundlePath(): string { try { @@ -64,6 +65,8 @@ export default async function serve(opts: OptionValues) { ? mkdocsDockerAddr : mkdocsLocalAddr; + await getMkdocsYml('./', opts.siteName); + let mkdocsServerHasStarted = false; const mkdocsLogFunc: LogFunc = data => { // Sometimes the lines contain an unnecessary extra new line diff --git a/plugins/techdocs-backend/src/DocsBuilder/builder.ts b/plugins/techdocs-backend/src/DocsBuilder/builder.ts index 2ae1462ad9..43d05f7b6f 100644 --- a/plugins/techdocs-backend/src/DocsBuilder/builder.ts +++ b/plugins/techdocs-backend/src/DocsBuilder/builder.ts @@ -186,7 +186,7 @@ export class DocsBuilder { etag: newEtag, logger: this.logger, logStream: this.logStream, - entity: this.entity, + siteName: this.entity.metadata.title ?? this.entity.metadata.name, }); // Remove Prepared directory since it is no longer needed. diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index 253f1c29fa..68a7b80152 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -54,7 +54,7 @@ export type GeneratorRunOptions = { etag?: string; logger: Logger; logStream?: Writable; - entity: Entity; + siteName?: string; }; // @public @@ -86,6 +86,15 @@ export const getLocationForEntity: ( scmIntegration: ScmIntegrationRegistry, ) => ParsedLocationAnnotation; +// @public +export const getMkdocsYml: ( + inputDir: string, + siteName?: string, +) => Promise<{ + path: string; + content: string; +}>; + // @public export type MigrateRequest = { removeOriginal?: boolean; diff --git a/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml b/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml index f6d2b01ce4..c0c5a203df 100644 --- a/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml +++ b/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml @@ -1,4 +1,4 @@ site_name: Test site name docs_dir: docs plugins: - - techdocs-core \ No newline at end of file + - techdocs-core diff --git a/plugins/techdocs-node/src/stages/generate/helpers.test.ts b/plugins/techdocs-node/src/stages/generate/helpers.test.ts index fb21643e46..158e8710f2 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.test.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.test.ts @@ -524,7 +524,7 @@ describe('helpers', () => { mockFs({ [key]: mkdocsYml }); const { path: mkdocsPath, content } = await getMkdocsYml( inputDir, - mockEntity, + mockEntity.metadata.title, ); expect(mkdocsPath).toBe(key); @@ -536,7 +536,7 @@ describe('helpers', () => { mockFs({ [key]: mkdocsYml }); const { path: mkdocsPath, content } = await getMkdocsYml( inputDir, - mockEntity, + mockEntity.metadata.title, ); expect(mkdocsPath).toBe(key); expect(content).toBe(mkdocsYml.toString()); @@ -547,7 +547,7 @@ describe('helpers', () => { mockFs({ [key]: mkdocsDefaultYml }); const { path: mkdocsPath, content } = await getMkdocsYml( inputDir, - mockEntity, + mockEntity.metadata.title, ); expect(mkdocsPath).toBe(key); expect(content).toBe(mkdocsDefaultYml.toString()); @@ -555,7 +555,9 @@ describe('helpers', () => { it('throws when neither .yml nor .yaml nor default file is present', async () => { const invalidInputDir = resolvePath(__filename); - await expect(getMkdocsYml(invalidInputDir, mockEntity)).rejects.toThrow( + await expect( + getMkdocsYml(invalidInputDir, mockEntity.metadata.title), + ).rejects.toThrow( /Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml or default for validation/, ); }); diff --git a/plugins/techdocs-node/src/stages/generate/helpers.ts b/plugins/techdocs-node/src/stages/generate/helpers.ts index ebb72c420c..198b48cf00 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.ts @@ -150,16 +150,50 @@ export const MKDOCS_SCHEMA = DEFAULT_SCHEMA.extend([ }), ]); +/** + * Generates a mkdocs.yml configuration file + * + * @param inputDir - base dir to where the mkdocs.yml file will be created + * @param siteName - name of site to be used in mkdocs.yml for the + * required `site_name` property, default value is "Table of Contents" + */ +export const generateMkdocsYml = async ( + inputDir: string, + siteName?: string, +) => { + try { + // TODO(awanlin): Use a provided default mkdocs.yml + // from config or some specified location. If this is + // not provided then fall back to generating bare + // minimum mkdocs.yml file + + const mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml'); + const defaultSiteName = siteName ?? 'Table of Contents'; + const defaultMkdocsContent = + `site_name: ${defaultSiteName}\n` + + 'docs_dir: docs\n' + + 'plugins:\n' + + ' - techdocs-core\n'; + + await fs.writeFile(mkdocsYmlPath, defaultMkdocsContent); + } catch (error) { + throw new ForwardedError('Could not generate mkdocs.yml file', error); + } +}; + /** * Finds and loads the contents of either an mkdocs.yml or mkdocs.yaml file, * depending on which is present (MkDocs supports both as of v1.2.2). + * @public * * @param inputDir - base dir to be searched for either an mkdocs.yml or * mkdocs.yaml file. + * @param siteName - name of site to be used in mkdocs.yml for the + * required `site_name` property, default value is "Table of Contents" */ export const getMkdocsYml = async ( inputDir: string, - entity: Entity, + siteName?: string, ): Promise<{ path: string; content: string }> => { let mkdocsYmlPath: string; let mkdocsYmlFileString: string; @@ -182,14 +216,8 @@ export const getMkdocsYml = async ( }; } - // No mkdocs file, use default - const defaultMkdocsContent = - `site_name: ${entity.metadata.title ?? entity.metadata.name}\n` + - 'docs_dir: docs\n' + - 'plugins:\n' + - ' - techdocs-core\n'; - - await fs.writeFile(mkdocsYmlPath, defaultMkdocsContent); + // No mkdocs file, generate it + await generateMkdocsYml(inputDir, siteName); mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8'); } catch (error) { throw new ForwardedError( diff --git a/plugins/techdocs-node/src/stages/generate/index.ts b/plugins/techdocs-node/src/stages/generate/index.ts index 1c20c58887..3bd42643c1 100644 --- a/plugins/techdocs-node/src/stages/generate/index.ts +++ b/plugins/techdocs-node/src/stages/generate/index.ts @@ -15,6 +15,7 @@ */ export { TechdocsGenerator } from './techdocs'; export { Generators } from './generators'; +export { getMkdocsYml } from './helpers'; export type { GeneratorBase, GeneratorOptions, diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index 45b2f9689e..82857e9f73 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -96,13 +96,13 @@ export class TechdocsGenerator implements GeneratorBase { etag, logger: childLogger, logStream, - entity, + siteName, } = options; // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url const { path: mkdocsYmlPath, content } = await getMkdocsYml( inputDir, - entity, + siteName, ); // validate the docs_dir first diff --git a/plugins/techdocs-node/src/stages/generate/types.ts b/plugins/techdocs-node/src/stages/generate/types.ts index 26c26f4410..86f8f96d44 100644 --- a/plugins/techdocs-node/src/stages/generate/types.ts +++ b/plugins/techdocs-node/src/stages/generate/types.ts @@ -53,6 +53,7 @@ export type GeneratorConfig = { * @param etag - A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json. * @param logger - A logger that forwards the messages to the caller to be displayed outside of the backend. * @param logStream - A log stream that can send raw log messages to the caller to be displayed outside of the backend. + * @param siteName - Name of the site to be used in mkdocs.yml for the required `site_name` property, default value is "Table of Contents" */ export type GeneratorRunOptions = { inputDir: string; @@ -61,7 +62,7 @@ export type GeneratorRunOptions = { etag?: string; logger: Logger; logStream?: Writable; - entity: Entity; + siteName?: string; }; /**