@roadiehq/backstage-plugin-github-insights
Version:
131 lines (128 loc) • 4.43 kB
JavaScript
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