From d4ce273a3efb0ae62863fcd5c49997ad82596adf Mon Sep 17 00:00:00 2001 From: Shivaditya Shivganesh Date: Fri, 27 Sep 2024 21:34:46 -0400 Subject: [PATCH] fix: removed code for assign issues --- README.md | 2 +- manifest.json | 2 +- src/handlers/issue-assignees-changed.ts | 26 ------ src/handlers/issue-matching.ts | 108 +++++++++++++++++++----- src/plugin.ts | 5 +- src/types/context.ts | 4 +- 6 files changed, 93 insertions(+), 54 deletions(-) delete mode 100644 src/handlers/issue-assignees-changed.ts diff --git a/README.md b/README.md index 6b03a0f..75ffd81 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ To set up the `.dev.vars` file, you will need to provide the following variables - Add the following to your `.ubiquibot-config.yml` file with the appropriate URL: ```javascript -plugin: http://127.0.0.1:4000 - runsOn: [ "issue_comment.created", "issue_comment.edited", "issue_comment.deleted" , "issues.opened", "issues.edited", "issues.deleted", "issues.labeled", "issues.assigned", "issues.unassigned"] + runsOn: [ "issue_comment.created", "issue_comment.edited", "issue_comment.deleted" , "issues.opened", "issues.edited", "issues.deleted", "issues.labeled"] ``` diff --git a/manifest.json b/manifest.json index f52ef4e..dbd801c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "name": "@ubiquity-os/comment-vector-embeddings", "description": "Issue comment plugin for Ubiquibot. It enables the storage, updating, and deletion of issue comment embeddings.", - "ubiquity:listeners": ["issue_comment.created", "issue_comment.edited", "issue_comment.deleted", "issues.opened", "issues.edited", "issues.deleted", "issues.labeled", "issues.assigned", "issues.unassigned"] + "ubiquity:listeners": ["issue_comment.created", "issue_comment.edited", "issue_comment.deleted", "issues.opened", "issues.edited", "issues.deleted", "issues.labeled"] } diff --git a/src/handlers/issue-assignees-changed.ts b/src/handlers/issue-assignees-changed.ts deleted file mode 100644 index d8d74a8..0000000 --- a/src/handlers/issue-assignees-changed.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Context } from "../types"; -import { IssuePayload } from "../types/payload"; - -export async function updateAssignees(context: Context) { - const { - logger, - adapters: { supabase }, - } = context; - const { payload } = context as { payload: IssuePayload }; - const issue = payload.issue; - - try { - await supabase.issue.updatePayload(issue.node_id, payload); - } catch (error) { - if (error instanceof Error) { - logger.error(`Error updating assignees:`, { error: error, stack: error.stack }); - throw error; - } else { - logger.error(`Error updating assignees:`, { err: error, error: new Error() }); - throw error; - } - } - - logger.ok(`Successfully updated assignees!`); - logger.debug(`Exiting updateAssignees`); -} diff --git a/src/handlers/issue-matching.ts b/src/handlers/issue-matching.ts index 6835b1a..8e56f94 100644 --- a/src/handlers/issue-matching.ts +++ b/src/handlers/issue-matching.ts @@ -1,6 +1,29 @@ import { Context } from "../types"; import { IssuePayload } from "../types/payload"; +export interface IssueGraphqlResponse { + node: { + title: string; + url: string; + state: string; + stateReason: string; + closed: boolean; + repository: { + owner: { + login: string; + }; + name: string; + }; + assignees: { + nodes: Array<{ + login: string; + url: string; + }>; + }; + }; + similarity: number; +} + export async function issueMatching(context: Context) { const { logger, @@ -15,30 +38,67 @@ export async function issueMatching(context: Context) { // On Adding the labels to the issue, the bot should // create a new comment with users who completed task most similar to the issue // if the comment already exists, it should update the comment with the new users - const matchResultArray: Array = []; + const matchResultArray: Map> = new Map(); const similarIssues = await supabase.issue.findSimilarIssues(issueContent, context.config.jobMatchingThreshold, issue.node_id); if (similarIssues && similarIssues.length > 0) { // Find the most similar issue and the users who completed the task + console.log(similarIssues); similarIssues.sort((a, b) => b.similarity - a.similarity); - similarIssues.forEach(async (issue) => { - const data = await supabase.issue.getIssue(issue.issue_id); - if (data) { - const issuePayload = (data[0].payload as IssuePayload) || []; - const users = issuePayload?.issue.assignees; - //Make the string - // ## [User Name](Link to User Profile) - // - [Issue] X% Match - users.forEach(async (user) => { - if (user && user.login && user.html_url) { - const similarityPercentage = Math.round(issue.similarity * 100); - const githubUserLink = user.html_url.replace(/https?:\/\//, "https://www."); - const issueLink = issuePayload.issue.html_url.replace(/https?:\/\//, "https://www."); - matchResultArray.push(`## [${user.login}](${githubUserLink})\n- [Issue](${issueLink}) ${similarityPercentage}% Match`); + const fetchPromises = similarIssues.map(async (issue) => { + logger.info("Issue ID: " + issue.issue_id); + logger.info("Before query"); + const issueObject: IssueGraphqlResponse = await context.octokit.graphql( + `query ($issueNodeId: ID!) { + node(id: $issueNodeId) { + ... on Issue { + title + url + state + repository{ + name + owner { + login + } + } + stateReason + closed + assignees(first: 10) { + nodes { + login + url + } + } + } + } + }`, + { issueNodeId: issue.issue_id } + ); + issueObject.similarity = issue.similarity; + return issueObject; + }); + + const issueList = await Promise.all(fetchPromises); + issueList.forEach((issue) => { + if (issue.node.closed && issue.node.stateReason === "COMPLETED" && issue.node.assignees.nodes.length > 0) { + const assignees = issue.node.assignees.nodes; + assignees.forEach((assignee) => { + const similarityPercentage = Math.round(issue.similarity * 100); + const githubUserLink = assignee.url.replace(/https?:\/\/github.com/, "https://www.github.com"); + const issueLink = issue.node.url.replace(/https?:\/\/github.com/, "https://www.github.com"); + if (matchResultArray.has(assignee.login)) { + matchResultArray + .get(assignee.login) + ?.push( + `## [${assignee.login}](${githubUserLink})\n- [${issue.node.repository.owner.login}/${issue.node.repository.name}#${issue.node.url.split("/").pop()}](${issueLink}) ${similarityPercentage}% Match` + ); + } else { + matchResultArray.set(assignee.login, [ + `## [${assignee.login}](${githubUserLink})\n- [${issue.node.repository.owner.login}/${issue.node.repository.name}#${issue.node.url.split("/").pop()}](${issueLink}) ${similarityPercentage}% Match`, + ]); } }); } }); - // Fetch if any previous comment exists const listIssues = await octokit.issues.listComments({ owner: payload.repository.owner.login, @@ -49,7 +109,7 @@ export async function issueMatching(context: Context) { const existingComment = listIssues.data.find((comment) => comment.body && comment.body.startsWith(commentStart)); //Check if matchResultArray is empty - if (matchResultArray.length === 0) { + if (matchResultArray && matchResultArray.size === 0) { if (existingComment) { // If the comment already exists, delete it await octokit.issues.deleteComment({ @@ -67,14 +127,24 @@ export async function issueMatching(context: Context) { owner: payload.repository.owner.login, repo: payload.repository.name, comment_id: existingComment.id, - body: commentStart + "\n\n" + matchResultArray.join("\n"), + body: + commentStart + + "\n\n" + + Array.from(matchResultArray.values()) + .map((arr) => arr.join("\n")) + .join("\n"), }); } else { await context.octokit.issues.createComment({ owner: payload.repository.owner.login, repo: payload.repository.name, issue_number: payload.issue.number, - body: commentStart + "\n\n" + matchResultArray.join("\n"), + body: + commentStart + + "\n\n" + + Array.from(matchResultArray.values()) + .map((arr) => arr.join("\n")) + .join("\n"), }); } } diff --git a/src/plugin.ts b/src/plugin.ts index 962e74c..197948b 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -15,7 +15,6 @@ import { addIssue } from "./handlers/add-issue"; import { updateIssue } from "./handlers/update-issue"; import { issueChecker } from "./handlers/issue-deduplication"; import { issueMatching } from "./handlers/issue-matching"; -import { updateAssignees } from "./handlers/issue-assignees-changed"; /** * The main plugin function. Split for easier testing. @@ -45,9 +44,7 @@ export async function runPlugin(context: Context) { return await deleteIssues(context); } } else if (eventName == "issues.labeled") { - await issueMatching(context); - } else if (eventName == "issues.assigned" || eventName == "issues.unassigned") { - await updateAssignees(context); + return await issueMatching(context); } else { logger.error(`Unsupported event: ${eventName}`); } diff --git a/src/types/context.ts b/src/types/context.ts index 3a1cf2c..b11ac2f 100644 --- a/src/types/context.ts +++ b/src/types/context.ts @@ -17,9 +17,7 @@ export type SupportedEventsU = | "issues.opened" | "issues.edited" | "issues.deleted" - | "issues.labeled" - | "issues.assigned" - | "issues.unassigned"; + | "issues.labeled"; export type SupportedEvents = { [K in SupportedEventsU]: K extends WebhookEventName ? WebhookEvent : never;