Skip to content

Commit

Permalink
refactor done
Browse files Browse the repository at this point in the history
  • Loading branch information
RajuGangitla committed Sep 17, 2024
1 parent dca48ec commit c4f4d1f
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 85 deletions.
158 changes: 74 additions & 84 deletions lib/github/hooks/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ import {
REJECT_IDENTIFIER,
UNASSIGN_IDENTIFIER,
} from "@/lib/constants";
import { assignUserPoints } from "@/lib/points/service";
import { getRepositoryByGithubId } from "@/lib/repository/service";
import { createUser, getUser, getUserByGithubId } from "@/lib/user/service";
import { getUser } from "@/lib/user/service";
import { triggerDotDevClient } from "@/trigger";
import { Webhooks } from "@octokit/webhooks";

import { isMemberOfRepository } from "../services/user";
import { extractIssueNumbers, extractIssueNumbersFromPrBody, getOctokitInstance } from "../utils";
import { checkOssGgLabel, extractIssueNumbers, extractIssueNumbersFromPrBody, extractPointsFromLabels, filterValidLabels, getOctokitInstance, postComment, processAndComment, processUserPoints } from "../utils";

export const onIssueOpened = async (webhooks: Webhooks) => {
webhooks.on(EVENT_TRIGGERS.ISSUE_OPENED, async (context) => {
Expand Down Expand Up @@ -334,7 +333,6 @@ export const onAwardPoints = async (webhooks: Webhooks) => {
const isPR = !!context.payload.issue.pull_request;
const issueNumber = isPR ? context.payload.issue.number : undefined;
const owner = context.payload.repository.owner.login;

let comment: string = "";

if (match) {
Expand Down Expand Up @@ -364,33 +362,25 @@ export const onAwardPoints = async (webhooks: Webhooks) => {
if (!ossGgRepo) {
comment = "If you are the repo owner, please register at oss.gg to be able to award points";
} else {
const prAuthorGithubId = context.payload.issue.user.id;
const prAuthorUsername = context.payload.issue.user.login;
const { data: prAuthorProfile } = await octokit.users.getByUsername({
username: prAuthorUsername,
});
let user = await getUserByGithubId(prAuthorGithubId);
if (!user) {
user = await createUser({
githubId: prAuthorGithubId,
login: prAuthorUsername,
email: prAuthorProfile.email,
name: prAuthorProfile.name,
avatarUrl: context.payload.issue.user.avatar_url,
});
comment = "Please register at oss.gg to be able to claim your rewards.";
}
await assignUserPoints(
user?.id,
const prAuthorUsername = context.payload.issue.user.login

//process user points
let user = await processUserPoints({
installationId: context.payload.installation?.id!,
prAuthorGithubId: context.payload.issue.user.id,
prAuthorUsername: prAuthorUsername,
avatarUrl: context.payload.issue.user.avatar_url,
points,
"Awarded points",
context.payload.comment.html_url,
ossGgRepo?.id
);
url: context.payload.comment.html_url,
repoId: ossGgRepo?.id,
comment
})

comment =
`Awarding ${user.login}: ${points} points! Check out your new contribution on [oss.gg/${user.login}](https://oss.gg/${user.login})` +
" " +
comment;

await triggerDotDevClient.sendEvent({
name: DISCORD_POINTS_MESSAGE_TRIGGER_ID,
payload: {
Expand All @@ -401,12 +391,14 @@ export const onAwardPoints = async (webhooks: Webhooks) => {
}
}

await octokit.issues.createComment({
//post comment
postComment({
installationId: context.payload.installation?.id!,
body: comment,
issue_number: issueNumber,
issueNumber: issueNumber,
repo,
owner,
});
})
}
} catch (err) {
console.error(err);
Expand Down Expand Up @@ -440,75 +432,73 @@ export const onPullRequestMerged = async (webhooks: Webhooks) => {

const octokit = getOctokitInstance(context.payload.installation?.id!);

// Parse the pull request body to find linked issues (e.g., " #123")
const issueNumbers = extractIssueNumbersFromPrBody(pullRequest.body!);
if (!issueNumbers.length) {
console.log("No issues are mentioned in the pull request.");
return;
}

// Check repository enrollment first
const ossGgRepo = await getRepositoryByGithubId(context.payload.repository.id);
if (!ossGgRepo) {
console.log("Repository is not enrolled in oss.gg.");
return;
}

// Loop through all the extracted issue numbers
for (const issueNumber of issueNumbers) {
try {
// Fetch the issue details using the GitHub API
const { data: issue } = await octokit.issues.get({
owner,
// Check if the pull request itself has the 🕹️ oss.gg label and process it
const validPrLabels = filterValidLabels(pullRequest.labels);
const isPrOssGgLabel = checkOssGgLabel(validPrLabels);

if (isPrOssGgLabel) {
const points = extractPointsFromLabels(validPrLabels);
if (points) {
await processAndComment({
context,
pullRequest,
repo,
issue_number: issueNumber,
owner,
points,
issueNumber: pullRequest.number,
ossGgRepoId: ossGgRepo.id,
});
return; // Early exit since points were awarded based on PR labels
}
}

// Get the labels of the linked issue
const issueLabels = issue.labels.map((label: { name: string }) => label.name);
// If no oss.gg label on the PR, proceed with issue checks
const issueNumbers = extractIssueNumbersFromPrBody(pullRequest.body!);
if (!issueNumbers.length) {
console.log("No issues are mentioned in the pull request.");
return;
}

// Check if the "🕹️ oss.gg" label is present, skip if not
const ossLabel = issueLabels.find((label) => label.includes(OSS_GG_LABEL));
if (!ossLabel) {
console.log(`Issue #${issueNumber} does not have the 🕹️ oss.gg label. Skipping.`);
continue; // Skip this issue and move to the next one
}
// Process each issue
for (const issueNumber of issueNumbers) {
const { data: issue } = await octokit.issues.get({
owner,
repo,
issue_number: issueNumber,
});

// Extract points from labels like "🕹️ 50 points", "🕹️ 100 points", etc.
const pointsLabel = issueLabels.find(
(label) => (label.includes("🕹️") || label.includes(":joystick:")) && label.includes("points")
);
if (pointsLabel) {
// Extract number from the points label
const points = parseInt(pointsLabel.match(/\d+/)?.[0] || "0", 10);
console.log(`Points for issue #${issueNumber}:`, points);

// Fetch PR author details only if the oss.gg label is present
const prAuthorGithubId = pullRequest.user.id;
const prAuthorUsername = pullRequest.user.login;
const { data: prAuthorProfile } = await octokit.users.getByUsername({
username: prAuthorUsername,
});
const validLabels = filterValidLabels(issue.labels);
const isOssGgLabel = checkOssGgLabel(validLabels);

// Fetch or create user profile only if the oss.gg label is present
let user = await getUserByGithubId(prAuthorGithubId);
if (!user) {
user = await createUser({
githubId: prAuthorGithubId,
login: prAuthorUsername,
email: prAuthorProfile.email,
name: prAuthorProfile.name,
avatarUrl: pullRequest.user.avatar_url,
});
}
if (!isOssGgLabel) {
console.log(`Issue #${issueNumber} does not have the 🕹️ oss.gg label. Skipping.`);
return;
}

// Award points to the user
await assignUserPoints(user?.id, points, "Awarded points", pullRequest.html_url, ossGgRepo?.id);
} else {
console.log(`No points label found for issue #${issueNumber}.`);
}
} catch (error) {
console.error(`Failed to fetch details for issue #${issueNumber}:`, error);
const points = extractPointsFromLabels(validLabels);

if (points) {
console.log(`Points for issue #${issueNumber}:`, points);

await processAndComment({
context,
pullRequest,
repo,
owner,
points,
issueNumber: pullRequest.number,
// issueNumber,
ossGgRepoId: ossGgRepo.id,
});
} else {
console.log(`No points label found for issue #${issueNumber}.`);
}
}
});
Expand Down
104 changes: 103 additions & 1 deletion lib/github/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { createAppAuth } from "@octokit/auth-app";
import { Octokit } from "@octokit/rest";
import crypto from "node:crypto";
import { GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, OSS_GG_LABEL } from "../constants";
import { createUser, getUserByGithubId } from "../user/service";
import { assignUserPoints } from "../points/service";
import { TUser } from "@/types/user";
import { TPostComment, TUserPoints } from "@/types/githubUser";

import { GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY } from "../constants";

export const getOctokitInstance = (installationId: number) => {
if (!installationId) {
Expand Down Expand Up @@ -74,3 +78,101 @@ export const extractPointsFromLabels = (labels: { name: string }[]): number | nu

return null;
};

// Helper to process user points and post a comment
export const processAndComment = async ({
context,
pullRequest,
repo,
owner,
points,
issueNumber,
ossGgRepoId,
}: {
context: any;
pullRequest: any;
repo: string;
owner: string;
points: number;
issueNumber: number;
ossGgRepoId: string;
}) => {
const user = await processUserPoints({
installationId: context.payload.installation?.id!,
prAuthorGithubId: pullRequest.user.id,
prAuthorUsername: pullRequest.user.login,
avatarUrl: pullRequest.user.avatar_url,
points,
url: pullRequest.html_url,
repoId: ossGgRepoId,
comment: "",
});

const comment = `Awarding ${user.login}: ${points} points! Check out your new contribution on [oss.gg/${user.login}](https://oss.gg/${user.login})`;

// Post comment on the issue or pull request
postComment({
installationId: context.payload.installation?.id!,
body: comment,
issueNumber: issueNumber,
repo,
owner,
});
};

export const processUserPoints = async ({
installationId,
prAuthorGithubId,
prAuthorUsername,
avatarUrl,
points,
url,
repoId,
comment
}: TUserPoints): Promise<TUser> => {
const octokit = getOctokitInstance(installationId!);

const { data: prAuthorProfile } = await octokit.users.getByUsername({
username: prAuthorUsername,
});

// Fetch or create user profile only if the oss.gg label is present
let user = await getUserByGithubId(prAuthorGithubId);
if (!user) {
user = await createUser({
githubId: prAuthorGithubId,
login: prAuthorUsername,
email: prAuthorProfile.email,
name: prAuthorProfile.name,
avatarUrl: avatarUrl,
});
comment = "Please register at oss.gg to be able to claim your rewards.";
}

// Award points to the user
await assignUserPoints(user?.id, points, "Awarded points", url, repoId);

return user
}

export const postComment = async ({
installationId,
body,
issueNumber,
repo,
owner,
}: TPostComment) => {
const octokit = getOctokitInstance(installationId!);
await octokit.issues.createComment({
body,
issue_number: issueNumber,
repo,
owner,
});
};

export const filterValidLabels = (labels: any[]) => labels.filter((label: any) => typeof label === 'object' && label.name);

export const checkOssGgLabel = (labels: any[]) => labels.some((label: { name: string }) => label.name === OSS_GG_LABEL);


28 changes: 28 additions & 0 deletions types/githubUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,31 @@ export const ZGithubUserData = z
.strict();

export type TGithubUserData = z.infer<typeof ZGithubUserData>;


// Zod schema for ZUserPointsSchema
export const ZUserPointsSchema = z.object({
installationId: z.number(),
prAuthorGithubId: z.number(),
prAuthorUsername: z.string(),
avatarUrl: z.string(),
points: z.number(),
url: z.string(),
repoId: z.string(),
comment: z.string(),
});

export type TUserPoints = z.infer<typeof ZUserPointsSchema>;


// Zod schema for PostCommentProps
export const PostComment = z.object({
installationId: z.number(),
body: z.string(),
issueNumber: z.number(),
repo: z.string(),
owner: z.string(),
});

export type TPostComment = z.infer<typeof PostComment>;

0 comments on commit c4f4d1f

Please sign in to comment.