Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref: Optimize file fetching code #96

Merged
merged 3 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫡

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
157 changes: 80 additions & 77 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 { isFileUrl } from "../common/utils";
import Sentry from '../../common/sentry';
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 @@ -62,22 +60,61 @@ function init(): Promise<void> {
}

async function main(): Promise<void> {
try {
if (!isFileUrl(document.URL)) {
print("file not detected at current URL");
return;
}
const urlMetadata = getMetadataFromURL();
if (!urlMetadata) {
print("file not detected at current URL");
return;
}

let metadata: FileMetadata;
metadata = await getMetadata(document.URL);
globals.coverageButton = createCoverageButton();

globals.coverageButton = createCoverageButton();
process(urlMetadata).catch((e) => {
print("unexpected error", e);
updateButton("Coverage: ⚠");
});
}

process(metadata)
} catch (e) {
Sentry.captureException(e)
throw e
function getMetadataFromURL(): { [key: string]: string } | null {
const regexp =
/\/(?<owner>.+?)\/(?<repo>.+?)\/blob\/(?<branch>.+?)\/(?<path>.+?)$/;
const matches = regexp.exec(window.location.pathname);
const groups = matches?.groups;
if (!groups) {
return null;
}

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

// 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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the long sha can be found inside a few links on this page, that's what this code extracts.

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,34 +187,36 @@ 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) {
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([
spalmurray-codecov marked this conversation as resolved.
Show resolved Hide resolved
await getCommitReport(metadata, undefined, undefined),
await getReportFn(metadata, undefined, undefined),
]);
}
spalmurray-codecov marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
Expand Down Expand Up @@ -220,7 +258,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 +269,6 @@ async function process(metadata: FileMetadata): Promise<void> {
animateAndAnnotateLines(noVirtLineSelector, annotateLine);
}

async function promptPastReport(metadata: FileMetadata): Promise<void> {
if (!metadata.branch) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will never be a need for this code anymore. This was called when the metadata for a branch gave the HEAD commit and there was no coverage for that HEAD commit. If you're on a branch now, Codecov will handle this on the API side and give you the last good coverage.

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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're looking at a file at a commit, the old button we were building from does not exist. I adjusted the code to use a button that exists on both types of view (the raw/copy/download group). Additionally, I made the code a bit safer by removing !s

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
Loading