Skip to content

Instantly share code, notes, and snippets.

@nsdevaraj
Created August 11, 2025 09:12
Show Gist options
  • Save nsdevaraj/ed02f7605dfb9fad841cdb2ae05052a2 to your computer and use it in GitHub Desktop.
Save nsdevaraj/ed02f7605dfb9fad841cdb2ae05052a2 to your computer and use it in GitHub Desktop.
GitHub pr counter
// background.js (robust counting + diagnostics)
chrome.action.onClicked.addListener(async () => {
console.log("Extension clicked — starting PR count...");
const tabs = await chrome.tabs.query({ url: "https://github.com/*" });
if (!tabs.length) {
console.warn("No matching GitHub tabs open.");
return;
}
for (const tab of tabs) {
try {
const results = await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
const txt = el => (el && el.textContent ? el.textContent.trim() : "");
const delay = ms => new Promise(r => setTimeout(r, ms));
const scanOnce = () => {
const anchors = Array.from(document.querySelectorAll('a[href*="/pull/"]'));
const allPaths = new Set();
anchors.forEach(a => {
try { allPaths.add(new URL(a.href, location.origin).pathname); } catch(e) {}
});
// match anchors that appear inside an activity/timeline node that mentions "pull request" + verbs
const matched = anchors.filter(a => {
let node = a;
for (let i = 0; i < 8 && node; i++) {
const t = txt(node);
if (/\bpull request\b/i.test(t) &&
/(created|opened|submitted|merged|closed|opened other|opened.*other)/i.test(t)) {
return true;
}
node = node.parentElement;
}
return false;
});
const explicitPaths = new Set(matched.map(a => {
try { return new URL(a.href, location.origin).pathname; } catch(e) { return a.getAttribute('href'); }
}));
// summary patterns like "Opened 10 other pull requests in 2 repositories"
let otherCount = 0;
const summaryCandidate = Array.from(document.querySelectorAll('*')).find(el =>
/\bOpened\s+\d+\s+other pull requests\b/i.test(txt(el)) ||
/\bopened\s+\d+\s+other pull requests\b/i.test(txt(el)) ||
/\bOpened\s+\d+\s+pull requests\b/i.test(txt(el))
);
if (summaryCandidate) {
const m = txt(summaryCandidate).match(/(\d+)/);
if (m) otherCount = parseInt(m[1], 10);
}
return {
anchorsFound: anchors.length,
uniquePRPaths: allPaths.size,
matchedAnchors: matched.length,
explicitPRs: explicitPaths.size,
otherCount,
total: explicitPaths.size + otherCount
};
};
// retry a few times to let dynamic content render
return (async () => {
const maxRetries = 6;
for (let i = 0; i <= maxRetries; i++) {
const r = scanOnce();
if (r.anchorsFound > 0 || i === maxRetries) {
chrome.runtime.sendMessage({ __pr_counter_result: r, url: location.href });
return r;
}
await delay(300);
}
})();
}
});
console.log(`Injected into tab ${tab.id}`, results);
} catch (err) {
console.error('Injection error for tab', tab.id, err);
}
}
});
chrome.runtime.onMessage.addListener((message) => {
if (message && message.__pr_counter_result) {
const r = message.__pr_counter_result;
console.log(`Results from ${message.url}`);
console.log(`- anchorsFound: ${r.anchorsFound}`);
// console.log(`- uniquePRPaths: ${r.uniquePRPaths}`);
// console.log(`- matchedAnchors: ${r.matchedAnchors}`);
// console.log(`- explicitPRs: ${r.explicitPRs}`);
// console.log(`- otherCount: ${r.otherCount}`);
// console.log(`- total: ${r.total}`);
}
});
{
"manifest_version": 3,
"name": "GitHub PR Counter",
"version": "1.0",
"description": "Counts PRs from GitHub profile pages.",
"permissions": [
"tabs",
"scripting"
],
"host_permissions": [
"https://github.com/*"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Count GitHub PRs"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment