feat(techdocs): add app-config option to disable external font download
Signed-off-by: Karthik <karthik.jk11@gmail.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-backend': minor
|
||||
'@backstage/plugin-techdocs-node': minor
|
||||
---
|
||||
|
||||
Add support for disabling external font downloads via app-config option `techdocs.generator.mkdocs.disableExternalFonts`, useful for air-gapped Backstage instances.
|
||||
@@ -551,7 +551,31 @@ Done! You now have support for TechDocs in your own software template!
|
||||
|
||||
### Prevent download of Google fonts
|
||||
|
||||
If your Backstage instance does not have internet access, the generation will fail. TechDocs tries to download the Roboto font from Google. You can disable it by adding the following lines to mkdocs.yaml:
|
||||
If your Backstage instance does not have internet access, the generation will fail. TechDocs tries to download the Roboto font from Google. You can disable it by configuring your `app-config.yaml` or by manually updating your `mkdocs.yml` file.
|
||||
|
||||
#### Using app-config
|
||||
|
||||
Add the following configuration to your `app-config.yaml` to automatically
|
||||
disable external font downloads for all TechDocs sites:
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
generator:
|
||||
mkdocs:
|
||||
disableExternalFonts: true
|
||||
```
|
||||
|
||||
This configuration will automatically patch the `mkdocs.yml` file during the
|
||||
generation process. If no `theme` section exists, it will create one with `name:
|
||||
material` and `font: false`. If a `theme` section exists but `font` is not
|
||||
configured, it will add `font: false` to the existing theme. If `font` is
|
||||
already explicitly configured in your `mkdocs.yml`, the patcher will respect
|
||||
your file-level configuration and not override it.
|
||||
|
||||
#### Manual configuration in mkdocs.yml
|
||||
|
||||
Alternatively, you can manually add the following configuration to your `mkdocs.yaml`
|
||||
file:
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
@@ -561,7 +585,11 @@ theme:
|
||||
|
||||
:::note Note
|
||||
|
||||
The addition `name: material` is necessary. Otherwise it will not work
|
||||
The addition `name: material` is necessary. Otherwise it will not work.
|
||||
|
||||
If you explicitly set `font: true` or `font: false` in your `mkdocs.yml`, the
|
||||
app-config patcher will respect that setting and not override it. The patcher
|
||||
only adds `font: false` when the `font` property is not already configured.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
Vendored
+8
@@ -76,6 +76,14 @@ export interface Config {
|
||||
* @see https://www.mkdocs.org/user-guide/configuration/#hooks
|
||||
*/
|
||||
dangerouslyAllowAdditionalKeys?: string[];
|
||||
|
||||
/**
|
||||
* Disable external fonts for all TechDocs sites.
|
||||
* If not set, the default value is false.
|
||||
* If set to true, the external font will be disabled for all TechDocs sites.
|
||||
* If set to false, the external font will be enabled for all TechDocs sites.
|
||||
*/
|
||||
disableExternalFonts?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
patchMkdocsYmlPreBuild,
|
||||
patchMkdocsYmlWithPlugins,
|
||||
sanitizeMkdocsYml,
|
||||
patchMkdocsYmlWithFontDisabled
|
||||
} from './mkdocsPatchers';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
@@ -468,6 +469,101 @@ describe('helpers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('patchMkdocsYmlWithFontDisabled', () => {
|
||||
beforeEach(() => {
|
||||
mockDir.setContent({
|
||||
'mkdocs_without_theme.yml': `site_name: Test Site
|
||||
docs_dir: docs
|
||||
`,
|
||||
'mkdocs_with_theme_no_font.yml': `site_name: Test Site
|
||||
docs_dir: docs
|
||||
theme:
|
||||
name: material
|
||||
`,
|
||||
'mkdocs_with_theme_font_true.yml': `site_name: Test Site
|
||||
docs_dir: docs
|
||||
theme:
|
||||
name: material
|
||||
font: true
|
||||
`,
|
||||
'mkdocs_with_theme_font_false.yml': `site_name: Test Site
|
||||
docs_dir: docs
|
||||
theme:
|
||||
name: material
|
||||
font: false
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create theme section with font disabled when no theme exists', async () => {
|
||||
await patchMkdocsYmlWithFontDisabled(
|
||||
mockDir.resolve('mkdocs_without_theme.yml'),
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const updatedMkdocsYml = await fs.readFile(
|
||||
mockDir.resolve('mkdocs_without_theme.yml'),
|
||||
);
|
||||
const parsedYml = yaml.load(updatedMkdocsYml.toString()) as {
|
||||
theme?: { name?: string; font?: boolean };
|
||||
};
|
||||
expect(parsedYml.theme).toBeDefined();
|
||||
expect(parsedYml.theme?.name).toBe('material');
|
||||
expect(parsedYml.theme?.font).toBe(false);
|
||||
});
|
||||
|
||||
it('should add font: false when theme exists but font is not configured', async () => {
|
||||
await patchMkdocsYmlWithFontDisabled(
|
||||
mockDir.resolve('mkdocs_with_theme_no_font.yml'),
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const updatedMkdocsYml = await fs.readFile(
|
||||
mockDir.resolve('mkdocs_with_theme_no_font.yml'),
|
||||
);
|
||||
const parsedYml = yaml.load(updatedMkdocsYml.toString()) as {
|
||||
theme?: { name?: string; font?: boolean };
|
||||
};
|
||||
expect(parsedYml.theme).toBeDefined();
|
||||
expect(parsedYml.theme?.name).toBe('material');
|
||||
expect(parsedYml.theme?.font).toBe(false);
|
||||
});
|
||||
|
||||
it('should not override font when font is already set to true', async () => {
|
||||
await patchMkdocsYmlWithFontDisabled(
|
||||
mockDir.resolve('mkdocs_with_theme_font_true.yml'),
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const updatedMkdocsYml = await fs.readFile(
|
||||
mockDir.resolve('mkdocs_with_theme_font_true.yml'),
|
||||
);
|
||||
const parsedYml = yaml.load(updatedMkdocsYml.toString()) as {
|
||||
theme?: { name?: string; font?: boolean };
|
||||
};
|
||||
expect(parsedYml.theme).toBeDefined();
|
||||
expect(parsedYml.theme?.name).toBe('material');
|
||||
expect(parsedYml.theme?.font).toBe(true);
|
||||
});
|
||||
|
||||
it('should not override font when font is already set to false', async () => {
|
||||
await patchMkdocsYmlWithFontDisabled(
|
||||
mockDir.resolve('mkdocs_with_theme_font_false.yml'),
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const updatedMkdocsYml = await fs.readFile(
|
||||
mockDir.resolve('mkdocs_with_theme_font_false.yml'),
|
||||
);
|
||||
const parsedYml = yaml.load(updatedMkdocsYml.toString()) as {
|
||||
theme?: { name?: string; font?: boolean };
|
||||
};
|
||||
expect(parsedYml.theme).toBeDefined();
|
||||
expect(parsedYml.theme?.name).toBe('material');
|
||||
expect(parsedYml.theme?.font).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('patchIndexPreBuild', () => {
|
||||
afterEach(() => {
|
||||
warn.mockClear();
|
||||
|
||||
@@ -25,11 +25,17 @@ import { assertError } from '@backstage/errors';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
const MATERIAL_THEME = 'material';
|
||||
|
||||
type MkDocsObject = {
|
||||
plugins?: string[];
|
||||
docs_dir: string;
|
||||
repo_url?: string;
|
||||
edit_uri?: string;
|
||||
theme?: {
|
||||
name?: string;
|
||||
font?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const patchMkdocsFile = async (
|
||||
@@ -185,6 +191,39 @@ export const patchMkdocsYmlWithPlugins = async (
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable external font download for the material theme.
|
||||
* @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site
|
||||
* @param logger
|
||||
*/
|
||||
export const patchMkdocsYmlWithFontDisabled = async (
|
||||
mkdocsYmlPath: string,
|
||||
logger: LoggerService,
|
||||
) => {
|
||||
await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {
|
||||
if (!('theme' in mkdocsYml)) {
|
||||
// No theme section exists, create it with font disabled
|
||||
mkdocsYml.theme = {
|
||||
name: MATERIAL_THEME,
|
||||
font: false,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
// Theme section exists, check if font is not configured, add font: false
|
||||
if (
|
||||
mkdocsYml.theme &&
|
||||
typeof mkdocsYml.theme === 'object' &&
|
||||
!('font' in mkdocsYml.theme)
|
||||
) {
|
||||
mkdocsYml.theme.font = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitize mkdocs.yml by keeping only allowed configuration keys.
|
||||
*
|
||||
@@ -249,3 +288,4 @@ export const sanitizeMkdocsYml = async (
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
|
||||
import {
|
||||
patchMkdocsYmlPreBuild,
|
||||
patchMkdocsYmlWithFontDisabled,
|
||||
patchMkdocsYmlWithPlugins,
|
||||
sanitizeMkdocsYml,
|
||||
} from './mkdocsPatchers';
|
||||
@@ -150,6 +151,9 @@ export class TechdocsGenerator implements GeneratorBase {
|
||||
}
|
||||
|
||||
await patchMkdocsYmlWithPlugins(mkdocsYmlPath, childLogger, defaultPlugins);
|
||||
if (this.options.disableExternalFonts) {
|
||||
await patchMkdocsYmlWithFontDisabled(mkdocsYmlPath, childLogger);
|
||||
}
|
||||
|
||||
// Directories to bind on container
|
||||
const mountDirs = {
|
||||
@@ -264,5 +268,8 @@ export function readGeneratorConfig(
|
||||
dangerouslyAllowAdditionalKeys: config.getOptionalStringArray(
|
||||
'techdocs.generator.mkdocs.dangerouslyAllowAdditionalKeys',
|
||||
),
|
||||
disableExternalFonts: config.getOptionalBoolean(
|
||||
'techdocs.generator.mkdocs.disableExternalFonts'
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ export type GeneratorConfig = {
|
||||
legacyCopyReadmeMdToIndexMd?: boolean;
|
||||
defaultPlugins?: string[];
|
||||
dangerouslyAllowAdditionalKeys?: string[];
|
||||
disableExternalFonts?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user