Skip to content

Commit d9e2837

Browse files
committed
correctly adding commits
1 parent 3675295 commit d9e2837

File tree

1 file changed

+156
-65
lines changed

1 file changed

+156
-65
lines changed

src/scripts/scrumHelper.js

Lines changed: 156 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function allIncluded(outputTarget = 'email') {
3737
let issue_opened_button =
3838
'<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>';
3939

40-
const DEBUG = true; // Set to false to disable debug logs
40+
const DEBUG = false; // Set to false to disable debug logs
4141

4242
function log(...args) {
4343
if (DEBUG) {
@@ -224,20 +224,17 @@ function allIncluded(outputTarget = 'email') {
224224
chrome.storage.local.get('githubCache', (result) => {
225225
const cache = result.githubCache;
226226
if (!cache) {
227-
log('No cache found in storage');
227+
228228
resolve(false);
229229
return;
230230
}
231231
const isCacheExpired = (Date.now() - cache.timestamp) > githubCache.ttl;
232232
if (isCacheExpired) {
233-
log('Cached data is expired');
233+
234234
resolve(false);
235235
return;
236236
}
237-
log('Found valid cache:', {
238-
cacheKey: cache.cacheKey,
239-
age: `${((Date.now() - cache.timestamp) / 1000 / 60).toFixed(1)} minutes`,
240-
});
237+
241238

242239
githubCache.data = cache.data;
243240
githubCache.cacheKey = cache.cacheKey;
@@ -256,47 +253,69 @@ function allIncluded(outputTarget = 'email') {
256253
async function fetchGithubData() {
257254
const cacheKey = `${githubUsername}-${startingDate}-${endingDate}`;
258255

259-
if (githubCache.fetching || (githubCache.cacheKey === cacheKey && githubCache.data)) {
260-
return;
261-
}
262-
263-
log('Fetching Github data:', {
256+
log('Fetch request:', {
264257
username: githubUsername,
265-
dateRange: `${startingDate} to ${endingDate}`
258+
startDate: startingDate,
259+
endDate: endingDate,
260+
cacheKey: cacheKey
266261
});
267262

263+
if (githubCache.fetching) {
264+
log('Fetch already in progress, queuing request');
265+
return new Promise((resolve, reject) => {
266+
githubCache.queue.push({ resolve, reject });
267+
});
268+
}
269+
270+
if (githubCache.cacheKey === cacheKey && githubCache.data) {
271+
log('Using cached data:', {
272+
age: `${((Date.now() - githubCache.timestamp) / 1000 / 60).toFixed(1)} minutes`,
273+
dataTypes: Object.keys(githubCache.data)
274+
});
275+
return;
276+
}
277+
268278
// Check if we need to load from storage
269279
if (!githubCache.data && !githubCache.fetching) {
270-
await loadFromStorage();
280+
const loaded = await loadFromStorage();
281+
log('Storage load result:', { loaded, hasCachedData: !!githubCache.data });
271282
}
272283

273284
const now = Date.now();
274285
const isCacheFresh = (now - githubCache.timestamp) < githubCache.ttl;
275286
const isCacheKeyMatch = githubCache.cacheKey === cacheKey;
276287

288+
log('Cache status:', {
289+
isFresh: isCacheFresh,
290+
keyMatch: isCacheKeyMatch,
291+
age: githubCache.timestamp ? `${((now - githubCache.timestamp) / 1000 / 60).toFixed(1)} minutes` : 'no cache'
292+
});
293+
277294
if (githubCache.data && isCacheFresh && isCacheKeyMatch) {
295+
log('Using existing cache');
278296
processGithubData(githubCache.data);
279297
return Promise.resolve();
280298
}
281299

282300
if (!isCacheKeyMatch) {
301+
log('Cache key mismatch, clearing data');
283302
githubCache.data = null;
284303
}
285304

286-
// if fetching is in progress, queue the calls and return a promise resolved when done
287-
if (githubCache.fetching) {
288-
return new Promise((resolve, reject) => {
289-
githubCache.queue.push({ resolve, reject });
290-
});
291-
}
292-
293305
githubCache.fetching = true;
294306
githubCache.cacheKey = cacheKey;
295307

296308
let issueUrl = `https://api.github.com/search/issues?q=author%3A${githubUsername}+org%3Afossasia+created%3A${startingDate}..${endingDate}&per_page=100`;
297309
let prUrl = `https://api.github.com/search/issues?q=commenter%3A${githubUsername}+org%3Afossasia+updated%3A${startingDate}..${endingDate}&per_page=100`;
298310
let userUrl = `https://api.github.com/users/${githubUsername}`;
299-
let allPrsUrl = `https://api.github.com/search/issues?q=type:pr+author:${githubUsername}+org:fossasia&per_page=100`;
311+
let allPrsUrl = `https://api.github.com/search/issues?q=type:pr+author:${githubUsername}+org:fossasia+state:open&per_page=100`;
312+
313+
log('Fetching data from URLs:', {
314+
issues: issueUrl,
315+
prs: prUrl,
316+
user: userUrl,
317+
allPrs: allPrsUrl
318+
});
300319

301320
try {
302321
// throttling 500ms to avoid burst
@@ -325,93 +344,154 @@ function allIncluded(outputTarget = 'email') {
325344

326345
// Fetch commits for each open PR with better rate limiting and caching
327346
const fetchCommitsWithRetry = async (owner, project, pr_number, retryCount = 3) => {
328-
const commitsUrl = `https://api.github.com/repos/${owner}/${project}/pulls/${pr_number}/commits`;
347+
const fetchCommitsPage = async (pageUrl) => {
348+
const response = await fetch(pageUrl);
349+
if (!response.ok) {
350+
throw new Error(`HTTP ${response.status}`);
351+
}
352+
353+
// Get pagination links from header
354+
const linkHeader = response.headers.get('Link');
355+
let nextPage = null;
356+
if (linkHeader) {
357+
const links = linkHeader.split(',');
358+
const nextLink = links.find(link => link.includes('rel="next"'));
359+
if (nextLink) {
360+
const match = nextLink.match(/<([^>]+)>/);
361+
if (match) nextPage = match[1];
362+
}
363+
}
364+
365+
const commits = await response.json();
366+
return { commits, nextPage };
367+
};
368+
369+
const getAllCommits = async (initialUrl) => {
370+
let url = initialUrl;
371+
let allCommits = [];
372+
373+
while (url) {
374+
log(`Fetching commits page from ${url}`);
375+
const { commits, nextPage } = await fetchCommitsPage(url);
376+
allCommits = allCommits.concat(commits);
377+
url = nextPage;
378+
379+
if (nextPage) {
380+
// Add delay before fetching next page
381+
await new Promise(res => setTimeout(res, 1000));
382+
}
383+
}
384+
385+
return allCommits;
386+
};
387+
388+
const commitsUrl = `https://api.github.com/repos/${owner}/${project}/pulls/${pr_number}/commits?per_page=100`;
389+
log(`Fetching all commits for PR #${pr_number} from ${commitsUrl}`);
329390

330391
// Check if we have an error cached for this URL
331392
const errorKey = `${owner}/${project}/${pr_number}`;
332393
const cachedError = githubCache.errors[errorKey];
333394
if (cachedError && (Date.now() - cachedError.timestamp) < githubCache.errorTTL) {
334-
log(`Skipping ${errorKey} due to recent error`);
395+
log(`Skipping ${errorKey} due to recent error:`, cachedError);
335396
return null;
336397
}
337398

338399
for (let i = 0; i < retryCount; i++) {
339400
try {
340401
// Add exponential backoff between retries
341402
if (i > 0) {
342-
await new Promise(res => setTimeout(res, Math.pow(2, i) * 1000));
343-
}
344-
345-
const commitsRes = await fetch(commitsUrl);
346-
if (commitsRes.status === 404) {
347-
// Cache 404 errors to avoid retrying
348-
githubCache.errors[errorKey] = { timestamp: Date.now(), status: 404 };
349-
return null;
403+
const delay = Math.pow(2, i) * 1000;
404+
log(`Retry ${i + 1}/${retryCount} for PR #${pr_number}, waiting ${delay}ms`);
405+
await new Promise(res => setTimeout(res, delay));
350406
}
351407

352-
if (commitsRes.status === 403) {
353-
// Rate limit hit - wait longer
354-
const resetTime = commitsRes.headers.get('X-RateLimit-Reset');
355-
if (resetTime) {
356-
const waitTime = (parseInt(resetTime) * 1000) - Date.now();
357-
if (waitTime > 0) {
358-
await new Promise(res => setTimeout(res, waitTime));
359-
}
360-
}
361-
continue;
362-
}
363-
364-
if (!commitsRes.ok) {
365-
throw new Error(`HTTP ${commitsRes.status}`);
366-
}
408+
const commits = await getAllCommits(commitsUrl);
409+
log(`Fetched total ${commits.length} commits for PR #${pr_number} in ${owner}/${project}`);
410+
411+
// Log commit details for debugging
412+
commits.forEach(commit => {
413+
log(`Commit in PR #${pr_number}:`, {
414+
sha: commit.sha.substring(0, 7),
415+
author: commit.author?.login,
416+
date: commit.commit.author.date,
417+
message: commit.commit.message.split('\n')[0]
418+
});
419+
});
367420

368-
const commits = await commitsRes.json();
369-
log(`Fetched ${commits.length} commits for PR #${pr_number} in ${owner}/${project}`);
370421
return commits;
371422

372423
} catch (err) {
424+
logError(`Error fetching commits for PR #${pr_number} (attempt ${i + 1}/${retryCount}):`, err);
373425
if (i === retryCount - 1) {
374-
// Cache error on final retry
375426
githubCache.errors[errorKey] = { timestamp: Date.now(), error: err.message };
376-
logError(`Failed to fetch commits for PR #${pr_number} after ${retryCount} retries:`, err);
377427
return null;
378428
}
379429
}
380430
}
381431
return null;
382432
};
383433

384-
// Process PRs in batches to avoid rate limiting
385-
const batchSize = 3;
434+
// Process PRs in smaller batches with longer delays
435+
const batchSize = 2;
386436
const prCommits = [];
387437

388438
for (let i = 0; i < openPrs.length; i += batchSize) {
389439
const batch = openPrs.slice(i, i + batchSize);
440+
log(`Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(openPrs.length / batchSize)}`);
441+
390442
const batchResults = await Promise.all(batch.map(async pr => {
391443
const repository_url = pr.repository_url;
392444
const [owner, project] = repository_url.split('/').slice(-2);
393445

394-
// Add delay between PR commit fetches
395-
await new Promise(res => setTimeout(res, 1000));
446+
// Increased delay between PR commit fetches
447+
await new Promise(res => setTimeout(res, 2000));
396448

397449
const commits = await fetchCommitsWithRetry(owner, project, pr.number);
398450
if (!commits) return null;
399451

400-
const filteredCommits = commits.filter(commit =>
401-
commit.author?.login === githubUsername &&
402-
new Date(commit.commit.author.date) >= new Date(startingDate) &&
403-
new Date(commit.commit.author.date) <= new Date(endingDate)
404-
);
452+
const filteredCommits = commits.filter(commit => {
453+
const isAuthor = commit.author?.login === githubUsername;
454+
const commitDate = new Date(commit.commit.author.date);
455+
456+
// Create start and end date objects
457+
const startDateObj = new Date(startingDate);
458+
const endDateObj = new Date(endingDate);
459+
// Set end date to end of day (23:59:59.999)
460+
endDateObj.setHours(23, 59, 59, 999);
461+
462+
const isInDateRange = commitDate >= startDateObj &&
463+
commitDate <= endDateObj;
464+
465+
log(`Filtering commit ${commit.sha.substring(0, 7)}:`, {
466+
isAuthor,
467+
author: commit.author?.login,
468+
commitDate: commit.commit.author.date,
469+
inRange: isInDateRange,
470+
startDate: startDateObj.toISOString(),
471+
endDate: endDateObj.toISOString()
472+
});
405473

406-
if (filteredCommits.length === 0) return null;
474+
return isAuthor && isInDateRange;
475+
});
407476

477+
if (filteredCommits.length === 0) {
478+
log(`No matching commits found for PR #${pr.number}`);
479+
return null;
480+
}
481+
482+
log(`Found ${filteredCommits.length} matching commits in PR #${pr.number}`);
408483
return {
409484
pr,
410485
commits: filteredCommits
411486
};
412487
}));
413488

414489
prCommits.push(...batchResults.filter(Boolean));
490+
491+
// Add delay between batches
492+
if (i + batchSize < openPrs.length) {
493+
await new Promise(res => setTimeout(res, 3000));
494+
}
415495
}
416496

417497
// Filter out null results and empty commits
@@ -481,7 +561,14 @@ function allIncluded(outputTarget = 'email') {
481561
verifyCacheStatus();
482562

483563
async function forceGithubDataRefresh() {
564+
log('Starting force refresh...');
484565
const oldCacheKey = githubCache.cacheKey;
566+
log('Old cache state:', {
567+
key: oldCacheKey,
568+
hasData: !!githubCache.data,
569+
timestamp: githubCache.timestamp
570+
});
571+
485572
githubCache = {
486573
data: null,
487574
cacheKey: oldCacheKey,
@@ -494,21 +581,25 @@ function allIncluded(outputTarget = 'email') {
494581
subject: null
495582
};
496583

584+
log('Cache reset complete');
585+
497586
await new Promise(resolve => {
498-
chrome.storage.local.remove('githubCache', resolve);
587+
chrome.storage.local.remove('githubCache', () => {
588+
log('Storage cache cleared');
589+
resolve();
590+
});
499591
});
500592

501593
try {
594+
log('Starting fresh data fetch...');
502595
await fetchGithubData();
596+
log('Force refresh completed successfully');
503597
return { success: true, timestamp: Date.now() };
504598
} catch (err) {
505599
logError('Force refresh failed:', err);
506600
throw err;
507601
}
508602
}
509-
if (typeof window !== 'undefined') {
510-
window.forceGithubDataRefresh = forceGithubDataRefresh;
511-
}
512603

513604
function processGithubData(data) {
514605
githubIssuesData = data.githubIssuesData;

0 commit comments

Comments
 (0)