Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

feat: add comment-incentive command #840

Open
wants to merge 17 commits into
base: development
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions src/configs/ubiquibot-config-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export const DefaultConfig: MergedConfig = {
name: "start",
enabled: false,
},
{
name: "comment-incentive",
enabled: false,
},
{
name: "stop",
enabled: false,
Expand Down
1 change: 1 addition & 0 deletions src/handlers/comment/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum IssueCommentCommands {
MULTIPLIER = "/multiplier", // set bounty multiplier (for treasury)
QUERY = "/query",
ASK = "/ask", // ask GPT a question
COMMENTINCENTIVE = "/comment-incentive",
// Access Controls

ALLOW = "/allow",
Expand Down
22 changes: 22 additions & 0 deletions src/handlers/comment/handlers/comment-incentive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getBotContext, getLogger } from "../../../bindings";
import { Payload } from "../../../types";

export const commentIncentive = async (body: string) => {
const context = getBotContext();
const logger = getLogger();
const payload = context.payload as Payload;
const sender = payload.sender.login;

logger.debug(`Received '/comment-incentive' command from user: ${sender}`);

if (!payload.issue) {
logger.info(`Skipping '/comment-incentive' because of no issue instance`);
return `Skipping '/comment-incentive' because of no issue instance`;
}
const toggle = (body.includes("true") || body.includes("false")) && body.match(/@([\w-]+)/g);
if (!toggle) {
return `invalid syntax for /comment-incentive \n usage /comment-incentive @user @user1... true|false \n ex /comment-incentive @user true`;
} else {
return;
}
};
11 changes: 10 additions & 1 deletion src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { approveLabelChange } from "./authorize";
import { setAccess } from "./allow";
import { ask } from "./ask";
import { multiplier } from "./multiplier";

import { BigNumber, ethers } from "ethers";
import { addPenalty } from "../../../adapters/supabase";
import {
Expand All @@ -33,6 +34,7 @@ import {
calculateIssueAssigneeReward,
calculatePullRequestReviewsReward,
} from "../../payout";
import { commentIncentive } from "./comment-incentive";
import { query } from "./query";
import { autoPay } from "./payout";
import { getTargetPriceLabel } from "../../shared";
Expand All @@ -48,6 +50,7 @@ export * from "./multiplier";
export * from "./query";
export * from "./ask";
export * from "./authorize";
export * from "./comment-incentive";

export interface RewardsResponse {
error: string | null;
Expand All @@ -74,7 +77,7 @@ export interface RewardsResponse {
*/

export const commentParser = (body: string): IssueCommentCommands[] => {
const regex = /^\/(\w+)\b/; // Regex pattern to match the command at the beginning of the body
const regex = /^\/([\w-]+)\b/; // Regex pattern to match the command at the beginning of the body

const matches = regex.exec(body);
if (matches) {
Expand Down Expand Up @@ -264,6 +267,12 @@ export const userCommands = (): UserCommands[] => {
handler: unassign,
callback: commandCallback,
},
{
id: IssueCommentCommands.COMMENTINCENTIVE,
description: "Enables or Disables comment incentive for a user",
handler: commentIncentive,
callback: commandCallback,
},
{
handler: listAvailableCommands,
id: IssueCommentCommands.HELP,
Expand Down
7 changes: 5 additions & 2 deletions src/handlers/payout/post.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getWalletAddress } from "../../adapters/supabase";
import { getBotContext, getLogger } from "../../bindings";
import { getAllIssueComments, getAllPullRequestReviews, getIssueDescription, parseComments } from "../../helpers";
import { getAllIssueComments, getAllPullRequestReviews, getIncentivizedUsers, getIssueDescription, parseComments } from "../../helpers";
import { getLatestPullRequest, gitLinkedPrParser } from "../../helpers/parser";
import { Incentives, MarkdownItem, Payload, UserType } from "../../types";
import { RewardsResponse, commentParser } from "../comment";
Expand Down Expand Up @@ -44,7 +44,7 @@ export const calculateIssueConversationReward = async (calculateIncentives: Ince
const issueCommentsByUser: Record<string, { id: number; comments: string[] }> = {};
for (const issueComment of issueComments) {
const user = issueComment.user;
if (user.type == UserType.Bot || user.login == assignee.login) continue;
if (user.type == UserType.Bot) continue;
const commands = commentParser(issueComment.body);
if (commands.length > 0) {
logger.info(`Skipping to parse the comment because it contains commands. comment: ${JSON.stringify(issueComment)}`);
Expand Down Expand Up @@ -75,8 +75,11 @@ export const calculateIssueConversationReward = async (calculateIncentives: Ince
penaltyAmount: BigNumber;
debug: Record<string, { count: number; reward: Decimal }>;
}[] = [];
const users = await getIncentivizedUsers(calculateIncentives.issue.number);
if (!users) return { error: "Error: Could not find any incentivized users" };

for (const user of Object.keys(issueCommentsByUser)) {
if (!users[user]) continue;
const commentsByUser = issueCommentsByUser[user];
const commentsByNode = await parseComments(commentsByUser.comments, ItemsToExclude);
const rewardValue = calculateRewardValue(commentsByNode, calculateIncentives.incentives);
Expand Down
22 changes: 22 additions & 0 deletions src/helpers/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ export const clearAllPriceLabelsOnIssue = async (): Promise<void> => {
}
};

export const getIncentivizedUsers = async (issue_number: number) => {
const comments = await getAllIssueComments(issue_number);
const incentiveComments = comments.filter((comment) => comment.body.startsWith("/comment-incentive"));
const users: { [key: string]: boolean } = {};
for (const incentiveComment of incentiveComments) {
const parts = incentiveComment.body.split(" ");
parts.shift();
const toggle: RegExpMatchArray | null = incentiveComment.body.match(/\b(true|false)\b/);

if (!toggle) {
BeanieMen marked this conversation as resolved.
Show resolved Hide resolved
continue;
} else {
for (const part of parts) {
if (part.startsWith("@")) {
users[part.substring(1)] = toggle[0] === "true";
}
}
}
}
return users;
};

export const addLabelToIssue = async (labelName: string) => {
const context = getBotContext();
const logger = getLogger();
Expand Down
Loading