From d6264ef4ac4c67ab937c21b4a0b23c12ee3b6767 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sat, 21 Sep 2024 13:49:29 -0500 Subject: [PATCH] Huge speed improvements to commit fetching --- .../charts/GithubContributionChart.js | 34 ++++++-- src/lib/github.js | 85 ++++++++----------- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/components/charts/GithubContributionChart.js b/src/components/charts/GithubContributionChart.js index e1417ef..418a3f7 100644 --- a/src/components/charts/GithubContributionChart.js +++ b/src/components/charts/GithubContributionChart.js @@ -1,9 +1,11 @@ import React, { useState, useEffect, useCallback } from 'react'; -import { getContributions } from '../../lib/github'; +import { getAllCommits } from '@/lib/github'; const GithubContributionChart = ({ username }) => { const [contributionData, setContributionData] = useState({}); const [loading, setLoading] = useState(true); + const [timeTaken, setTimeTaken] = useState(null); + const [totalCommits, setTotalCommits] = useState(0); const getColor = useCallback((count) => { if (count === 0) return 'bg-gray-100'; @@ -30,15 +32,27 @@ const GithubContributionChart = ({ username }) => { useEffect(() => { const fetchData = async () => { setLoading(true); - try { - await getContributions(username, (data) => { - setContributionData(data); - setLoading(false); + const startTime = Date.now(); + const sixMonthsAgo = new Date(); + sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); + + let commitCount = 0; + + for await (const commit of getAllCommits(username, sixMonthsAgo)) { + const date = commit.commit.author.date.split('T')[0]; + setContributionData(prev => { + const newData = { ...prev }; + newData[date] = (newData[date] || 0) + 1; + return newData; }); - } catch (error) { - console.error("Error fetching contribution data:", error); - setLoading(false); + commitCount++; + setTotalCommits(commitCount); } + + const endTime = Date.now(); + setTimeTaken(((endTime - startTime) / 1000).toFixed(2)); + setLoading(false); + console.log(`Total commits fetched: ${commitCount}`); }; fetchData(); @@ -49,7 +63,9 @@ const GithubContributionChart = ({ username }) => { return (

Github Contributions for {username}

- {loading &&

Loading contribution data...

} + {loading &&

Loading contribution data... ({totalCommits} commits fetched)

} + {timeTaken &&

Time taken to fetch data: {timeTaken} seconds

} + {!loading &&

Total commits: {totalCommits}

}
{calendar.map((day, index) => (
{ octokit.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`); @@ -21,55 +20,45 @@ const octokit = new ThrottledOctokit({ }, }); -async function getContributions(username, updateCallback) { - const sixMonthsAgo = new Date(); - sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); - const sinceDate = sixMonthsAgo.toISOString(); +export async function* getAllCommits(username, since) { + let page = 1; - const contributionData = {}; + while (true) { + try { + const { data: repos } = await octokit.repos.listForUser({ + username, + per_page: 100, + page, + }); - try { - const repos = await octokit.paginate(octokit.repos.listForUser, { - username, - per_page: 100, - }); + if (repos.length === 0) break; - console.log(`Fetched ${repos.length} repositories for ${username}`); + const repoPromises = repos.map(repo => + octokit.repos.listCommits({ + owner: username, + repo: repo.name, + since: since.toISOString(), + per_page: 100, + }) + ); - // Call updateCallback immediately after fetching repos - updateCallback({}); + const repoResults = await Promise.allSettled(repoPromises); - for (const repo of repos) { - console.log(`Fetching commits for ${repo.name}`); - try { - const commits = await octokit.paginate(octokit.repos.listCommits, { - owner: repo.owner.login, - repo: repo.name, - author: username, - since: sinceDate, - per_page: 100, - }); + for (const result of repoResults) { + if (result.status === 'fulfilled') { + for (const commit of result.value.data) { + yield commit; + } + } else { + console.warn(`Error fetching commits: ${result.reason}`); + } + } - console.log(`Fetched ${commits.length} commits for ${repo.name}`); - - commits.forEach(commit => { - const date = commit.commit.author.date.split('T')[0]; - contributionData[date] = (contributionData[date] || 0) + 1; - // Call the update callback after processing each commit - updateCallback({...contributionData}); - }); - } catch (repoError) { - console.error(`Error fetching commits for ${repo.name}:`, repoError.message); - } + page++; + } catch (error) { + console.error("Error fetching repositories:", error.message); + break; + } } - - console.log('Final contribution data:', contributionData); - return contributionData; - } catch (error) { - console.error("Error fetching contribution data:", error); - throw error; - } } -export { getContributions }; -