Add gitlab to provides
This commit is contained in:
parent
46315d9a62
commit
277e05fa2e
3 changed files with 101 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
test.html
|
test.html
|
||||||
activity.json
|
activity.json
|
||||||
|
public/
|
||||||
|
|
|
||||||
6
get_history/.env.example
Normal file
6
get_history/.env.example
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
GH_API_KEY=
|
||||||
|
FJ_API_KEY=
|
||||||
|
FJ_USER=
|
||||||
|
FJ_URL=
|
||||||
|
GL_API_KEY=
|
||||||
|
GL_USER=
|
||||||
|
|
@ -9,6 +9,9 @@ const config = {
|
||||||
forgejoApiKey: requireEnv("FJ_API_KEY"),
|
forgejoApiKey: requireEnv("FJ_API_KEY"),
|
||||||
forgejoUsername: requireEnv("FJ_USER"),
|
forgejoUsername: requireEnv("FJ_USER"),
|
||||||
forgejoURL: requireEnv("FJ_URL"),
|
forgejoURL: requireEnv("FJ_URL"),
|
||||||
|
gitlabApiKey: process.env["GL_API_KEY"],
|
||||||
|
gitlabUsername: process.env["GL_USER"],
|
||||||
|
gitlabURL: process.env["GL_URL"] ?? "https://gitlab.com",
|
||||||
};
|
};
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
@ -269,13 +272,102 @@ async function getGitHubActivityMap(): Promise<ActivityMap> {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseGitLabEvents(events: any[]): ActivityMap {
|
||||||
|
const result: ActivityMap = {};
|
||||||
|
|
||||||
|
for (const event of events) {
|
||||||
|
const pushData = event.push_data;
|
||||||
|
if (!pushData) continue;
|
||||||
|
// "deleted" is a branch deletion — no commits to count
|
||||||
|
if (pushData.action === "deleted") continue;
|
||||||
|
|
||||||
|
// New branch pushes report commit_count=0 even though commits exist;
|
||||||
|
// fall back to 1 when there's a known head commit.
|
||||||
|
const commitCount: number =
|
||||||
|
pushData.commit_count > 0
|
||||||
|
? pushData.commit_count
|
||||||
|
: pushData.commit_to
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
if (commitCount === 0) continue;
|
||||||
|
|
||||||
|
// GitLab doesn't include a nested project object in the events API response;
|
||||||
|
// construct a name from the fields that are always present.
|
||||||
|
const repoFullName: string =
|
||||||
|
event.project?.path_with_namespace ??
|
||||||
|
(event.author_username && event.target_title
|
||||||
|
? `${event.author_username}/${event.target_title}`
|
||||||
|
: "unknown");
|
||||||
|
const isPrivate: boolean = event.project?.visibility === "private";
|
||||||
|
const displayName = isPrivate ? "private" : repoFullName;
|
||||||
|
|
||||||
|
const day: string = event.created_at.split("T")[0]!;
|
||||||
|
|
||||||
|
if (!result[day]) result[day] = {};
|
||||||
|
result[day]![displayName] = (result[day]![displayName] ?? 0) + commitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGitLabActivityMap(): Promise<ActivityMap> {
|
||||||
|
if (!config.gitlabApiKey || !config.gitlabUsername) {
|
||||||
|
console.log("[GitLab] Skipping: GL_API_KEY or GL_USER not set");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageLimit = 100;
|
||||||
|
let page = 1;
|
||||||
|
const map: ActivityMap = {};
|
||||||
|
const afterDate = oneYearAgo.toISOString().split("T")[0]!;
|
||||||
|
|
||||||
|
console.log(`[GitLab] Fetching events for user "${config.gitlabUsername}" from ${config.gitlabURL} after ${afterDate}`);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const url = `${config.gitlabURL}/api/v4/users/${config.gitlabUsername}/events?action=pushed&after=${afterDate}&per_page=${pageLimit}&page=${page}`;
|
||||||
|
console.log(`[GitLab] GET ${url}`);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: { "PRIVATE-TOKEN": config.gitlabApiKey },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[GitLab] Response: ${response.status} ${response.statusText}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const body = await response.text();
|
||||||
|
console.error(`[GitLab] Error body: ${body}`);
|
||||||
|
throw new Error(`GitLab API error: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const events: any[] = await response.json();
|
||||||
|
console.log(`[GitLab] Page ${page}: received ${events.length} events`);
|
||||||
|
|
||||||
|
if (events.length > 0) {
|
||||||
|
console.log(`[GitLab] First event sample:`, JSON.stringify(events[0], null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.length === 0) break;
|
||||||
|
|
||||||
|
const parsed = parseGitLabEvents(events);
|
||||||
|
console.log(`[GitLab] Page ${page}: parsed ${Object.keys(parsed).length} days of activity`);
|
||||||
|
mergeInto(map, parsed);
|
||||||
|
|
||||||
|
if (events.length < pageLimit) break;
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
async function makeActivityMap(): Promise<ActivityMap> {
|
async function makeActivityMap(): Promise<ActivityMap> {
|
||||||
const [ghMap, fjMap] = await Promise.all([
|
const [ghMap, fjMap, glMap] = await Promise.all([
|
||||||
getGitHubActivityMap(),
|
getGitHubActivityMap(),
|
||||||
getForgejoActivityMap(),
|
getForgejoActivityMap(),
|
||||||
|
getGitLabActivityMap(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return deduplicateAcrossPlatforms(ghMap, fjMap);
|
const merged = deduplicateAcrossPlatforms(ghMap, fjMap);
|
||||||
|
return deduplicateAcrossPlatforms(merged, glMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
const activityMap = await makeActivityMap();
|
const activityMap = await makeActivityMap();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue