Large refactor
Signed-off-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com>
This commit is contained in:
committed by
Renan Mendes Carvalho
parent
339d9a5b5c
commit
15b6eaf533
@@ -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
|
||||
|
||||
@@ -33,6 +33,7 @@ Options:
|
||||
--no-docker
|
||||
--techdocs-ref <HOST_TYPE:URL>
|
||||
--etag <ETAG>
|
||||
--site-name
|
||||
-v --verbose
|
||||
--omitTechdocsCoreMkdocsPlugin
|
||||
--legacyCopyReadmeMdToIndexMd
|
||||
@@ -98,6 +99,7 @@ Options:
|
||||
--docker-entrypoint <DOCKER_ENTRYPOINT>
|
||||
--docker-option <DOCKER_OPTION...>
|
||||
--no-docker
|
||||
--site-name
|
||||
--mkdocs-port <PORT>
|
||||
-v --verbose
|
||||
--preview-app-bundle-path <PATH_TO_BUNDLE>
|
||||
@@ -115,6 +117,7 @@ Options:
|
||||
--docker-entrypoint <DOCKER_ENTRYPOINT>
|
||||
--docker-option <DOCKER_OPTION...>
|
||||
--no-docker
|
||||
--site-name
|
||||
-p, --port <PORT>
|
||||
-v --verbose
|
||||
-h, --help
|
||||
|
||||
@@ -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!');
|
||||
|
||||
@@ -54,6 +54,11 @@ export function registerCommands(program: Command) {
|
||||
'--etag <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>', '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>', 'Port for MkDocs server to use', '8000')
|
||||
.option('-v --verbose', 'Enable verbose output.', false)
|
||||
.option(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
site_name: Test site name
|
||||
docs_dir: docs
|
||||
plugins:
|
||||
- techdocs-core
|
||||
- techdocs-core
|
||||
|
||||
@@ -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/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
export { TechdocsGenerator } from './techdocs';
|
||||
export { Generators } from './generators';
|
||||
export { getMkdocsYml } from './helpers';
|
||||
export type {
|
||||
GeneratorBase,
|
||||
GeneratorOptions,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user