UNPKG

@roadiehq/backstage-plugin-github-insights

Version:
131 lines (128 loc) 4.43 kB
import { Octokit } from '@octokit/rest'; import parseGitUrl from 'git-url-parse'; import { readGithubIntegrationConfigs } from '@backstage/integration'; const mimeTypeMap = { svg: "image/svg+xml", png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif", webp: "image/webp" }; const mimeTypeLookup = (href) => { const match = href.match(/\.([a-zA-Z]*)$/); const extension = match ? match[1] : void 0; return extension ? mimeTypeMap[extension.toLowerCase()] : void 0; }; const getRepositoryDefaultBranch = (url) => { return new URL(url).searchParams.get("ref"); }; const combinePaths = (readmePath, relativePath) => { const readmeUrl = new URL(`file://${readmePath}`); const dirUrl = new URL(".", readmeUrl); const combinedUrl = new URL(relativePath, dirUrl); return combinedUrl.pathname.startsWith("/") ? combinedUrl.pathname : `/${combinedUrl.pathname}`; }; class GithubClient { configApi; scmAuthApi; constructor(options) { this.configApi = options.configApi; this.scmAuthApi = options.scmAuthApi; } async getOctokit(hostname = "github.com") { const { token } = await this.scmAuthApi.getCredentials({ url: `https://${hostname}/`, additionalScope: { customScopes: { github: ["repo"] } } }); const configs = readGithubIntegrationConfigs( this.configApi.getOptionalConfigArray("integrations.github") ?? [] ); const githubIntegrationConfig = configs.find((v) => v.host === hostname); const baseUrl = githubIntegrationConfig?.apiBaseUrl; return new Octokit({ auth: token, baseUrl }); } async getContent(props) { const { path: customReadmePath, repo, owner, branch, hostname } = props; const octokit = await this.getOctokit(hostname); let query = "readme"; if (customReadmePath) { query = `contents/${customReadmePath}`; } const readmePath = query; const response = await octokit.request( `GET /repos/{owner}/{repo}/${query}`, { owner, repo, ...branch && { ref: branch } } ); const content = Buffer.from(response.data.content, "base64").toString( "utf8" ); const mediaLinks = [ ...content.matchAll( /!\[([^\]]*)\]\(([^)]+\.(?:png|jpg|jpeg|gif|webp|svg))\)/gi ) ].map((match) => [match[2], match[3]].join("")); const media = {}; const { ref, resource: domain, protocol } = parseGitUrl(response.data.url); const domainLowerCased = domain.toLocaleLowerCase("en-US"); for (const mediaLink of mediaLinks) { const mimeType = mimeTypeLookup(mediaLink); if (!mimeType) { continue; } const getUrl = () => { const linkLowerCased = mediaLink.toLocaleLowerCase("en-US"); if (!linkLowerCased.startsWith("http")) { return new URL(mediaLink, response.data.url); } if (linkLowerCased.includes(domainLowerCased)) { const { owner: ownerLink, name: repoLink, ref: refLink, filepath } = parseGitUrl(mediaLink); if (filepath) { return `/repos/${ownerLink}/${repoLink}/contents/${filepath}${refLink && `?ref=${refLink}`}`; } } return void 0; }; const url = getUrl(); if (url) { try { const contentResponse = await octokit.request(`GET ${url}`); media[mediaLink] = `data:${mimeType};base64,${contentResponse.data.content.replaceAll( "\n", "" )}`; } catch (e) { console.warn( `There was a problem loading the image content at ${url} via the GitHub API due to error: ${e.message}` ); } } } const markdownLinks = [ ...content.matchAll(/\[([^\[\]]*)\]\((?!https?:\/\/)(.*?)(\.md)\)/gim) ].map((match) => [match[2], match[3]].join("")); const links = {}; const loadFromBranch = branch || ref || getRepositoryDefaultBranch(response.data.url); for (const markdownLink of markdownLinks) { const basicLink = `${protocol}://${domain}/${owner}/${repo}/blob/${loadFromBranch}`; const combinedPath = combinePaths(readmePath, markdownLink); links[markdownLink] = `${basicLink}${combinedPath}`; } return { content, media, links }; } } export { GithubClient }; //# sourceMappingURL=GithubClient.esm.js.map