Fix github query to grab all contributions

This commit is contained in:
Alex Selimov 2026-05-13 06:54:12 -04:00
parent 620121b505
commit 53084c4e6f

View file

@ -11,19 +11,27 @@ const config = {
forgejoURL: requireEnv("FJ_URL"),
};
const now = new Date();
const oneYearAgo = new Date();
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
const formattedOneYearAgo = oneYearAgo.toISOString().replace("Z", "+00:00");
const ghQuery = `
{
user(login: "aselimov") {
contributionsCollection {
function buildGhQuery(from: string, to: string): string {
return `{
viewer {
contributionsCollection(from: "${from}", to: "${to}") {
contributionCalendar {
weeks {
contributionDays {
date
contributionCount
}
}
}
commitContributionsByRepository(maxRepositories: 100) {
repository {
nameWithOwner
isMirror
isPrivate
}
contributions(first: 100) {
nodes {
@ -34,8 +42,8 @@ const ghQuery = `
}
}
}
}`;
}
`;
type DayContributions = {
[repo: string]: number;
@ -126,25 +134,33 @@ function deduplicateAcrossPlatforms(
function parseGitHubContributions(data: any): ActivityMap {
const result: ActivityMap = {};
const repos =
data?.data?.user?.contributionsCollection
?.commitContributionsByRepository ?? [];
const collection = data?.data?.viewer?.contributionsCollection;
for (const repoEntry of repos) {
const calendarMap: { [day: string]: number } = {};
for (const week of collection?.contributionCalendar?.weeks ?? []) {
for (const day of week.contributionDays) {
if (day.contributionCount > 0) calendarMap[day.date] = day.contributionCount;
}
}
for (const repoEntry of collection?.commitContributionsByRepository ?? []) {
const repoName: string = repoEntry.repository.nameWithOwner;
const isMirror: boolean = repoEntry.repository.isMirror;
const isPrivate: boolean = repoEntry.repository.isPrivate;
if (isMirror) continue;
const displayName = isPrivate ? "private" : repoName;
if (repoEntry.repository.isMirror) continue;
for (const contribution of repoEntry.contributions.nodes) {
const day: string = contribution.occurredAt.split("T")[0];
const count: number = contribution.commitCount;
if (!result[day]) result[day] = {};
result[day]![displayName] = (result[day]![displayName] ?? 0) + count;
result[day]![repoName] = (result[day]![repoName] ?? 0) + count;
}
}
for (const [day, total] of Object.entries(calendarMap)) {
const known = Object.values(result[day] ?? {}).reduce((a, b) => a + b, 0);
const hidden = total - known;
if (hidden > 0) {
if (!result[day]) result[day] = {};
result[day]!["private"] = (result[day]!["private"] ?? 0) + hidden;
}
}
@ -215,25 +231,49 @@ async function getForgejoActivityMap(): Promise<ActivityMap> {
return map;
}
async function makeActivityMap(): Promise<ActivityMap> {
const ghResponse = await fetch("https://api.github.com/graphql", {
async function ghFetch(query: string): Promise<any> {
const response = await fetch("https://api.github.com/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${config.githubApiKey}`,
},
body: JSON.stringify({ query: ghQuery }),
body: JSON.stringify({ query }),
});
if (!ghResponse.ok) {
if (!response.ok) {
throw new Error(
`GitHub API error: ${ghResponse.status} ${ghResponse.statusText}`,
`GitHub API error: ${response.status} ${response.statusText}`,
);
}
return response.json();
}
const ghData = await ghResponse.json();
const ghMap = parseGitHubContributions(ghData);
const fjMap = await getForgejoActivityMap();
async function getGitHubActivityMap(): Promise<ActivityMap> {
const ranges = Array.from({ length: 12 }, (_, i) => {
const to = new Date(now);
to.setMonth(to.getMonth() - i);
const from = new Date(to);
from.setMonth(from.getMonth() - 1);
return { from: from.toISOString(), to: to.toISOString() };
});
const results = await Promise.all(
ranges.map(({ from, to }) => ghFetch(buildGhQuery(from, to))),
);
const map: ActivityMap = {};
for (const data of results) {
mergeInto(map, parseGitHubContributions(data));
}
return map;
}
async function makeActivityMap(): Promise<ActivityMap> {
const [ghMap, fjMap] = await Promise.all([
getGitHubActivityMap(),
getForgejoActivityMap(),
]);
return deduplicateAcrossPlatforms(ghMap, fjMap);
}