add --mkdocs-config-file-name cli argument to the techdocs-cli serve command
Signed-off-by: Morgan Bentell <mbentell@spotify.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@techdocs/cli': minor
|
||||
'@backstage/plugin-techdocs-node': minor
|
||||
---
|
||||
|
||||
Add possibility to use a mkdocs config file with a different name than `mkdocs.<yaml|yml> with the serve command using the `--mkdocs-config-file-name` argument
|
||||
@@ -285,6 +285,10 @@ export function registerCommands(program: Command) {
|
||||
'Port for the preview app to be served on',
|
||||
defaultPreviewAppPort,
|
||||
)
|
||||
.option(
|
||||
'-c, --mkdocs-config-file-name <FILENAME>',
|
||||
'Mkdocs config file name',
|
||||
)
|
||||
.hook('preAction', command => {
|
||||
if (
|
||||
command.opts().previewAppPort !== defaultPreviewAppPort &&
|
||||
|
||||
@@ -65,11 +65,13 @@ export default async function serve(opts: OptionValues) {
|
||||
const mkdocsExpectedDevAddr = opts.docker
|
||||
? mkdocsDockerAddr
|
||||
: mkdocsLocalAddr;
|
||||
const mkdocsConfigFileName = opts.mkdocsConfigFileName;
|
||||
const siteName = opts.siteName;
|
||||
|
||||
const { path: mkdocsYmlPath, configIsTemporary } = await getMkdocsYml(
|
||||
'./',
|
||||
opts.siteName,
|
||||
);
|
||||
const { path: mkdocsYmlPath, configIsTemporary } = await getMkdocsYml('./', {
|
||||
name: siteName,
|
||||
mkdocsConfigFileName,
|
||||
});
|
||||
|
||||
let mkdocsServerHasStarted = false;
|
||||
const mkdocsLogFunc: LogFunc = data => {
|
||||
@@ -104,6 +106,7 @@ export default async function serve(opts: OptionValues) {
|
||||
useDocker: opts.docker,
|
||||
stdoutLogFunc: mkdocsLogFunc,
|
||||
stderrLogFunc: mkdocsLogFunc,
|
||||
mkdocsConfigFileName: mkdocsYmlPath,
|
||||
});
|
||||
|
||||
// Wait until mkdocs server has started so that Backstage starts with docs loaded
|
||||
|
||||
@@ -25,6 +25,7 @@ export const runMkdocsServer = async (options: {
|
||||
dockerOptions?: string[];
|
||||
stdoutLogFunc?: LogFunc;
|
||||
stderrLogFunc?: LogFunc;
|
||||
mkdocsConfigFileName?: string;
|
||||
}): Promise<ChildProcess> => {
|
||||
const port = options.port ?? '8000';
|
||||
const useDocker = options.useDocker ?? true;
|
||||
@@ -51,6 +52,9 @@ export const runMkdocsServer = async (options: {
|
||||
'serve',
|
||||
'--dev-addr',
|
||||
`0.0.0.0:${port}`,
|
||||
...(options.mkdocsConfigFileName
|
||||
? ['--config-file', options.mkdocsConfigFileName]
|
||||
: []),
|
||||
],
|
||||
{
|
||||
stdoutLogFunc: options.stdoutLogFunc,
|
||||
@@ -59,8 +63,19 @@ export const runMkdocsServer = async (options: {
|
||||
);
|
||||
}
|
||||
|
||||
return await run('mkdocs', ['serve', '--dev-addr', `127.0.0.1:${port}`], {
|
||||
stdoutLogFunc: options.stdoutLogFunc,
|
||||
stderrLogFunc: options.stderrLogFunc,
|
||||
});
|
||||
return await run(
|
||||
'mkdocs',
|
||||
[
|
||||
'serve',
|
||||
'--dev-addr',
|
||||
`127.0.0.1:${port}`,
|
||||
...(options.mkdocsConfigFileName
|
||||
? ['--config-file', options.mkdocsConfigFileName]
|
||||
: []),
|
||||
],
|
||||
{
|
||||
stdoutLogFunc: options.stdoutLogFunc,
|
||||
stderrLogFunc: options.stderrLogFunc,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -540,7 +540,7 @@ describe('helpers', () => {
|
||||
});
|
||||
|
||||
describe('getMkdocsYml', () => {
|
||||
const siteOptions = {
|
||||
const defaultOptions = {
|
||||
name: mockEntity.metadata.title,
|
||||
};
|
||||
|
||||
@@ -550,7 +550,7 @@ describe('helpers', () => {
|
||||
path: mkdocsPath,
|
||||
content,
|
||||
configIsTemporary,
|
||||
} = await getMkdocsYml(mockDir.path, siteOptions);
|
||||
} = await getMkdocsYml(mockDir.path, defaultOptions);
|
||||
|
||||
expect(mkdocsPath).toBe(mockDir.resolve('mkdocs.yml'));
|
||||
expect(content).toBe(mkdocsYml.toString());
|
||||
@@ -563,14 +563,14 @@ describe('helpers', () => {
|
||||
path: mkdocsPath,
|
||||
content,
|
||||
configIsTemporary,
|
||||
} = await getMkdocsYml(mockDir.path, siteOptions);
|
||||
} = await getMkdocsYml(mockDir.path, defaultOptions);
|
||||
expect(mkdocsPath).toBe(mockDir.resolve('mkdocs.yaml'));
|
||||
expect(content).toBe(mkdocsYml.toString());
|
||||
expect(configIsTemporary).toBe(false);
|
||||
});
|
||||
|
||||
it('returns expected contents when default file is present', async () => {
|
||||
const defaultSiteOptions = {
|
||||
const options = {
|
||||
name: 'Default Test site name',
|
||||
};
|
||||
const mockPathExists = jest.spyOn(fs, 'pathExists');
|
||||
@@ -580,21 +580,49 @@ describe('helpers', () => {
|
||||
path: mkdocsPath,
|
||||
content,
|
||||
configIsTemporary,
|
||||
} = await getMkdocsYml(mockDir.path, defaultSiteOptions);
|
||||
} = await getMkdocsYml(mockDir.path, options);
|
||||
|
||||
expect(mkdocsPath).toBe(mockDir.resolve('mkdocs.yml'));
|
||||
expect(content.split(/[\r\n]+/g)).toEqual(
|
||||
mkdocsDefaultYml.toString().split(/[\r\n]+/g),
|
||||
);
|
||||
expect(configIsTemporary).toBe(true);
|
||||
mockPathExists.mockRestore();
|
||||
});
|
||||
|
||||
it('throws when neither .yml nor .yaml nor default file is present', async () => {
|
||||
const invalidInputDir = resolvePath(__filename);
|
||||
await expect(getMkdocsYml(invalidInputDir, siteOptions)).rejects.toThrow(
|
||||
await expect(
|
||||
getMkdocsYml(invalidInputDir, defaultOptions),
|
||||
).rejects.toThrow(
|
||||
/Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml or default for validation/,
|
||||
);
|
||||
});
|
||||
|
||||
it('returns expected content when custom file is specified', async () => {
|
||||
const options = { mkdocsConfigFileName: 'another-name.yaml' };
|
||||
mockDIr.setContent({'mkdocs.yml': mkdocsYml})
|
||||
|
||||
const {
|
||||
path: mkdocsPath,
|
||||
content,
|
||||
configIsTemporary,
|
||||
} = await getMkdocsYml(inputDir, options);
|
||||
|
||||
expect(mkdocsPath).toBe(key);
|
||||
expect(content).toBe(mkdocsYml.toString());
|
||||
expect(configIsTemporary).toBe(false);
|
||||
});
|
||||
|
||||
it('throws when specifying a specific mkdocs config file that does not exist', async () => {
|
||||
const options = { mkdocsConfigFileName: 'another-name.yaml' };
|
||||
mockDir.setContent({ 'mkdocs.yml': mkdocsDefaultYml });
|
||||
|
||||
|
||||
await expect(getMkdocsYml(inputDir, options)).rejects.toThrow(
|
||||
/The specified file .* does not exist/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateMkdocsYaml', () => {
|
||||
|
||||
@@ -185,21 +185,38 @@ export const generateMkdocsYml = async (
|
||||
};
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* Finds and loads the contents of an mkdocs.yml, mkdocs.yaml file, a file
|
||||
* with a specified name or an ad-hoc created file with minimal config.
|
||||
* @public
|
||||
*
|
||||
* @param inputDir - base dir to be searched for either an mkdocs.yml or mkdocs.yaml file.
|
||||
* @param siteOptions - options for the site: `name` property will be used in mkdocs.yml for the
|
||||
* required `site_name` property, default value is "Documentation Site"
|
||||
* @param options - ```
|
||||
* {
|
||||
* name: default mkdocs site_name to be used with a ad hoc file default value is "Documentation Site"
|
||||
* mkdocsConfigFileName (optional): a non-default file name to be used as the config
|
||||
* }```
|
||||
*/
|
||||
export const getMkdocsYml = async (
|
||||
inputDir: string,
|
||||
siteOptions?: { name?: string },
|
||||
options?: { name?: string; mkdocsConfigFileName?: string },
|
||||
): Promise<{ path: string; content: string; configIsTemporary: boolean }> => {
|
||||
let mkdocsYmlPath: string;
|
||||
let mkdocsYmlFileString: string;
|
||||
try {
|
||||
if (options?.mkdocsConfigFileName) {
|
||||
mkdocsYmlPath = path.join(inputDir, options.mkdocsConfigFileName);
|
||||
if (!(await fs.pathExists(mkdocsYmlPath))) {
|
||||
throw new Error(`The specified file ${mkdocsYmlPath} does not exist`);
|
||||
}
|
||||
|
||||
mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');
|
||||
return {
|
||||
path: mkdocsYmlPath,
|
||||
content: mkdocsYmlFileString,
|
||||
configIsTemporary: false,
|
||||
};
|
||||
}
|
||||
|
||||
mkdocsYmlPath = path.join(inputDir, 'mkdocs.yaml');
|
||||
if (await fs.pathExists(mkdocsYmlPath)) {
|
||||
mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');
|
||||
@@ -221,7 +238,7 @@ export const getMkdocsYml = async (
|
||||
}
|
||||
|
||||
// No mkdocs file, generate it
|
||||
await generateMkdocsYml(inputDir, siteOptions);
|
||||
await generateMkdocsYml(inputDir, options);
|
||||
mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');
|
||||
} catch (error) {
|
||||
throw new ForwardedError(
|
||||
|
||||
Reference in New Issue
Block a user