Skip to content

Commit

Permalink
Update cron job for non github orgs repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
dexter-sim committed Oct 26, 2024
1 parent bd4ee58 commit ce73b4b
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 29 deletions.
90 changes: 62 additions & 28 deletions backend/jobs/publicGithubJob.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import CourseModel from '@models/Course';
import { Review, TeamContribution, TeamPR } from '@shared/types/TeamData';
import cron from 'node-cron';
import { Octokit } from 'octokit';
import { App, Octokit } from 'octokit';
import TeamData from '../models/TeamData';
import { getGitHubApp } from 'utils/github';

const fetchPublicRepoData = async () => {
const octokit = new Octokit(); // No need for GitHub App authentication for public repos

const courses = await CourseModel.find();

await Promise.all(
courses.map(async course => {
if (course && course.gitHubRepoLinks.length > 0) {
try {
// Call getPublicCourseData to process the course and repo data
await getPublicCourseData(octokit, course);
await getPublicCourseData(course);
} catch (error) {
console.error(
`Error fetching repository data for ${course.name}:`,
Expand All @@ -28,31 +27,30 @@ const fetchPublicRepoData = async () => {
console.log('fetchPublicRepoData job done');
};

const getPublicCourseData = async (octokit: Octokit, course: any) => {
const getPublicCourseData = async (course: any) => {
if (!course.gitHubRepoLinks || course.gitHubRepoLinks.length === 0) return;

const app: App = getGitHubApp();
const genericOctokit = app.octokit; // Use a generic octokit instance

for (const repoUrl of course.gitHubRepoLinks) {
const urlParts = repoUrl.split('/');
const owner = urlParts[3]; // Get the 'owner' part of the URL
const repo = urlParts[4]; // Get the 'repo' part of the URL

const installationId = await checkAppInstalled(owner);

const octokit = installationId
? await app.getInstallationOctokit(installationId)
: genericOctokit;

try {
// Fetch repository data using public Octokit instance
const repoData = await octokit.rest.repos.get({
owner,
repo,
});

console.log('Repository Data:', repoData.data);

// Fetch branches or other details
const branches = await octokit.rest.repos.listBranches({
owner,
repo,
});

console.log('Branches:', branches.data);

const teamContributions: Record<string, TeamContribution> = {};

const [commits, issues, prs, contributors, milestones] =
Expand Down Expand Up @@ -252,25 +250,61 @@ const getPublicCourseData = async (octokit: Octokit, course: any) => {
}
};

const fetchCodeFrequencyStats = async (
octokit: Octokit,
owner: string,
repo: string
) => {
const checkAppInstalled = async (username: string) => {
try {
const response = await octokit.rest.repos.getCodeFrequencyStats({
owner,
repo,
const app = getGitHubApp(); // Get the GitHub App instance
const octokit = app.octokit; // Create an Octokit instance authenticated as the App

const response = await octokit.rest.apps.getUserInstallation({
username,
});

if (response.status === 200) {
return response.data;
const installationId = response.data.id;
console.log(
`App is installed for user ${username}, Installation ID: ${installationId}`
);
return installationId;
}
} catch (error: any) {
if (error.status === 404) {
console.log(`App is not installed for user ${username}`);
} else {
throw new Error('Failed to fetch code frequency stats');
console.error(`Error checking app installation: ${error.message}`);
}
} catch (error: unknown) {
if (error instanceof Error) {
throw new Error(`Error fetching code frequency stats: ${error.message}`);
}
};

const fetchCodeFrequencyStats = async (
octokit: Octokit,
owner: string,
repo: string
) => {
let attempt = 0;
const maxAttempts = 10;
const delayBetweenAttempts = 2000;

while (attempt < maxAttempts) {
try {
const response = await octokit.rest.repos.getCodeFrequencyStats({
owner,
repo,
});

if (response.status === 200) {
return response.data;
} else if (response.status === 202) {
await new Promise(resolve => setTimeout(resolve, delayBetweenAttempts));
attempt++;
} else {
throw new Error('Failed to fetch code frequency stats');
}
} catch (error: unknown) {
if (error instanceof Error) {
throw new Error(
`Error fetching code frequency stats: ${error.message}`
);
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion backend/services/githubService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,21 @@ export const getAuthorizedTeamDataByCourse = async (
if (!(await CourseModel.exists({ _id: courseId, faculty: user._id }))) {
throw new NotFoundError('User is not authorized to view course');
}

// Extract the owner names from the course's GitHub repo links
const ownersFromRepoLinks = (course.gitHubRepoLinks || []).map(repoUrl => {
const urlParts = (repoUrl as string).split('/');
return urlParts[3].toLowerCase(); // Get the 'owner' part of the URL in lowercase

Check warning on line 80 in backend/services/githubService.ts

View check run for this annotation

Codecov / codecov/patch

backend/services/githubService.ts#L79-L80

Added lines #L79 - L80 were not covered by tests
});

// Query for team data based on gitHubOrgName or gitHubRepoLinks
const teamDatas = await TeamDataModel.find({
gitHubOrgName: course.gitHubOrgName,
$or: [
{ gitHubOrgName: course.gitHubOrgName },
{ gitHubOrgName: { $in: ownersFromRepoLinks } },
],
});

if (!teamDatas) {
throw new NotFoundError('No team data found for course');
}
Expand Down

0 comments on commit ce73b4b

Please sign in to comment.