Skip to content

Commit

Permalink
ref: Optimize file fetching code (#96)
Browse files Browse the repository at this point in the history
While looking around in here I noticed we were doing a whole extra fetch
to get the metadata for the file when all of the info we need was
already present on the page. This PR updates the code to remove that
fetch. Additionally, adds support for file coverage when browsing at a
specific commit, this was previously not supported.
  • Loading branch information
spalmurray-codecov authored Nov 19, 2024
1 parent 3ec8392 commit 662b957
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 109 deletions.
24 changes: 5 additions & 19 deletions src/content/github/common/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,6 @@ import {
MessageType,
} from "src/types";

export async function getMetadata(url: string): Promise<FileMetadata> {
const response = await fetch(url, {
headers: {
"Accept": "application/json",
},
}).then((response) => response.json());
let branch = undefined;
if (response.payload.refInfo.refType === "branch") {
branch = response.payload.refInfo.name;
}
return {
owner: response.payload.repo.ownerLogin,
repo: response.payload.repo.name,
path: response.payload.path,
commit: response.payload.refInfo.currentOid,
branch: branch,
};
}

export async function getFlags(metadata: FileMetadata): Promise<string[]> {
const payload = {
service: "github",
Expand Down Expand Up @@ -65,6 +46,11 @@ export async function getCommitReport(
flag: string | undefined,
component_id: string | undefined
): Promise<FileCoverageReportResponse> {
// metadata.commit must be defined, check it before calling
if (!metadata.commit) {
throw new Error("getCommitReport called without commit sha");
}

const payload = {
service: "github",
owner: metadata.owner,
Expand Down
163 changes: 87 additions & 76 deletions src/content/github/file/main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from "dom-chef";
import browser from "webextension-polyfill";
import alpha from "color-alpha";
import Drop from "tether-drop";
Expand Down Expand Up @@ -27,15 +26,14 @@ import {
import { colors } from "../common/constants";
import { createDropdown } from "./utils/dropdown";
import {
getMetadata,
getComponents,
getCommitReport,
getFlags,
getBranchReport,
} from "../common/fetchers";
import { print } from "src/utils";
import Sentry from "../../common/sentry";
import { isFileUrl } from "../common/utils";
import Sentry from '../../common/sentry';

const globals: {
coverageReport?: FileCoverageReport;
Expand All @@ -47,7 +45,7 @@ const globals: {
prompt?: HTMLElement;
} = {};

init()
init();

function init(): Promise<void> {
// this event discovered by "reverse-engineering GitHub"
Expand All @@ -63,21 +61,60 @@ function init(): Promise<void> {

async function main(): Promise<void> {
try {
if (!isFileUrl(document.URL)) {
const urlMetadata = getMetadataFromURL();
if (!urlMetadata) {
print("file not detected at current URL");
return;
}
globals.coverageButton = createCoverageButton();
process(urlMetadata);
} catch (e) {
Sentry.captureException(e);
throw e;
}
}

let metadata: FileMetadata;
metadata = await getMetadata(document.URL);
function getMetadataFromURL(): FileMetadata | null {
const regexp =
/\/(?<owner>.+?)\/(?<repo>.+?)\/blob\/(?<branch>.+?)\/(?<path>.+?)$/;
const matches = regexp.exec(window.location.pathname);
const groups = matches?.groups;
if (!groups) {
return null;
}

globals.coverageButton = createCoverageButton();
const branch = groups.branch;
const commitMatch = branch.match(/[\da-f]+/);

process(metadata)
} catch (e) {
Sentry.captureException(e)
throw e
// branch could be a commit sha
if (
commitMatch &&
commitMatch[0].length == branch.length &&
(groups.branch.length === 40 || branch.length === 7)
) {
// branch is actually a commit sha
let commit = branch;

// if it's a short sha, we need to get the full sha
if (commit.length === 7) {
const commitLink = document.querySelector(
`[href^="/${groups.owner}/${groups.repo}/tree/${commit}"]`
);
if (!commitLink)
throw new Error("Could not find commit link from short sha");
const longSha = commitLink
.getAttribute("href")
?.match(/[\da-f]{40}/)?.[0];
if (!longSha) throw new Error("Could not get long sha from commit link");
commit = longSha;
}

return {
...groups,
commit,
};
}
return groups;
}

async function process(metadata: FileMetadata): Promise<void> {
Expand Down Expand Up @@ -111,17 +148,16 @@ async function process(metadata: FileMetadata): Promise<void> {
previousElement: globals.coverageButton!,
selectedOptions: selectedFlags,
onClick: handleFlagClick,
})
.then(({ button, list }) => {
globals.flagsButton = button;
globals.flagsDrop = new Drop({
target: button,
content: list,
classes: "drop-theme-arrows codecov-z1 codecov-bg-white",
position: "bottom right",
openOn: "click",
});
})
}).then(({ button, list }) => {
globals.flagsButton = button;
globals.flagsDrop = new Drop({
target: button,
content: list,
classes: "drop-theme-arrows codecov-z1 codecov-bg-white",
position: "bottom right",
openOn: "click",
});
});
}

const components = await getComponents(metadata);
Expand All @@ -134,7 +170,7 @@ async function process(metadata: FileMetadata): Promise<void> {
return [];
});

// TODO: allow setting selected flags for different files at the same time
// TODO: allow setting selected components for different files at the same time
if (
selectedComponents.length > 0 &&
_.intersection(components, selectedComponents).length === 0
Expand All @@ -151,35 +187,45 @@ async function process(metadata: FileMetadata): Promise<void> {
previousElement: globals.coverageButton!,
onClick: handleComponentClick,
selectedOptions: selectedComponents,
})
.then(({ button, list }) => {
globals.componentsButton = button;
globals.componentsDrop = new Drop({
target: button,
content: list,
classes: "drop-theme-arrows codecov-z1 codecov-bg-white",
position: "bottom right",
openOn: "click",
});
})
}).then(({ button, list }) => {
globals.componentsButton = button;
globals.componentsDrop = new Drop({
target: button,
content: list,
classes: "drop-theme-arrows codecov-z1 codecov-bg-white",
position: "bottom right",
openOn: "click",
});
});
}

// If commit sha is defined use that, otherwise just branch name
const getReportFn = metadata.commit ? getCommitReport : getBranchReport;

let coverageReportResponses: Array<FileCoverageReportResponse>;
try {
if (selectedFlags?.length > 0) {
if (selectedFlags?.length > 0 && selectedComponents?.length > 0) {
coverageReportResponses = await Promise.all(
selectedFlags.flatMap((flag) =>
selectedComponents.map((component) =>
getReportFn(metadata, flag, component)
)
)
);
} else if (selectedFlags?.length > 0) {
coverageReportResponses = await Promise.all(
selectedFlags.map((flag) => getCommitReport(metadata, flag, undefined))
selectedFlags.map((flag) => getReportFn(metadata, flag, undefined))
);
} else if (selectedComponents?.length > 0) {
coverageReportResponses = await Promise.all(
selectedComponents.map((component) =>
getCommitReport(metadata, undefined, component)
getReportFn(metadata, undefined, component)
)
);
} else {
coverageReportResponses = await Promise.all([
await getCommitReport(metadata, undefined, undefined),
]);
coverageReportResponses = [
await getReportFn(metadata, undefined, undefined),
];
}
} catch (e) {
updateButton(`Coverage: ⚠`);
Expand Down Expand Up @@ -220,7 +266,6 @@ async function process(metadata: FileMetadata): Promise<void> {
if (_.isEmpty(coverageReport)) {
updateButton(`Coverage: N/A`);
globals.coverageReport = {};
await promptPastReport(metadata);
return;
}

Expand All @@ -232,40 +277,6 @@ async function process(metadata: FileMetadata): Promise<void> {
animateAndAnnotateLines(noVirtLineSelector, annotateLine);
}

async function promptPastReport(metadata: FileMetadata): Promise<void> {
if (!metadata.branch) {
return;
}
const response = await getBranchReport(metadata);
const regexp = /app.codecov.io\/github\/.*\/.*\/commit\/(?<commit>.*)\/blob/;
const matches = regexp.exec(response.commit_file_url);
const commit = matches?.groups?.commit;
if (!commit) {
throw new Error("Could not parse commit hash from response for past coverage report")
}
const link = document.URL.replace(
`blob/${metadata.branch}`,
`blob/${commit}`
);
globals.prompt = createPrompt(
<span>
Coverage report not available for branch HEAD (
{metadata.commit.substr(0, 7)}), most recent coverage report for this
branch available at commit <a href={link}>{commit.substr(0, 7)}</a>
</span>
);
}

function createPrompt(child: any) {
const ref = document.querySelector('[data-testid="latest-commit"]')
?.parentElement?.parentElement;
if (!ref) {
throw new Error("Could not find reference element to render prompt")
}
const prompt = <div className="codecov-mb2 codecov-mx1">{child}</div>;
return ref.insertAdjacentElement("afterend", prompt) as HTMLElement;
}

function createCoverageButton() {
const rawButton = document.querySelector('[data-testid="raw-button"]');
if (!rawButton) {
Expand Down
33 changes: 26 additions & 7 deletions src/content/github/file/utils/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,34 @@ export async function createDropdown({
previousElement: HTMLElement;
selectedOptions: string[];
}) {
const editButton = document
.querySelector('[data-testid="more-edit-button"]')!
.closest("div")!;
const dropdownButton = editButton.cloneNode(true) as HTMLElement;
const textNode: HTMLElement = dropdownButton.querySelector('[data-component="IconButton"]')!;
// Build the button out of the Raw/copy/download button group
const rawButton = document
.querySelector('[data-testid="download-raw-button"]')!
.closest("div");
if (!rawButton) throw new Error("Could not find raw button group");
const dropdownButton = rawButton.cloneNode(true) as HTMLElement;
// Remove copy button
const copyButton = dropdownButton.querySelector(
'[data-testid="copy-raw-button"]'
);
if (!copyButton) throw new Error("Could not find copy button");
dropdownButton.removeChild(copyButton);
// Replace download button with dropdown button
const downloadButton = dropdownButton.querySelector(
'[data-testid="download-raw-button"]'
);
if (!downloadButton || !downloadButton.firstChild)
throw new Error("Could not find download button or it is missing children");
const triangleDownSvg = document.querySelector(".octicon-triangle-down");
if (!triangleDownSvg) throw new Error("Could not find triangle down svg");
downloadButton.replaceChild(triangleDownSvg, downloadButton.firstChild);

const textNode = dropdownButton.querySelector('[data-testid="raw-button"]');
if (!textNode || !textNode.parentElement)
throw new Error("Could not find textNode");
textNode.innerHTML = "";
textNode.ariaDisabled = "false";
textNode.parentElement!.ariaLabel = tooltip;
textNode.style.padding = `0 ${title.length * 5}px`;
textNode.parentElement.ariaLabel = tooltip;
textNode.appendChild(<span>{title}</span>);
previousElement.insertAdjacentElement("afterend", dropdownButton);

Expand Down
9 changes: 2 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
export type FileMetadata = {
owner: string;
repo: string;
path: string;
commit: string;
branch: string | undefined;
};
export type FileMetadata = { [key: string]: string };
export type PRMetadata = { [key: string]: string };

export enum CoverageStatus {
COVERED,
Expand Down

0 comments on commit 662b957

Please sign in to comment.