Skip to content

Commit 4f5c080

Browse files
committed
Show bounty amounts in issue notifications
1 parent 0f9c94a commit 4f5c080

1 file changed

Lines changed: 65 additions & 10 deletions

File tree

scripts/issue-notifications.ts

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { WebhookClient, type MessageCreateOptions } from "discord.js"
1+
import { type MessageCreateOptions, WebhookClient } from "discord.js"
2+
import { EXCLUDED_BOTS } from "lib/constants"
23
import { getRepos } from "lib/data-retrieval/getRepos"
34
import { octokit } from "lib/sdks"
4-
import { EXCLUDED_BOTS } from "lib/constants"
55

66
const discordWebhook = new WebhookClient({
77
url: process.env.ISSUES_DISCORD_WEBHOOK_URL || "",
@@ -11,6 +11,13 @@ interface Issue {
1111
number: number
1212
title: string
1313
html_url: string
14+
body?: string | null
15+
labels: Array<
16+
| string
17+
| {
18+
name?: string
19+
}
20+
>
1421
user: {
1522
login: string
1623
}
@@ -21,6 +28,53 @@ function getUTCDateTime(): string {
2128
return new Date().toISOString()
2229
}
2330

31+
function getLabelNames(issue: Issue): string[] {
32+
return issue.labels
33+
.map((label) => (typeof label === "string" ? label : label.name))
34+
.filter((label): label is string => Boolean(label))
35+
}
36+
37+
function findBountyAmount(text: string): string | null {
38+
const bountyMatch = text.match(
39+
/(?:\/bounty|bounty)\s*\$\s*([\d,]+(?:\.\d{1,2})?)/i,
40+
)
41+
if (bountyMatch) return `$${bountyMatch[1]}`
42+
43+
const dollarMatch = text.match(/\$\s*([\d,]+(?:\.\d{1,2})?)/)
44+
if (dollarMatch) return `$${dollarMatch[1]}`
45+
46+
return null
47+
}
48+
49+
async function getIssueBounty(
50+
repo: string,
51+
issue: Issue,
52+
): Promise<string | null> {
53+
const labelBounty = getLabelNames(issue)
54+
.filter((label) => !label.toLowerCase().includes("rewarded"))
55+
.map(findBountyAmount)
56+
.find((amount) => amount)
57+
58+
if (labelBounty) return labelBounty
59+
60+
const bodyBounty = findBountyAmount(issue.body ?? "")
61+
if (bodyBounty) return bodyBounty
62+
63+
const [owner, repoName] = repo.split("/")
64+
const { data: comments } = await octokit.issues.listComments({
65+
owner,
66+
repo: repoName,
67+
issue_number: issue.number,
68+
per_page: 20,
69+
})
70+
71+
return (
72+
comments
73+
.map((comment) => findBountyAmount(comment.body ?? ""))
74+
.find((amount) => amount) ?? null
75+
)
76+
}
77+
2478
async function getRecentIssues(repo: string): Promise<Issue[]> {
2579
const [owner, repoName] = repo.split("/")
2680
const sixtyMinutesAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString()
@@ -61,14 +115,15 @@ async function notifyDiscord(issues: Issue[], repo: string) {
61115
`[${getUTCDateTime()}] Sending notification for ${issues.length} issues from ${repo} to Discord`,
62116
)
63117

64-
const messageContent =
65-
`New issues in ${repo}:\n` +
66-
issues
67-
.map(
68-
(issue) =>
69-
`• #${issue.number} ${issue.title} by ${issue.user.login} - <${issue.html_url}>`,
70-
)
71-
.join("\n")
118+
const issueLines = await Promise.all(
119+
issues.map(async (issue) => {
120+
const bounty = await getIssueBounty(repo, issue)
121+
const bountyText = bounty ? ` [bounty: ${bounty}]` : ""
122+
return `• #${issue.number} ${issue.title}${bountyText} by ${issue.user.login} - <${issue.html_url}>`
123+
}),
124+
)
125+
126+
const messageContent = `New issues in ${repo}:\n${issueLines.join("\n")}`
72127

73128
const messageOptions: MessageCreateOptions = {
74129
content: messageContent,

0 commit comments

Comments
 (0)