Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: /assign & /unassign #16

Merged
merged 7 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/(dashboard)/issues/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const metadata = {
export default async function IssuesPage() {
const openPRs = await getAllOpenIssuesOfRepo("formbricks/formbricks");
const enrolledRepos = await getEnrolledRepositoriesAction();
console.log("enrolledRepos", enrolledRepos);

return (
<DashboardShell>
Expand All @@ -26,7 +25,7 @@ export default async function IssuesPage() {
{enrolledRepos ? (
openPRs.map((issue) => <GitHubIssue issue={issue} key={issue.title} />)
) : (
<div className="flex h-96 flex-col items-center justify-center space-y-4 rounded-md bg-slate-50">
<div className="flex h-96 flex-col items-center justify-center space-y-4 rounded-md bg-slate-900">
<p>You have not yet enrolled to play in a repository 🕹️</p>
<Button href="/enroll">Explore oss.gg repositories</Button>
</div>
Expand Down
2 changes: 2 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export const GITHUB_APP_WEBHOOK_SECRET = env.GITHUB_APP_WEBHOOK_SECRET as string

export const GITHUB_APP_SLUG = env.GITHUB_APP_SLUG as string;
export const GITHUB_APP_ACCESS_TOKEN = env.GITHUB_APP_ACCESS_TOKEN as string;

export const OSS_GG_LABEL = "🕹️ oss.gg" as const;
136 changes: 122 additions & 14 deletions lib/github/hooks/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AWARD_POINTS_IDENTIFIER,
EVENT_TRIGGERS,
LEVEL_LABEL,
OSS_GG_LABEL,
UNASSIGN_IDENTIFIER,
} from "@/lib/constants";
import { assignUserPoints } from "@/lib/points/service";
Expand Down Expand Up @@ -50,18 +51,62 @@ export const onIssueOpened = async (webhooks: Webhooks) => {
export const onAssignCommented = async (webhooks: Webhooks) => {
webhooks.on(EVENT_TRIGGERS.ISSUE_COMMENTED, async (context) => {
try {
const octokit = getOctokitInstance(context.payload.installation?.id!);

const issueNumber = context.payload.issue.number;
const repo = context.payload.repository.name;
const issueCommentBody = context.payload.comment.body;

if (issueCommentBody === ASSIGN_IDENTIFIER) {
await octokit.issues.createComment({
body: "ok brother",
const isOssGgLabel = context.payload.issue.labels.some((label) => label.name === OSS_GG_LABEL);
if (!isOssGgLabel) return;

const issueNumber = context.payload.issue.number;
const repo = context.payload.repository.name;
const owner = context.payload.repository.owner.login;
const commenter = context.payload.comment.user.login;
const octokit = getOctokitInstance(context.payload.installation?.id!);

const isAssigned = context.payload.issue.assignees.length > 0;
if (isAssigned) {
const assignee = context.payload.issue.assignees[0].login;
const message =
assignee === commenter
? `This issue is already assigned to you. Let's get this shipped!`
: `This issue is already assigned to another person. Please find more issues [here](https://oss.gg/issues).`;
await octokit.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: message,
});
return;
}

const { data: userIssues } = await octokit.issues.listForRepo({
owner,
repo,
assignee: commenter,
state: "open",
});

if (userIssues.length > 0) {
const assignedIssue = userIssues[0];
await octokit.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: `You already have an open issue assigned to you [here](${assignedIssue.html_url}). Once that's closed or unassigned, only then we recommend you to take up more.`,
});
return;
}

await octokit.issues.addAssignees({
owner,
repo,
issue_number: issueNumber,
assignees: [commenter],
});
await octokit.issues.createComment({
owner,
repo,
owner: "formbricks",
issue_number: issueNumber,
body: `Assigned to @${commenter}! Excited to have you ship this 🕹️`,
});
}
} catch (err) {
Expand All @@ -73,20 +118,81 @@ export const onAssignCommented = async (webhooks: Webhooks) => {
export const onUnassignCommented = async (webhooks: Webhooks) => {
webhooks.on(EVENT_TRIGGERS.ISSUE_COMMENTED, async (context) => {
try {
const octokit = getOctokitInstance(context.payload.installation?.id!);
const issueCommentBody = context.payload.comment.body;
if (issueCommentBody !== UNASSIGN_IDENTIFIER) {
return;
}

const isOssGgLabel = context.payload.issue.labels.some((label) => label.name === OSS_GG_LABEL);
if (!isOssGgLabel) {
return;
}

const issueNumber = context.payload.issue.number;
const repo = context.payload.repository.name;
const issueCommentBody = context.payload.comment.body;
const owner = context.payload.repository.owner.login;
const commenter = context.payload.comment.user.login;
const octokit = getOctokitInstance(context.payload.installation?.id!);

const isAssigned = context.payload.issue.assignees.length > 0;
if (!isAssigned) {
await octokit.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: "This issue is not assigned to anyone.",
});
return;
}

if (issueCommentBody === UNASSIGN_IDENTIFIER) {
const assignee = context.payload.issue.assignees[0].login;
if (assignee === commenter) {
await octokit.issues.removeAssignees({
owner,
repo,
issue_number: issueNumber,
assignees: [assignee],
});
await octokit.issues.createComment({
body: "no brother",
owner,
repo,
issue_number: issueNumber,
body: "Issue unassigned.",
});
return;
}

const ossGgRepo = await getRepositoryByGithubId(context.payload.repository.id);
const usersThatCanUnassign = ossGgRepo?.installation.memberships.map((m) => m.userId) || [];
const ossGgUsers = await Promise.all(
usersThatCanUnassign.map(async (userId) => {
const user = await getUser(userId);
return user?.githubId;
})
);

const isUserAllowedToUnassign = ossGgUsers?.includes(context.payload.comment.user.id);
if (!isUserAllowedToUnassign) {
await octokit.issues.createComment({
owner,
repo,
owner: "formbricks",
issue_number: issueNumber,
body: "You cannot unassign this issue as it is not assigned to you.",
});
return;
}
await octokit.issues.removeAssignees({
owner,
repo,
issue_number: issueNumber,
assignees: [assignee],
});
await octokit.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: "Issue unassigned.",
});
} catch (err) {
console.error(err);
}
Expand All @@ -103,6 +209,7 @@ export const onAwardPoints = async (webhooks: Webhooks) => {
const match = issueCommentBody.match(awardPointsRegex);
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 = "";

Expand Down Expand Up @@ -164,11 +271,12 @@ export const onAwardPoints = async (webhooks: Webhooks) => {
body: comment,
issue_number: issueNumber,
repo,
owner: "formbricks",
owner,
});
}
} catch (err) {
console.error(err);
throw new Error(err);
}
});
};
4 changes: 2 additions & 2 deletions lib/github/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "server-only";
import { ZGithubApiResponseSchema } from "@/types/issue";
import { unstable_cache } from "next/cache";

import { GITHUB_APP_ACCESS_TOKEN, GITHUB_CACHE_REVALIDATION_INTERVAL } from "../constants";
import { GITHUB_APP_ACCESS_TOKEN, GITHUB_CACHE_REVALIDATION_INTERVAL, OSS_GG_LABEL } from "../constants";

export const getMergedPullRequestsByGithubLogin = (repo: string, githubLogin: string) =>
unstable_cache(
Expand Down Expand Up @@ -76,7 +76,7 @@ export const getOpenPullRequestsByGithubLogin = (repo: string, githubLogin: stri
export const getAllOpenIssuesOfRepo = (repo: string) =>
unstable_cache(
async () => {
const url = `https://api.github.com/search/issues?q=repo:${repo}+is:issue+is:open+label:"🕹️ oss.gg"&sort=created&order=desc`;
const url = `https://api.github.com/search/issues?q=repo:${repo}+is:issue+is:open+no:assignee+label:"${OSS_GG_LABEL}"&sort=created&order=desc`;

const headers = {
Authorization: `Bearer ${GITHUB_APP_ACCESS_TOKEN}`,
Expand Down
4 changes: 0 additions & 4 deletions lib/points/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ export const assignUserPoints = async (
});
return pointsUpdated;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
console.error("An error occurred while updating user points:", error.message);
throw new Error("Database error occurred");
}
throw error;
}
};
Loading