diff --git a/.changeset/techdocs-warm-walls-smile.md b/.changeset/techdocs-warm-walls-smile.md new file mode 100644 index 0000000000..ab7469ec65 --- /dev/null +++ b/.changeset/techdocs-warm-walls-smile.md @@ -0,0 +1,17 @@ +--- +'@backstage/techdocs-common': minor +--- + +Set the correct `edit_uri` or `repo_url` for documentation pages that are hosted on GitHub and GitLab. + +The constructor of the `TechDocsGenerator` changed. +Prefer the use of `TechdocsGenerator.fromConfig(…)` instead: + +```diff +- const techdocsGenerator = new TechdocsGenerator({ ++ const techdocsGenerator = TechdocsGenerator.fromConfig(config, { + logger, + containerRunner, +- config, + }); +``` diff --git a/packages/techdocs-common/api-report.md b/packages/techdocs-common/api-report.md index 0c7e5b03c7..32ada1ad29 100644 --- a/packages/techdocs-common/api-report.md +++ b/packages/techdocs-common/api-report.md @@ -230,10 +230,12 @@ export class TechdocsGenerator implements GeneratorBase { logger, containerRunner, config, + scmIntegrations, }: { logger: Logger_2; containerRunner: ContainerRunner; config: Config; + scmIntegrations: ScmIntegrationRegistry; }); // (undocumented) static fromConfig( @@ -245,7 +247,7 @@ export class TechdocsGenerator implements GeneratorBase { containerRunner: ContainerRunner; logger: Logger_2; }, - ): Promise; + ): TechdocsGenerator; // (undocumented) run({ inputDir, diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index f529d93ca6..b4c407cbd3 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -49,6 +49,7 @@ "aws-sdk": "^2.840.0", "express": "^4.17.1", "fs-extra": "9.1.0", + "git-url-parse": "~11.4.4", "js-yaml": "^4.0.0", "json5": "^2.1.3", "mime-types": "^2.1.27", diff --git a/packages/techdocs-common/src/stages/generate/__fixtures__/mkdocs_with_edit_uri.yml b/packages/techdocs-common/src/stages/generate/__fixtures__/mkdocs_with_edit_uri.yml new file mode 100644 index 0000000000..c7f402ec12 --- /dev/null +++ b/packages/techdocs-common/src/stages/generate/__fixtures__/mkdocs_with_edit_uri.yml @@ -0,0 +1,4 @@ +site_name: Test site name +site_description: Test site description + +edit_uri: https://github.com/backstage/backstage/edit/main/docs diff --git a/packages/techdocs-common/src/stages/generate/generators.test.ts b/packages/techdocs-common/src/stages/generate/generators.test.ts index a2ace2628c..56343763e9 100644 --- a/packages/techdocs-common/src/stages/generate/generators.test.ts +++ b/packages/techdocs-common/src/stages/generate/generators.test.ts @@ -44,10 +44,9 @@ describe('generators', () => { it('should return correct registered generator', async () => { const generators = new Generators(); - const techdocs = new TechdocsGenerator({ + const techdocs = TechdocsGenerator.fromConfig(new ConfigReader({}), { logger, containerRunner, - config: new ConfigReader({}), }); generators.register('techdocs', techdocs); diff --git a/packages/techdocs-common/src/stages/generate/generators.ts b/packages/techdocs-common/src/stages/generate/generators.ts index af7958dcfb..3d1ad2b73b 100644 --- a/packages/techdocs-common/src/stages/generate/generators.ts +++ b/packages/techdocs-common/src/stages/generate/generators.ts @@ -38,10 +38,9 @@ export class Generators implements GeneratorBuilder { ): Promise { const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator({ + const techdocsGenerator = TechdocsGenerator.fromConfig(config, { logger, containerRunner, - config, }); generators.register('techdocs', techdocsGenerator); diff --git a/packages/techdocs-common/src/stages/generate/helpers.test.ts b/packages/techdocs-common/src/stages/generate/helpers.test.ts index 4039d340f2..50bcc45343 100644 --- a/packages/techdocs-common/src/stages/generate/helpers.test.ts +++ b/packages/techdocs-common/src/stages/generate/helpers.test.ts @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; import fs from 'fs-extra'; import mockFs from 'mock-fs'; import os from 'os'; import path, { resolve as resolvePath } from 'path'; import { ParsedLocationAnnotation } from '../../helpers'; -import { RemoteProtocol } from '../prepare/types'; import { addBuildTimestampMetadata, getGeneratorKey, getMkdocsYml, getRepoUrlFromLocationAnnotation, - isValidRepoUrlForMkdocs, patchMkdocsYmlPreBuild, storeEtagMetadata, validateMkdocsYaml, @@ -48,6 +49,9 @@ const mkdocsYmlWithExtensions = fs.readFileSync( const mkdocsYmlWithRepoUrl = fs.readFileSync( resolvePath(__filename, '../__fixtures__/mkdocs_with_repo_url.yml'), ); +const mkdocsYmlWithEditUri = fs.readFileSync( + resolvePath(__filename, '../__fixtures__/mkdocs_with_edit_uri.yml'), +); const mkdocsYmlWithValidDocDir = fs.readFileSync( resolvePath(__filename, '../__fixtures__/mkdocs_valid_doc_dir.yml'), ); @@ -60,6 +64,8 @@ const mkdocsYmlWithInvalidDocDir2 = fs.readFileSync( const mockLogger = getVoidLogger(); const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir'; +const scmIntegrations = ScmIntegrations.fromConfig(new ConfigReader({})); + describe('helpers', () => { describe('getGeneratorKey', () => { it('should return techdocs as the only generator key', () => { @@ -68,120 +74,85 @@ describe('helpers', () => { }); }); - describe('isValidRepoUrlForMkdocs', () => { - it('should return true for valid repo_url values for mkdocs', () => { - const validRepoUrls = [ - 'https://github.com/org/repo', - 'https://github.com/backstage/backstage/', - 'https://github.com/org123/repo1-2-3/', - 'http://github.com/insecureOrg/insecureRepo', - 'https://gitlab.com/org/repo', - 'https://gitlab.com/backstage/backstage/', - 'https://gitlab.com/org123/repo1-2-3/', - 'http://gitlab.com/insecureOrg/insecureRepo', - ]; - - const validRemoteProtocols = ['github', 'gitlab']; - - validRepoUrls.forEach(url => { - validRemoteProtocols.forEach(targetType => { - expect( - isValidRepoUrlForMkdocs(url, targetType as RemoteProtocol), - ).toBe(true); - }); - }); - }); - - it('should return false for invalid repo_urls values for mkdocs', () => { - const invalidRepoUrls = [ - 'git@github.com:org/repo', - 'https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend', - ]; - - invalidRepoUrls.forEach(url => { - expect(isValidRepoUrlForMkdocs(url, 'github')).toBe(false); - }); - }); - - it('should return false for unsupported remote protocols', () => { - const validRepoUrl = 'https://github.com/backstage/backstage'; - - const unsupportedRemoteProtocols = ['dir', 'file', 'url']; - - unsupportedRemoteProtocols.forEach(targetType => { - expect( - isValidRepoUrlForMkdocs(validRepoUrl, targetType as RemoteProtocol), - ).toBe(false); - }); - }); - }); - describe('getRepoUrlFromLocationAnnotation', () => { - it('should return undefined for unsupported location type', () => { - const parsedLocationAnnotation1: ParsedLocationAnnotation = { + it.each` + url | repo_url | edit_uri + ${'https://github.com/backstage/backstage'} | ${'https://github.com/backstage/backstage'} | ${undefined} + ${'https://github.com/backstage/backstage/tree/main/examples/techdocs/'} | ${undefined} | ${'https://github.com/backstage/backstage/edit/main/examples/techdocs/docs'} + ${'https://github.com/backstage/backstage/tree/main/'} | ${undefined} | ${'https://github.com/backstage/backstage/edit/main/docs'} + ${'https://gitlab.com/backstage/backstage'} | ${'https://gitlab.com/backstage/backstage'} | ${undefined} + ${'https://gitlab.com/backstage/backstage/-/blob/main/examples/techdocs/'} | ${undefined} | ${'https://gitlab.com/backstage/backstage/-/edit/main/examples/techdocs/docs'} + ${'https://gitlab.com/backstage/backstage/-/blob/main/'} | ${undefined} | ${'https://gitlab.com/backstage/backstage/-/edit/main/docs'} + `('should convert $url', ({ url: target, repo_url, edit_uri }) => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { + type: 'url', + target, + }; + + expect( + getRepoUrlFromLocationAnnotation( + parsedLocationAnnotation, + scmIntegrations, + ), + ).toEqual({ repo_url, edit_uri }); + }); + + it.each` + url | edit_uri + ${'https://github.com/backstage/backstage/tree/main/examples/techdocs/'} | ${'https://github.com/backstage/backstage/edit/main/examples/techdocs/custom/folder'} + ${'https://github.com/backstage/backstage/tree/main/'} | ${'https://github.com/backstage/backstage/edit/main/custom/folder'} + ${'https://gitlab.com/backstage/backstage/-/blob/main/examples/techdocs/'} | ${'https://gitlab.com/backstage/backstage/-/edit/main/examples/techdocs/custom/folder'} + ${'https://gitlab.com/backstage/backstage/-/blob/main/'} | ${'https://gitlab.com/backstage/backstage/-/edit/main/custom/folder'} + `( + 'should convert $url with custom docsFolder', + ({ url: target, edit_uri }) => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { + type: 'url', + target, + }; + + expect( + getRepoUrlFromLocationAnnotation( + parsedLocationAnnotation, + scmIntegrations, + './custom/folder', + ), + ).toEqual({ edit_uri }); + }, + ); + + it.each` + url + ${'https://bitbucket.org/backstage/backstage/src/master/examples/techdocs/'} + ${'https://bitbucket.org/backstage/backstage/src/master/'} + ${'https://dev.azure.com/organization/project/_git/repository?path=%2Fexamples%2Ftechdocs'} + ${'https://dev.azure.com/organization/project/_git/repository?path=%2F'} + `('should ignore $url', ({ url: target }) => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { + type: 'url', + target, + }; + + expect( + getRepoUrlFromLocationAnnotation( + parsedLocationAnnotation, + scmIntegrations, + ), + ).toEqual({}); + }); + + it('should ignore unsupported location type', () => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { type: 'dir', target: '/home/user/workspace/docs-repository', }; - const parsedLocationAnnotation2: ParsedLocationAnnotation = { - type: 'file' as RemoteProtocol, - target: '/home/user/workspace/docs-repository/catalog-info.yaml', - }; - - const parsedLocationAnnotation3: ParsedLocationAnnotation = { - type: 'url', - target: 'https://my-website.com/storage/this/docs/repository', - }; - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation1)).toBe( - undefined, - ); - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation2)).toBe( - undefined, - ); - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation3)).toBe( - undefined, - ); - }); - - it('should return correct target url for supported hosts', () => { - const parsedLocationAnnotation1: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, - target: 'https://github.com/backstage/backstage.git', - }; - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation1)).toBe( - 'https://github.com/backstage/backstage', - ); - - const parsedLocationAnnotation2: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, - target: 'https://github.com/org/repo', - }; - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation2)).toBe( - 'https://github.com/org/repo', - ); - - const parsedLocationAnnotation3: ParsedLocationAnnotation = { - type: 'gitlab' as RemoteProtocol, - target: 'https://gitlab.com/org/repo', - }; - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation3)).toBe( - 'https://gitlab.com/org/repo', - ); - - const parsedLocationAnnotation4: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, - target: - 'github.com/backstage/backstage/blob/master/plugins/techdocs-backend/examples/documented-component', - }; - - expect(getRepoUrlFromLocationAnnotation(parsedLocationAnnotation4)).toBe( - 'github.com/backstage/backstage/blob/master/plugins/techdocs-backend/examples/documented-component', - ); + expect( + getRepoUrlFromLocationAnnotation( + parsedLocationAnnotation, + scmIntegrations, + ), + ).toEqual({}); }); }); @@ -190,6 +161,7 @@ describe('helpers', () => { mockFs({ '/mkdocs.yml': mkdocsYml, '/mkdocs_with_repo_url.yml': mkdocsYmlWithRepoUrl, + '/mkdocs_with_edit_uri.yml': mkdocsYmlWithEditUri, '/mkdocs_with_extensions.yml': mkdocsYmlWithExtensions, }); }); @@ -198,9 +170,9 @@ describe('helpers', () => { mockFs.restore(); }); - it('should add repo_url to mkdocs.yml', async () => { + it('should add edit_uri to mkdocs.yml', async () => { const parsedLocationAnnotation: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, + type: 'url', target: 'https://github.com/backstage/backstage', }; @@ -208,6 +180,7 @@ describe('helpers', () => { '/mkdocs.yml', mockLogger, parsedLocationAnnotation, + scmIntegrations, ); const updatedMkdocsYml = await fs.readFile('/mkdocs.yml'); @@ -219,7 +192,7 @@ describe('helpers', () => { it('should add repo_url to mkdocs.yml that contains custom yaml tags', async () => { const parsedLocationAnnotation: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, + type: 'url', target: 'https://github.com/backstage/backstage', }; @@ -227,6 +200,7 @@ describe('helpers', () => { '/mkdocs_with_extensions.yml', mockLogger, parsedLocationAnnotation, + scmIntegrations, ); const updatedMkdocsYml = await fs.readFile('/mkdocs_with_extensions.yml'); @@ -241,7 +215,7 @@ describe('helpers', () => { it('should not override existing repo_url in mkdocs.yml', async () => { const parsedLocationAnnotation: ParsedLocationAnnotation = { - type: 'github' as RemoteProtocol, + type: 'url', target: 'https://github.com/neworg/newrepo', }; @@ -249,6 +223,7 @@ describe('helpers', () => { '/mkdocs_with_repo_url.yml', mockLogger, parsedLocationAnnotation, + scmIntegrations, ); const updatedMkdocsYml = await fs.readFile('/mkdocs_with_repo_url.yml'); @@ -260,6 +235,29 @@ describe('helpers', () => { 'repo_url: https://github.com/neworg/newrepo', ); }); + + it('should not override existing edit_uri in mkdocs.yml', async () => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { + type: 'url', + target: 'https://github.com/neworg/newrepo', + }; + + await patchMkdocsYmlPreBuild( + '/mkdocs_with_edit_uri.yml', + mockLogger, + parsedLocationAnnotation, + scmIntegrations, + ); + + const updatedMkdocsYml = await fs.readFile('/mkdocs_with_edit_uri.yml'); + + expect(updatedMkdocsYml.toString()).toContain( + 'edit_uri: https://github.com/backstage/backstage/edit/main/docs', + ); + expect(updatedMkdocsYml.toString()).not.toContain( + 'https://github.com/neworg/newrepo', + ); + }); }); describe('addBuildTimestampMetadata', () => { diff --git a/packages/techdocs-common/src/stages/generate/helpers.ts b/packages/techdocs-common/src/stages/generate/helpers.ts index 7c60c7667f..aa4402323c 100644 --- a/packages/techdocs-common/src/stages/generate/helpers.ts +++ b/packages/techdocs-common/src/stages/generate/helpers.ts @@ -14,10 +14,12 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; import { isChildPath } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { spawn } from 'child_process'; import fs from 'fs-extra'; +import gitUrlParse from 'git-url-parse'; import yaml, { DEFAULT_SCHEMA, Type } from 'js-yaml'; import path, { resolve as resolvePath } from 'path'; import { PassThrough, Writable } from 'stream'; @@ -80,63 +82,42 @@ export const runCommand = async ({ }; /** - * Return true if mkdocs can compile docs with provided repo_url - * - * Valid repo_url examples in mkdocs.yml - * - https://github.com/backstage/backstage - * - https://gitlab.com/org/repo/ - * - http://github.com/backstage/backstage - * - A http(s) protocol URL to the root of the repository - * - * Invalid repo_url examples in mkdocs.yml - * - https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/examples/documented-component - * - (anything that is not valid as described above) - * - * @param {string} repoUrl URL supposed to be used as repo_url in mkdocs.yml - * @param {string} locationType Type of source code host - github, gitlab, dir, url, etc. - * @returns {boolean} - */ -export const isValidRepoUrlForMkdocs = ( - repoUrl: string, - locationType: string, -): boolean => { - // Trim trailing slash - const cleanRepoUrl = repoUrl.replace(/\/$/, ''); - - if (locationType === 'github' || locationType === 'gitlab') { - // A valid repoUrl to the root of the repository will be split into 5 strings if split using the / delimiter. - // We do not want URLs which have more than that number of forward slashes since they will signify a non-root location - // Note: This is not the best possible implementation but will work most of the times.. Feel free to improve or - // highlight edge cases. - return cleanRepoUrl.split('/').length === 5; - } - - return false; -}; - -/** - * Return a valid URL of the repository used in backstage.io/techdocs-ref annotation. - * Return undefined if the `target` is not valid in context of repo_url in mkdocs.yml - * Alter URL so that it is a valid repo_url config in mkdocs.yml + * Return the source url for MkDocs based on the backstage.io/techdocs-ref annotation. + * Depending on the type of target, it can either return a repo_url, an edit_uri, both, or none. * * @param {ParsedLocationAnnotation} parsedLocationAnnotation Object with location url and type - * @returns {string | undefined} + * @param {ScmIntegrationRegistry} scmIntegrations the scmIntegration to do url transformations + * @param {string} docsFolder the configured docs folder in the mkdocs.yml (defaults to 'docs') + * @returns the settings for the mkdocs.yml */ export const getRepoUrlFromLocationAnnotation = ( parsedLocationAnnotation: ParsedLocationAnnotation, -): string | undefined => { + scmIntegrations: ScmIntegrationRegistry, + docsFolder: string = 'docs', +): { repo_url?: string; edit_uri?: string } => { const { type: locationType, target } = parsedLocationAnnotation; - // Add more options from the RemoteProtocol type of parsedLocationAnnotation.type here - // when TechDocs supports more hosts and if mkdocs can generated an Edit URL for them. - const supportedHosts = ['github', 'gitlab']; + if (locationType === 'url') { + const integration = scmIntegrations.byUrl(target); - if (supportedHosts.includes(locationType)) { - // Trim .git or .git/ from the end of repository url - return target.replace(/.git\/*$/, ''); + // We only support it for github and gitlab for now as the edit_uri + // is not properly supported for others yet. + if (integration && ['github', 'gitlab'].includes(integration.type)) { + // handle the case where a user manually writes url:https://github.com/backstage/backstage i.e. without /blob/... + const { filepathtype } = gitUrlParse(target); + if (filepathtype === '') { + return { repo_url: target }; + } + + const sourceFolder = integration.resolveUrl({ + url: `./${docsFolder}`, + base: target, + }); + return { edit_uri: integration.resolveEditUrl(sourceFolder) }; + } } - return undefined; + return {}; }; class UnknownTag { @@ -217,7 +198,7 @@ export const validateMkdocsYaml = async ( * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site. * * List of tasks: - * - Add repo_url if it does not exists + * - Add repo_url or edit_uri if it does not exists * If mkdocs.yml has a repo_url, the generated docs site gets an Edit button on the pages by default. * If repo_url is missing in mkdocs.yml, we will use techdocs annotation of the entity to possibly get * the repository URL. @@ -228,11 +209,13 @@ export const validateMkdocsYaml = async ( * @param {string} mkdocsYmlPath Absolute path to mkdocs.yml or equivalent of a docs site * @param {Logger} logger * @param {ParsedLocationAnnotation} parsedLocationAnnotation Object with location url and type + * @param {ScmIntegrationRegistry} scmIntegrations the scmIntegration to do url transformations */ export const patchMkdocsYmlPreBuild = async ( mkdocsYmlPath: string, logger: Logger, parsedLocationAnnotation: ParsedLocationAnnotation, + scmIntegrations: ScmIntegrationRegistry, ) => { let mkdocsYmlFileString; try { @@ -260,16 +243,25 @@ export const patchMkdocsYmlPreBuild = async ( return; } - // Add repo_url to mkdocs.yml if it is missing. This will enable the Page edit button generated by MkDocs. - if (!('repo_url' in mkdocsYml)) { - const repoUrl = getRepoUrlFromLocationAnnotation(parsedLocationAnnotation); - if (repoUrl !== undefined) { - // mkdocs.yml will not build with invalid repo_url. So, make sure it is valid. - // TODO: this is no longer working/meaningful because annotation type is - // now only ever "url" or "dir." Should be re-implemented! - if (isValidRepoUrlForMkdocs(repoUrl, parsedLocationAnnotation.type)) { - mkdocsYml.repo_url = repoUrl; - } + // Add edit_uri and/or repo_url to mkdocs.yml if it is missing. + // This will enable the Page edit button generated by MkDocs. + // If the either has been set, keep the original value + if (!('repo_url' in mkdocsYml) && !('edit_uri' in mkdocsYml)) { + const result = getRepoUrlFromLocationAnnotation( + parsedLocationAnnotation, + scmIntegrations, + mkdocsYml.docs_dir, + ); + + if (result.repo_url || result.edit_uri) { + mkdocsYml.repo_url = result.repo_url; + mkdocsYml.edit_uri = result.edit_uri; + + logger.info( + `Set ${JSON.stringify( + result, + )}. You can disable this feature by manually setting 'repo_url' or 'edit_uri' according to the MkDocs documentation at https://www.mkdocs.org/user-guide/configuration/#repo_url`, + ); } } diff --git a/packages/techdocs-common/src/stages/generate/techdocs.ts b/packages/techdocs-common/src/stages/generate/techdocs.ts index 1a6577cad9..c3d48507ce 100644 --- a/packages/techdocs-common/src/stages/generate/techdocs.ts +++ b/packages/techdocs-common/src/stages/generate/techdocs.ts @@ -18,6 +18,10 @@ import { ContainerRunner } from '@backstage/backend-common'; import { Config } from '@backstage/config'; import path from 'path'; import { Logger } from 'winston'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; import { addBuildTimestampMetadata, getMkdocsYml, @@ -39,29 +43,39 @@ export class TechdocsGenerator implements GeneratorBase { private readonly logger: Logger; private readonly containerRunner: ContainerRunner; private readonly options: GeneratorConfig; + private readonly scmIntegrations: ScmIntegrationRegistry; - static async fromConfig( + static fromConfig( config: Config, { containerRunner, logger, }: { containerRunner: ContainerRunner; logger: Logger }, ) { - return new TechdocsGenerator({ logger, containerRunner, config }); + const scmIntegrations = ScmIntegrations.fromConfig(config); + return new TechdocsGenerator({ + logger, + containerRunner, + config, + scmIntegrations, + }); } constructor({ logger, containerRunner, config, + scmIntegrations, }: { logger: Logger; containerRunner: ContainerRunner; config: Config; + scmIntegrations: ScmIntegrationRegistry; }) { this.logger = logger; this.options = readGeneratorConfig(config, logger); this.containerRunner = containerRunner; + this.scmIntegrations = scmIntegrations; } public async run({ @@ -74,16 +88,19 @@ export class TechdocsGenerator implements GeneratorBase { }: GeneratorRunOptions): Promise { // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url const { path: mkdocsYmlPath, content } = await getMkdocsYml(inputDir); + + // validate the docs_dir first + await validateMkdocsYaml(inputDir, content); + if (parsedLocationAnnotation) { await patchMkdocsYmlPreBuild( mkdocsYmlPath, childLogger, parsedLocationAnnotation, + this.scmIntegrations, ); } - await validateMkdocsYaml(inputDir, content); - // Directories to bind on container const mountDirs = { [inputDir]: '/input', diff --git a/plugins/techdocs-backend/src/service/standaloneServer.ts b/plugins/techdocs-backend/src/service/standaloneServer.ts index 57298d8852..e8981963f1 100644 --- a/plugins/techdocs-backend/src/service/standaloneServer.ts +++ b/plugins/techdocs-backend/src/service/standaloneServer.ts @@ -70,10 +70,9 @@ export async function startStandaloneServer( const containerRunner = new DockerContainerRunner({ dockerClient }); const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator({ + const techdocsGenerator = TechdocsGenerator.fromConfig(config, { logger, containerRunner, - config, }); generators.register('techdocs', techdocsGenerator);