Skip to content

Commit 7e27f91

Browse files
committed
changes for error handling
1 parent 7e80b1f commit 7e27f91

File tree

1 file changed

+241
-40
lines changed

1 file changed

+241
-40
lines changed

src/scripts/scrumHelper.js

Lines changed: 241 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ function allIncluded(outputTarget = 'email') {
2828
let showClosedLabel = true;
2929
let userReason = '';
3030

31-
let pr_merged_button =
32-
'<div style="vertical-align:middle;display: inline-block;padding: 0px 4px;font-size:9px;font-weight: 600;color: #fff;text-align: center;background-color: #6f42c1;border-radius: 3px;line-height: 12px;margin-bottom: 2px;" class="State State--purple">closed</div>';
33-
let pr_unmerged_button =
31+
let pr_open_button =
3432
'<div style="vertical-align:middle;display: inline-block;padding: 0px 4px;font-size:9px;font-weight: 600;color: #fff;text-align: center;background-color: #2cbe4e;border-radius: 3px;line-height: 12px;margin-bottom: 2px;" class="State State--green">open</div>';
33+
let pr_closed_button =
34+
'<div style="vertical-align:middle;display: inline-block;padding: 0px 4px;font-size:9px;font-weight: 600;color: #fff;text-align: center;background-color: #d73a49;border-radius: 3px;line-height: 12px;margin-bottom: 2px;" class="State State--red">closed</div>';
35+
let pr_merged_button =
36+
'<div style="vertical-align:middle;display: inline-block;padding: 0px 4px;font-size:9px;font-weight: 600;color: #fff;text-align: center;background-color: #6f42c1;border-radius: 3px;line-height: 12px;margin-bottom: 2px;" class="State State--purple">merged</div>';
3537

3638
let issue_closed_button =
3739
'<div style="vertical-align:middle;display: inline-block;padding: 0px 4px;font-size:9px;font-weight: 600;color: #fff;text-align: center;background-color: #6f42c1;border-radius: 3px;line-height: 12px;margin-bottom: 2px;" class="State State--purple">closed</div>';
@@ -119,13 +121,13 @@ function allIncluded(outputTarget = 'email') {
119121
}
120122
if (!items.showOpenLabel) {
121123
showOpenLabel = false;
122-
pr_unmerged_button = '';
124+
pr_open_button = '';
123125
issue_opened_button = '';
124126
}
125127
if (!items.showClosedLabel) {
126128
showClosedLabel = false;
127-
pr_merged_button = '';
128-
129+
pr_closed_button = '';
130+
129131
}
130132
if (items.userReason) {
131133
userReason = items.userReason;
@@ -708,20 +710,29 @@ ${userReason}`;
708710
return Math.ceil((d2 - d1) / (1000 * 60 * 60 * 24));
709711
}
710712

711-
// Helper to fetch PR details for merged status
712-
async function fetchPrMergedStatus(owner, repo, number, headers) {
713+
// Session cache for merged status
714+
let sessionMergedStatusCache = {};
715+
716+
// Helper to fetch PR details for merged status (REST, single PR)
717+
async function fetchPrMergedStatusREST(owner, repo, number, headers) {
718+
const cacheKey = `${owner}/${repo}#${number}`;
719+
if (sessionMergedStatusCache[cacheKey] !== undefined) {
720+
return sessionMergedStatusCache[cacheKey];
721+
}
713722
const url = `https://api.github.com/repos/${owner}/${repo}/pulls/${number}`;
714723
try {
715724
const res = await fetch(url, { headers });
716725
if (!res.ok) return null;
717726
const data = await res.json();
718-
return data.merged_at ? true : false;
727+
const merged = !!data.merged_at;
728+
sessionMergedStatusCache[cacheKey] = merged;
729+
return merged;
719730
} catch (e) {
720731
return null;
721732
}
722733
}
723734

724-
// Update: make this async to allow merged status fetch and fallback
735+
// Refactor writeGithubIssuesPrs to implement the new logic
725736
async function writeGithubIssuesPrs() {
726737
let items = githubIssuesData.items;
727738
lastWeekArray = [];
@@ -735,7 +746,42 @@ ${userReason}`;
735746
let useMergedStatus = false;
736747
let fallbackToSimple = false;
737748
let daysRange = getDaysBetween(startingDate, endingDate);
738-
if (daysRange <= 14) useMergedStatus = true;
749+
if (daysRange <= 7) useMergedStatus = true;
750+
751+
// Collect PRs to batch fetch merged status
752+
let prsToCheck = [];
753+
for (let i = 0; i < items.length; i++) {
754+
let item = items[i];
755+
if (item.pull_request && item.state === 'closed' && useMergedStatus && !fallbackToSimple) {
756+
let repository_url = item.repository_url;
757+
let repoParts = repository_url.split('/');
758+
let owner = repoParts[repoParts.length - 2];
759+
let repo = repoParts[repoParts.length - 1];
760+
prsToCheck.push({ owner, repo, number: item.number, idx: i });
761+
}
762+
}
763+
764+
let mergedStatusResults = {};
765+
if (githubToken) {
766+
// Use GraphQL batching for all cases
767+
if (prsToCheck.length > 0) {
768+
mergedStatusResults = await fetchPrsMergedStatusBatch(prsToCheck, headers);
769+
}
770+
} else if (useMergedStatus) {
771+
if (prsToCheck.length > 30) {
772+
fallbackToSimple = true;
773+
if (typeof Materialize !== 'undefined' && Materialize.toast) {
774+
Materialize.toast('API limit exceeded. Please use a GitHub token for full status. Showing only open/closed PRs.', 5000);
775+
}
776+
} else {
777+
// Use REST API for each PR, cache results
778+
for (let pr of prsToCheck) {
779+
let merged = await fetchPrMergedStatusREST(pr.owner, pr.repo, pr.number, headers);
780+
mergedStatusResults[`${pr.owner}/${pr.repo}#${pr.number}`] = merged;
781+
}
782+
}
783+
}
784+
739785
for (let i = 0; i < items.length; i++) {
740786
let item = items[i];
741787
let html_url = item.html_url;
@@ -746,29 +792,23 @@ ${userReason}`;
746792
let li = '';
747793
if (item.pull_request) {
748794
if (item.state === 'open') {
749-
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_unmerged_button}</li>`;
795+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_open_button}</li>`;
750796
} else if (item.state === 'closed') {
751-
if (useMergedStatus && !fallbackToSimple) {
752-
let owner = repository_url.split('/')[repository_url.split('/').length - 2];
753-
let merged = null;
754-
try {
755-
merged = await fetchPrMergedStatus(owner, project, number, headers);
756-
if (merged === true) {
757-
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_true_button}</li>`;
758-
} else if (merged === false) {
759-
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_false_button}</li>`;
760-
} else {
761-
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_false_button}</li>`;
762-
}
763-
} catch (e) {
764-
fallbackToSimple = true;
797+
if ((githubToken || (useMergedStatus && !fallbackToSimple)) && mergedStatusResults) {
798+
let repository_url = item.repository_url;
799+
let repoParts = repository_url.split('/');
800+
let owner = repoParts[repoParts.length - 2];
801+
let repo = repoParts[repoParts.length - 1];
802+
let merged = mergedStatusResults[`${owner}/${repo}#${number}`];
803+
if (merged === true) {
765804
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_button}</li>`;
766-
if (typeof Materialize !== 'undefined' && Materialize.toast) {
767-
Materialize.toast('API limit exceeded or error occurred. Please use a GitHub token for higher limits.', 5000);
768-
}
805+
} else if (merged === false) {
806+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
807+
} else {
808+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
769809
}
770810
} else {
771-
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_button}</li>`;
811+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
772812
}
773813
}
774814
} else {
@@ -845,16 +885,20 @@ ${userReason}`;
845885

846886
//check for github safe writing
847887
let intervalWriteGithubIssues = setInterval(async () => {
848-
if (outputTarget === 'popup') {
849-
if (githubUsername && githubIssuesData) {
850-
clearInterval(intervalWriteGithubIssues);
851-
await writeGithubIssuesPrs();
852-
}
853-
} else {
854-
if (scrumBody && githubUsername && githubIssuesData) {
855-
clearInterval(intervalWriteGithubIssues);
856-
await writeGithubIssuesPrs();
888+
try {
889+
if (outputTarget === 'popup') {
890+
if (githubUsername && githubIssuesData) {
891+
clearInterval(intervalWriteGithubIssues);
892+
await writeGithubIssuesPrs();
893+
}
894+
} else {
895+
if (scrumBody && githubUsername && githubIssuesData) {
896+
clearInterval(intervalWriteGithubIssues);
897+
await writeGithubIssuesPrs();
898+
}
857899
}
900+
} catch (err) {
901+
logError('Interval writeGithubIssuesPrs error:', err);
858902
}
859903
}, 500);
860904
let intervalWriteGithubPrs = setInterval(() => {
@@ -914,4 +958,161 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
914958
});
915959
return true;
916960
}
917-
});
961+
});
962+
963+
// Replace all references to pr_unmerged_button, pr_merged_true_button, pr_merged_false_button with unified names
964+
// ... existing code ...
965+
// Refactor fetchPrMergedStatus to batch requests
966+
async function fetchPrsMergedStatusBatch(prs, headers) {
967+
// prs: Array of {owner, repo, number}
968+
const results = {};
969+
if (prs.length === 0) return results;
970+
// Use GitHub GraphQL API for batching
971+
const query = `query {
972+
${prs.map((pr, i) => ` repo${i}: repository(owner: \"${pr.owner}\", name: \"${pr.repo}\") {
973+
pr${i}: pullRequest(number: ${pr.number}) { merged }
974+
}`).join('\n')}
975+
}`;
976+
try {
977+
const res = await fetch('https://api.github.com/graphql', {
978+
method: 'POST',
979+
headers: {
980+
...headers,
981+
'Content-Type': 'application/json',
982+
},
983+
body: JSON.stringify({ query }),
984+
});
985+
if (!res.ok) return results;
986+
const data = await res.json();
987+
prs.forEach((pr, i) => {
988+
const merged = data.data[`repo${i}`]?.[`pr${i}`]?.merged;
989+
results[`${pr.owner}/${pr.repo}#${pr.number}`] = merged;
990+
});
991+
return results;
992+
} catch (e) {
993+
return results;
994+
}
995+
}
996+
// ... existing code ...
997+
// Refactor writeGithubIssuesPrs to batch merged status requests
998+
async function writeGithubIssuesPrs() {
999+
let items = githubIssuesData.items;
1000+
lastWeekArray = [];
1001+
nextWeekArray = [];
1002+
if (!items) {
1003+
logError('No Github issues data available');
1004+
return;
1005+
}
1006+
const headers = { 'Accept': 'application/vnd.github.v3+json' };
1007+
if (githubToken) headers['Authorization'] = `token ${githubToken}`;
1008+
let useMergedStatus = false;
1009+
let fallbackToSimple = false;
1010+
let daysRange = getDaysBetween(startingDate, endingDate);
1011+
if (daysRange <= 14) useMergedStatus = true;
1012+
1013+
// Collect PRs to batch fetch merged status
1014+
let prsToCheck = [];
1015+
for (let i = 0; i < items.length; i++) {
1016+
let item = items[i];
1017+
if (item.pull_request && item.state === 'closed' && useMergedStatus && !fallbackToSimple) {
1018+
let repository_url = item.repository_url;
1019+
let repoParts = repository_url.split('/');
1020+
let owner = repoParts[repoParts.length - 2];
1021+
let repo = repoParts[repoParts.length - 1];
1022+
prsToCheck.push({ owner, repo, number: item.number, idx: i });
1023+
}
1024+
}
1025+
let mergedStatusResults = {};
1026+
if (prsToCheck.length > 0 && githubToken) {
1027+
mergedStatusResults = await fetchPrsMergedStatusBatch(prsToCheck, headers);
1028+
}
1029+
1030+
for (let i = 0; i < items.length; i++) {
1031+
let item = items[i];
1032+
let html_url = item.html_url;
1033+
let repository_url = item.repository_url;
1034+
let project = repository_url.substr(repository_url.lastIndexOf('/') + 1);
1035+
let title = item.title;
1036+
let number = item.number;
1037+
let li = '';
1038+
if (item.pull_request) {
1039+
if (item.state === 'open') {
1040+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_open_button}</li>`;
1041+
} else if (item.state === 'closed') {
1042+
if (useMergedStatus && !fallbackToSimple && githubToken) {
1043+
let repository_url = item.repository_url;
1044+
let repoParts = repository_url.split('/');
1045+
let owner = repoParts[repoParts.length - 2];
1046+
let repo = repoParts[repoParts.length - 1];
1047+
let merged = mergedStatusResults[`${owner}/${repo}#${number}`];
1048+
if (merged === true) {
1049+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_merged_button}</li>`;
1050+
} else if (merged === false) {
1051+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
1052+
} else {
1053+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
1054+
}
1055+
} else {
1056+
li = `<li><i>(${project})</i> - Made PR (#${number}) - <a href='${html_url}'>${title}</a> ${pr_closed_button}</li>`;
1057+
}
1058+
}
1059+
} else {
1060+
// is a issue
1061+
if (item.state === 'open' && item.body?.toUpperCase().indexOf('YES') > 0) {
1062+
let li2 =
1063+
'<li><i>(' +
1064+
project +
1065+
')</i> - Work on Issue(#' +
1066+
number +
1067+
") - <a href='" +
1068+
html_url +
1069+
"' target='_blank'>" +
1070+
title +
1071+
'</a> ' +
1072+
issue_opened_button +
1073+
'&nbsp;&nbsp;</li>';
1074+
nextWeekArray.push(li2);
1075+
}
1076+
if (item.state === 'open') {
1077+
li = `<li><i>(${project})</i> - Opened Issue(#${number}) - <a href='${html_url}'>${title}</a> ${issue_opened_button}</li>`;
1078+
} else if (item.state === 'closed') {
1079+
// Always show closed label for closed issues
1080+
li = `<li><i>(${project})</i> - Opened Issue(#${number}) - <a href='${html_url}'>${title}</a> ${issue_closed_button}</li>`;
1081+
} else {
1082+
li =
1083+
'<li><i>(' +
1084+
project +
1085+
')</i> - Opened Issue(#' +
1086+
number +
1087+
") - <a href='" +
1088+
html_url +
1089+
"' target='_blank'>" +
1090+
title +
1091+
'</a> </li>';
1092+
}
1093+
}
1094+
lastWeekArray.push(li);
1095+
}
1096+
issuesDataProcessed = true;
1097+
triggerScrumGeneration();
1098+
}
1099+
// ... existing code ...
1100+
// Wrap setInterval async handlers in try/catch
1101+
let intervalWriteGithubIssues = setInterval(async () => {
1102+
try {
1103+
if (outputTarget === 'popup') {
1104+
if (githubUsername && githubIssuesData) {
1105+
clearInterval(intervalWriteGithubIssues);
1106+
await writeGithubIssuesPrs();
1107+
}
1108+
} else {
1109+
if (scrumBody && githubUsername && githubIssuesData) {
1110+
clearInterval(intervalWriteGithubIssues);
1111+
await writeGithubIssuesPrs();
1112+
}
1113+
}
1114+
} catch (err) {
1115+
logError('Interval writeGithubIssuesPrs error:', err);
1116+
}
1117+
}, 500);
1118+
// ... existing code ...

0 commit comments

Comments
 (0)