diff --git a/.changeset/perfect-pears-care.md b/.changeset/perfect-pears-care.md new file mode 100644 index 0000000000..13db9ad0c1 --- /dev/null +++ b/.changeset/perfect-pears-care.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs-node': patch +--- + +Added support for using a default `mkdocs.yml` configuration file when none is provided diff --git a/plugins/techdocs-backend/src/DocsBuilder/builder.ts b/plugins/techdocs-backend/src/DocsBuilder/builder.ts index 09eee1fc12..2ae1462ad9 100644 --- a/plugins/techdocs-backend/src/DocsBuilder/builder.ts +++ b/plugins/techdocs-backend/src/DocsBuilder/builder.ts @@ -186,6 +186,7 @@ export class DocsBuilder { etag: newEtag, logger: this.logger, logStream: this.logStream, + entity: this.entity, }); // 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 e27b406478..253f1c29fa 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -54,6 +54,7 @@ export type GeneratorRunOptions = { etag?: string; logger: Logger; logStream?: Writable; + entity: Entity; }; // @public diff --git a/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml b/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml new file mode 100644 index 0000000000..f6d2b01ce4 --- /dev/null +++ b/plugins/techdocs-node/src/stages/generate/__fixtures__/mkdocs_default.yml @@ -0,0 +1,4 @@ +site_name: Test site name +docs_dir: docs +plugins: + - techdocs-core \ No newline at end of file diff --git a/plugins/techdocs-node/src/stages/generate/helpers.test.ts b/plugins/techdocs-node/src/stages/generate/helpers.test.ts index e894b0602e..fb21643e46 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.test.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.test.ts @@ -42,12 +42,16 @@ const mockEntity = { kind: 'TestKind', metadata: { name: 'testName', + title: 'Test site name', }, }; const mkdocsYml = fs.readFileSync( resolvePath(__filename, '../__fixtures__/mkdocs.yml'), ); +const mkdocsDefaultYml = fs.readFileSync( + resolvePath(__filename, '../__fixtures__/mkdocs_default.yml'), +); const mkdocsYmlWithExtensions = fs.readFileSync( resolvePath(__filename, '../__fixtures__/mkdocs_with_extensions.yml'), ); @@ -518,7 +522,10 @@ describe('helpers', () => { it('returns expected contents when .yml file is present', async () => { const key = path.join(inputDir, 'mkdocs.yml'); mockFs({ [key]: mkdocsYml }); - const { path: mkdocsPath, content } = await getMkdocsYml(inputDir); + const { path: mkdocsPath, content } = await getMkdocsYml( + inputDir, + mockEntity, + ); expect(mkdocsPath).toBe(key); expect(content).toBe(mkdocsYml.toString()); @@ -527,15 +534,29 @@ describe('helpers', () => { it('returns expected contents when .yaml file is present', async () => { const key = path.join(inputDir, 'mkdocs.yaml'); mockFs({ [key]: mkdocsYml }); - const { path: mkdocsPath, content } = await getMkdocsYml(inputDir); + const { path: mkdocsPath, content } = await getMkdocsYml( + inputDir, + mockEntity, + ); expect(mkdocsPath).toBe(key); expect(content).toBe(mkdocsYml.toString()); }); - it('throws when neither .yml nor .yaml file is present', async () => { + it('returns expected contents when default file is present', async () => { + const key = path.join(inputDir, 'mkdocs.yml'); + mockFs({ [key]: mkdocsDefaultYml }); + const { path: mkdocsPath, content } = await getMkdocsYml( + inputDir, + mockEntity, + ); + expect(mkdocsPath).toBe(key); + expect(content).toBe(mkdocsDefaultYml.toString()); + }); + + it('throws when neither .yml nor .yaml nor default file is present', async () => { const invalidInputDir = resolvePath(__filename); - await expect(getMkdocsYml(invalidInputDir)).rejects.toThrow( - /Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml for validation/, + await expect(getMkdocsYml(invalidInputDir, mockEntity)).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 50db0eb86a..ebb72c420c 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.ts @@ -159,22 +159,43 @@ export const MKDOCS_SCHEMA = DEFAULT_SCHEMA.extend([ */ export const getMkdocsYml = async ( inputDir: string, + entity: Entity, ): Promise<{ path: string; content: string }> => { let mkdocsYmlPath: string; let mkdocsYmlFileString: string; try { mkdocsYmlPath = path.join(inputDir, 'mkdocs.yaml'); - mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8'); - } catch { - try { - mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml'); + if (await fs.pathExists(mkdocsYmlPath)) { mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8'); - } catch (error) { - throw new ForwardedError( - 'Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml for validation', - error, - ); + return { + path: mkdocsYmlPath, + content: mkdocsYmlFileString, + }; } + + mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml'); + if (await fs.pathExists(mkdocsYmlPath)) { + mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8'); + return { + path: mkdocsYmlPath, + content: mkdocsYmlFileString, + }; + } + + // 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); + mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8'); + } catch (error) { + throw new ForwardedError( + 'Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml or default for validation', + error, + ); } return { diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index 9bbc58ebdc..45b2f9689e 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -96,10 +96,14 @@ export class TechdocsGenerator implements GeneratorBase { etag, logger: childLogger, logStream, + entity, } = options; // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url - const { path: mkdocsYmlPath, content } = await getMkdocsYml(inputDir); + const { path: mkdocsYmlPath, content } = await getMkdocsYml( + inputDir, + entity, + ); // validate the docs_dir first const docsDir = await validateMkdocsYaml(inputDir, content); diff --git a/plugins/techdocs-node/src/stages/generate/types.ts b/plugins/techdocs-node/src/stages/generate/types.ts index 2b2bbb21c9..26c26f4410 100644 --- a/plugins/techdocs-node/src/stages/generate/types.ts +++ b/plugins/techdocs-node/src/stages/generate/types.ts @@ -61,6 +61,7 @@ export type GeneratorRunOptions = { etag?: string; logger: Logger; logStream?: Writable; + entity: Entity; }; /**