@backstage/plugin-techdocs-node 1.12.10 → 1.12.11-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/stages/publish/helpers.ts","../src/stages/generate/helpers.ts","../src/stages/generate/mkdocsPatchers.ts","../src/stages/generate/DockerContainerRunner.ts","../src/stages/generate/techdocs.ts","../src/stages/generate/generators.ts","../src/stages/generate/index.ts","../src/helpers.ts","../src/stages/prepare/dir.ts","../src/stages/prepare/url.ts","../src/stages/prepare/preparers.ts","../src/stages/publish/awsS3.ts","../src/stages/publish/azureBlobStorage.ts","../src/stages/publish/migrations/GoogleMigration.ts","../src/stages/publish/googleStorage.ts","../src/stages/publish/local.ts","../src/stages/publish/openStackSwift.ts","../src/stages/publish/publish.ts","../src/extensions.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport mime from 'mime-types';\nimport path from 'path';\nimport createLimiter from 'p-limit';\nimport recursiveReadDir from 'recursive-readdir';\n\n/**\n * Helper to get the expected content-type for a given file extension. Also\n * takes XSS mitigation into account.\n */\nconst getContentTypeForExtension = (ext: string): string => {\n const defaultContentType = 'text/plain; charset=utf-8';\n\n // Prevent sanitization bypass by preventing browsers from directly rendering\n // the contents of untrusted files.\n if (ext.match(/htm|xml|svg/i)) {\n return defaultContentType;\n }\n\n return mime.contentType(ext) || defaultContentType;\n};\n\nexport type responseHeadersType = {\n 'Content-Type': string;\n};\n\n/**\n * Some files need special headers to be used correctly by the frontend. This function\n * generates headers in the response to those file requests.\n * @param fileExtension - .html, .css, .js, .png etc.\n */\nexport const getHeadersForFileExtension = (\n fileExtension: string,\n): responseHeadersType => {\n return {\n 'Content-Type': getContentTypeForExtension(fileExtension),\n };\n};\n\n/**\n * Recursively traverse all the sub-directories of a path and return\n * a list of absolute paths of all the files. e.g. tree command in Unix\n *\n * @example\n *\n * /User/username/my_dir\n * dirA\n * | subDirA\n * | | file1\n * EmptyDir\n * dirB\n * | file2\n * file3\n *\n * getFileListRecursively('/Users/username/myDir')\n * // returns\n * [\n * '/User/username/my_dir/dirA/subDirA/file1',\n * '/User/username/my_dir/dirB/file2',\n * '/User/username/my_dir/file3'\n * ]\n * @param rootDirPath - Absolute path to the root directory.\n */\nexport const getFileTreeRecursively = async (\n rootDirPath: string,\n): Promise<string[]> => {\n // Iterate on all the files in the directory and its sub-directories\n const fileList = await recursiveReadDir(rootDirPath).catch(error => {\n throw new Error(`Failed to read template directory: ${error.message}`);\n });\n return fileList;\n};\n\n/**\n * Takes a posix path and returns a lower-cased version of entity's triplet\n * with the remaining path in posix.\n *\n * Path must not include a starting slash.\n *\n * @example\n * lowerCaseEntityTriplet('default/Component/backstage')\n * // return default/component/backstage\n */\nexport const lowerCaseEntityTriplet = (posixPath: string): string => {\n const [namespace, kind, name, ...rest] = posixPath.split(path.posix.sep);\n const lowerNamespace = namespace.toLowerCase();\n const lowerKind = kind.toLowerCase();\n const lowerName = name.toLowerCase();\n return [lowerNamespace, lowerKind, lowerName, ...rest].join(path.posix.sep);\n};\n\n/**\n * Takes either a win32 or posix path and returns a lower-cased version of entity's triplet\n * with the remaining path in posix.\n *\n * Starting slashes will be trimmed.\n *\n * Throws an error if the path does not appear to be an entity triplet.\n *\n * @example\n * lowerCaseEntityTripletInStoragePath('/default/Component/backstage/file.txt')\n * // return default/component/backstage/file.txt\n */\nexport const lowerCaseEntityTripletInStoragePath = (\n originalPath: string,\n): string => {\n let posixPath = originalPath;\n if (originalPath.includes(path.win32.sep)) {\n posixPath = originalPath.split(path.win32.sep).join(path.posix.sep);\n }\n\n // remove leading slash\n const parts = posixPath.split(path.posix.sep);\n if (parts[0] === '') {\n parts.shift();\n }\n\n // check if all parts of the entity exist (name, namespace, kind) plus filename\n if (parts.length <= 3) {\n throw new Error(\n `Encountered file unmanaged by TechDocs ${originalPath}. Skipping.`,\n );\n }\n\n return lowerCaseEntityTriplet(parts.join(path.posix.sep));\n};\n\n/**\n * Take a posix path and return a path without leading and trailing\n * separators\n *\n * @example\n * normalizeExternalStorageRootPath('/backstage-data/techdocs/')\n * // return backstage-data/techdocs\n */\nexport const normalizeExternalStorageRootPath = (posixPath: string): string => {\n // remove leading slash\n let normalizedPath = posixPath;\n if (posixPath.startsWith(path.posix.sep)) {\n normalizedPath = posixPath.slice(1);\n }\n\n // remove trailing slash\n if (normalizedPath.endsWith(path.posix.sep)) {\n normalizedPath = normalizedPath.slice(0, normalizedPath.length - 1);\n }\n\n return normalizedPath;\n};\n\n// Only returns the files that existed previously and are not present anymore.\nexport const getStaleFiles = (\n newFiles: string[],\n oldFiles: string[],\n): string[] => {\n const staleFiles = new Set(oldFiles);\n const removedParentDirs = new Set();\n newFiles.forEach(newFile => {\n staleFiles.delete(newFile);\n\n // We have to traverse through the directory hierarchy of a new file and\n // ensure that we won't try to delete one of the parent directories.\n let parentDir = newFile.substring(0, newFile.lastIndexOf('/'));\n while (\n !removedParentDirs.has(parentDir) &&\n parentDir.length >= newFile.indexOf('/')\n ) {\n staleFiles.delete(parentDir);\n removedParentDirs.add(parentDir);\n parentDir = parentDir.substring(0, parentDir.lastIndexOf('/'));\n }\n });\n return Array.from(staleFiles);\n};\n\n// Compose actual filename on remote bucket including entity information\nexport const getCloudPathForLocalPath = (\n entity: Entity,\n localPath = '',\n useLegacyPathCasing = false,\n externalStorageRootPath = '',\n): string => {\n // Convert destination file path to a POSIX path for uploading.\n // GCS expects / as path separator and relativeFilePath will contain \\\\ on Windows.\n // https://cloud.google.com/storage/docs/gsutil/addlhelp/HowSubdirectoriesWork\n const relativeFilePathPosix = localPath.split(path.sep).join(path.posix.sep);\n\n // The / delimiter is intentional since it represents the cloud storage and not the local file system.\n const entityRootDir = `${entity.metadata?.namespace ?? DEFAULT_NAMESPACE}/${\n entity.kind\n }/${entity.metadata.name}`;\n\n const relativeFilePathTriplet = `${entityRootDir}/${relativeFilePathPosix}`;\n\n const destination = useLegacyPathCasing\n ? relativeFilePathTriplet\n : lowerCaseEntityTriplet(relativeFilePathTriplet);\n\n // Again, the / delimiter is intentional, as it represents remote storage.\n const destinationWithRoot = [\n // The extra filter prevents unintended double slashes and prefixes.\n ...externalStorageRootPath.split(path.posix.sep).filter(s => s !== ''),\n destination,\n ].join('/');\n\n return destinationWithRoot; // Remote storage file relative path\n};\n\n// Perform rate limited generic operations by passing a function and a list of arguments\nexport const bulkStorageOperation = async <T>(\n operation: (arg: T) => Promise<unknown>,\n args: T[],\n { concurrencyLimit } = { concurrencyLimit: 25 },\n) => {\n const limiter = createLimiter(concurrencyLimit);\n await Promise.all(args.map(arg => limiter(operation, arg)));\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isChildPath } from '@backstage/backend-plugin-api';\nimport { Entity } from '@backstage/catalog-model';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { SpawnOptionsWithoutStdio, spawn } from 'child_process';\nimport fs from 'fs-extra';\nimport gitUrlParse from 'git-url-parse';\nimport yaml, { DEFAULT_SCHEMA, Type } from 'js-yaml';\nimport path, { resolve as resolvePath } from 'path';\nimport { PassThrough, Writable } from 'stream';\nimport { Logger } from 'winston';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport { DefaultMkdocsContent, SupportedGeneratorKey } from './types';\nimport { getFileTreeRecursively } from '../publish/helpers';\n\n// TODO: Implement proper support for more generators.\nexport function getGeneratorKey(entity: Entity): SupportedGeneratorKey {\n if (!entity) {\n throw new Error('No entity provided');\n }\n\n return 'techdocs';\n}\n\nexport type RunCommandOptions = {\n /** command to run */\n command: string;\n /** arguments to pass the command */\n args: string[];\n /** options to pass to spawn */\n options: SpawnOptionsWithoutStdio;\n /** stream to capture stdout and stderr output */\n logStream?: Writable;\n};\n\n/**\n * Run a command in a sub-process, normally a shell command.\n */\nexport const runCommand = async ({\n command,\n args,\n options,\n logStream = new PassThrough(),\n}: RunCommandOptions) => {\n await new Promise<void>((resolve, reject) => {\n const process = spawn(command, args, options);\n\n process.stdout.on('data', stream => {\n logStream.write(stream);\n });\n\n process.stderr.on('data', stream => {\n logStream.write(stream);\n });\n\n process.on('error', error => {\n return reject(error);\n });\n\n process.on('close', code => {\n if (code !== 0) {\n return reject(`Command ${command} failed, exit code: ${code}`);\n }\n return resolve();\n });\n });\n};\n\n/**\n * Return the source url for MkDocs based on the backstage.io/techdocs-ref annotation.\n * Depending on the type of target, it can either return a repo_url, an edit_uri, both, or none.\n *\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n * @param docsFolder - the configured docs folder in the mkdocs.yml (defaults to 'docs')\n * @returns the settings for the mkdocs.yml\n */\nexport const getRepoUrlFromLocationAnnotation = (\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n docsFolder: string = 'docs',\n): { repo_url?: string; edit_uri?: string } => {\n const { type: locationType, target } = parsedLocationAnnotation;\n\n if (locationType === 'url') {\n const integration = scmIntegrations.byUrl(target);\n\n // We only support it for github, gitlab, bitbucketServer and harness for now as the edit_uri\n // is not properly supported for others yet.\n if (\n integration &&\n ['github', 'gitlab', 'bitbucketServer', 'harness'].includes(\n integration.type,\n )\n ) {\n // handle the case where a user manually writes url:https://github.com/backstage/backstage i.e. without /blob/...\n const { filepathtype } = gitUrlParse(target);\n if (filepathtype === '') {\n return { repo_url: target };\n }\n\n const sourceFolder = integration.resolveUrl({\n url: `./${docsFolder}`,\n base: target.endsWith('/') ? target : `${target}/`,\n });\n return {\n repo_url: target,\n edit_uri: integration.resolveEditUrl(sourceFolder),\n };\n }\n }\n\n return {};\n};\n\nclass UnknownTag {\n constructor(public readonly data: any, public readonly type?: string) {}\n}\n\nexport const MKDOCS_SCHEMA = DEFAULT_SCHEMA.extend([\n new Type('', {\n kind: 'scalar',\n multi: true,\n representName: o => (o as UnknownTag).type,\n represent: o => (o as UnknownTag).data ?? '',\n instanceOf: UnknownTag,\n construct: (data: string, type?: string) => new UnknownTag(data, type),\n }),\n new Type('', {\n kind: 'sequence',\n multi: true,\n representName: o => (o as UnknownTag).type,\n represent: o => (o as UnknownTag).data ?? '',\n instanceOf: UnknownTag,\n construct: (data: string, type?: string) => new UnknownTag(data, type),\n }),\n]);\n\n/**\n * Generates a mkdocs.yml configuration file\n *\n * @param inputDir - base dir to where the mkdocs.yml file will be created\n * @param siteOptions - options for the site: `name` property will be used in mkdocs.yml for the\n * required `site_name` property, default value is \"Documentation Site\"\n */\nexport const generateMkdocsYml = async (\n inputDir: string,\n siteOptions?: { name?: string },\n) => {\n try {\n // TODO(awanlin): Use a provided default mkdocs.yml\n // from config or some specified location. If this is\n // not provided then fall back to generating bare\n // minimum mkdocs.yml file\n\n const mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml');\n const defaultSiteName = siteOptions?.name ?? 'Documentation Site';\n const defaultMkdocsContent: DefaultMkdocsContent = {\n site_name: defaultSiteName,\n docs_dir: 'docs',\n plugins: ['techdocs-core'],\n };\n\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(defaultMkdocsContent, { schema: MKDOCS_SCHEMA }),\n );\n } catch (error) {\n throw new ForwardedError('Could not generate mkdocs.yml file', error);\n }\n};\n\n/**\n * Finds and loads the contents of an mkdocs.yml, mkdocs.yaml file, a file\n * with a specified name or an ad-hoc created file with minimal config.\n * @public\n *\n * @param inputDir - base dir to be searched for either an mkdocs.yml or mkdocs.yaml file.\n * @param options - name: default mkdocs site_name to be used with a ad hoc file default value is \"Documentation Site\"\n * mkdocsConfigFileName (optional): a non-default file name to be used as the config\n */\nexport const getMkdocsYml = async (\n inputDir: string,\n options?: { name?: string; mkdocsConfigFileName?: string },\n): Promise<{ path: string; content: string; configIsTemporary: boolean }> => {\n let mkdocsYmlPath: string;\n let mkdocsYmlFileString: string;\n try {\n if (options?.mkdocsConfigFileName) {\n mkdocsYmlPath = path.join(inputDir, options.mkdocsConfigFileName);\n if (!(await fs.pathExists(mkdocsYmlPath))) {\n throw new Error(`The specified file ${mkdocsYmlPath} does not exist`);\n }\n\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n mkdocsYmlPath = path.join(inputDir, 'mkdocs.yaml');\n if (await fs.pathExists(mkdocsYmlPath)) {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml');\n if (await fs.pathExists(mkdocsYmlPath)) {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n // No mkdocs file, generate it\n await generateMkdocsYml(inputDir, options);\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n throw new ForwardedError(\n 'Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml or default for validation',\n error,\n );\n }\n\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: true,\n };\n};\n\n/**\n * Validating mkdocs config file for incorrect/insecure values\n * Throws on invalid configs\n *\n * @param inputDir - base dir to be used as a docs_dir path validity check\n * @param mkdocsYmlFileString - The string contents of the loaded\n * mkdocs.yml or equivalent of a docs site\n * @returns the parsed docs_dir or undefined\n */\nexport const validateMkdocsYaml = async (\n inputDir: string,\n mkdocsYmlFileString: string,\n): Promise<string | undefined> => {\n const mkdocsYml = yaml.load(mkdocsYmlFileString, {\n schema: MKDOCS_SCHEMA,\n });\n\n if (mkdocsYml === null || typeof mkdocsYml !== 'object') {\n return undefined;\n }\n\n const parsedMkdocsYml: Record<string, any> = mkdocsYml;\n if (\n parsedMkdocsYml.docs_dir &&\n !isChildPath(inputDir, resolvePath(inputDir, parsedMkdocsYml.docs_dir))\n ) {\n throw new Error(\n `docs_dir configuration value in mkdocs can't be an absolute directory or start with ../ for security reasons.\n Use relative paths instead which are resolved relative to your mkdocs.yml file location.`,\n );\n }\n return parsedMkdocsYml.docs_dir;\n};\n\n/**\n * Update docs/index.md file before TechDocs generator uses it to generate docs site,\n * falling back to docs/README.md or README.md in case a default docs/index.md\n * is not provided.\n */\nexport const patchIndexPreBuild = async ({\n inputDir,\n logger,\n docsDir = 'docs',\n}: {\n inputDir: string;\n logger: Logger;\n docsDir?: string;\n}) => {\n const docsPath = path.join(inputDir, docsDir);\n const indexMdPath = path.join(docsPath, 'index.md');\n\n if (await fs.pathExists(indexMdPath)) {\n return;\n }\n logger.warn(`${path.join(docsDir, 'index.md')} not found.`);\n const fallbacks = [\n path.join(docsPath, 'README.md'),\n path.join(docsPath, 'readme.md'),\n path.join(inputDir, 'README.md'),\n path.join(inputDir, 'readme.md'),\n ];\n\n await fs.ensureDir(docsPath);\n for (const filePath of fallbacks) {\n try {\n await fs.copyFile(filePath, indexMdPath);\n return;\n } catch (error) {\n logger.warn(`${path.relative(inputDir, filePath)} not found.`);\n }\n }\n\n logger.warn(\n `Could not find any techdocs' index file. Please make sure at least one of ${[\n indexMdPath,\n ...fallbacks,\n ].join(' ')} exists.`,\n );\n};\n\n/**\n * Create or update the techdocs_metadata.json. Values initialized/updated are:\n * - The build_timestamp (now)\n * - The list of files generated\n *\n * @param techdocsMetadataPath - File path to techdocs_metadata.json\n */\nexport const createOrUpdateMetadata = async (\n techdocsMetadataPath: string,\n logger: Logger,\n): Promise<void> => {\n const techdocsMetadataDir = techdocsMetadataPath\n .split(path.sep)\n .slice(0, -1)\n .join(path.sep);\n // check if file exists, create if it does not.\n try {\n await fs.access(techdocsMetadataPath, fs.constants.F_OK);\n } catch (err) {\n // Bootstrap file with empty JSON\n await fs.writeJson(techdocsMetadataPath, JSON.parse('{}'));\n }\n // check if valid Json\n let json;\n try {\n json = await fs.readJson(techdocsMetadataPath);\n } catch (err) {\n assertError(err);\n const message = `Invalid JSON at ${techdocsMetadataPath} with error ${err.message}`;\n logger.error(message);\n throw new Error(message);\n }\n\n json.build_timestamp = Date.now();\n\n // Get and write generated files to the metadata JSON. Each file string is in\n // a form appropriate for invalidating the associated object from cache.\n try {\n json.files = (await getFileTreeRecursively(techdocsMetadataDir)).map(file =>\n file.replace(`${techdocsMetadataDir}${path.sep}`, ''),\n );\n } catch (err) {\n assertError(err);\n json.files = [];\n logger.warn(`Unable to add files list to metadata: ${err.message}`);\n }\n\n await fs.writeJson(techdocsMetadataPath, json);\n return;\n};\n\n/**\n * Update the techdocs_metadata.json to add etag of the prepared tree (e.g. commit SHA or actual Etag of the resource).\n * This is helpful to check if a TechDocs site in storage has gone outdated, without maintaining an in-memory build info\n * per Backstage instance.\n *\n * @param techdocsMetadataPath - File path to techdocs_metadata.json\n * @param etag - The ETag to use\n */\nexport const storeEtagMetadata = async (\n techdocsMetadataPath: string,\n etag: string,\n): Promise<void> => {\n const json = await fs.readJson(techdocsMetadataPath);\n json.etag = etag;\n await fs.writeJson(techdocsMetadataPath, json);\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Logger } from 'winston';\nimport fs from 'fs-extra';\nimport yaml from 'js-yaml';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport { getRepoUrlFromLocationAnnotation, MKDOCS_SCHEMA } from './helpers';\nimport { assertError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\n\ntype MkDocsObject = {\n plugins?: string[];\n docs_dir: string;\n repo_url?: string;\n edit_uri?: string;\n};\n\nconst patchMkdocsFile = async (\n mkdocsYmlPath: string,\n logger: Logger,\n updateAction: (mkdocsYml: MkDocsObject) => boolean,\n) => {\n // We only want to override the mkdocs.yml if it has actually changed. This is relevant if\n // used with a 'dir' location on the file system as this would permanently update the file.\n let didEdit = false;\n\n let mkdocsYmlFileString;\n try {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not read MkDocs YAML config file ${mkdocsYmlPath} before running the generator: ${error.message}`,\n );\n return;\n }\n\n let mkdocsYml: any;\n try {\n mkdocsYml = yaml.load(mkdocsYmlFileString, { schema: MKDOCS_SCHEMA });\n\n // mkdocsYml should be an object type after successful parsing.\n // But based on its type definition, it can also be a string or undefined, which we don't want.\n if (typeof mkdocsYml === 'string' || typeof mkdocsYml === 'undefined') {\n throw new Error('Bad YAML format.');\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Error in parsing YAML at ${mkdocsYmlPath} before running the generator. ${error.message}`,\n );\n return;\n }\n\n didEdit = updateAction(mkdocsYml);\n\n try {\n if (didEdit) {\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(mkdocsYml, { schema: MKDOCS_SCHEMA }),\n 'utf8',\n );\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not write to ${mkdocsYmlPath} after updating it before running the generator. ${error.message}`,\n );\n return;\n }\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add repo_url or edit_uri if it does not exists\n * If mkdocs.yml has a repo_url, the generated docs site gets an Edit button on the pages by default.\n * If repo_url is missing in mkdocs.yml, we will use techdocs annotation of the entity to possibly get\n * the repository URL.\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n */\nexport const patchMkdocsYmlPreBuild = async (\n mkdocsYmlPath: string,\n logger: Logger,\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n if (!('repo_url' in mkdocsYml) || !('edit_uri' in mkdocsYml)) {\n // Add edit_uri and/or repo_url to mkdocs.yml if it is missing.\n // This will enable the Page edit button generated by MkDocs.\n // If the either has been set, keep the original value\n const result = getRepoUrlFromLocationAnnotation(\n parsedLocationAnnotation,\n scmIntegrations,\n mkdocsYml.docs_dir,\n );\n\n if (result.repo_url || result.edit_uri) {\n mkdocsYml.repo_url = mkdocsYml.repo_url || result.repo_url;\n mkdocsYml.edit_uri = mkdocsYml.edit_uri || result.edit_uri;\n\n logger.info(\n `Set ${JSON.stringify(\n result,\n )}. 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`,\n );\n return true;\n }\n }\n return false;\n });\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add all provided default plugins\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param defaultPlugins - List of default mkdocs plugins\n */\nexport const patchMkdocsYmlWithPlugins = async (\n mkdocsYmlPath: string,\n logger: Logger,\n defaultPlugins: string[] = ['techdocs-core'],\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Modify mkdocs.yaml to contain the required default plugins.\n // If no plugins are defined we can just return the defaults.\n if (!('plugins' in mkdocsYml)) {\n mkdocsYml.plugins = defaultPlugins;\n return true;\n }\n\n // Otherwise, check each default plugin and include it if necessary.\n let changesMade = false;\n\n defaultPlugins.forEach(dp => {\n // if the plugin isn't there as a string, and isn't there as an object (which may itself contain extra config)\n // then we need to add it\n if (\n !(\n mkdocsYml.plugins!.includes(dp) ||\n mkdocsYml.plugins!.some(p => p.hasOwnProperty(dp))\n )\n ) {\n mkdocsYml.plugins = [...new Set([...mkdocsYml.plugins!, dp])];\n changesMade = true;\n }\n });\n\n return changesMade;\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Docker from 'dockerode';\nimport fs from 'fs-extra';\nimport { ForwardedError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { pipeline as pipelineStream } from 'stream';\nimport { promisify } from 'util';\nimport { Writable } from 'stream';\n\nconst pipeline = promisify(pipelineStream);\n\nexport type UserOptions = {\n User?: string;\n};\n\n/**\n * @internal\n */\nexport class DockerContainerRunner {\n private readonly dockerClient: Docker;\n\n constructor() {\n this.dockerClient = new Docker();\n }\n\n async runContainer(options: {\n imageName: string;\n command?: string | string[];\n args: string[];\n logStream?: Writable;\n mountDirs?: Record<string, string>;\n workingDir?: string;\n envVars?: Record<string, string>;\n pullImage?: boolean;\n defaultUser?: boolean;\n }) {\n const {\n imageName,\n command,\n args,\n logStream = new PassThrough(),\n mountDirs = {},\n workingDir,\n envVars = {},\n pullImage = true,\n defaultUser = false,\n } = options;\n\n // Show a better error message when Docker is unavailable.\n try {\n await this.dockerClient.ping();\n } catch (e) {\n throw new ForwardedError(\n 'This operation requires Docker. Docker does not appear to be available. Docker.ping() failed with',\n e,\n );\n }\n\n if (pullImage) {\n await new Promise<void>((resolve, reject) => {\n this.dockerClient.pull(imageName, {}, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n pipeline(stream, logStream, { end: false })\n .then(resolve)\n .catch(reject);\n });\n });\n }\n\n const userOptions: UserOptions = {};\n if (!defaultUser && process.getuid && process.getgid) {\n // Files that are created inside the Docker container will be owned by\n // root on the host system on non Mac systems, because of reasons. Mainly the fact that\n // volume sharing is done using NFS on Mac and actual mounts in Linux world.\n // So we set the user in the container as the same user and group id as the host.\n // On Windows we don't have process.getuid nor process.getgid\n userOptions.User = `${process.getuid()}:${process.getgid()}`;\n }\n\n // Initialize volumes to mount based on mountDirs map\n const Volumes: { [T: string]: object } = {};\n for (const containerDir of Object.values(mountDirs)) {\n Volumes[containerDir] = {};\n }\n\n // Create bind volumes\n const Binds: string[] = [];\n for (const [hostDir, containerDir] of Object.entries(mountDirs)) {\n // Need to use realpath here as Docker mounting does not like\n // symlinks for binding volumes\n const realHostDir = await fs.realpath(hostDir);\n Binds.push(`${realHostDir}:${containerDir}`);\n }\n\n // Create docker environment variables array\n const Env = [];\n for (const [key, value] of Object.entries(envVars)) {\n Env.push(`${key}=${value}`);\n }\n\n const [{ Error: error, StatusCode: statusCode }] =\n await this.dockerClient.run(imageName, args, logStream, {\n Volumes,\n HostConfig: {\n AutoRemove: true,\n Binds,\n },\n ...(workingDir ? { WorkingDir: workingDir } : {}),\n Entrypoint: command,\n Env,\n ...userOptions,\n } as Docker.ContainerCreateOptions);\n\n if (error) {\n throw new Error(\n `Docker failed to run with the following error message: ${error}`,\n );\n }\n\n if (statusCode !== 0) {\n throw new Error(\n `Docker container returned a non-zero exit code (${statusCode})`,\n );\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'path';\nimport { Logger } from 'winston';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n createOrUpdateMetadata,\n getMkdocsYml,\n patchIndexPreBuild,\n runCommand,\n storeEtagMetadata,\n validateMkdocsYaml,\n} from './helpers';\n\nimport {\n patchMkdocsYmlPreBuild,\n patchMkdocsYmlWithPlugins,\n} from './mkdocsPatchers';\nimport {\n GeneratorBase,\n GeneratorConfig,\n GeneratorOptions,\n GeneratorRunInType,\n GeneratorRunOptions,\n} from './types';\nimport { ForwardedError } from '@backstage/errors';\nimport { DockerContainerRunner } from './DockerContainerRunner';\nimport { ContainerRunner } from '@backstage/backend-common';\n\n/**\n * Generates documentation files\n * @public\n */\nexport class TechdocsGenerator implements GeneratorBase {\n /**\n * The default docker image (and version) used to generate content. Public\n * and static so that techdocs-node consumers can use the same version.\n */\n public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.4';\n private readonly logger: Logger;\n private readonly containerRunner?: ContainerRunner;\n private readonly options: GeneratorConfig;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n\n /**\n * Returns a instance of TechDocs generator\n * @param config - A Backstage configuration\n * @param options - Options to configure the generator\n */\n static fromConfig(config: Config, options: GeneratorOptions) {\n const { containerRunner, logger } = options;\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n return new TechdocsGenerator({\n logger,\n containerRunner,\n config,\n scmIntegrations,\n });\n }\n\n constructor(options: {\n logger: Logger;\n containerRunner?: ContainerRunner;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n }) {\n this.logger = options.logger;\n this.options = readGeneratorConfig(options.config, options.logger);\n this.containerRunner = options.containerRunner;\n this.scmIntegrations = options.scmIntegrations;\n }\n\n /** {@inheritDoc GeneratorBase.run} */\n public async run(options: GeneratorRunOptions): Promise<void> {\n const {\n inputDir,\n outputDir,\n parsedLocationAnnotation,\n etag,\n logger: childLogger,\n logStream,\n siteOptions,\n runAsDefaultUser,\n } = options;\n\n // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url\n const { path: mkdocsYmlPath, content } = await getMkdocsYml(\n inputDir,\n siteOptions,\n );\n\n // validate the docs_dir first\n const docsDir = await validateMkdocsYaml(inputDir, content);\n\n if (parsedLocationAnnotation) {\n await patchMkdocsYmlPreBuild(\n mkdocsYmlPath,\n childLogger,\n parsedLocationAnnotation,\n this.scmIntegrations,\n );\n }\n\n if (this.options.legacyCopyReadmeMdToIndexMd) {\n await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir });\n }\n\n // patch the list of mkdocs plugins\n const defaultPlugins = this.options.defaultPlugins ?? [];\n\n if (\n !this.options.omitTechdocsCoreMkdocsPlugin &&\n !defaultPlugins.includes('techdocs-core')\n ) {\n defaultPlugins.push('techdocs-core');\n }\n\n await patchMkdocsYmlWithPlugins(mkdocsYmlPath, childLogger, defaultPlugins);\n\n // Directories to bind on container\n const mountDirs = {\n [inputDir]: '/input',\n [outputDir]: '/output',\n };\n\n try {\n switch (this.options.runIn) {\n case 'local':\n await runCommand({\n command: 'mkdocs',\n args: ['build', '-d', outputDir, '-v'],\n options: {\n cwd: inputDir,\n },\n logStream,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using local mkdocs`,\n );\n break;\n case 'docker': {\n const containerRunner =\n this.containerRunner || new DockerContainerRunner();\n await containerRunner.runContainer({\n imageName:\n this.options.dockerImage ?? TechdocsGenerator.defaultDockerImage,\n args: ['build', '-d', '/output'],\n logStream,\n mountDirs,\n workingDir: '/input',\n // Set the home directory inside the container as something that applications can\n // write to, otherwise they will just fail trying to write to /\n envVars: { HOME: '/tmp' },\n pullImage: this.options.pullImage,\n defaultUser: runAsDefaultUser,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using techdocs-container`,\n );\n break;\n }\n default:\n throw new Error(\n `Invalid config value \"${this.options.runIn}\" provided in 'techdocs.generators.techdocs'.`,\n );\n }\n } catch (error) {\n this.logger.debug(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n );\n throw new ForwardedError(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n error,\n );\n }\n\n /**\n * Post Generate steps\n */\n\n // Add build timestamp and files to techdocs_metadata.json\n // Creates techdocs_metadata.json if file does not exist.\n await createOrUpdateMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n childLogger,\n );\n\n // Add etag of the prepared tree to techdocs_metadata.json\n // Assumes that the file already exists.\n if (etag) {\n await storeEtagMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n etag,\n );\n }\n }\n}\n\nexport function readGeneratorConfig(\n config: Config,\n logger: Logger,\n): GeneratorConfig {\n const legacyGeneratorType = config.getOptionalString(\n 'techdocs.generators.techdocs',\n ) as GeneratorRunInType;\n\n if (legacyGeneratorType) {\n logger.warn(\n `The 'techdocs.generators.techdocs' configuration key is deprecated and will be removed in the future. Please use 'techdocs.generator' instead. ` +\n `See here https://backstage.io/docs/features/techdocs/configuration`,\n );\n }\n\n return {\n runIn:\n legacyGeneratorType ??\n config.getOptionalString('techdocs.generator.runIn') ??\n 'docker',\n dockerImage: config.getOptionalString('techdocs.generator.dockerImage'),\n pullImage: config.getOptionalBoolean('techdocs.generator.pullImage'),\n omitTechdocsCoreMkdocsPlugin: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.omitTechdocsCorePlugin',\n ),\n legacyCopyReadmeMdToIndexMd: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.legacyCopyReadmeMdToIndexMd',\n ),\n defaultPlugins: config.getOptionalStringArray(\n 'techdocs.generator.mkdocs.defaultPlugins',\n ),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ContainerRunner } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\nimport { getGeneratorKey } from './helpers';\nimport { TechdocsGenerator } from './techdocs';\nimport {\n GeneratorBase,\n GeneratorBuilder,\n SupportedGeneratorKey,\n} from './types';\n\n/**\n * Collection of docs generators\n * @public\n */\nexport class Generators implements GeneratorBuilder {\n private generatorMap = new Map<SupportedGeneratorKey, GeneratorBase>();\n\n /**\n * Returns a generators instance containing a generator for TechDocs\n * @param config - A Backstage configuration\n * @param options - Options to configure the TechDocs generator\n */\n static async fromConfig(\n config: Config,\n options: {\n logger: Logger;\n containerRunner?: ContainerRunner;\n customGenerator?: TechdocsGenerator;\n },\n ): Promise<GeneratorBuilder> {\n const generators = new Generators();\n\n const techdocsGenerator =\n options.customGenerator ?? TechdocsGenerator.fromConfig(config, options);\n generators.register('techdocs', techdocsGenerator);\n\n return generators;\n }\n\n /**\n * Register a generator in the generators collection\n * @param generatorKey - Unique identifier for the generator\n * @param generator - The generator instance to register\n */\n register(generatorKey: SupportedGeneratorKey, generator: GeneratorBase) {\n this.generatorMap.set(generatorKey, generator);\n }\n\n /**\n * Returns the generator for a given TechDocs entity\n * @param entity - A TechDocs entity instance\n */\n get(entity: Entity): GeneratorBase {\n const generatorKey = getGeneratorKey(entity);\n const generator = this.generatorMap.get(generatorKey);\n\n if (!generator) {\n throw new Error(`No generator registered for entity: \"${generatorKey}\"`);\n }\n\n return generator;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport { TechdocsGenerator } from './techdocs';\nexport { Generators } from './generators';\nexport { getMkdocsYml } from './helpers';\nexport type {\n GeneratorBase,\n GeneratorOptions,\n GeneratorBuilder,\n GeneratorRunOptions,\n SupportedGeneratorKey,\n} from './types';\nimport { getMkdocsYml } from './helpers';\n/**\n * @public\n * @deprecated\n * Deprecated in favor of getMkdocsYml (lowercase 'd')\n */\nexport const getMkDocsYml = getMkdocsYml;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReaderService } from '@backstage/backend-plugin-api';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport {\n Entity,\n getEntitySourceLocation,\n parseLocationRef,\n} from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport path from 'path';\nimport { Logger } from 'winston';\nimport { PreparerResponse, RemoteProtocol } from './stages/prepare/types';\n\n/**\n * Parsed location annotation\n * @public\n */\nexport type ParsedLocationAnnotation = {\n type: RemoteProtocol;\n target: string;\n};\n\n/**\n * Returns a parset locations annotation\n * @public\n * @param annotationName - The name of the annotation in the entity metadata\n * @param entity - A TechDocs entity instance\n */\nexport const parseReferenceAnnotation = (\n annotationName: string,\n entity: Entity,\n): ParsedLocationAnnotation => {\n const annotation = entity.metadata.annotations?.[annotationName];\n if (!annotation) {\n throw new InputError(\n `No location annotation provided in entity: ${entity.metadata.name}`,\n );\n }\n\n const { type, target } = parseLocationRef(annotation);\n return {\n type: type as RemoteProtocol,\n target,\n };\n};\n\n/**\n * TechDocs references of type `dir` are relative the source location of the entity.\n * This function transforms relative references to absolute ones, based on the\n * location the entity was ingested from. If the entity was registered by a `url`\n * location, it returns a `url` location with a resolved target that points to the\n * targeted subfolder. If the entity was registered by a `file` location, it returns\n * an absolute `dir` location.\n * @public\n * @param entity - the entity with annotations\n * @param dirAnnotation - the parsed techdocs-ref annotation of type 'dir'\n * @param scmIntegrations - access to the scmIntegration to do url transformations\n * @throws if the entity doesn't specify a `dir` location or is ingested from an unsupported location.\n * @returns the transformed location with an absolute target.\n */\nexport const transformDirLocation = (\n entity: Entity,\n dirAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n): { type: 'dir' | 'url'; target: string } => {\n const location = getEntitySourceLocation(entity);\n\n switch (location.type) {\n case 'url': {\n const target = scmIntegrations.resolveUrl({\n url: dirAnnotation.target,\n base: location.target,\n });\n\n return {\n type: 'url',\n target,\n };\n }\n\n case 'file': {\n // only permit targets in the same folder as the target of the `file` location!\n const target = resolveSafeChildPath(\n path.dirname(location.target),\n dirAnnotation.target,\n );\n\n return {\n type: 'dir',\n target,\n };\n }\n\n default:\n throw new InputError(`Unable to resolve location type ${location.type}`);\n }\n};\n\n/**\n * Returns a entity reference based on the TechDocs annotation type\n * @public\n * @param entity - A TechDocs instance\n * @param scmIntegration - An implementation for SCM integration API\n */\nexport const getLocationForEntity = (\n entity: Entity,\n scmIntegration: ScmIntegrationRegistry,\n): ParsedLocationAnnotation => {\n const annotation = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n\n switch (annotation.type) {\n case 'url':\n return annotation;\n case 'dir':\n return transformDirLocation(entity, annotation, scmIntegration);\n default:\n throw new Error(`Invalid reference annotation ${annotation.type}`);\n }\n};\n\n/**\n * Returns a preparer response {@link PreparerResponse}\n * @public\n * @param reader - Read a tree of files from a repository\n * @param entity - A TechDocs entity instance\n * @param opts - Options for configuring the reader, e.g. logger, etag, etc.\n */\nexport const getDocFilesFromRepository = async (\n reader: UrlReaderService,\n entity: Entity,\n opts?: { etag?: string; logger?: Logger },\n): Promise<PreparerResponse> => {\n const { target } = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n\n opts?.logger?.debug(`Reading files from ${target}`);\n // readTree will throw NotModifiedError if etag has not changed.\n const readTreeResponse = await reader.readTree(target, { etag: opts?.etag });\n const preparedDir = await readTreeResponse.dir();\n\n opts?.logger?.debug(`Tree downloaded and stored at ${preparedDir}`);\n\n return {\n preparedDir,\n etag: readTreeResponse.etag,\n };\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReaderService } from '@backstage/backend-plugin-api';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport { Logger } from 'winston';\nimport { parseReferenceAnnotation, transformDirLocation } from '../../helpers';\nimport {\n PreparerBase,\n PreparerConfig,\n PreparerOptions,\n PreparerResponse,\n} from './types';\n\n/**\n * Preparer used to retrieve documentation files from a local directory\n * @public\n */\nexport class DirectoryPreparer implements PreparerBase {\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly reader: UrlReaderService;\n\n /**\n * Returns a directory preparer instance\n * @param config - A backstage config\n * @param options - A directory preparer options containing a logger and reader\n */\n static fromConfig(\n config: Config,\n options: PreparerConfig,\n ): DirectoryPreparer {\n return new DirectoryPreparer(config, options.logger, options.reader);\n }\n\n private constructor(\n config: Config,\n _logger: Logger | null,\n reader: UrlReaderService,\n ) {\n this.reader = reader;\n this.scmIntegrations = ScmIntegrations.fromConfig(config);\n }\n\n /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */\n shouldCleanPreparedDirectory() {\n return false;\n }\n\n /** {@inheritDoc PreparerBase.prepare} */\n async prepare(\n entity: Entity,\n options?: PreparerOptions,\n ): Promise<PreparerResponse> {\n const annotation = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n const { type, target } = transformDirLocation(\n entity,\n annotation,\n this.scmIntegrations,\n );\n\n switch (type) {\n case 'url': {\n options?.logger?.debug(`Reading files from ${target}`);\n // the target is an absolute url since it has already been transformed\n const response = await this.reader.readTree(target, {\n etag: options?.etag,\n });\n const preparedDir = await response.dir();\n\n options?.logger?.debug(`Tree downloaded and stored at ${preparedDir}`);\n\n return {\n preparedDir,\n etag: response.etag,\n };\n }\n\n case 'dir': {\n return {\n // the transformation already validated that the target is in a safe location\n preparedDir: target,\n // Instead of supporting caching on local sources, use techdocs-cli for local development and debugging.\n etag: '',\n };\n }\n\n default:\n throw new InputError(`Unable to resolve location type ${type}`);\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { UrlReaderService } from '@backstage/backend-plugin-api';\nimport { Entity } from '@backstage/catalog-model';\nimport { Logger } from 'winston';\nimport { getDocFilesFromRepository } from '../../helpers';\nimport {\n PreparerBase,\n PreparerConfig,\n PreparerOptions,\n PreparerResponse,\n} from './types';\n\n/**\n * Preparer used to retrieve documentation files from a remote repository\n * @public\n */\nexport class UrlPreparer implements PreparerBase {\n private readonly logger: Logger;\n private readonly reader: UrlReaderService;\n\n /**\n * Returns a directory preparer instance\n * @param config - A URL preparer config containing the a logger and reader\n */\n static fromConfig(options: PreparerConfig): UrlPreparer {\n return new UrlPreparer(options.reader, options.logger);\n }\n\n private constructor(reader: UrlReaderService, logger: Logger) {\n this.logger = logger;\n this.reader = reader;\n }\n\n /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */\n shouldCleanPreparedDirectory() {\n return true;\n }\n\n /** {@inheritDoc PreparerBase.prepare} */\n async prepare(\n entity: Entity,\n options?: PreparerOptions,\n ): Promise<PreparerResponse> {\n try {\n return await getDocFilesFromRepository(this.reader, entity, {\n etag: options?.etag,\n logger: this.logger,\n });\n } catch (error) {\n assertError(error);\n // NotModifiedError means that etag based cache is still valid.\n if (error.name === 'NotModifiedError') {\n this.logger.debug(`Cache is valid for etag ${options?.etag}`);\n } else {\n this.logger.debug(\n `Unable to fetch files for building docs ${error.message}`,\n );\n }\n\n throw error;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport { parseReferenceAnnotation } from '../../helpers';\nimport { DirectoryPreparer } from './dir';\nimport { UrlPreparer } from './url';\nimport {\n PreparerBase,\n PreparerBuilder,\n PreparerConfig,\n RemoteProtocol,\n} from './types';\n\n/**\n * Collection of docs preparers (dir and url)\n * @public\n */\nexport class Preparers implements PreparerBuilder {\n private preparerMap = new Map<RemoteProtocol, PreparerBase>();\n\n /**\n * Returns a generators instance containing a generator for TechDocs\n * @public\n * @param backstageConfig - A Backstage configuration\n * @param preparerConfig - Options to configure preparers\n */\n static async fromConfig(\n backstageConfig: Config,\n options: PreparerConfig,\n ): Promise<PreparerBuilder> {\n const preparers = new Preparers();\n\n const urlPreparer = UrlPreparer.fromConfig({\n reader: options.reader,\n logger: options.logger,\n });\n preparers.register('url', urlPreparer);\n\n /**\n * Dir preparer is a syntactic sugar for users to define techdocs-ref annotation.\n * When using dir preparer, the docs will be fetched using URL Reader.\n */\n const directoryPreparer = DirectoryPreparer.fromConfig(backstageConfig, {\n reader: options.reader,\n logger: options.logger,\n });\n preparers.register('dir', directoryPreparer);\n\n return preparers;\n }\n\n /**\n * Register a preparer in the preparers collection\n * @param protocol - url or dir to associate with preparer\n * @param preparer - The preparer instance to set\n */\n register(protocol: RemoteProtocol, preparer: PreparerBase) {\n this.preparerMap.set(protocol, preparer);\n }\n\n /**\n * Returns the preparer for a given TechDocs entity\n * @param entity - A TechDocs entity instance\n * @returns\n */\n get(entity: Entity): PreparerBase {\n const { type } = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n const preparer = this.preparerMap.get(type);\n\n if (!preparer) {\n throw new Error(`No preparer registered for type: \"${type}\"`);\n }\n\n return preparer;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n GetObjectCommand,\n CopyObjectCommand,\n DeleteObjectCommand,\n HeadBucketCommand,\n HeadObjectCommand,\n PutObjectCommandInput,\n ListObjectsV2CommandOutput,\n ListObjectsV2Command,\n S3Client,\n} from '@aws-sdk/client-s3';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { HttpsProxyAgent } from 'hpagent';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport { Logger } from 'winston';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n getStaleFiles,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\n\nconst streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nexport class AwsS3Publish implements PublisherBase {\n private readonly storageClient: S3Client;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: Logger;\n private readonly bucketRootPath: string;\n private readonly sse?: 'aws:kms' | 'AES256';\n\n constructor(options: {\n storageClient: S3Client;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: Logger;\n bucketRootPath: string;\n sse?: 'aws:kms' | 'AES256';\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n this.sse = options.sse;\n }\n\n static async fromConfig(\n config: Config,\n logger: Logger,\n ): Promise<PublisherBase> {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.awsS3.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'awsS3' in your app config, \" +\n 'techdocs.publisher.awsS3.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.awsS3.bucketRootPath') || '',\n );\n\n const sse = config.getOptionalString('techdocs.publisher.awsS3.sse') as\n | 'aws:kms'\n | 'AES256'\n | undefined;\n\n // AWS Region is an optional config. If missing, default AWS env variable AWS_REGION\n // or AWS shared credentials file at ~/.aws/credentials will be used.\n const region = config.getOptionalString('techdocs.publisher.awsS3.region');\n\n // Credentials can optionally be configured by specifying the AWS account ID, which will retrieve credentials\n // for the account from the 'aws' section of the app config.\n // Credentials can also optionally be directly configured in the techdocs awsS3 config, but this method is\n // deprecated.\n // If no credentials are configured, the AWS SDK V3's default credential chain will be used.\n const accountId = config.getOptionalString(\n 'techdocs.publisher.awsS3.accountId',\n );\n const credentialsConfig = config.getOptionalConfig(\n 'techdocs.publisher.awsS3.credentials',\n );\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n const sdkCredentialProvider = await AwsS3Publish.buildCredentials(\n credsManager,\n accountId,\n credentialsConfig,\n region,\n );\n\n // AWS endpoint is an optional config. If missing, the default endpoint is built from\n // the configured region.\n const endpoint = config.getOptionalString(\n 'techdocs.publisher.awsS3.endpoint',\n );\n\n // AWS HTTPS proxy is an optional config. If missing, no proxy is used\n const httpsProxy = config.getOptionalString(\n 'techdocs.publisher.awsS3.httpsProxy',\n );\n\n // AWS forcePathStyle is an optional config. If missing, it defaults to false. Needs to be enabled for cases\n // where endpoint url points to locally hosted S3 compatible storage like Localstack\n const forcePathStyle = config.getOptionalBoolean(\n 'techdocs.publisher.awsS3.s3ForcePathStyle',\n );\n\n const storageClient = new S3Client({\n customUserAgent: 'backstage-aws-techdocs-s3-publisher',\n credentialDefaultProvider: () => sdkCredentialProvider,\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new AwsS3Publish({\n storageClient,\n bucketName,\n bucketRootPath,\n legacyPathCasing,\n logger,\n sse,\n });\n }\n\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return Promise.resolve({\n accessKeyId,\n secretAccessKey,\n });\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n accountId?: string,\n config?: Config,\n region?: string,\n ): Promise<AwsCredentialIdentityProvider> {\n // Pull credentials for the specified account ID from the 'aws' config section\n if (accountId) {\n return (await credsManager.getCredentialProvider({ accountId }))\n .sdkCredentialProvider;\n }\n\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!config) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n // Pull credentials from the techdocs config section (deprecated)\n const accessKeyId = config.getOptionalString('accessKeyId');\n const secretAccessKey = config.getOptionalString('secretAccessKey');\n const explicitCredentials: AwsCredentialIdentityProvider =\n accessKeyId && secretAccessKey\n ? AwsS3Publish.buildStaticCredentials(accessKeyId, secretAccessKey)\n : (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n\n const roleArn = config.getOptionalString('roleArn');\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-techdocs-s3-publisher',\n RoleArn: roleArn,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.send(\n new HeadBucketCommand({ Bucket: this.bucketName }),\n );\n\n this.logger.info(\n `Successfully connected to the AWS S3 bucket ${this.bucketName}.`,\n );\n\n return { isAvailable: true };\n } catch (error) {\n this.logger.error(\n `Could not retrieve metadata about the AWS S3 bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.awsS3 in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from AWS client library`, error);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the S3 bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucketRootPath = this.bucketRootPath;\n const sse = this.sse;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getAllObjectsFromBucket({\n prefix: remoteFolder,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const fileStream = fs.createReadStream(absoluteFilePath);\n\n const params: PutObjectCommandInput = {\n Bucket: this.bucketName,\n Key: getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n ),\n Body: fileStream,\n ...(sse && { ServerSideEncryption: sse }),\n };\n\n objects.push(params.Key!);\n\n const upload = new Upload({\n client: this.storageClient,\n params,\n });\n return upload.done();\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to AWS S3. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: relativeFilePath,\n }),\n );\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from AWS S3. ${error}`;\n this.logger.error(errorMessage);\n }\n return { objects };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n try {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/techdocs_metadata.json`,\n }),\n );\n\n const techdocsMetadataJson = await streamToBuffer(\n resp.Body as Readable,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n });\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({ Bucket: this.bucketName, Key: filePath }),\n );\n\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n res.send(await streamToBuffer(resp.Body as Readable));\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n try {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n await this.storageClient.send(\n new HeadObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/index.html`,\n }),\n );\n return Promise.resolve(true);\n } catch (e) {\n return Promise.resolve(false);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromBucket();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.verbose(`Migrating ${file}`);\n await this.storageClient.send(\n new CopyObjectCommand({\n Bucket: this.bucketName,\n CopySource: [this.bucketName, file].join('/'),\n Key: newPath,\n }),\n );\n\n if (removeOriginal) {\n await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: file,\n }),\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured bucket.\n */\n protected async getAllObjectsFromBucket(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n const objects: string[] = [];\n let nextContinuation: string | undefined;\n let allObjects: ListObjectsV2CommandOutput;\n // Iterate through every file in the root of the publisher.\n do {\n allObjects = await this.storageClient.send(\n new ListObjectsV2Command({\n Bucket: this.bucketName,\n ContinuationToken: nextContinuation,\n ...(prefix ? { Prefix: prefix } : {}),\n }),\n );\n objects.push(\n ...(allObjects.Contents || []).map(f => f.Key || '').filter(f => !!f),\n );\n nextContinuation = allObjects.NextContinuationToken;\n } while (nextContinuation);\n\n return objects;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DefaultAzureCredential } from '@azure/identity';\nimport {\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport express from 'express';\nimport JSON5 from 'json5';\nimport limiterFactory from 'p-limit';\nimport { default as path, default as platformPath } from 'path';\nimport { Logger } from 'winston';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTriplet,\n getStaleFiles,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\n\n// The number of batches that may be ongoing at the same time.\nconst BATCH_CONCURRENCY = 3;\n\nexport class AzureBlobStoragePublish implements PublisherBase {\n private readonly storageClient: BlobServiceClient;\n private readonly containerName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: Logger;\n\n constructor(options: {\n storageClient: BlobServiceClient;\n containerName: string;\n legacyPathCasing: boolean;\n logger: Logger;\n }) {\n this.storageClient = options.storageClient;\n this.containerName = options.containerName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n }\n\n static fromConfig(config: Config, logger: Logger): PublisherBase {\n let storageClient: BlobServiceClient;\n let containerName = '';\n try {\n containerName = config.getString(\n 'techdocs.publisher.azureBlobStorage.containerName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, \" +\n 'techdocs.publisher.azureBlobStorage.containerName is required.',\n );\n }\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n // Give more priority for connectionString, if configured, return the AzureBlobStoragePublish object here itself\n const connectionStringKey =\n 'techdocs.publisher.azureBlobStorage.connectionString';\n const connectionString = config.getOptionalString(connectionStringKey);\n\n if (connectionString) {\n logger.info(\n `Using '${connectionStringKey}' configuration to create storage client`,\n );\n storageClient = BlobServiceClient.fromConnectionString(connectionString);\n } else {\n let accountName = '';\n try {\n accountName = config.getString(\n 'techdocs.publisher.azureBlobStorage.credentials.accountName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, \" +\n 'techdocs.publisher.azureBlobStorage.credentials.accountName is required.',\n );\n }\n\n // Credentials is an optional config. If missing, default Azure Blob Storage environment variables will be used.\n // https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-app\n const accountKey = config.getOptionalString(\n 'techdocs.publisher.azureBlobStorage.credentials.accountKey',\n );\n\n let credential;\n if (accountKey) {\n credential = new StorageSharedKeyCredential(accountName, accountKey);\n } else {\n credential = new DefaultAzureCredential();\n }\n\n storageClient = new BlobServiceClient(\n `https://${accountName}.blob.core.windows.net`,\n credential,\n );\n }\n\n return new AzureBlobStoragePublish({\n storageClient: storageClient,\n containerName: containerName,\n legacyPathCasing: legacyPathCasing,\n logger: logger,\n });\n }\n\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n const response = await this.storageClient\n .getContainerClient(this.containerName)\n .getProperties();\n\n if (response._response.status === 200) {\n return {\n isAvailable: true,\n };\n }\n\n if (response._response.status >= 400) {\n this.logger.error(\n `Failed to retrieve metadata from ${response._response.request.url} with status code ${response._response.status}.`,\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.error(`from Azure Blob Storage client library: ${e.message}`);\n }\n\n this.logger.error(\n `Could not retrieve metadata about the Azure Blob Storage container ${this.containerName}. ` +\n 'Make sure that the Azure project and container exist and the access key is setup correctly ' +\n 'techdocs.publisher.azureBlobStorage.credentials defined in app config has correct permissions. ' +\n 'Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n\n return { isAvailable: false };\n }\n\n /**\n * Upload all the files from the generated `directory` to the Azure Blob Storage container.\n * Directory structure used in the container is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n\n // First, try to retrieve a list of all individual files currently existing\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n );\n let existingFiles: string[] = [];\n try {\n existingFiles = await this.getAllBlobsFromContainer({\n prefix: remoteFolder,\n maxPageSize: BATCH_CONCURRENCY,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n let container: ContainerClient;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n container = this.storageClient.getContainerClient(this.containerName);\n const failedOperations: Error[] = [];\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.normalize(\n path.relative(directory, absoluteFilePath),\n );\n const remotePath = getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n );\n objects.push(remotePath);\n const response = await container\n .getBlockBlobClient(remotePath)\n .uploadFile(absoluteFilePath);\n\n if (response._response.status >= 400) {\n failedOperations.push(\n new Error(\n `Upload failed for ${absoluteFilePath} with status code ${response._response.status}`,\n ),\n );\n }\n\n return response;\n },\n absoluteFilesToUpload,\n { concurrencyLimit: BATCH_CONCURRENCY },\n );\n\n if (failedOperations.length > 0) {\n throw new Error(\n failedOperations\n .map(r => r.message)\n .filter(Boolean)\n .join(' '),\n );\n }\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to Azure. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n ),\n );\n\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await container.deleteBlob(relativeFilePath);\n },\n staleFiles,\n { concurrencyLimit: BATCH_CONCURRENCY },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from Azure. ${error}`;\n this.logger.error(errorMessage);\n }\n\n return { objects };\n }\n\n private download(containerName: string, blobPath: string): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const fileStreamChunks: Array<any> = [];\n this.storageClient\n .getContainerClient(containerName)\n .getBlockBlobClient(blobPath)\n .download()\n .then(res => {\n const body = res.readableStreamBody;\n if (!body) {\n reject(new Error(`Unable to parse the response data`));\n return;\n }\n body\n .on('error', reject)\n .on('data', chunk => {\n fileStreamChunks.push(chunk);\n })\n .on('end', () => {\n resolve(Buffer.concat(fileStreamChunks));\n });\n })\n .catch(reject);\n });\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityRootDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n try {\n const techdocsMetadataJson = await this.download(\n this.containerName,\n `${entityRootDir}/techdocs_metadata.json`,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n return techdocsMetadata;\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return (req, res) => {\n // Decode and trim the leading forward slash\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/Component/documented-component/index.html\n const filePath = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = platformPath.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n this.download(this.containerName, filePath)\n .then(fileContent => {\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n res.send(fileContent);\n })\n .catch(e => {\n this.logger.warn(\n `TechDocs Azure router failed to serve content from container ${this.containerName} at path ${filePath}: ${e.message}`,\n );\n res.status(404).send('File Not Found');\n });\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityRootDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n return this.storageClient\n .getContainerClient(this.containerName)\n .getBlockBlobClient(`${entityRootDir}/index.html`)\n .exists();\n }\n\n protected async renameBlob(\n originalName: string,\n newName: string,\n removeOriginal = false,\n ): Promise<void> {\n const container = this.storageClient.getContainerClient(this.containerName);\n const blob = container.getBlobClient(newName);\n const { url } = container.getBlobClient(originalName);\n const response = await blob.beginCopyFromURL(url);\n await response.pollUntilDone();\n if (removeOriginal) {\n await container.deleteBlob(originalName);\n }\n }\n\n protected async renameBlobToLowerCase(\n originalPath: string,\n removeOriginal: boolean,\n ) {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(originalPath);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n if (originalPath === newPath) return;\n try {\n this.logger.verbose(`Migrating ${originalPath}`);\n await this.renameBlob(originalPath, newPath, removeOriginal);\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${originalPath}: ${e.message}`);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n const promises = [];\n const limiter = limiterFactory(concurrency);\n const container = this.storageClient.getContainerClient(this.containerName);\n\n for await (const blob of container.listBlobsFlat()) {\n promises.push(\n limiter(\n this.renameBlobToLowerCase.bind(this),\n blob.name,\n removeOriginal,\n ),\n );\n }\n\n await Promise.all(promises);\n }\n\n protected async getAllBlobsFromContainer({\n prefix,\n maxPageSize,\n }: {\n prefix: string;\n maxPageSize: number;\n }): Promise<string[]> {\n const blobs: string[] = [];\n const container = this.storageClient.getContainerClient(this.containerName);\n\n let iterator = container.listBlobsFlat({ prefix }).byPage({ maxPageSize });\n let response = (await iterator.next()).value;\n\n do {\n for (const blob of response?.segment?.blobItems ?? []) {\n blobs.push(blob.name);\n }\n iterator = container\n .listBlobsFlat({ prefix })\n .byPage({ continuationToken: response.continuationToken, maxPageSize });\n response = (await iterator.next()).value;\n } while (response && response.continuationToken);\n\n return blobs;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { File } from '@google-cloud/storage';\nimport { Writable } from 'stream';\nimport { Logger } from 'winston';\nimport { lowerCaseEntityTripletInStoragePath } from '../helpers';\n\n/**\n * Writable stream to handle object copy/move operations. This implementation\n * ensures we don't read in files from GCS faster than GCS can copy/move them.\n */\nexport class MigrateWriteStream extends Writable {\n protected logger: Logger;\n protected removeOriginal: boolean;\n protected maxConcurrency: number;\n protected inFlight = 0;\n\n constructor(logger: Logger, removeOriginal: boolean, concurrency: number) {\n super({ objectMode: true });\n this.logger = logger;\n this.removeOriginal = removeOriginal;\n this.maxConcurrency = concurrency;\n }\n\n _write(file: File, _encoding: BufferEncoding, next: Function) {\n let shouldCallNext = true;\n let newFile;\n try {\n newFile = lowerCaseEntityTripletInStoragePath(file.name);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n next();\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (newFile === file.name) {\n next();\n return;\n }\n\n // Allow up to n-many files to be migrated at a time.\n this.inFlight++;\n if (this.inFlight < this.maxConcurrency) {\n next();\n shouldCallNext = false;\n }\n\n // Otherwise, copy or move the file.\n const migrate = this.removeOriginal\n ? file.move.bind(file)\n : file.copy.bind(file);\n this.logger.verbose(`Migrating ${file.name}`);\n migrate(newFile)\n .catch(e =>\n this.logger.warn(`Unable to migrate ${file.name}: ${e.message}`),\n )\n .finally(() => {\n this.inFlight--;\n if (shouldCallNext) {\n next();\n }\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError } from '@backstage/errors';\nimport {\n File,\n FileExistsResponse,\n Storage,\n StorageOptions,\n} from '@google-cloud/storage';\nimport express from 'express';\nimport JSON5 from 'json5';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport { Logger } from 'winston';\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getStaleFiles,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport { MigrateWriteStream } from './migrations';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\n\nexport class GoogleGCSPublish implements PublisherBase {\n private readonly storageClient: Storage;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: Logger;\n private readonly bucketRootPath: string;\n\n constructor(options: {\n storageClient: Storage;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: Logger;\n bucketRootPath: string;\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n }\n\n static fromConfig(config: Config, logger: Logger): PublisherBase {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.googleGcs.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'googleGcs' in your app config, \" +\n 'techdocs.publisher.googleGcs.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.googleGcs.bucketRootPath') ||\n '',\n );\n\n // Credentials is an optional config. If missing, default GCS environment variables will be used.\n // Read more here https://cloud.google.com/docs/authentication/production\n const credentials = config.getOptionalString(\n 'techdocs.publisher.googleGcs.credentials',\n );\n const projectId = config.getOptionalString(\n 'techdocs.publisher.googleGcs.projectId',\n );\n let credentialsJson: any = {};\n if (credentials) {\n try {\n credentialsJson = JSON.parse(credentials);\n } catch (err) {\n throw new Error(\n 'Error in parsing techdocs.publisher.googleGcs.credentials config to JSON.',\n );\n }\n }\n\n const clientOpts: StorageOptions = {};\n if (projectId) {\n clientOpts.projectId = projectId;\n }\n\n const storageClient = new Storage({\n ...(credentials && {\n projectId: credentialsJson.project_id,\n credentials: credentialsJson,\n }),\n ...clientOpts,\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new GoogleGCSPublish({\n storageClient,\n bucketName,\n legacyPathCasing,\n logger,\n bucketRootPath,\n });\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.bucket(this.bucketName).getMetadata();\n this.logger.info(\n `Successfully connected to the GCS bucket ${this.bucketName}.`,\n );\n\n return {\n isAvailable: true,\n };\n } catch (err) {\n assertError(err);\n this.logger.error(\n `Could not retrieve metadata about the GCS bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by explicitly defining ' +\n 'techdocs.publisher.googleGcs.credentials in app config or by using environment variables. ' +\n 'Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from GCS client library: ${err.message}`);\n\n return { isAvailable: false };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the GCS bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucket = this.storageClient.bucket(this.bucketName);\n const bucketRootPath = this.bucketRootPath;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getFilesForFolder(remoteFolder);\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const destination = getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n );\n objects.push(destination);\n return await bucket.upload(absoluteFilePath, { destination });\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to Google Cloud Storage. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await bucket.file(relativeFilePath).delete();\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from Google Cloud Storage. ${error}`;\n this.logger.error(errorMessage);\n }\n\n return { objects };\n }\n\n fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n return new Promise((resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n const fileStreamChunks: Array<any> = [];\n this.storageClient\n .bucket(this.bucketName)\n .file(`${entityRootDir}/techdocs_metadata.json`)\n .createReadStream()\n .on('error', err => {\n this.logger.error(err.message);\n reject(err);\n })\n .on('data', chunk => {\n fileStreamChunks.push(chunk);\n })\n .on('end', () => {\n const techdocsMetadataJson =\n Buffer.concat(fileStreamChunks).toString('utf-8');\n resolve(JSON5.parse(techdocsMetadataJson));\n });\n });\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n // Pipe file chunks directly from storage to client.\n this.storageClient\n .bucket(this.bucketName)\n .file(filePath)\n .createReadStream()\n .on('pipe', () => {\n res.writeHead(200, responseHeaders);\n })\n .on('error', err => {\n this.logger.warn(\n `TechDocs Google GCS router failed to serve content from bucket ${this.bucketName} at path ${filePath}: ${err.message}`,\n );\n // Send a 404 with a meaningful message if possible.\n if (!res.headersSent) {\n res.status(404).send('File Not Found');\n } else {\n res.destroy();\n }\n })\n .pipe(res);\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n return new Promise(resolve => {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n this.storageClient\n .bucket(this.bucketName)\n .file(`${entityRootDir}/index.html`)\n .exists()\n .then((response: FileExistsResponse) => {\n resolve(response[0]);\n })\n .catch(() => {\n resolve(false);\n });\n });\n }\n\n migrateDocsCase({ removeOriginal = false, concurrency = 25 }): Promise<void> {\n return new Promise((resolve, reject) => {\n // Iterate through every file in the root of the publisher.\n const allFileMetadata: Readable = this.storageClient\n .bucket(this.bucketName)\n .getFilesStream();\n const migrateFiles = new MigrateWriteStream(\n this.logger,\n removeOriginal,\n concurrency,\n );\n migrateFiles.on('finish', resolve).on('error', reject);\n allFileMetadata.pipe(migrateFiles).on('error', error => {\n migrateFiles.destroy();\n reject(error);\n });\n });\n }\n\n private getFilesForFolder(folder: string): Promise<string[]> {\n const fileMetadataStream: Readable = this.storageClient\n .bucket(this.bucketName)\n .getFilesStream({ prefix: folder });\n\n return new Promise((resolve, reject) => {\n const files: string[] = [];\n\n fileMetadataStream.on('error', error => {\n // push file to file array\n reject(error);\n });\n\n fileMetadataStream.on('data', (file: File) => {\n // push file to file array\n files.push(file.name);\n });\n\n fileMetadataStream.on('end', () => {\n // resolve promise\n resolve(files);\n });\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport {\n resolvePackagePath,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport {\n Entity,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { Logger } from 'winston';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport { ForwardedError } from '@backstage/errors';\n\n/**\n * Local publisher which uses the local filesystem to store the generated static files. It uses by default a\n * directory called \"static\" at the root of techdocs-backend plugin unless a directory has been configured by\n * \"techdocs.publisher.local.publishDirectory\".\n */\nexport class LocalPublish implements PublisherBase {\n private readonly legacyPathCasing: boolean;\n private readonly logger: Logger;\n private readonly discovery: PluginEndpointDiscovery;\n private readonly staticDocsDir: string;\n\n constructor(options: {\n logger: Logger;\n discovery: PluginEndpointDiscovery;\n legacyPathCasing: boolean;\n staticDocsDir: string;\n }) {\n this.logger = options.logger;\n this.discovery = options.discovery;\n this.legacyPathCasing = options.legacyPathCasing;\n this.staticDocsDir = options.staticDocsDir;\n }\n\n static fromConfig(\n config: Config,\n logger: Logger,\n discovery: PluginEndpointDiscovery,\n ): PublisherBase {\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n let staticDocsDir = config.getOptionalString(\n 'techdocs.publisher.local.publishDirectory',\n );\n if (!staticDocsDir) {\n try {\n staticDocsDir = resolvePackagePath(\n '@backstage/plugin-techdocs-backend',\n 'static/docs',\n );\n } catch (err) {\n // This will most probably never be used.\n // The try/catch is introduced so that techdocs-cli can import @backstage/plugin-techdocs-node\n // on CI/CD without installing techdocs backend plugin.\n staticDocsDir = os.tmpdir();\n }\n }\n\n return new LocalPublish({\n logger,\n discovery,\n legacyPathCasing,\n staticDocsDir,\n });\n }\n\n async getReadiness(): Promise<ReadinessResponse> {\n return {\n isAvailable: true,\n };\n }\n\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const entityNamespace = entity.metadata.namespace ?? 'default';\n let publishDir: string;\n\n try {\n publishDir = this.staticEntityPathJoin(\n entityNamespace,\n entity.kind,\n entity.metadata.name,\n );\n } catch (error) {\n throw new ForwardedError(\n `Unable to publish TechDocs site for entity: ${stringifyEntityRef(\n entity,\n )}`,\n error,\n );\n }\n\n if (!fs.existsSync(publishDir)) {\n this.logger.info(`Could not find ${publishDir}, creating the directory.`);\n fs.mkdirSync(publishDir, { recursive: true });\n }\n\n try {\n await fs.copy(directory, publishDir);\n this.logger.info(`Published site stored at ${publishDir}`);\n } catch (error) {\n this.logger.debug(\n `Failed to copy docs from ${directory} to ${publishDir}`,\n );\n throw error;\n }\n\n // Generate publish response.\n const techdocsApiUrl = await this.discovery.getBaseUrl('techdocs');\n const publishedFilePaths = (await getFileTreeRecursively(publishDir)).map(\n abs => {\n return abs.split(`${this.staticDocsDir}/`)[1];\n },\n );\n\n return {\n remoteUrl: `${techdocsApiUrl}/static/docs/${encodeURIComponent(\n entity.metadata.name,\n )}`,\n objects: publishedFilePaths,\n };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n let metadataPath: string;\n\n try {\n metadataPath = this.staticEntityPathJoin(\n entityName.namespace,\n entityName.kind,\n entityName.name,\n 'techdocs_metadata.json',\n );\n } catch (err) {\n throw new ForwardedError(\n `Unexpected entity when fetching metadata: ${stringifyEntityRef(\n entityName,\n )}`,\n err,\n );\n }\n\n try {\n return await fs.readJson(metadataPath);\n } catch (err) {\n throw new ForwardedError(\n `Unable to read techdocs_metadata.json at ${metadataPath}. Error: ${err}`,\n err,\n );\n }\n }\n\n docsRouter(): express.Handler {\n const router = express.Router();\n\n // Redirect middleware ensuring that requests to case-sensitive entity\n // triplet paths are always sent to lower-case versions.\n router.use((req, res, next) => {\n // If legacy path casing is on, let the request immediately continue.\n if (this.legacyPathCasing) {\n return next();\n }\n\n // Generate a lower-case entity triplet path.\n const [_, namespace, kind, name, ...rest] = req.path.split('/');\n\n // Ignore non-triplet objects.\n if (!namespace || !kind || !name) {\n return next();\n }\n\n const newPath = [\n _,\n namespace.toLowerCase(),\n kind.toLowerCase(),\n name.toLowerCase(),\n ...rest,\n ].join('/');\n\n // If there was no change, then let express.static() handle the request.\n if (newPath === req.path) {\n return next();\n }\n\n // Otherwise, redirect to the new path.\n return res.redirect(301, req.baseUrl + newPath);\n });\n router.use(\n express.static(this.staticDocsDir, {\n // Handle content-type header the same as all other publishers.\n setHeaders: (res, filePath) => {\n const fileExtension = path.extname(filePath);\n const headers = getHeadersForFileExtension(fileExtension);\n for (const [header, value] of Object.entries(headers)) {\n res.setHeader(header, value);\n }\n },\n }),\n );\n\n return router;\n }\n\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const namespace = entity.metadata.namespace ?? 'default';\n\n // Check if the file exists\n try {\n const indexHtmlPath = this.staticEntityPathJoin(\n namespace,\n entity.kind,\n entity.metadata.name,\n 'index.html',\n );\n\n await fs.access(indexHtmlPath, fs.constants.F_OK);\n\n return true;\n } catch (err) {\n if (err.name === 'NotAllowedError') {\n this.logger.error(\n `Unexpected entity when checking if generated: ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n return false;\n }\n }\n\n /**\n * This code will never run in practice. It is merely here to illustrate how\n * to implement this method for other storage providers.\n */\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const files = await getFileTreeRecursively(this.staticDocsDir);\n const limit = createLimiter(concurrency);\n\n await Promise.all(\n files.map(f =>\n limit(async file => {\n const relativeFile = file.replace(\n `${this.staticDocsDir}${path.sep}`,\n '',\n );\n const newFile = lowerCaseEntityTripletInStoragePath(relativeFile);\n\n // If all parts are already lowercase, ignore.\n if (relativeFile === newFile) {\n return;\n }\n\n // Otherwise, copy or move the file.\n await new Promise<void>(resolve => {\n const migrate = removeOriginal ? fs.move : fs.copyFile;\n this.logger.verbose(`Migrating ${relativeFile}`);\n migrate(file, newFile, err => {\n if (err) {\n this.logger.warn(\n `Unable to migrate ${relativeFile}: ${err.message}`,\n );\n }\n resolve();\n });\n });\n }, f),\n ),\n );\n }\n\n /**\n * Utility wrapper around path.join(), used to control legacy case logic.\n */\n protected staticEntityPathJoin(...allParts: string[]): string {\n let staticEntityPath = this.staticDocsDir;\n\n allParts\n .map(part => part.split(path.sep))\n .flat()\n .forEach((part, index) => {\n // Respect legacy path casing when operating on namespace, kind, or name.\n if (index < 3) {\n staticEntityPath = resolveSafeChildPath(\n staticEntityPath,\n this.legacyPathCasing ? part : part.toLowerCase(),\n );\n return;\n }\n\n // Otherwise, respect the provided case.\n staticEntityPath = resolveSafeChildPath(staticEntityPath, part);\n });\n\n return staticEntityPath;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { SwiftClient } from '@trendyol-js/openstack-swift-sdk';\nimport { NotFound } from '@trendyol-js/openstack-swift-sdk/lib/types';\nimport { Stream, Readable } from 'stream';\nimport { Logger } from 'winston';\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { assertError, ForwardedError } from '@backstage/errors';\n\nconst streamToBuffer = (stream: Stream | Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', reject);\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nconst bufferToStream = (buffer: Buffer): Readable => {\n const stream = new Readable();\n stream.push(buffer);\n stream.push(null);\n return stream;\n};\n\nexport class OpenStackSwiftPublish implements PublisherBase {\n private readonly storageClient: SwiftClient;\n private readonly containerName: string;\n private readonly logger: Logger;\n\n constructor(options: {\n storageClient: SwiftClient;\n containerName: string;\n logger: Logger;\n }) {\n this.storageClient = options.storageClient;\n this.containerName = options.containerName;\n this.logger = options.logger;\n }\n\n static fromConfig(config: Config, logger: Logger): PublisherBase {\n let containerName = '';\n try {\n containerName = config.getString(\n 'techdocs.publisher.openStackSwift.containerName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'openStackSwift' in your app config, \" +\n 'techdocs.publisher.openStackSwift.containerName is required.',\n );\n }\n\n const openStackSwiftConfig = config.getConfig(\n 'techdocs.publisher.openStackSwift',\n );\n\n const storageClient = new SwiftClient({\n authEndpoint: openStackSwiftConfig.getString('authUrl'),\n swiftEndpoint: openStackSwiftConfig.getString('swiftUrl'),\n credentialId: openStackSwiftConfig.getString('credentials.id'),\n secret: openStackSwiftConfig.getString('credentials.secret'),\n });\n\n return new OpenStackSwiftPublish({ storageClient, containerName, logger });\n }\n\n /*\n * Check if the defined container exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n const container = await this.storageClient.getContainerMetadata(\n this.containerName,\n );\n\n if (!(container instanceof NotFound)) {\n this.logger.info(\n `Successfully connected to the OpenStack Swift container ${this.containerName}.`,\n );\n return {\n isAvailable: true,\n };\n }\n this.logger.error(\n `Could not retrieve metadata about the OpenStack Swift container ${this.containerName}. ` +\n 'Make sure the container exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.openStackSwift in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n return {\n isAvailable: false,\n };\n } catch (err) {\n assertError(err);\n this.logger.error(`from OpenStack client library: ${err.message}`);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the OpenStack Swift container.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n try {\n const objects: string[] = [];\n\n // Note: OpenStack Swift manages creation of parent directories if they do not exist.\n // So collecting path of only the files is good enough.\n const allFilesToUpload = await getFileTreeRecursively(directory);\n const limiter = createLimiter(10);\n const uploadPromises: Array<Promise<unknown>> = [];\n for (const filePath of allFilesToUpload) {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n const relativeFilePath = path.relative(directory, filePath);\n // Convert destination file path to a POSIX path for uploading.\n // Swift expects / as path separator and relativeFilePath will contain \\\\ on Windows.\n // https://docs.openstack.org/python-openstackclient/pike/cli/man/openstack.html\n const relativeFilePathPosix = relativeFilePath\n .split(path.sep)\n .join(path.posix.sep);\n\n // The / delimiter is intentional since it represents the cloud storage and not the local file system.\n const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const destination = `${entityRootDir}/${relativeFilePathPosix}`; // Swift container file relative path\n objects.push(destination);\n\n // Rate limit the concurrent execution of file uploads to batches of 10 (per publish)\n const uploadFile = limiter(async () => {\n const fileBuffer = await fs.readFile(filePath);\n const stream = bufferToStream(fileBuffer);\n return this.storageClient.upload(\n this.containerName,\n destination,\n stream,\n );\n });\n uploadPromises.push(uploadFile);\n }\n await Promise.all(uploadPromises);\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${allFilesToUpload.length}`,\n );\n return { objects };\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to OpenStack Swift. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityRootDir = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n\n const downloadResponse = await this.storageClient.download(\n this.containerName,\n `${entityRootDir}/techdocs_metadata.json`,\n );\n\n if (!(downloadResponse instanceof NotFound)) {\n const stream = downloadResponse.data;\n try {\n const techdocsMetadataJson = await streamToBuffer(stream);\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n } else {\n reject({\n message: `TechDocs metadata fetch failed, The file /rootDir/${entityRootDir}/techdocs_metadata.json does not exist !`,\n });\n }\n });\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n // Decode and trim the leading forward slash\n // filePath example - /default/Component/documented-component/index.html\n const filePath = decodeURI(req.path.replace(/^\\//, ''));\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n const downloadResponse = await this.storageClient.download(\n this.containerName,\n filePath,\n );\n\n if (!(downloadResponse instanceof NotFound)) {\n const stream = downloadResponse.data;\n\n try {\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n res.send(await streamToBuffer(stream));\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs OpenStack swift router failed to serve content from container ${this.containerName} at path ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n } else {\n this.logger.warn(\n `TechDocs OpenStack swift router failed to serve content from container ${this.containerName} at path ${filePath}: Not found`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n try {\n const fileResponse = await this.storageClient.getMetadata(\n this.containerName,\n `${entityRootDir}/index.html`,\n );\n\n if (!(fileResponse instanceof NotFound)) {\n return true;\n }\n return false;\n } catch (err) {\n assertError(err);\n this.logger.warn(err.message);\n return false;\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromContainer();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.verbose(`Migrating ${file} to ${newPath}`);\n await this.storageClient.copy(\n this.containerName,\n file,\n this.containerName,\n newPath,\n );\n if (removeOriginal) {\n await this.storageClient.delete(this.containerName, file);\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured container.\n */\n protected async getAllObjectsFromContainer(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n let objects: string[] = [];\n const OSS_MAX_LIMIT = Math.pow(2, 31) - 1;\n\n const allObjects = await this.storageClient.list(\n this.containerName,\n prefix,\n OSS_MAX_LIMIT,\n );\n objects = allObjects.map((object: any) => object.name);\n\n return objects;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { AwsS3Publish } from './awsS3';\nimport { AzureBlobStoragePublish } from './azureBlobStorage';\nimport { GoogleGCSPublish } from './googleStorage';\nimport { LocalPublish } from './local';\nimport { OpenStackSwiftPublish } from './openStackSwift';\nimport {\n PublisherFactory,\n PublisherBase,\n PublisherType,\n PublisherBuilder,\n} from './types';\n\n/**\n * Factory class to create a TechDocs publisher based on defined publisher type in app config.\n * Uses `techdocs.publisher.type`.\n * @public\n */\nexport class Publisher implements PublisherBuilder {\n private publishers: Map<PublisherType | 'techdocs', PublisherBase> =\n new Map();\n\n register(type: PublisherType | 'techdocs', publisher: PublisherBase): void {\n this.publishers.set(type, publisher);\n }\n\n get(config: Config): PublisherBase {\n const publisherType = (config.getOptionalString(\n 'techdocs.publisher.type',\n ) ?? 'local') as PublisherType;\n\n if (!publisherType) {\n throw new Error('TechDocs publisher type not specified for the entity');\n }\n\n const publisher = this.publishers.get(publisherType);\n if (!publisher) {\n throw new Error(\n `TechDocs publisher '${publisherType}' is not registered`,\n );\n }\n\n return publisher;\n }\n\n /**\n * Returns a instance of TechDocs publisher\n * @param config - A Backstage configuration\n * @param options - Options for configuring the publisher factory\n */\n static async fromConfig(\n config: Config,\n options: PublisherFactory,\n ): Promise<PublisherBase> {\n const { logger, discovery, customPublisher } = options;\n\n const publishers = new Publisher();\n\n if (customPublisher) {\n publishers.register('techdocs', customPublisher);\n return customPublisher;\n }\n\n const publisherType = (config.getOptionalString(\n 'techdocs.publisher.type',\n ) ?? 'local') as PublisherType;\n\n switch (publisherType) {\n case 'googleGcs':\n logger.info('Creating Google Storage Bucket publisher for TechDocs');\n publishers.register(\n publisherType,\n GoogleGCSPublish.fromConfig(config, logger),\n );\n break;\n case 'awsS3':\n logger.info('Creating AWS S3 Bucket publisher for TechDocs');\n publishers.register(\n publisherType,\n await AwsS3Publish.fromConfig(config, logger),\n );\n break;\n case 'azureBlobStorage':\n logger.info(\n 'Creating Azure Blob Storage Container publisher for TechDocs',\n );\n publishers.register(\n publisherType,\n AzureBlobStoragePublish.fromConfig(config, logger),\n );\n break;\n case 'openStackSwift':\n logger.info(\n 'Creating OpenStack Swift Container publisher for TechDocs',\n );\n publishers.register(\n publisherType,\n OpenStackSwiftPublish.fromConfig(config, logger),\n );\n break;\n case 'local':\n logger.info('Creating Local publisher for TechDocs');\n publishers.register(\n publisherType,\n LocalPublish.fromConfig(config, logger, discovery),\n );\n break;\n default:\n logger.info('Creating Local publisher for TechDocs');\n publishers.register(\n publisherType,\n LocalPublish.fromConfig(config, logger, discovery),\n );\n }\n\n return publishers.get(config);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { DocsBuildStrategy } from './techdocsTypes';\nimport {\n PreparerBase,\n PublisherBase,\n PublisherType,\n RemoteProtocol,\n TechdocsGenerator,\n} from './stages';\nimport * as winston from 'winston';\n\n/**\n * Extension point type for configuring Techdocs builds.\n *\n * @public\n */\nexport interface TechdocsBuildsExtensionPoint {\n setBuildStrategy(buildStrategy: DocsBuildStrategy): void;\n setBuildLogTransport(transport: winston.transport): void;\n}\n\n/**\n * Extension point for configuring Techdocs builds.\n *\n * @public\n */\nexport const techdocsBuildsExtensionPoint =\n createExtensionPoint<TechdocsBuildsExtensionPoint>({\n id: 'techdocs.builds',\n });\n\n/**\n * Extension point type for configuring a custom Techdocs generator\n *\n * @public\n */\nexport interface TechdocsGeneratorExtensionPoint {\n setTechdocsGenerator(generator: TechdocsGenerator): void;\n}\n\n/**\n * Extension point for configuring a custom Techdocs generator\n *\n * @public\n */\nexport const techdocsGeneratorExtensionPoint =\n createExtensionPoint<TechdocsGeneratorExtensionPoint>({\n id: 'techdocs.generator',\n });\n\n/**\n * Extension point type for configuring a custom Techdocs preparer\n *\n * @public\n */\nexport interface TechdocsPreparerExtensionPoint {\n registerPreparer(protocol: RemoteProtocol, preparer: PreparerBase): void;\n}\n\n/**\n * Extension point for configuring a custom Techdocs preparer\n *\n * @public\n */\nexport const techdocsPreparerExtensionPoint =\n createExtensionPoint<TechdocsPreparerExtensionPoint>({\n id: 'techdocs.preparer',\n });\n\n/**\n * Extension point type for configuring a custom Techdocs publisher\n *\n * @public\n */\nexport interface TechdocsPublisherExtensionPoint {\n registerPublisher(type: PublisherType, publisher: PublisherBase): void;\n}\n\n/**\n * Extension point for configuring a custom Techdocs publisher\n *\n * @public\n */\nexport const techdocsPublisherExtensionPoint =\n createExtensionPoint<TechdocsPublisherExtensionPoint>({\n id: 'techdocs.publisher',\n });\n"],"names":["mime","recursiveReadDir","path","DEFAULT_NAMESPACE","createLimiter","PassThrough","spawn","gitUrlParse","DEFAULT_SCHEMA","Type","fs","yaml","ForwardedError","isChildPath","resolvePath","assertError","promisify","pipelineStream","Docker","ScmIntegrations","getMkdocsYml","InputError","parseLocationRef","getEntitySourceLocation","resolveSafeChildPath","TECHDOCS_ANNOTATION","streamToBuffer","DefaultAwsCredentialsManager","S3Client","NodeHttpHandler","HttpsProxyAgent","fromTemporaryCredentials","HeadBucketCommand","Upload","DeleteObjectCommand","GetObjectCommand","JSON5","HeadObjectCommand","CopyObjectCommand","ListObjectsV2Command","BlobServiceClient","StorageSharedKeyCredential","DefaultAzureCredential","platformPath","limiterFactory","Writable","Storage","resolvePackagePath","os","stringifyEntityRef","express","stream","Readable","SwiftClient","NotFound","createExtensionPoint"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/stages/publish/helpers.ts","../src/stages/generate/helpers.ts","../src/stages/generate/mkdocsPatchers.ts","../src/stages/generate/DockerContainerRunner.ts","../src/stages/generate/techdocs.ts","../src/stages/generate/generators.ts","../src/stages/generate/index.ts","../src/helpers.ts","../src/stages/prepare/dir.ts","../src/stages/prepare/url.ts","../src/stages/prepare/preparers.ts","../src/stages/publish/awsS3.ts","../src/stages/publish/azureBlobStorage.ts","../src/stages/publish/migrations/GoogleMigration.ts","../src/stages/publish/googleStorage.ts","../src/stages/publish/local.ts","../src/stages/publish/openStackSwift.ts","../src/stages/publish/publish.ts","../src/extensions.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport mime from 'mime-types';\nimport path from 'path';\nimport createLimiter from 'p-limit';\nimport recursiveReadDir from 'recursive-readdir';\n\n/**\n * Helper to get the expected content-type for a given file extension. Also\n * takes XSS mitigation into account.\n */\nconst getContentTypeForExtension = (ext: string): string => {\n const defaultContentType = 'text/plain; charset=utf-8';\n\n // Prevent sanitization bypass by preventing browsers from directly rendering\n // the contents of untrusted files.\n if (ext.match(/htm|xml|svg/i)) {\n return defaultContentType;\n }\n\n return mime.contentType(ext) || defaultContentType;\n};\n\nexport type responseHeadersType = {\n 'Content-Type': string;\n};\n\n/**\n * Some files need special headers to be used correctly by the frontend. This function\n * generates headers in the response to those file requests.\n * @param fileExtension - .html, .css, .js, .png etc.\n */\nexport const getHeadersForFileExtension = (\n fileExtension: string,\n): responseHeadersType => {\n return {\n 'Content-Type': getContentTypeForExtension(fileExtension),\n };\n};\n\n/**\n * Recursively traverse all the sub-directories of a path and return\n * a list of absolute paths of all the files. e.g. tree command in Unix\n *\n * @example\n *\n * /User/username/my_dir\n * dirA\n * | subDirA\n * | | file1\n * EmptyDir\n * dirB\n * | file2\n * file3\n *\n * getFileListRecursively('/Users/username/myDir')\n * // returns\n * [\n * '/User/username/my_dir/dirA/subDirA/file1',\n * '/User/username/my_dir/dirB/file2',\n * '/User/username/my_dir/file3'\n * ]\n * @param rootDirPath - Absolute path to the root directory.\n */\nexport const getFileTreeRecursively = async (\n rootDirPath: string,\n): Promise<string[]> => {\n // Iterate on all the files in the directory and its sub-directories\n const fileList = await recursiveReadDir(rootDirPath).catch(error => {\n throw new Error(`Failed to read template directory: ${error.message}`);\n });\n return fileList;\n};\n\n/**\n * Takes a posix path and returns a lower-cased version of entity's triplet\n * with the remaining path in posix.\n *\n * Path must not include a starting slash.\n *\n * @example\n * lowerCaseEntityTriplet('default/Component/backstage')\n * // return default/component/backstage\n */\nexport const lowerCaseEntityTriplet = (posixPath: string): string => {\n const [namespace, kind, name, ...rest] = posixPath.split(path.posix.sep);\n const lowerNamespace = namespace.toLowerCase();\n const lowerKind = kind.toLowerCase();\n const lowerName = name.toLowerCase();\n return [lowerNamespace, lowerKind, lowerName, ...rest].join(path.posix.sep);\n};\n\n/**\n * Takes either a win32 or posix path and returns a lower-cased version of entity's triplet\n * with the remaining path in posix.\n *\n * Starting slashes will be trimmed.\n *\n * Throws an error if the path does not appear to be an entity triplet.\n *\n * @example\n * lowerCaseEntityTripletInStoragePath('/default/Component/backstage/file.txt')\n * // return default/component/backstage/file.txt\n */\nexport const lowerCaseEntityTripletInStoragePath = (\n originalPath: string,\n): string => {\n let posixPath = originalPath;\n if (originalPath.includes(path.win32.sep)) {\n posixPath = originalPath.split(path.win32.sep).join(path.posix.sep);\n }\n\n // remove leading slash\n const parts = posixPath.split(path.posix.sep);\n if (parts[0] === '') {\n parts.shift();\n }\n\n // check if all parts of the entity exist (name, namespace, kind) plus filename\n if (parts.length <= 3) {\n throw new Error(\n `Encountered file unmanaged by TechDocs ${originalPath}. Skipping.`,\n );\n }\n\n return lowerCaseEntityTriplet(parts.join(path.posix.sep));\n};\n\n/**\n * Take a posix path and return a path without leading and trailing\n * separators\n *\n * @example\n * normalizeExternalStorageRootPath('/backstage-data/techdocs/')\n * // return backstage-data/techdocs\n */\nexport const normalizeExternalStorageRootPath = (posixPath: string): string => {\n // remove leading slash\n let normalizedPath = posixPath;\n if (posixPath.startsWith(path.posix.sep)) {\n normalizedPath = posixPath.slice(1);\n }\n\n // remove trailing slash\n if (normalizedPath.endsWith(path.posix.sep)) {\n normalizedPath = normalizedPath.slice(0, normalizedPath.length - 1);\n }\n\n return normalizedPath;\n};\n\n// Only returns the files that existed previously and are not present anymore.\nexport const getStaleFiles = (\n newFiles: string[],\n oldFiles: string[],\n): string[] => {\n const staleFiles = new Set(oldFiles);\n const removedParentDirs = new Set();\n newFiles.forEach(newFile => {\n staleFiles.delete(newFile);\n\n // We have to traverse through the directory hierarchy of a new file and\n // ensure that we won't try to delete one of the parent directories.\n let parentDir = newFile.substring(0, newFile.lastIndexOf('/'));\n while (\n !removedParentDirs.has(parentDir) &&\n parentDir.length >= newFile.indexOf('/')\n ) {\n staleFiles.delete(parentDir);\n removedParentDirs.add(parentDir);\n parentDir = parentDir.substring(0, parentDir.lastIndexOf('/'));\n }\n });\n return Array.from(staleFiles);\n};\n\n// Compose actual filename on remote bucket including entity information\nexport const getCloudPathForLocalPath = (\n entity: Entity,\n localPath = '',\n useLegacyPathCasing = false,\n externalStorageRootPath = '',\n): string => {\n // Convert destination file path to a POSIX path for uploading.\n // GCS expects / as path separator and relativeFilePath will contain \\\\ on Windows.\n // https://cloud.google.com/storage/docs/gsutil/addlhelp/HowSubdirectoriesWork\n const relativeFilePathPosix = localPath.split(path.sep).join(path.posix.sep);\n\n // The / delimiter is intentional since it represents the cloud storage and not the local file system.\n const entityRootDir = `${entity.metadata?.namespace ?? DEFAULT_NAMESPACE}/${\n entity.kind\n }/${entity.metadata.name}`;\n\n const relativeFilePathTriplet = `${entityRootDir}/${relativeFilePathPosix}`;\n\n const destination = useLegacyPathCasing\n ? relativeFilePathTriplet\n : lowerCaseEntityTriplet(relativeFilePathTriplet);\n\n // Again, the / delimiter is intentional, as it represents remote storage.\n const destinationWithRoot = [\n // The extra filter prevents unintended double slashes and prefixes.\n ...externalStorageRootPath.split(path.posix.sep).filter(s => s !== ''),\n destination,\n ].join('/');\n\n return destinationWithRoot; // Remote storage file relative path\n};\n\n// Perform rate limited generic operations by passing a function and a list of arguments\nexport const bulkStorageOperation = async <T>(\n operation: (arg: T) => Promise<unknown>,\n args: T[],\n { concurrencyLimit } = { concurrencyLimit: 25 },\n) => {\n const limiter = createLimiter(concurrencyLimit);\n await Promise.all(args.map(arg => limiter(operation, arg)));\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isChildPath, LoggerService } from '@backstage/backend-plugin-api';\nimport { Entity } from '@backstage/catalog-model';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { SpawnOptionsWithoutStdio, spawn } from 'child_process';\nimport fs from 'fs-extra';\nimport gitUrlParse from 'git-url-parse';\nimport yaml, { DEFAULT_SCHEMA, Type } from 'js-yaml';\nimport path, { resolve as resolvePath } from 'path';\nimport { PassThrough, Writable } from 'stream';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport { DefaultMkdocsContent, SupportedGeneratorKey } from './types';\nimport { getFileTreeRecursively } from '../publish/helpers';\n\n// TODO: Implement proper support for more generators.\nexport function getGeneratorKey(entity: Entity): SupportedGeneratorKey {\n if (!entity) {\n throw new Error('No entity provided');\n }\n\n return 'techdocs';\n}\n\nexport type RunCommandOptions = {\n /** command to run */\n command: string;\n /** arguments to pass the command */\n args: string[];\n /** options to pass to spawn */\n options: SpawnOptionsWithoutStdio;\n /** stream to capture stdout and stderr output */\n logStream?: Writable;\n};\n\n/**\n * Run a command in a sub-process, normally a shell command.\n */\nexport const runCommand = async ({\n command,\n args,\n options,\n logStream = new PassThrough(),\n}: RunCommandOptions) => {\n await new Promise<void>((resolve, reject) => {\n const process = spawn(command, args, options);\n\n process.stdout.on('data', stream => {\n logStream.write(stream);\n });\n\n process.stderr.on('data', stream => {\n logStream.write(stream);\n });\n\n process.on('error', error => {\n return reject(error);\n });\n\n process.on('close', code => {\n if (code !== 0) {\n return reject(`Command ${command} failed, exit code: ${code}`);\n }\n return resolve();\n });\n });\n};\n\n/**\n * Return the source url for MkDocs based on the backstage.io/techdocs-ref annotation.\n * Depending on the type of target, it can either return a repo_url, an edit_uri, both, or none.\n *\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n * @param docsFolder - the configured docs folder in the mkdocs.yml (defaults to 'docs')\n * @returns the settings for the mkdocs.yml\n */\nexport const getRepoUrlFromLocationAnnotation = (\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n docsFolder: string = 'docs',\n): { repo_url?: string; edit_uri?: string } => {\n const { type: locationType, target } = parsedLocationAnnotation;\n\n if (locationType === 'url') {\n const integration = scmIntegrations.byUrl(target);\n\n // We only support it for github, gitlab, bitbucketServer and harness for now as the edit_uri\n // is not properly supported for others yet.\n if (\n integration &&\n ['github', 'gitlab', 'bitbucketServer', 'harness'].includes(\n integration.type,\n )\n ) {\n // handle the case where a user manually writes url:https://github.com/backstage/backstage i.e. without /blob/...\n const { filepathtype } = gitUrlParse(target);\n if (filepathtype === '') {\n return { repo_url: target };\n }\n\n const sourceFolder = integration.resolveUrl({\n url: `./${docsFolder}`,\n base: target.endsWith('/') ? target : `${target}/`,\n });\n return {\n repo_url: target,\n edit_uri: integration.resolveEditUrl(sourceFolder),\n };\n }\n }\n\n return {};\n};\n\nclass UnknownTag {\n constructor(public readonly data: any, public readonly type?: string) {}\n}\n\nexport const MKDOCS_SCHEMA = DEFAULT_SCHEMA.extend([\n new Type('', {\n kind: 'scalar',\n multi: true,\n representName: o => (o as UnknownTag).type,\n represent: o => (o as UnknownTag).data ?? '',\n instanceOf: UnknownTag,\n construct: (data: string, type?: string) => new UnknownTag(data, type),\n }),\n new Type('', {\n kind: 'sequence',\n multi: true,\n representName: o => (o as UnknownTag).type,\n represent: o => (o as UnknownTag).data ?? '',\n instanceOf: UnknownTag,\n construct: (data: string, type?: string) => new UnknownTag(data, type),\n }),\n]);\n\n/**\n * Generates a mkdocs.yml configuration file\n *\n * @param inputDir - base dir to where the mkdocs.yml file will be created\n * @param siteOptions - options for the site: `name` property will be used in mkdocs.yml for the\n * required `site_name` property, default value is \"Documentation Site\"\n */\nexport const generateMkdocsYml = async (\n inputDir: string,\n siteOptions?: { name?: string },\n) => {\n try {\n // TODO(awanlin): Use a provided default mkdocs.yml\n // from config or some specified location. If this is\n // not provided then fall back to generating bare\n // minimum mkdocs.yml file\n\n const mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml');\n const defaultSiteName = siteOptions?.name ?? 'Documentation Site';\n const defaultMkdocsContent: DefaultMkdocsContent = {\n site_name: defaultSiteName,\n docs_dir: 'docs',\n plugins: ['techdocs-core'],\n };\n\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(defaultMkdocsContent, { schema: MKDOCS_SCHEMA }),\n );\n } catch (error) {\n throw new ForwardedError('Could not generate mkdocs.yml file', error);\n }\n};\n\n/**\n * Finds and loads the contents of an mkdocs.yml, mkdocs.yaml file, a file\n * with a specified name or an ad-hoc created file with minimal config.\n * @public\n *\n * @param inputDir - base dir to be searched for either an mkdocs.yml or mkdocs.yaml file.\n * @param options - name: default mkdocs site_name to be used with a ad hoc file default value is \"Documentation Site\"\n * mkdocsConfigFileName (optional): a non-default file name to be used as the config\n */\nexport const getMkdocsYml = async (\n inputDir: string,\n options?: { name?: string; mkdocsConfigFileName?: string },\n): Promise<{ path: string; content: string; configIsTemporary: boolean }> => {\n let mkdocsYmlPath: string;\n let mkdocsYmlFileString: string;\n try {\n if (options?.mkdocsConfigFileName) {\n mkdocsYmlPath = path.join(inputDir, options.mkdocsConfigFileName);\n if (!(await fs.pathExists(mkdocsYmlPath))) {\n throw new Error(`The specified file ${mkdocsYmlPath} does not exist`);\n }\n\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n mkdocsYmlPath = path.join(inputDir, 'mkdocs.yaml');\n if (await fs.pathExists(mkdocsYmlPath)) {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n mkdocsYmlPath = path.join(inputDir, 'mkdocs.yml');\n if (await fs.pathExists(mkdocsYmlPath)) {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: false,\n };\n }\n\n // No mkdocs file, generate it\n await generateMkdocsYml(inputDir, options);\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n throw new ForwardedError(\n 'Could not read MkDocs YAML config file mkdocs.yml or mkdocs.yaml or default for validation',\n error,\n );\n }\n\n return {\n path: mkdocsYmlPath,\n content: mkdocsYmlFileString,\n configIsTemporary: true,\n };\n};\n\n/**\n * Validating mkdocs config file for incorrect/insecure values\n * Throws on invalid configs\n *\n * @param inputDir - base dir to be used as a docs_dir path validity check\n * @param mkdocsYmlFileString - The string contents of the loaded\n * mkdocs.yml or equivalent of a docs site\n * @returns the parsed docs_dir or undefined\n */\nexport const validateMkdocsYaml = async (\n inputDir: string,\n mkdocsYmlFileString: string,\n): Promise<string | undefined> => {\n const mkdocsYml = yaml.load(mkdocsYmlFileString, {\n schema: MKDOCS_SCHEMA,\n });\n\n if (mkdocsYml === null || typeof mkdocsYml !== 'object') {\n return undefined;\n }\n\n const parsedMkdocsYml: Record<string, any> = mkdocsYml;\n if (\n parsedMkdocsYml.docs_dir &&\n !isChildPath(inputDir, resolvePath(inputDir, parsedMkdocsYml.docs_dir))\n ) {\n throw new Error(\n `docs_dir configuration value in mkdocs can't be an absolute directory or start with ../ for security reasons.\n Use relative paths instead which are resolved relative to your mkdocs.yml file location.`,\n );\n }\n return parsedMkdocsYml.docs_dir;\n};\n\n/**\n * Update docs/index.md file before TechDocs generator uses it to generate docs site,\n * falling back to docs/README.md or README.md in case a default docs/index.md\n * is not provided.\n */\nexport const patchIndexPreBuild = async ({\n inputDir,\n logger,\n docsDir = 'docs',\n}: {\n inputDir: string;\n logger: LoggerService;\n docsDir?: string;\n}) => {\n const docsPath = path.join(inputDir, docsDir);\n const indexMdPath = path.join(docsPath, 'index.md');\n\n if (await fs.pathExists(indexMdPath)) {\n return;\n }\n logger.warn(`${path.join(docsDir, 'index.md')} not found.`);\n const fallbacks = [\n path.join(docsPath, 'README.md'),\n path.join(docsPath, 'readme.md'),\n path.join(inputDir, 'README.md'),\n path.join(inputDir, 'readme.md'),\n ];\n\n await fs.ensureDir(docsPath);\n for (const filePath of fallbacks) {\n try {\n await fs.copyFile(filePath, indexMdPath);\n return;\n } catch (error) {\n logger.warn(`${path.relative(inputDir, filePath)} not found.`);\n }\n }\n\n logger.warn(\n `Could not find any techdocs' index file. Please make sure at least one of ${[\n indexMdPath,\n ...fallbacks,\n ].join(' ')} exists.`,\n );\n};\n\n/**\n * Create or update the techdocs_metadata.json. Values initialized/updated are:\n * - The build_timestamp (now)\n * - The list of files generated\n *\n * @param techdocsMetadataPath - File path to techdocs_metadata.json\n */\nexport const createOrUpdateMetadata = async (\n techdocsMetadataPath: string,\n logger: LoggerService,\n): Promise<void> => {\n const techdocsMetadataDir = techdocsMetadataPath\n .split(path.sep)\n .slice(0, -1)\n .join(path.sep);\n // check if file exists, create if it does not.\n try {\n await fs.access(techdocsMetadataPath, fs.constants.F_OK);\n } catch (err) {\n // Bootstrap file with empty JSON\n await fs.writeJson(techdocsMetadataPath, JSON.parse('{}'));\n }\n // check if valid Json\n let json;\n try {\n json = await fs.readJson(techdocsMetadataPath);\n } catch (err) {\n assertError(err);\n const message = `Invalid JSON at ${techdocsMetadataPath} with error ${err.message}`;\n logger.error(message);\n throw new Error(message);\n }\n\n json.build_timestamp = Date.now();\n\n // Get and write generated files to the metadata JSON. Each file string is in\n // a form appropriate for invalidating the associated object from cache.\n try {\n json.files = (await getFileTreeRecursively(techdocsMetadataDir)).map(file =>\n file.replace(`${techdocsMetadataDir}${path.sep}`, ''),\n );\n } catch (err) {\n assertError(err);\n json.files = [];\n logger.warn(`Unable to add files list to metadata: ${err.message}`);\n }\n\n await fs.writeJson(techdocsMetadataPath, json);\n return;\n};\n\n/**\n * Update the techdocs_metadata.json to add etag of the prepared tree (e.g. commit SHA or actual Etag of the resource).\n * This is helpful to check if a TechDocs site in storage has gone outdated, without maintaining an in-memory build info\n * per Backstage instance.\n *\n * @param techdocsMetadataPath - File path to techdocs_metadata.json\n * @param etag - The ETag to use\n */\nexport const storeEtagMetadata = async (\n techdocsMetadataPath: string,\n etag: string,\n): Promise<void> => {\n const json = await fs.readJson(techdocsMetadataPath);\n json.etag = etag;\n await fs.writeJson(techdocsMetadataPath, json);\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport fs from 'fs-extra';\nimport yaml from 'js-yaml';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport { getRepoUrlFromLocationAnnotation, MKDOCS_SCHEMA } from './helpers';\nimport { assertError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype MkDocsObject = {\n plugins?: string[];\n docs_dir: string;\n repo_url?: string;\n edit_uri?: string;\n};\n\nconst patchMkdocsFile = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n updateAction: (mkdocsYml: MkDocsObject) => boolean,\n) => {\n // We only want to override the mkdocs.yml if it has actually changed. This is relevant if\n // used with a 'dir' location on the file system as this would permanently update the file.\n let didEdit = false;\n\n let mkdocsYmlFileString;\n try {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not read MkDocs YAML config file ${mkdocsYmlPath} before running the generator: ${error.message}`,\n );\n return;\n }\n\n let mkdocsYml: any;\n try {\n mkdocsYml = yaml.load(mkdocsYmlFileString, { schema: MKDOCS_SCHEMA });\n\n // mkdocsYml should be an object type after successful parsing.\n // But based on its type definition, it can also be a string or undefined, which we don't want.\n if (typeof mkdocsYml === 'string' || typeof mkdocsYml === 'undefined') {\n throw new Error('Bad YAML format.');\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Error in parsing YAML at ${mkdocsYmlPath} before running the generator. ${error.message}`,\n );\n return;\n }\n\n didEdit = updateAction(mkdocsYml);\n\n try {\n if (didEdit) {\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(mkdocsYml, { schema: MKDOCS_SCHEMA }),\n 'utf8',\n );\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not write to ${mkdocsYmlPath} after updating it before running the generator. ${error.message}`,\n );\n return;\n }\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add repo_url or edit_uri if it does not exists\n * If mkdocs.yml has a repo_url, the generated docs site gets an Edit button on the pages by default.\n * If repo_url is missing in mkdocs.yml, we will use techdocs annotation of the entity to possibly get\n * the repository URL.\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n */\nexport const patchMkdocsYmlPreBuild = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n if (!('repo_url' in mkdocsYml) || !('edit_uri' in mkdocsYml)) {\n // Add edit_uri and/or repo_url to mkdocs.yml if it is missing.\n // This will enable the Page edit button generated by MkDocs.\n // If the either has been set, keep the original value\n const result = getRepoUrlFromLocationAnnotation(\n parsedLocationAnnotation,\n scmIntegrations,\n mkdocsYml.docs_dir,\n );\n\n if (result.repo_url || result.edit_uri) {\n mkdocsYml.repo_url = mkdocsYml.repo_url || result.repo_url;\n mkdocsYml.edit_uri = mkdocsYml.edit_uri || result.edit_uri;\n\n logger.info(\n `Set ${JSON.stringify(\n result,\n )}. 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`,\n );\n return true;\n }\n }\n return false;\n });\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add all provided default plugins\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param defaultPlugins - List of default mkdocs plugins\n */\nexport const patchMkdocsYmlWithPlugins = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n defaultPlugins: string[] = ['techdocs-core'],\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Modify mkdocs.yaml to contain the required default plugins.\n // If no plugins are defined we can just return the defaults.\n if (!('plugins' in mkdocsYml)) {\n mkdocsYml.plugins = defaultPlugins;\n return true;\n }\n\n // Otherwise, check each default plugin and include it if necessary.\n let changesMade = false;\n\n defaultPlugins.forEach(dp => {\n // if the plugin isn't there as a string, and isn't there as an object (which may itself contain extra config)\n // then we need to add it\n if (\n !(\n mkdocsYml.plugins!.includes(dp) ||\n mkdocsYml.plugins!.some(p => p.hasOwnProperty(dp))\n )\n ) {\n mkdocsYml.plugins = [...new Set([...mkdocsYml.plugins!, dp])];\n changesMade = true;\n }\n });\n\n return changesMade;\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Docker from 'dockerode';\nimport fs from 'fs-extra';\nimport { ForwardedError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { pipeline as pipelineStream } from 'stream';\nimport { promisify } from 'util';\nimport { Writable } from 'stream';\n\nconst pipeline = promisify(pipelineStream);\n\nexport type UserOptions = {\n User?: string;\n};\n\n/**\n * @internal\n */\nexport class DockerContainerRunner {\n private readonly dockerClient: Docker;\n\n constructor() {\n this.dockerClient = new Docker();\n }\n\n async runContainer(options: {\n imageName: string;\n command?: string | string[];\n args: string[];\n logStream?: Writable;\n mountDirs?: Record<string, string>;\n workingDir?: string;\n envVars?: Record<string, string>;\n pullImage?: boolean;\n defaultUser?: boolean;\n }) {\n const {\n imageName,\n command,\n args,\n logStream = new PassThrough(),\n mountDirs = {},\n workingDir,\n envVars = {},\n pullImage = true,\n defaultUser = false,\n } = options;\n\n // Show a better error message when Docker is unavailable.\n try {\n await this.dockerClient.ping();\n } catch (e) {\n throw new ForwardedError(\n 'This operation requires Docker. Docker does not appear to be available. Docker.ping() failed with',\n e,\n );\n }\n\n if (pullImage) {\n await new Promise<void>((resolve, reject) => {\n this.dockerClient.pull(imageName, {}, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n pipeline(stream, logStream, { end: false })\n .then(resolve)\n .catch(reject);\n });\n });\n }\n\n const userOptions: UserOptions = {};\n if (!defaultUser && process.getuid && process.getgid) {\n // Files that are created inside the Docker container will be owned by\n // root on the host system on non Mac systems, because of reasons. Mainly the fact that\n // volume sharing is done using NFS on Mac and actual mounts in Linux world.\n // So we set the user in the container as the same user and group id as the host.\n // On Windows we don't have process.getuid nor process.getgid\n userOptions.User = `${process.getuid()}:${process.getgid()}`;\n }\n\n // Initialize volumes to mount based on mountDirs map\n const Volumes: { [T: string]: object } = {};\n for (const containerDir of Object.values(mountDirs)) {\n Volumes[containerDir] = {};\n }\n\n // Create bind volumes\n const Binds: string[] = [];\n for (const [hostDir, containerDir] of Object.entries(mountDirs)) {\n // Need to use realpath here as Docker mounting does not like\n // symlinks for binding volumes\n const realHostDir = await fs.realpath(hostDir);\n Binds.push(`${realHostDir}:${containerDir}`);\n }\n\n // Create docker environment variables array\n const Env = [];\n for (const [key, value] of Object.entries(envVars)) {\n Env.push(`${key}=${value}`);\n }\n\n const [{ Error: error, StatusCode: statusCode }] =\n await this.dockerClient.run(imageName, args, logStream, {\n Volumes,\n HostConfig: {\n AutoRemove: true,\n Binds,\n },\n ...(workingDir ? { WorkingDir: workingDir } : {}),\n Entrypoint: command,\n Env,\n ...userOptions,\n } as Docker.ContainerCreateOptions);\n\n if (error) {\n throw new Error(\n `Docker failed to run with the following error message: ${error}`,\n );\n }\n\n if (statusCode !== 0) {\n throw new Error(\n `Docker container returned a non-zero exit code (${statusCode})`,\n );\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'path';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n createOrUpdateMetadata,\n getMkdocsYml,\n patchIndexPreBuild,\n runCommand,\n storeEtagMetadata,\n validateMkdocsYaml,\n} from './helpers';\n\nimport {\n patchMkdocsYmlPreBuild,\n patchMkdocsYmlWithPlugins,\n} from './mkdocsPatchers';\nimport {\n GeneratorBase,\n GeneratorConfig,\n GeneratorOptions,\n GeneratorRunInType,\n GeneratorRunOptions,\n} from './types';\nimport { ForwardedError } from '@backstage/errors';\nimport { DockerContainerRunner } from './DockerContainerRunner';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TechDocsContainerRunner } from '../publish/types';\n\n/**\n * Generates documentation files\n * @public\n */\nexport class TechdocsGenerator implements GeneratorBase {\n /**\n * The default docker image (and version) used to generate content. Public\n * and static so that techdocs-node consumers can use the same version.\n */\n public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.4';\n private readonly logger: LoggerService;\n private readonly containerRunner?: TechDocsContainerRunner;\n private readonly options: GeneratorConfig;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n\n /**\n * Returns a instance of TechDocs generator\n * @param config - A Backstage configuration\n * @param options - Options to configure the generator\n */\n static fromConfig(config: Config, options: GeneratorOptions) {\n const { containerRunner, logger } = options;\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n return new TechdocsGenerator({\n logger,\n containerRunner,\n config,\n scmIntegrations,\n });\n }\n\n constructor(options: {\n logger: LoggerService;\n containerRunner?: TechDocsContainerRunner;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n }) {\n this.logger = options.logger;\n this.options = readGeneratorConfig(options.config, options.logger);\n this.containerRunner = options.containerRunner;\n this.scmIntegrations = options.scmIntegrations;\n }\n\n /** {@inheritDoc GeneratorBase.run} */\n public async run(options: GeneratorRunOptions): Promise<void> {\n const {\n inputDir,\n outputDir,\n parsedLocationAnnotation,\n etag,\n logger: childLogger,\n logStream,\n siteOptions,\n runAsDefaultUser,\n } = options;\n\n // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url\n const { path: mkdocsYmlPath, content } = await getMkdocsYml(\n inputDir,\n siteOptions,\n );\n\n // validate the docs_dir first\n const docsDir = await validateMkdocsYaml(inputDir, content);\n\n if (parsedLocationAnnotation) {\n await patchMkdocsYmlPreBuild(\n mkdocsYmlPath,\n childLogger,\n parsedLocationAnnotation,\n this.scmIntegrations,\n );\n }\n\n if (this.options.legacyCopyReadmeMdToIndexMd) {\n await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir });\n }\n\n // patch the list of mkdocs plugins\n const defaultPlugins = this.options.defaultPlugins ?? [];\n\n if (\n !this.options.omitTechdocsCoreMkdocsPlugin &&\n !defaultPlugins.includes('techdocs-core')\n ) {\n defaultPlugins.push('techdocs-core');\n }\n\n await patchMkdocsYmlWithPlugins(mkdocsYmlPath, childLogger, defaultPlugins);\n\n // Directories to bind on container\n const mountDirs = {\n [inputDir]: '/input',\n [outputDir]: '/output',\n };\n\n try {\n switch (this.options.runIn) {\n case 'local':\n await runCommand({\n command: 'mkdocs',\n args: ['build', '-d', outputDir, '-v'],\n options: {\n cwd: inputDir,\n },\n logStream,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using local mkdocs`,\n );\n break;\n case 'docker': {\n const containerRunner =\n this.containerRunner || new DockerContainerRunner();\n await containerRunner.runContainer({\n imageName:\n this.options.dockerImage ?? TechdocsGenerator.defaultDockerImage,\n args: ['build', '-d', '/output'],\n logStream,\n mountDirs,\n workingDir: '/input',\n // Set the home directory inside the container as something that applications can\n // write to, otherwise they will just fail trying to write to /\n envVars: { HOME: '/tmp' },\n pullImage: this.options.pullImage,\n defaultUser: runAsDefaultUser,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using techdocs-container`,\n );\n break;\n }\n default:\n throw new Error(\n `Invalid config value \"${this.options.runIn}\" provided in 'techdocs.generators.techdocs'.`,\n );\n }\n } catch (error) {\n this.logger.debug(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n );\n throw new ForwardedError(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n error,\n );\n }\n\n /**\n * Post Generate steps\n */\n\n // Add build timestamp and files to techdocs_metadata.json\n // Creates techdocs_metadata.json if file does not exist.\n await createOrUpdateMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n childLogger,\n );\n\n // Add etag of the prepared tree to techdocs_metadata.json\n // Assumes that the file already exists.\n if (etag) {\n await storeEtagMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n etag,\n );\n }\n }\n}\n\nexport function readGeneratorConfig(\n config: Config,\n logger: LoggerService,\n): GeneratorConfig {\n const legacyGeneratorType = config.getOptionalString(\n 'techdocs.generators.techdocs',\n ) as GeneratorRunInType;\n\n if (legacyGeneratorType) {\n logger.warn(\n `The 'techdocs.generators.techdocs' configuration key is deprecated and will be removed in the future. Please use 'techdocs.generator' instead. ` +\n `See here https://backstage.io/docs/features/techdocs/configuration`,\n );\n }\n\n return {\n runIn:\n legacyGeneratorType ??\n config.getOptionalString('techdocs.generator.runIn') ??\n 'docker',\n dockerImage: config.getOptionalString('techdocs.generator.dockerImage'),\n pullImage: config.getOptionalBoolean('techdocs.generator.pullImage'),\n omitTechdocsCoreMkdocsPlugin: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.omitTechdocsCorePlugin',\n ),\n legacyCopyReadmeMdToIndexMd: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.legacyCopyReadmeMdToIndexMd',\n ),\n defaultPlugins: config.getOptionalStringArray(\n 'techdocs.generator.mkdocs.defaultPlugins',\n ),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { getGeneratorKey } from './helpers';\nimport { TechdocsGenerator } from './techdocs';\nimport {\n GeneratorBase,\n GeneratorBuilder,\n SupportedGeneratorKey,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TechDocsContainerRunner } from '../publish/types';\n\n/**\n * Collection of docs generators\n * @public\n */\nexport class Generators implements GeneratorBuilder {\n private generatorMap = new Map<SupportedGeneratorKey, GeneratorBase>();\n\n /**\n * Returns a generators instance containing a generator for TechDocs\n * @param config - A Backstage configuration\n * @param options - Options to configure the TechDocs generator\n */\n static async fromConfig(\n config: Config,\n options: {\n logger: LoggerService;\n containerRunner?: TechDocsContainerRunner;\n customGenerator?: TechdocsGenerator;\n },\n ): Promise<GeneratorBuilder> {\n const generators = new Generators();\n\n const techdocsGenerator =\n options.customGenerator ?? TechdocsGenerator.fromConfig(config, options);\n generators.register('techdocs', techdocsGenerator);\n\n return generators;\n }\n\n /**\n * Register a generator in the generators collection\n * @param generatorKey - Unique identifier for the generator\n * @param generator - The generator instance to register\n */\n register(generatorKey: SupportedGeneratorKey, generator: GeneratorBase) {\n this.generatorMap.set(generatorKey, generator);\n }\n\n /**\n * Returns the generator for a given TechDocs entity\n * @param entity - A TechDocs entity instance\n */\n get(entity: Entity): GeneratorBase {\n const generatorKey = getGeneratorKey(entity);\n const generator = this.generatorMap.get(generatorKey);\n\n if (!generator) {\n throw new Error(`No generator registered for entity: \"${generatorKey}\"`);\n }\n\n return generator;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport { TechdocsGenerator } from './techdocs';\nexport { Generators } from './generators';\nexport { getMkdocsYml } from './helpers';\nexport type {\n GeneratorBase,\n GeneratorOptions,\n GeneratorBuilder,\n GeneratorRunOptions,\n SupportedGeneratorKey,\n} from './types';\nimport { getMkdocsYml } from './helpers';\n/**\n * @public\n * @deprecated\n * Deprecated in favor of getMkdocsYml (lowercase 'd')\n */\nexport const getMkDocsYml = getMkdocsYml;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n UrlReaderService,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport {\n Entity,\n getEntitySourceLocation,\n parseLocationRef,\n} from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport path from 'path';\nimport { PreparerResponse, RemoteProtocol } from './stages/prepare/types';\n\n/**\n * Parsed location annotation\n * @public\n */\nexport type ParsedLocationAnnotation = {\n type: RemoteProtocol;\n target: string;\n};\n\n/**\n * Returns a parsed locations annotation\n * @public\n * @param annotationName - The name of the annotation in the entity metadata\n * @param entity - A TechDocs entity instance\n */\nexport const parseReferenceAnnotation = (\n annotationName: string,\n entity: Entity,\n): ParsedLocationAnnotation => {\n const annotation = entity.metadata.annotations?.[annotationName];\n if (!annotation) {\n throw new InputError(\n `No location annotation provided in entity: ${entity.metadata.name}`,\n );\n }\n\n const { type, target } = parseLocationRef(annotation);\n return {\n type: type as RemoteProtocol,\n target,\n };\n};\n\n/**\n * TechDocs references of type `dir` are relative the source location of the entity.\n * This function transforms relative references to absolute ones, based on the\n * location the entity was ingested from. If the entity was registered by a `url`\n * location, it returns a `url` location with a resolved target that points to the\n * targeted subfolder. If the entity was registered by a `file` location, it returns\n * an absolute `dir` location.\n * @public\n * @param entity - the entity with annotations\n * @param dirAnnotation - the parsed techdocs-ref annotation of type 'dir'\n * @param scmIntegrations - access to the scmIntegration to do url transformations\n * @throws if the entity doesn't specify a `dir` location or is ingested from an unsupported location.\n * @returns the transformed location with an absolute target.\n */\nexport const transformDirLocation = (\n entity: Entity,\n dirAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n): { type: 'dir' | 'url'; target: string } => {\n const location = getEntitySourceLocation(entity);\n\n switch (location.type) {\n case 'url': {\n const target = scmIntegrations.resolveUrl({\n url: dirAnnotation.target,\n base: location.target,\n });\n\n return {\n type: 'url',\n target,\n };\n }\n\n case 'file': {\n // only permit targets in the same folder as the target of the `file` location!\n const target = resolveSafeChildPath(\n path.dirname(location.target),\n dirAnnotation.target,\n );\n\n return {\n type: 'dir',\n target,\n };\n }\n\n default:\n throw new InputError(`Unable to resolve location type ${location.type}`);\n }\n};\n\n/**\n * Returns an entity reference based on the TechDocs annotation type\n * @public\n * @param entity - A TechDocs instance\n * @param scmIntegration - An implementation for SCM integration API\n */\nexport const getLocationForEntity = (\n entity: Entity,\n scmIntegration: ScmIntegrationRegistry,\n): ParsedLocationAnnotation => {\n const annotation = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n\n switch (annotation.type) {\n case 'url':\n return annotation;\n case 'dir':\n return transformDirLocation(entity, annotation, scmIntegration);\n default:\n throw new Error(`Invalid reference annotation ${annotation.type}`);\n }\n};\n\n/**\n * Returns a preparer response {@link PreparerResponse}\n * @public\n * @param reader - Read a tree of files from a repository\n * @param entity - A TechDocs entity instance\n * @param opts - Options for configuring the reader, e.g. logger, etag, etc.\n */\nexport const getDocFilesFromRepository = async (\n reader: UrlReaderService,\n entity: Entity,\n opts?: { etag?: string; logger?: LoggerService },\n): Promise<PreparerResponse> => {\n const { target } = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n\n opts?.logger?.debug(`Reading files from ${target}`);\n // readTree will throw NotModifiedError if etag has not changed.\n const readTreeResponse = await reader.readTree(target, { etag: opts?.etag });\n const preparedDir = await readTreeResponse.dir();\n\n opts?.logger?.debug(`Tree downloaded and stored at ${preparedDir}`);\n\n return {\n preparedDir,\n etag: readTreeResponse.etag,\n };\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport { parseReferenceAnnotation, transformDirLocation } from '../../helpers';\nimport {\n PreparerBase,\n PreparerConfig,\n PreparerOptions,\n PreparerResponse,\n} from './types';\nimport { LoggerService, UrlReaderService } from '@backstage/backend-plugin-api';\n\n/**\n * Preparer used to retrieve documentation files from a local directory\n * @public\n */\nexport class DirectoryPreparer implements PreparerBase {\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly reader: UrlReaderService;\n\n /**\n * Returns a directory preparer instance\n * @param config - A backstage config\n * @param options - A directory preparer options containing a logger and reader\n */\n static fromConfig(\n config: Config,\n options: PreparerConfig,\n ): DirectoryPreparer {\n return new DirectoryPreparer(config, options.logger, options.reader);\n }\n\n private constructor(\n config: Config,\n _logger: LoggerService | null,\n reader: UrlReaderService,\n ) {\n this.reader = reader;\n this.scmIntegrations = ScmIntegrations.fromConfig(config);\n }\n\n /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */\n shouldCleanPreparedDirectory() {\n return false;\n }\n\n /** {@inheritDoc PreparerBase.prepare} */\n async prepare(\n entity: Entity,\n options?: PreparerOptions,\n ): Promise<PreparerResponse> {\n const annotation = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n const { type, target } = transformDirLocation(\n entity,\n annotation,\n this.scmIntegrations,\n );\n\n switch (type) {\n case 'url': {\n options?.logger?.debug(`Reading files from ${target}`);\n // the target is an absolute url since it has already been transformed\n const response = await this.reader.readTree(target, {\n etag: options?.etag,\n });\n const preparedDir = await response.dir();\n\n options?.logger?.debug(`Tree downloaded and stored at ${preparedDir}`);\n\n return {\n preparedDir,\n etag: response.etag,\n };\n }\n\n case 'dir': {\n return {\n // the transformation already validated that the target is in a safe location\n preparedDir: target,\n // Instead of supporting caching on local sources, use techdocs-cli for local development and debugging.\n etag: '',\n };\n }\n\n default:\n throw new InputError(`Unable to resolve location type ${type}`);\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { Entity } from '@backstage/catalog-model';\nimport { getDocFilesFromRepository } from '../../helpers';\nimport {\n PreparerBase,\n PreparerConfig,\n PreparerOptions,\n PreparerResponse,\n} from './types';\nimport { LoggerService, UrlReaderService } from '@backstage/backend-plugin-api';\n\n/**\n * Preparer used to retrieve documentation files from a remote repository\n * @public\n */\nexport class UrlPreparer implements PreparerBase {\n private readonly logger: LoggerService;\n private readonly reader: UrlReaderService;\n\n /**\n * Returns a directory preparer instance\n * @param config - A URL preparer config containing the a logger and reader\n */\n static fromConfig(options: PreparerConfig): UrlPreparer {\n return new UrlPreparer(options.reader, options.logger);\n }\n\n private constructor(reader: UrlReaderService, logger: LoggerService) {\n this.logger = logger;\n this.reader = reader;\n }\n\n /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */\n shouldCleanPreparedDirectory() {\n return true;\n }\n\n /** {@inheritDoc PreparerBase.prepare} */\n async prepare(\n entity: Entity,\n options?: PreparerOptions,\n ): Promise<PreparerResponse> {\n try {\n return await getDocFilesFromRepository(this.reader, entity, {\n etag: options?.etag,\n logger: this.logger,\n });\n } catch (error) {\n assertError(error);\n // NotModifiedError means that etag based cache is still valid.\n if (error.name === 'NotModifiedError') {\n this.logger.debug(`Cache is valid for etag ${options?.etag}`);\n } else {\n this.logger.debug(\n `Unable to fetch files for building docs ${error.message}`,\n );\n }\n\n throw error;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport { parseReferenceAnnotation } from '../../helpers';\nimport { DirectoryPreparer } from './dir';\nimport { UrlPreparer } from './url';\nimport {\n PreparerBase,\n PreparerBuilder,\n PreparerConfig,\n RemoteProtocol,\n} from './types';\n\n/**\n * Collection of docs preparers (dir and url)\n * @public\n */\nexport class Preparers implements PreparerBuilder {\n private preparerMap = new Map<RemoteProtocol, PreparerBase>();\n\n /**\n * Returns a generators instance containing a generator for TechDocs\n * @public\n * @param backstageConfig - A Backstage configuration\n * @param preparerConfig - Options to configure preparers\n */\n static async fromConfig(\n backstageConfig: Config,\n options: PreparerConfig,\n ): Promise<PreparerBuilder> {\n const preparers = new Preparers();\n\n const urlPreparer = UrlPreparer.fromConfig({\n reader: options.reader,\n logger: options.logger,\n });\n preparers.register('url', urlPreparer);\n\n /**\n * Dir preparer is a syntactic sugar for users to define techdocs-ref annotation.\n * When using dir preparer, the docs will be fetched using URL Reader.\n */\n const directoryPreparer = DirectoryPreparer.fromConfig(backstageConfig, {\n reader: options.reader,\n logger: options.logger,\n });\n preparers.register('dir', directoryPreparer);\n\n return preparers;\n }\n\n /**\n * Register a preparer in the preparers collection\n * @param protocol - url or dir to associate with preparer\n * @param preparer - The preparer instance to set\n */\n register(protocol: RemoteProtocol, preparer: PreparerBase) {\n this.preparerMap.set(protocol, preparer);\n }\n\n /**\n * Returns the preparer for a given TechDocs entity\n * @param entity - A TechDocs entity instance\n * @returns\n */\n get(entity: Entity): PreparerBase {\n const { type } = parseReferenceAnnotation(TECHDOCS_ANNOTATION, entity);\n const preparer = this.preparerMap.get(type);\n\n if (!preparer) {\n throw new Error(`No preparer registered for type: \"${type}\"`);\n }\n\n return preparer;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n GetObjectCommand,\n CopyObjectCommand,\n DeleteObjectCommand,\n HeadBucketCommand,\n HeadObjectCommand,\n PutObjectCommandInput,\n ListObjectsV2CommandOutput,\n ListObjectsV2Command,\n S3Client,\n} from '@aws-sdk/client-s3';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { HttpsProxyAgent } from 'hpagent';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n getStaleFiles,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nexport class AwsS3Publish implements PublisherBase {\n private readonly storageClient: S3Client;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n private readonly bucketRootPath: string;\n private readonly sse?: 'aws:kms' | 'AES256';\n\n constructor(options: {\n storageClient: S3Client;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: LoggerService;\n bucketRootPath: string;\n sse?: 'aws:kms' | 'AES256';\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n this.sse = options.sse;\n }\n\n static async fromConfig(\n config: Config,\n logger: LoggerService,\n ): Promise<PublisherBase> {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.awsS3.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'awsS3' in your app config, \" +\n 'techdocs.publisher.awsS3.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.awsS3.bucketRootPath') || '',\n );\n\n const sse = config.getOptionalString('techdocs.publisher.awsS3.sse') as\n | 'aws:kms'\n | 'AES256'\n | undefined;\n\n // AWS Region is an optional config. If missing, default AWS env variable AWS_REGION\n // or AWS shared credentials file at ~/.aws/credentials will be used.\n const region = config.getOptionalString('techdocs.publisher.awsS3.region');\n\n // Credentials can optionally be configured by specifying the AWS account ID, which will retrieve credentials\n // for the account from the 'aws' section of the app config.\n // Credentials can also optionally be directly configured in the techdocs awsS3 config, but this method is\n // deprecated.\n // If no credentials are configured, the AWS SDK V3's default credential chain will be used.\n const accountId = config.getOptionalString(\n 'techdocs.publisher.awsS3.accountId',\n );\n const credentialsConfig = config.getOptionalConfig(\n 'techdocs.publisher.awsS3.credentials',\n );\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n const sdkCredentialProvider = await AwsS3Publish.buildCredentials(\n credsManager,\n accountId,\n credentialsConfig,\n region,\n );\n\n // AWS endpoint is an optional config. If missing, the default endpoint is built from\n // the configured region.\n const endpoint = config.getOptionalString(\n 'techdocs.publisher.awsS3.endpoint',\n );\n\n // AWS HTTPS proxy is an optional config. If missing, no proxy is used\n const httpsProxy = config.getOptionalString(\n 'techdocs.publisher.awsS3.httpsProxy',\n );\n\n // AWS forcePathStyle is an optional config. If missing, it defaults to false. Needs to be enabled for cases\n // where endpoint url points to locally hosted S3 compatible storage like Localstack\n const forcePathStyle = config.getOptionalBoolean(\n 'techdocs.publisher.awsS3.s3ForcePathStyle',\n );\n\n const storageClient = new S3Client({\n customUserAgent: 'backstage-aws-techdocs-s3-publisher',\n credentialDefaultProvider: () => sdkCredentialProvider,\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new AwsS3Publish({\n storageClient,\n bucketName,\n bucketRootPath,\n legacyPathCasing,\n logger,\n sse,\n });\n }\n\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return Promise.resolve({\n accessKeyId,\n secretAccessKey,\n });\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n accountId?: string,\n config?: Config,\n region?: string,\n ): Promise<AwsCredentialIdentityProvider> {\n // Pull credentials for the specified account ID from the 'aws' config section\n if (accountId) {\n return (await credsManager.getCredentialProvider({ accountId }))\n .sdkCredentialProvider;\n }\n\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!config) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n // Pull credentials from the techdocs config section (deprecated)\n const accessKeyId = config.getOptionalString('accessKeyId');\n const secretAccessKey = config.getOptionalString('secretAccessKey');\n const explicitCredentials: AwsCredentialIdentityProvider =\n accessKeyId && secretAccessKey\n ? AwsS3Publish.buildStaticCredentials(accessKeyId, secretAccessKey)\n : (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n\n const roleArn = config.getOptionalString('roleArn');\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-techdocs-s3-publisher',\n RoleArn: roleArn,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.send(\n new HeadBucketCommand({ Bucket: this.bucketName }),\n );\n\n this.logger.info(\n `Successfully connected to the AWS S3 bucket ${this.bucketName}.`,\n );\n\n return { isAvailable: true };\n } catch (error) {\n this.logger.error(\n `Could not retrieve metadata about the AWS S3 bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.awsS3 in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from AWS client library`, error);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the S3 bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucketRootPath = this.bucketRootPath;\n const sse = this.sse;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getAllObjectsFromBucket({\n prefix: remoteFolder,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const fileStream = fs.createReadStream(absoluteFilePath);\n\n const params: PutObjectCommandInput = {\n Bucket: this.bucketName,\n Key: getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n ),\n Body: fileStream,\n ...(sse && { ServerSideEncryption: sse }),\n };\n\n objects.push(params.Key!);\n\n const upload = new Upload({\n client: this.storageClient,\n params,\n });\n return upload.done();\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to AWS S3. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: relativeFilePath,\n }),\n );\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from AWS S3. ${error}`;\n this.logger.error(errorMessage);\n }\n return { objects };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n try {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/techdocs_metadata.json`,\n }),\n );\n\n const techdocsMetadataJson = await streamToBuffer(\n resp.Body as Readable,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n });\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({ Bucket: this.bucketName, Key: filePath }),\n );\n\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n res.send(await streamToBuffer(resp.Body as Readable));\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n try {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n await this.storageClient.send(\n new HeadObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/index.html`,\n }),\n );\n return Promise.resolve(true);\n } catch (e) {\n return Promise.resolve(false);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromBucket();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.debug(`Migrating ${file}`);\n await this.storageClient.send(\n new CopyObjectCommand({\n Bucket: this.bucketName,\n CopySource: [this.bucketName, file].join('/'),\n Key: newPath,\n }),\n );\n\n if (removeOriginal) {\n await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: file,\n }),\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured bucket.\n */\n protected async getAllObjectsFromBucket(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n const objects: string[] = [];\n let nextContinuation: string | undefined;\n let allObjects: ListObjectsV2CommandOutput;\n // Iterate through every file in the root of the publisher.\n do {\n allObjects = await this.storageClient.send(\n new ListObjectsV2Command({\n Bucket: this.bucketName,\n ContinuationToken: nextContinuation,\n ...(prefix ? { Prefix: prefix } : {}),\n }),\n );\n objects.push(\n ...(allObjects.Contents || []).map(f => f.Key || '').filter(f => !!f),\n );\n nextContinuation = allObjects.NextContinuationToken;\n } while (nextContinuation);\n\n return objects;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DefaultAzureCredential } from '@azure/identity';\nimport {\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport express from 'express';\nimport JSON5 from 'json5';\nimport limiterFactory from 'p-limit';\nimport { default as path, default as platformPath } from 'path';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTriplet,\n getStaleFiles,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// The number of batches that may be ongoing at the same time.\nconst BATCH_CONCURRENCY = 3;\n\nexport class AzureBlobStoragePublish implements PublisherBase {\n private readonly storageClient: BlobServiceClient;\n private readonly containerName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n\n constructor(options: {\n storageClient: BlobServiceClient;\n containerName: string;\n legacyPathCasing: boolean;\n logger: LoggerService;\n }) {\n this.storageClient = options.storageClient;\n this.containerName = options.containerName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n }\n\n static fromConfig(config: Config, logger: LoggerService): PublisherBase {\n let storageClient: BlobServiceClient;\n let containerName = '';\n try {\n containerName = config.getString(\n 'techdocs.publisher.azureBlobStorage.containerName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, \" +\n 'techdocs.publisher.azureBlobStorage.containerName is required.',\n );\n }\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n // Give more priority for connectionString, if configured, return the AzureBlobStoragePublish object here itself\n const connectionStringKey =\n 'techdocs.publisher.azureBlobStorage.connectionString';\n const connectionString = config.getOptionalString(connectionStringKey);\n\n if (connectionString) {\n logger.info(\n `Using '${connectionStringKey}' configuration to create storage client`,\n );\n storageClient = BlobServiceClient.fromConnectionString(connectionString);\n } else {\n let accountName = '';\n try {\n accountName = config.getString(\n 'techdocs.publisher.azureBlobStorage.credentials.accountName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, \" +\n 'techdocs.publisher.azureBlobStorage.credentials.accountName is required.',\n );\n }\n\n // Credentials is an optional config. If missing, default Azure Blob Storage environment variables will be used.\n // https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-app\n const accountKey = config.getOptionalString(\n 'techdocs.publisher.azureBlobStorage.credentials.accountKey',\n );\n\n let credential;\n if (accountKey) {\n credential = new StorageSharedKeyCredential(accountName, accountKey);\n } else {\n credential = new DefaultAzureCredential();\n }\n\n storageClient = new BlobServiceClient(\n `https://${accountName}.blob.core.windows.net`,\n credential,\n );\n }\n\n return new AzureBlobStoragePublish({\n storageClient: storageClient,\n containerName: containerName,\n legacyPathCasing: legacyPathCasing,\n logger: logger,\n });\n }\n\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n const response = await this.storageClient\n .getContainerClient(this.containerName)\n .getProperties();\n\n if (response._response.status === 200) {\n return {\n isAvailable: true,\n };\n }\n\n if (response._response.status >= 400) {\n this.logger.error(\n `Failed to retrieve metadata from ${response._response.request.url} with status code ${response._response.status}.`,\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.error(`from Azure Blob Storage client library: ${e.message}`);\n }\n\n this.logger.error(\n `Could not retrieve metadata about the Azure Blob Storage container ${this.containerName}. ` +\n 'Make sure that the Azure project and container exist and the access key is setup correctly ' +\n 'techdocs.publisher.azureBlobStorage.credentials defined in app config has correct permissions. ' +\n 'Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n\n return { isAvailable: false };\n }\n\n /**\n * Upload all the files from the generated `directory` to the Azure Blob Storage container.\n * Directory structure used in the container is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n\n // First, try to retrieve a list of all individual files currently existing\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n );\n let existingFiles: string[] = [];\n try {\n existingFiles = await this.getAllBlobsFromContainer({\n prefix: remoteFolder,\n maxPageSize: BATCH_CONCURRENCY,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n let container: ContainerClient;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n container = this.storageClient.getContainerClient(this.containerName);\n const failedOperations: Error[] = [];\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.normalize(\n path.relative(directory, absoluteFilePath),\n );\n const remotePath = getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n );\n objects.push(remotePath);\n const response = await container\n .getBlockBlobClient(remotePath)\n .uploadFile(absoluteFilePath);\n\n if (response._response.status >= 400) {\n failedOperations.push(\n new Error(\n `Upload failed for ${absoluteFilePath} with status code ${response._response.status}`,\n ),\n );\n }\n\n return response;\n },\n absoluteFilesToUpload,\n { concurrencyLimit: BATCH_CONCURRENCY },\n );\n\n if (failedOperations.length > 0) {\n throw new Error(\n failedOperations\n .map(r => r.message)\n .filter(Boolean)\n .join(' '),\n );\n }\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to Azure. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n ),\n );\n\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await container.deleteBlob(relativeFilePath);\n },\n staleFiles,\n { concurrencyLimit: BATCH_CONCURRENCY },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from Azure. ${error}`;\n this.logger.error(errorMessage);\n }\n\n return { objects };\n }\n\n private download(containerName: string, blobPath: string): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const fileStreamChunks: Array<any> = [];\n this.storageClient\n .getContainerClient(containerName)\n .getBlockBlobClient(blobPath)\n .download()\n .then(res => {\n const body = res.readableStreamBody;\n if (!body) {\n reject(new Error(`Unable to parse the response data`));\n return;\n }\n body\n .on('error', reject)\n .on('data', chunk => {\n fileStreamChunks.push(chunk);\n })\n .on('end', () => {\n resolve(Buffer.concat(fileStreamChunks));\n });\n })\n .catch(reject);\n });\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityRootDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n try {\n const techdocsMetadataJson = await this.download(\n this.containerName,\n `${entityRootDir}/techdocs_metadata.json`,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n return techdocsMetadata;\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return (req, res) => {\n // Decode and trim the leading forward slash\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/Component/documented-component/index.html\n const filePath = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = platformPath.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n this.download(this.containerName, filePath)\n .then(fileContent => {\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n res.send(fileContent);\n })\n .catch(e => {\n this.logger.warn(\n `TechDocs Azure router failed to serve content from container ${this.containerName} at path ${filePath}: ${e.message}`,\n );\n res.status(404).send('File Not Found');\n });\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityRootDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n return this.storageClient\n .getContainerClient(this.containerName)\n .getBlockBlobClient(`${entityRootDir}/index.html`)\n .exists();\n }\n\n protected async renameBlob(\n originalName: string,\n newName: string,\n removeOriginal = false,\n ): Promise<void> {\n const container = this.storageClient.getContainerClient(this.containerName);\n const blob = container.getBlobClient(newName);\n const { url } = container.getBlobClient(originalName);\n const response = await blob.beginCopyFromURL(url);\n await response.pollUntilDone();\n if (removeOriginal) {\n await container.deleteBlob(originalName);\n }\n }\n\n protected async renameBlobToLowerCase(\n originalPath: string,\n removeOriginal: boolean,\n ) {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(originalPath);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n if (originalPath === newPath) return;\n try {\n this.logger.debug(`Migrating ${originalPath}`);\n await this.renameBlob(originalPath, newPath, removeOriginal);\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${originalPath}: ${e.message}`);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n const promises = [];\n const limiter = limiterFactory(concurrency);\n const container = this.storageClient.getContainerClient(this.containerName);\n\n for await (const blob of container.listBlobsFlat()) {\n promises.push(\n limiter(\n this.renameBlobToLowerCase.bind(this),\n blob.name,\n removeOriginal,\n ),\n );\n }\n\n await Promise.all(promises);\n }\n\n protected async getAllBlobsFromContainer({\n prefix,\n maxPageSize,\n }: {\n prefix: string;\n maxPageSize: number;\n }): Promise<string[]> {\n const blobs: string[] = [];\n const container = this.storageClient.getContainerClient(this.containerName);\n\n let iterator = container.listBlobsFlat({ prefix }).byPage({ maxPageSize });\n let response = (await iterator.next()).value;\n\n do {\n for (const blob of response?.segment?.blobItems ?? []) {\n blobs.push(blob.name);\n }\n iterator = container\n .listBlobsFlat({ prefix })\n .byPage({ continuationToken: response.continuationToken, maxPageSize });\n response = (await iterator.next()).value;\n } while (response && response.continuationToken);\n\n return blobs;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { File } from '@google-cloud/storage';\nimport { Writable } from 'stream';\nimport { lowerCaseEntityTripletInStoragePath } from '../helpers';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Writable stream to handle object copy/move operations. This implementation\n * ensures we don't read in files from GCS faster than GCS can copy/move them.\n */\nexport class MigrateWriteStream extends Writable {\n protected logger: LoggerService;\n protected removeOriginal: boolean;\n protected maxConcurrency: number;\n protected inFlight = 0;\n\n constructor(\n logger: LoggerService,\n removeOriginal: boolean,\n concurrency: number,\n ) {\n super({ objectMode: true });\n this.logger = logger;\n this.removeOriginal = removeOriginal;\n this.maxConcurrency = concurrency;\n }\n\n _write(file: File, _encoding: BufferEncoding, next: Function) {\n let shouldCallNext = true;\n let newFile;\n try {\n newFile = lowerCaseEntityTripletInStoragePath(file.name);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n next();\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (newFile === file.name) {\n next();\n return;\n }\n\n // Allow up to n-many files to be migrated at a time.\n this.inFlight++;\n if (this.inFlight < this.maxConcurrency) {\n next();\n shouldCallNext = false;\n }\n\n // Otherwise, copy or move the file.\n const migrate = this.removeOriginal\n ? file.move.bind(file)\n : file.copy.bind(file);\n this.logger.debug(`Migrating ${file.name}`);\n migrate(newFile)\n .catch(e =>\n this.logger.warn(`Unable to migrate ${file.name}: ${e.message}`),\n )\n .finally(() => {\n this.inFlight--;\n if (shouldCallNext) {\n next();\n }\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError } from '@backstage/errors';\nimport {\n File,\n FileExistsResponse,\n Storage,\n StorageOptions,\n} from '@google-cloud/storage';\nimport express from 'express';\nimport JSON5 from 'json5';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getStaleFiles,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport { MigrateWriteStream } from './migrations';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class GoogleGCSPublish implements PublisherBase {\n private readonly storageClient: Storage;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n private readonly bucketRootPath: string;\n\n constructor(options: {\n storageClient: Storage;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: LoggerService;\n bucketRootPath: string;\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n }\n\n static fromConfig(config: Config, logger: LoggerService): PublisherBase {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.googleGcs.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'googleGcs' in your app config, \" +\n 'techdocs.publisher.googleGcs.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.googleGcs.bucketRootPath') ||\n '',\n );\n\n // Credentials is an optional config. If missing, default GCS environment variables will be used.\n // Read more here https://cloud.google.com/docs/authentication/production\n const credentials = config.getOptionalString(\n 'techdocs.publisher.googleGcs.credentials',\n );\n const projectId = config.getOptionalString(\n 'techdocs.publisher.googleGcs.projectId',\n );\n let credentialsJson: any = {};\n if (credentials) {\n try {\n credentialsJson = JSON.parse(credentials);\n } catch (err) {\n throw new Error(\n 'Error in parsing techdocs.publisher.googleGcs.credentials config to JSON.',\n );\n }\n }\n\n const clientOpts: StorageOptions = {};\n if (projectId) {\n clientOpts.projectId = projectId;\n }\n\n const storageClient = new Storage({\n ...(credentials && {\n projectId: credentialsJson.project_id,\n credentials: credentialsJson,\n }),\n ...clientOpts,\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new GoogleGCSPublish({\n storageClient,\n bucketName,\n legacyPathCasing,\n logger,\n bucketRootPath,\n });\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.bucket(this.bucketName).getMetadata();\n this.logger.info(\n `Successfully connected to the GCS bucket ${this.bucketName}.`,\n );\n\n return {\n isAvailable: true,\n };\n } catch (err) {\n assertError(err);\n this.logger.error(\n `Could not retrieve metadata about the GCS bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by explicitly defining ' +\n 'techdocs.publisher.googleGcs.credentials in app config or by using environment variables. ' +\n 'Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from GCS client library: ${err.message}`);\n\n return { isAvailable: false };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the GCS bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucket = this.storageClient.bucket(this.bucketName);\n const bucketRootPath = this.bucketRootPath;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getFilesForFolder(remoteFolder);\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const destination = getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n );\n objects.push(destination);\n return await bucket.upload(absoluteFilePath, { destination });\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to Google Cloud Storage. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await bucket.file(relativeFilePath).delete();\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from Google Cloud Storage. ${error}`;\n this.logger.error(errorMessage);\n }\n\n return { objects };\n }\n\n fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n return new Promise((resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n const fileStreamChunks: Array<any> = [];\n this.storageClient\n .bucket(this.bucketName)\n .file(`${entityRootDir}/techdocs_metadata.json`)\n .createReadStream()\n .on('error', err => {\n this.logger.error(err.message);\n reject(err);\n })\n .on('data', chunk => {\n fileStreamChunks.push(chunk);\n })\n .on('end', () => {\n const techdocsMetadataJson =\n Buffer.concat(fileStreamChunks).toString('utf-8');\n resolve(JSON5.parse(techdocsMetadataJson));\n });\n });\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n // Pipe file chunks directly from storage to client.\n this.storageClient\n .bucket(this.bucketName)\n .file(filePath)\n .createReadStream()\n .on('pipe', () => {\n res.writeHead(200, responseHeaders);\n })\n .on('error', err => {\n this.logger.warn(\n `TechDocs Google GCS router failed to serve content from bucket ${this.bucketName} at path ${filePath}: ${err.message}`,\n );\n // Send a 404 with a meaningful message if possible.\n if (!res.headersSent) {\n res.status(404).send('File Not Found');\n } else {\n res.destroy();\n }\n })\n .pipe(res);\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n return new Promise(resolve => {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n\n this.storageClient\n .bucket(this.bucketName)\n .file(`${entityRootDir}/index.html`)\n .exists()\n .then((response: FileExistsResponse) => {\n resolve(response[0]);\n })\n .catch(() => {\n resolve(false);\n });\n });\n }\n\n migrateDocsCase({ removeOriginal = false, concurrency = 25 }): Promise<void> {\n return new Promise((resolve, reject) => {\n // Iterate through every file in the root of the publisher.\n const allFileMetadata: Readable = this.storageClient\n .bucket(this.bucketName)\n .getFilesStream();\n const migrateFiles = new MigrateWriteStream(\n this.logger,\n removeOriginal,\n concurrency,\n );\n migrateFiles.on('finish', resolve).on('error', reject);\n allFileMetadata.pipe(migrateFiles).on('error', error => {\n migrateFiles.destroy();\n reject(error);\n });\n });\n }\n\n private getFilesForFolder(folder: string): Promise<string[]> {\n const fileMetadataStream: Readable = this.storageClient\n .bucket(this.bucketName)\n .getFilesStream({ prefix: folder });\n\n return new Promise((resolve, reject) => {\n const files: string[] = [];\n\n fileMetadataStream.on('error', error => {\n // push file to file array\n reject(error);\n });\n\n fileMetadataStream.on('data', (file: File) => {\n // push file to file array\n files.push(file.name);\n });\n\n fileMetadataStream.on('end', () => {\n // resolve promise\n resolve(files);\n });\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DiscoveryService,\n LoggerService,\n resolvePackagePath,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport {\n Entity,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport { ForwardedError } from '@backstage/errors';\n\n/**\n * Local publisher which uses the local filesystem to store the generated static files. It uses by default a\n * directory called \"static\" at the root of techdocs-backend plugin unless a directory has been configured by\n * \"techdocs.publisher.local.publishDirectory\".\n */\nexport class LocalPublish implements PublisherBase {\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n private readonly discovery: DiscoveryService;\n private readonly staticDocsDir: string;\n\n constructor(options: {\n logger: LoggerService;\n discovery: DiscoveryService;\n legacyPathCasing: boolean;\n staticDocsDir: string;\n }) {\n this.logger = options.logger;\n this.discovery = options.discovery;\n this.legacyPathCasing = options.legacyPathCasing;\n this.staticDocsDir = options.staticDocsDir;\n }\n\n static fromConfig(\n config: Config,\n logger: LoggerService,\n discovery: DiscoveryService,\n ): PublisherBase {\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n let staticDocsDir = config.getOptionalString(\n 'techdocs.publisher.local.publishDirectory',\n );\n if (!staticDocsDir) {\n try {\n staticDocsDir = resolvePackagePath(\n '@backstage/plugin-techdocs-backend',\n 'static/docs',\n );\n } catch (err) {\n // This will most probably never be used.\n // The try/catch is introduced so that techdocs-cli can import @backstage/plugin-techdocs-node\n // on CI/CD without installing techdocs backend plugin.\n staticDocsDir = os.tmpdir();\n }\n }\n\n return new LocalPublish({\n logger,\n discovery,\n legacyPathCasing,\n staticDocsDir,\n });\n }\n\n async getReadiness(): Promise<ReadinessResponse> {\n return {\n isAvailable: true,\n };\n }\n\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const entityNamespace = entity.metadata.namespace ?? 'default';\n let publishDir: string;\n\n try {\n publishDir = this.staticEntityPathJoin(\n entityNamespace,\n entity.kind,\n entity.metadata.name,\n );\n } catch (error) {\n throw new ForwardedError(\n `Unable to publish TechDocs site for entity: ${stringifyEntityRef(\n entity,\n )}`,\n error,\n );\n }\n\n if (!fs.existsSync(publishDir)) {\n this.logger.info(`Could not find ${publishDir}, creating the directory.`);\n fs.mkdirSync(publishDir, { recursive: true });\n }\n\n try {\n await fs.copy(directory, publishDir);\n this.logger.info(`Published site stored at ${publishDir}`);\n } catch (error) {\n this.logger.debug(\n `Failed to copy docs from ${directory} to ${publishDir}`,\n );\n throw error;\n }\n\n // Generate publish response.\n const techdocsApiUrl = await this.discovery.getBaseUrl('techdocs');\n const publishedFilePaths = (await getFileTreeRecursively(publishDir)).map(\n abs => {\n return abs.split(`${this.staticDocsDir}/`)[1];\n },\n );\n\n return {\n remoteUrl: `${techdocsApiUrl}/static/docs/${encodeURIComponent(\n entity.metadata.name,\n )}`,\n objects: publishedFilePaths,\n };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n let metadataPath: string;\n\n try {\n metadataPath = this.staticEntityPathJoin(\n entityName.namespace,\n entityName.kind,\n entityName.name,\n 'techdocs_metadata.json',\n );\n } catch (err) {\n throw new ForwardedError(\n `Unexpected entity when fetching metadata: ${stringifyEntityRef(\n entityName,\n )}`,\n err,\n );\n }\n\n try {\n return await fs.readJson(metadataPath);\n } catch (err) {\n throw new ForwardedError(\n `Unable to read techdocs_metadata.json at ${metadataPath}. Error: ${err}`,\n err,\n );\n }\n }\n\n docsRouter(): express.Handler {\n const router = express.Router();\n\n // Redirect middleware ensuring that requests to case-sensitive entity\n // triplet paths are always sent to lower-case versions.\n router.use((req, res, next) => {\n // If legacy path casing is on, let the request immediately continue.\n if (this.legacyPathCasing) {\n return next();\n }\n\n // Generate a lower-case entity triplet path.\n const [_, namespace, kind, name, ...rest] = req.path.split('/');\n\n // Ignore non-triplet objects.\n if (!namespace || !kind || !name) {\n return next();\n }\n\n const newPath = [\n _,\n namespace.toLowerCase(),\n kind.toLowerCase(),\n name.toLowerCase(),\n ...rest,\n ].join('/');\n\n // If there was no change, then let express.static() handle the request.\n if (newPath === req.path) {\n return next();\n }\n\n // Otherwise, redirect to the new path.\n return res.redirect(301, req.baseUrl + newPath);\n });\n router.use(\n express.static(this.staticDocsDir, {\n // Handle content-type header the same as all other publishers.\n setHeaders: (res, filePath) => {\n const fileExtension = path.extname(filePath);\n const headers = getHeadersForFileExtension(fileExtension);\n for (const [header, value] of Object.entries(headers)) {\n res.setHeader(header, value);\n }\n },\n }),\n );\n\n return router;\n }\n\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const namespace = entity.metadata.namespace ?? 'default';\n\n // Check if the file exists\n try {\n const indexHtmlPath = this.staticEntityPathJoin(\n namespace,\n entity.kind,\n entity.metadata.name,\n 'index.html',\n );\n\n await fs.access(indexHtmlPath, fs.constants.F_OK);\n\n return true;\n } catch (err) {\n if (err.name === 'NotAllowedError') {\n this.logger.error(\n `Unexpected entity when checking if generated: ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n return false;\n }\n }\n\n /**\n * This code will never run in practice. It is merely here to illustrate how\n * to implement this method for other storage providers.\n */\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const files = await getFileTreeRecursively(this.staticDocsDir);\n const limit = createLimiter(concurrency);\n\n await Promise.all(\n files.map(f =>\n limit(async file => {\n const relativeFile = file.replace(\n `${this.staticDocsDir}${path.sep}`,\n '',\n );\n const newFile = lowerCaseEntityTripletInStoragePath(relativeFile);\n\n // If all parts are already lowercase, ignore.\n if (relativeFile === newFile) {\n return;\n }\n\n // Otherwise, copy or move the file.\n await new Promise<void>(resolve => {\n const migrate = removeOriginal ? fs.move : fs.copyFile;\n this.logger.debug(`Migrating ${relativeFile}`);\n migrate(file, newFile, err => {\n if (err) {\n this.logger.warn(\n `Unable to migrate ${relativeFile}: ${err.message}`,\n );\n }\n resolve();\n });\n });\n }, f),\n ),\n );\n }\n\n /**\n * Utility wrapper around path.join(), used to control legacy case logic.\n */\n protected staticEntityPathJoin(...allParts: string[]): string {\n let staticEntityPath = this.staticDocsDir;\n\n allParts\n .map(part => part.split(path.sep))\n .flat()\n .forEach((part, index) => {\n // Respect legacy path casing when operating on namespace, kind, or name.\n if (index < 3) {\n staticEntityPath = resolveSafeChildPath(\n staticEntityPath,\n this.legacyPathCasing ? part : part.toLowerCase(),\n );\n return;\n }\n\n // Otherwise, respect the provided case.\n staticEntityPath = resolveSafeChildPath(staticEntityPath, part);\n });\n\n return staticEntityPath;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { SwiftClient } from '@trendyol-js/openstack-swift-sdk';\nimport { NotFound } from '@trendyol-js/openstack-swift-sdk/lib/types';\nimport { Stream, Readable } from 'stream';\n\nimport {\n getFileTreeRecursively,\n getHeadersForFileExtension,\n lowerCaseEntityTripletInStoragePath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst streamToBuffer = (stream: Stream | Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', reject);\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nconst bufferToStream = (buffer: Buffer): Readable => {\n const stream = new Readable();\n stream.push(buffer);\n stream.push(null);\n return stream;\n};\n\nexport class OpenStackSwiftPublish implements PublisherBase {\n private readonly storageClient: SwiftClient;\n private readonly containerName: string;\n private readonly logger: LoggerService;\n\n constructor(options: {\n storageClient: SwiftClient;\n containerName: string;\n logger: LoggerService;\n }) {\n this.storageClient = options.storageClient;\n this.containerName = options.containerName;\n this.logger = options.logger;\n }\n\n static fromConfig(config: Config, logger: LoggerService): PublisherBase {\n let containerName = '';\n try {\n containerName = config.getString(\n 'techdocs.publisher.openStackSwift.containerName',\n );\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'openStackSwift' in your app config, \" +\n 'techdocs.publisher.openStackSwift.containerName is required.',\n );\n }\n\n const openStackSwiftConfig = config.getConfig(\n 'techdocs.publisher.openStackSwift',\n );\n\n const storageClient = new SwiftClient({\n authEndpoint: openStackSwiftConfig.getString('authUrl'),\n swiftEndpoint: openStackSwiftConfig.getString('swiftUrl'),\n credentialId: openStackSwiftConfig.getString('credentials.id'),\n secret: openStackSwiftConfig.getString('credentials.secret'),\n });\n\n return new OpenStackSwiftPublish({ storageClient, containerName, logger });\n }\n\n /*\n * Check if the defined container exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n const container = await this.storageClient.getContainerMetadata(\n this.containerName,\n );\n\n if (!(container instanceof NotFound)) {\n this.logger.info(\n `Successfully connected to the OpenStack Swift container ${this.containerName}.`,\n );\n return {\n isAvailable: true,\n };\n }\n this.logger.error(\n `Could not retrieve metadata about the OpenStack Swift container ${this.containerName}. ` +\n 'Make sure the container exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.openStackSwift in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n return {\n isAvailable: false,\n };\n } catch (err) {\n assertError(err);\n this.logger.error(`from OpenStack client library: ${err.message}`);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the OpenStack Swift container.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n try {\n const objects: string[] = [];\n\n // Note: OpenStack Swift manages creation of parent directories if they do not exist.\n // So collecting path of only the files is good enough.\n const allFilesToUpload = await getFileTreeRecursively(directory);\n const limiter = createLimiter(10);\n const uploadPromises: Array<Promise<unknown>> = [];\n for (const filePath of allFilesToUpload) {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n const relativeFilePath = path.relative(directory, filePath);\n // Convert destination file path to a POSIX path for uploading.\n // Swift expects / as path separator and relativeFilePath will contain \\\\ on Windows.\n // https://docs.openstack.org/python-openstackclient/pike/cli/man/openstack.html\n const relativeFilePathPosix = relativeFilePath\n .split(path.sep)\n .join(path.posix.sep);\n\n // The / delimiter is intentional since it represents the cloud storage and not the local file system.\n const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const destination = `${entityRootDir}/${relativeFilePathPosix}`; // Swift container file relative path\n objects.push(destination);\n\n // Rate limit the concurrent execution of file uploads to batches of 10 (per publish)\n const uploadFile = limiter(async () => {\n const fileBuffer = await fs.readFile(filePath);\n const stream = bufferToStream(fileBuffer);\n return this.storageClient.upload(\n this.containerName,\n destination,\n stream,\n );\n });\n uploadPromises.push(uploadFile);\n }\n await Promise.all(uploadPromises);\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${allFilesToUpload.length}`,\n );\n return { objects };\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to OpenStack Swift. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityRootDir = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n\n const downloadResponse = await this.storageClient.download(\n this.containerName,\n `${entityRootDir}/techdocs_metadata.json`,\n );\n\n if (!(downloadResponse instanceof NotFound)) {\n const stream = downloadResponse.data;\n try {\n const techdocsMetadataJson = await streamToBuffer(stream);\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n } else {\n reject({\n message: `TechDocs metadata fetch failed, The file /rootDir/${entityRootDir}/techdocs_metadata.json does not exist !`,\n });\n }\n });\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n // Decode and trim the leading forward slash\n // filePath example - /default/Component/documented-component/index.html\n const filePath = decodeURI(req.path.replace(/^\\//, ''));\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n const downloadResponse = await this.storageClient.download(\n this.containerName,\n filePath,\n );\n\n if (!(downloadResponse instanceof NotFound)) {\n const stream = downloadResponse.data;\n\n try {\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n res.send(await streamToBuffer(stream));\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs OpenStack swift router failed to serve content from container ${this.containerName} at path ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n } else {\n this.logger.warn(\n `TechDocs OpenStack swift router failed to serve content from container ${this.containerName} at path ${filePath}: Not found`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n try {\n const fileResponse = await this.storageClient.getMetadata(\n this.containerName,\n `${entityRootDir}/index.html`,\n );\n\n if (!(fileResponse instanceof NotFound)) {\n return true;\n }\n return false;\n } catch (err) {\n assertError(err);\n this.logger.warn(err.message);\n return false;\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromContainer();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.debug(`Migrating ${file} to ${newPath}`);\n await this.storageClient.copy(\n this.containerName,\n file,\n this.containerName,\n newPath,\n );\n if (removeOriginal) {\n await this.storageClient.delete(this.containerName, file);\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured container.\n */\n protected async getAllObjectsFromContainer(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n let objects: string[] = [];\n const OSS_MAX_LIMIT = Math.pow(2, 31) - 1;\n\n const allObjects = await this.storageClient.list(\n this.containerName,\n prefix,\n OSS_MAX_LIMIT,\n );\n objects = allObjects.map((object: any) => object.name);\n\n return objects;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { AwsS3Publish } from './awsS3';\nimport { AzureBlobStoragePublish } from './azureBlobStorage';\nimport { GoogleGCSPublish } from './googleStorage';\nimport { LocalPublish } from './local';\nimport { OpenStackSwiftPublish } from './openStackSwift';\nimport {\n PublisherFactory,\n PublisherBase,\n PublisherType,\n PublisherBuilder,\n} from './types';\n\n/**\n * Factory class to create a TechDocs publisher based on defined publisher type in app config.\n * Uses `techdocs.publisher.type`.\n * @public\n */\nexport class Publisher implements PublisherBuilder {\n private publishers: Map<PublisherType | 'techdocs', PublisherBase> =\n new Map();\n\n register(type: PublisherType | 'techdocs', publisher: PublisherBase): void {\n this.publishers.set(type, publisher);\n }\n\n get(config: Config): PublisherBase {\n const publisherType = (config.getOptionalString(\n 'techdocs.publisher.type',\n ) ?? 'local') as PublisherType;\n\n if (!publisherType) {\n throw new Error('TechDocs publisher type not specified for the entity');\n }\n\n const publisher = this.publishers.get(publisherType);\n if (!publisher) {\n throw new Error(\n `TechDocs publisher '${publisherType}' is not registered`,\n );\n }\n\n return publisher;\n }\n\n /**\n * Returns a instance of TechDocs publisher\n * @param config - A Backstage configuration\n * @param options - Options for configuring the publisher factory\n */\n static async fromConfig(\n config: Config,\n options: PublisherFactory,\n ): Promise<PublisherBase> {\n const { logger, discovery, customPublisher } = options;\n\n const publishers = new Publisher();\n\n if (customPublisher) {\n publishers.register('techdocs', customPublisher);\n return customPublisher;\n }\n\n const publisherType = (config.getOptionalString(\n 'techdocs.publisher.type',\n ) ?? 'local') as PublisherType;\n\n switch (publisherType) {\n case 'googleGcs':\n logger.info('Creating Google Storage Bucket publisher for TechDocs');\n publishers.register(\n publisherType,\n GoogleGCSPublish.fromConfig(config, logger),\n );\n break;\n case 'awsS3':\n logger.info('Creating AWS S3 Bucket publisher for TechDocs');\n publishers.register(\n publisherType,\n await AwsS3Publish.fromConfig(config, logger),\n );\n break;\n case 'azureBlobStorage':\n logger.info(\n 'Creating Azure Blob Storage Container publisher for TechDocs',\n );\n publishers.register(\n publisherType,\n AzureBlobStoragePublish.fromConfig(config, logger),\n );\n break;\n case 'openStackSwift':\n logger.info(\n 'Creating OpenStack Swift Container publisher for TechDocs',\n );\n publishers.register(\n publisherType,\n OpenStackSwiftPublish.fromConfig(config, logger),\n );\n break;\n case 'local':\n logger.info('Creating Local publisher for TechDocs');\n publishers.register(\n publisherType,\n LocalPublish.fromConfig(config, logger, discovery),\n );\n break;\n default:\n logger.info('Creating Local publisher for TechDocs');\n publishers.register(\n publisherType,\n LocalPublish.fromConfig(config, logger, discovery),\n );\n }\n\n return publishers.get(config);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { DocsBuildStrategy } from './techdocsTypes';\nimport {\n PreparerBase,\n PublisherBase,\n PublisherType,\n RemoteProtocol,\n TechdocsGenerator,\n} from './stages';\nimport * as winston from 'winston';\n\n/**\n * Extension point type for configuring TechDocs builds.\n *\n * @public\n */\nexport interface TechdocsBuildsExtensionPoint {\n setBuildStrategy(buildStrategy: DocsBuildStrategy): void;\n setBuildLogTransport(transport: winston.transport): void;\n}\n\n/**\n * Extension point for configuring TechDocs builds.\n *\n * @public\n */\nexport const techdocsBuildsExtensionPoint =\n createExtensionPoint<TechdocsBuildsExtensionPoint>({\n id: 'techdocs.builds',\n });\n\n/**\n * Extension point type for configuring a custom TechDocs generator\n *\n * @public\n */\nexport interface TechdocsGeneratorExtensionPoint {\n setTechdocsGenerator(generator: TechdocsGenerator): void;\n}\n\n/**\n * Extension point for configuring a custom TechDocs generator\n *\n * @public\n */\nexport const techdocsGeneratorExtensionPoint =\n createExtensionPoint<TechdocsGeneratorExtensionPoint>({\n id: 'techdocs.generator',\n });\n\n/**\n * Extension point type for configuring a custom TechDocs preparer\n *\n * @public\n */\nexport interface TechdocsPreparerExtensionPoint {\n registerPreparer(protocol: RemoteProtocol, preparer: PreparerBase): void;\n}\n\n/**\n * Extension point for configuring a custom TechDocs preparer\n *\n * @public\n */\nexport const techdocsPreparerExtensionPoint =\n createExtensionPoint<TechdocsPreparerExtensionPoint>({\n id: 'techdocs.preparer',\n });\n\n/**\n * Extension point type for configuring a custom TechDocs publisher\n *\n * @public\n */\nexport interface TechdocsPublisherExtensionPoint {\n registerPublisher(type: PublisherType, publisher: PublisherBase): void;\n}\n\n/**\n * Extension point for configuring a custom TechDocs publisher\n *\n * @public\n */\nexport const techdocsPublisherExtensionPoint =\n createExtensionPoint<TechdocsPublisherExtensionPoint>({\n id: 'techdocs.publisher',\n });\n"],"names":["mime","recursiveReadDir","path","DEFAULT_NAMESPACE","createLimiter","PassThrough","spawn","gitUrlParse","DEFAULT_SCHEMA","Type","fs","yaml","ForwardedError","isChildPath","resolvePath","assertError","promisify","pipelineStream","Docker","ScmIntegrations","getMkdocsYml","InputError","parseLocationRef","getEntitySourceLocation","resolveSafeChildPath","TECHDOCS_ANNOTATION","streamToBuffer","DefaultAwsCredentialsManager","S3Client","NodeHttpHandler","HttpsProxyAgent","fromTemporaryCredentials","HeadBucketCommand","Upload","DeleteObjectCommand","GetObjectCommand","JSON5","HeadObjectCommand","CopyObjectCommand","ListObjectsV2Command","BlobServiceClient","StorageSharedKeyCredential","DefaultAzureCredential","platformPath","limiterFactory","Writable","Storage","resolvePackagePath","os","stringifyEntityRef","express","stream","Readable","SwiftClient","NotFound","createExtensionPoint"],"mappings":"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"}