From be91fcc23dcfa152c234646904323d25f15da517 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Fri, 16 Jan 2026 13:22:47 +0100 Subject: [PATCH 1/5] Move functions to utils file --- scripts/contributor-issue-comment.js | 48 ++--------------------- scripts/utils.js | 57 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/scripts/contributor-issue-comment.js b/scripts/contributor-issue-comment.js index 399ac7c..f0b4193 100644 --- a/scripts/contributor-issue-comment.js +++ b/scripts/contributor-issue-comment.js @@ -12,53 +12,11 @@ const { sendBotMessage, escapeIssueTitleForSlackMessage, hasRecentBotComment, + hasLabel, + getIssues, + getPullRequests, } = require('./utils'); -async function hasLabel(name, owner, repo, issueNumber, github, core) { - let labels = []; - try { - const response = await github.rest.issues.listLabelsOnIssue({ - owner, - repo, - issue_number: issueNumber, - }); - labels = response.data.map(label => label.name); - } catch (error) { - core.warning(`Failed to fetch labels on issue #${issueNumber}: ${error.message}`); - labels = []; - } - return labels.some(label => label.toLowerCase() === name.toLowerCase()); -} - -async function getIssues(assignee, state, owner, repo, github, core) { - try { - const response = await github.rest.issues.listForRepo({ - owner, - repo, - assignee, - state, - }); - return response.data.filter(issue => !issue.pull_request); - } catch (error) { - core.warning(`Failed to fetch issues: ${error.message}`); - return []; - } -} - -async function getPullRequests(assignee, state, owner, repo, github, core) { - try { - const response = await github.rest.pulls.list({ - owner, - repo, - state, - }); - return response.data.filter(pr => pr.user.login === assignee); - } catch (error) { - core.warning(`Failed to fetch pull requests: ${error.message}`); - return []; - } -} - // Format information about author's assigned open issues // as '(Issues #1 #2 | PRs #3)' and PRs for Slack message function formatAuthorActivity(issues, pullRequests) { diff --git a/scripts/utils.js b/scripts/utils.js index 5f65205..cbbdc19 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -170,6 +170,60 @@ async function hasRecentBotComment( } } +/** + * Checks if an issue has a label with the given name (case-insensitive). + */ +async function hasLabel(name, owner, repo, issueNumber, github, core) { + let labels = []; + try { + const response = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: issueNumber, + }); + labels = response.data.map(label => label.name); + } catch (error) { + core.warning(`Failed to fetch labels on issue #${issueNumber}: ${error.message}`); + labels = []; + } + return labels.some(label => label.toLowerCase() === name.toLowerCase()); +} + +/** + * Fetches issues assigned to a user. + */ +async function getIssues(assignee, state, owner, repo, github, core) { + try { + const response = await github.rest.issues.listForRepo({ + owner, + repo, + assignee, + state, + }); + return response.data.filter(issue => !issue.pull_request); + } catch (error) { + core.warning(`Failed to fetch issues: ${error.message}`); + return []; + } +} + +/** + * Fetches pull requests for an author. + */ +async function getPullRequests(author, state, owner, repo, github, core) { + try { + const response = await github.rest.pulls.list({ + owner, + repo, + state, + }); + return response.data.filter(pr => pr.user.login === author); + } catch (error) { + core.warning(`Failed to fetch pull requests: ${error.message}`); + return []; + } +} + module.exports = { isContributor, isCloseContributor, @@ -177,4 +231,7 @@ module.exports = { sendBotMessage, escapeIssueTitleForSlackMessage, hasRecentBotComment, + hasLabel, + getIssues, + getPullRequests, }; From 670bedf7a2eacbee63156d1993d5c384ec200190 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Fri, 16 Jan 2026 13:36:07 +0100 Subject: [PATCH 2/5] Fix Slack snippet showing info only for one repository We need the snippet to show information about issues and PRs from all repositories in which we typically accept contributions. --- scripts/constants.js | 4 ++ scripts/contributor-issue-comment.js | 5 ++- scripts/utils.js | 62 +++++++++++++++++----------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/scripts/constants.js b/scripts/constants.js index bccaecd..c730f11 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -96,6 +96,9 @@ const PR_STATS_REPOS = [ 'ricecooker', ]; +// Repositories in which we accept open-source contributions +const COMMUNITY_REPOS = [...PR_STATS_REPOS]; + module.exports = { LE_BOT_USERNAME, SENTRY_BOT_USERNAME, @@ -109,4 +112,5 @@ module.exports = { TEAMS_WITH_CLOSE_CONTRIBUTORS, HOLIDAY_MESSAGE, PR_STATS_REPOS, + COMMUNITY_REPOS, }; diff --git a/scripts/contributor-issue-comment.js b/scripts/contributor-issue-comment.js index f0b4193..2f00bf3 100644 --- a/scripts/contributor-issue-comment.js +++ b/scripts/contributor-issue-comment.js @@ -6,6 +6,7 @@ const { ISSUE_LABEL_HELP_WANTED, BOT_MESSAGE_ISSUE_NOT_OPEN, BOT_MESSAGE_ALREADY_ASSIGNED, + COMMUNITY_REPOS, } = require('./constants'); const { isCloseContributor, @@ -159,8 +160,8 @@ module.exports = async ({ github, context, core }) => { if (contactSupport) { const [assignedOpenIssues, openPRs] = await Promise.all([ - getIssues(commentAuthor, 'open', owner, repo, github, core), - getPullRequests(commentAuthor, 'open', owner, repo, github, core), + getIssues(commentAuthor, 'open', owner, COMMUNITY_REPOS, github, core), + getPullRequests(commentAuthor, 'open', owner, COMMUNITY_REPOS, github, core), ]); const authorActivity = formatAuthorActivity(assignedOpenIssues, openPRs); slackMessage += ` _${authorActivity}_`; diff --git a/scripts/utils.js b/scripts/utils.js index cbbdc19..acb560c 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -190,38 +190,50 @@ async function hasLabel(name, owner, repo, issueNumber, github, core) { } /** - * Fetches issues assigned to a user. + * Fetches issues assigned to an assignee in given repositories. */ -async function getIssues(assignee, state, owner, repo, github, core) { - try { - const response = await github.rest.issues.listForRepo({ - owner, - repo, - assignee, - state, - }); - return response.data.filter(issue => !issue.pull_request); - } catch (error) { - core.warning(`Failed to fetch issues: ${error.message}`); - return []; +async function getIssues(assignee, state, owner, repos, github, core) { + const allIssues = []; + + for (const repo of repos) { + try { + const response = await github.rest.issues.listForRepo({ + owner, + repo, + assignee, + state, + }); + const issues = response.data.filter(issue => !issue.pull_request); + allIssues.push(...issues); + } catch (error) { + core.warning(`Failed to fetch issues from ${repo}: ${error.message}`); + } } + + return allIssues; } /** - * Fetches pull requests for an author. + * Fetches pull requests by an author in given repositories. */ -async function getPullRequests(author, state, owner, repo, github, core) { - try { - const response = await github.rest.pulls.list({ - owner, - repo, - state, - }); - return response.data.filter(pr => pr.user.login === author); - } catch (error) { - core.warning(`Failed to fetch pull requests: ${error.message}`); - return []; +async function getPullRequests(author, state, owner, repos, github, core) { + const allPRs = []; + + for (const repo of repos) { + try { + const response = await github.rest.pulls.list({ + owner, + repo, + state, + }); + const prs = response.data.filter(pr => pr.user.login === author); + allPRs.push(...prs); + } catch (error) { + core.warning(`Failed to fetch pull requests from ${repo}: ${error.message}`); + } } + + return allPRs; } module.exports = { From 144958e2cd282d6b00668df1e01fb0b198adc41d Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Fri, 16 Jan 2026 13:40:39 +0100 Subject: [PATCH 3/5] Optimize fetching data to run in paralel --- scripts/utils.js | 50 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index acb560c..249f03d 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -193,47 +193,45 @@ async function hasLabel(name, owner, repo, issueNumber, github, core) { * Fetches issues assigned to an assignee in given repositories. */ async function getIssues(assignee, state, owner, repos, github, core) { - const allIssues = []; - - for (const repo of repos) { - try { - const response = await github.rest.issues.listForRepo({ + const promises = repos.map(repo => + github.rest.issues + .listForRepo({ owner, repo, assignee, state, - }); - const issues = response.data.filter(issue => !issue.pull_request); - allIssues.push(...issues); - } catch (error) { - core.warning(`Failed to fetch issues from ${repo}: ${error.message}`); - } - } + }) + .then(response => response.data.filter(issue => !issue.pull_request)) + .catch(error => { + core.warning(`Failed to fetch issues from ${repo}: ${error.message}`); + return []; + }), + ); - return allIssues; + const results = await Promise.all(promises); + return results.flat(); } /** * Fetches pull requests by an author in given repositories. */ async function getPullRequests(author, state, owner, repos, github, core) { - const allPRs = []; - - for (const repo of repos) { - try { - const response = await github.rest.pulls.list({ + const promises = repos.map(repo => + github.rest.pulls + .list({ owner, repo, state, - }); - const prs = response.data.filter(pr => pr.user.login === author); - allPRs.push(...prs); - } catch (error) { - core.warning(`Failed to fetch pull requests from ${repo}: ${error.message}`); - } - } + }) + .then(response => response.data.filter(pr => pr.user.login === author)) + .catch(error => { + core.warning(`Failed to fetch pull requests from ${repo}: ${error.message}`); + return []; + }), + ); - return allPRs; + const results = await Promise.all(promises); + return results.flat(); } module.exports = { From d7dcf7482c88d32110c5f914c3acc0fe72b997f1 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Fri, 16 Jan 2026 14:14:39 +0100 Subject: [PATCH 4/5] Uppdate close contributors list --- scripts/constants.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/constants.js b/scripts/constants.js index c730f11..2e5f3b4 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -22,10 +22,12 @@ const CLOSE_CONTRIBUTORS = [ 'muditchoudhary', 'nathanaelg16', 'nikkuAg', + 'Prashant-thakur77', 'Sahil-Sinha-11', 'shivam-daksh', 'shruti862', 'thesujai', + 'vtushar06', 'WinnyChang', 'yeshwanth235', ]; From e93df69e7bfe93b91bbc7177bef251743ecb8a53 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Wed, 21 Jan 2026 11:46:52 +0100 Subject: [PATCH 5/5] Add pagination --- scripts/utils.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index 249f03d..907c5f6 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -176,12 +176,12 @@ async function hasRecentBotComment( async function hasLabel(name, owner, repo, issueNumber, github, core) { let labels = []; try { - const response = await github.rest.issues.listLabelsOnIssue({ + const allLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, { owner, repo, issue_number: issueNumber, }); - labels = response.data.map(label => label.name); + labels = allLabels.map(label => label.name); } catch (error) { core.warning(`Failed to fetch labels on issue #${issueNumber}: ${error.message}`); labels = []; @@ -194,14 +194,14 @@ async function hasLabel(name, owner, repo, issueNumber, github, core) { */ async function getIssues(assignee, state, owner, repos, github, core) { const promises = repos.map(repo => - github.rest.issues - .listForRepo({ + github + .paginate(github.rest.issues.listForRepo, { owner, repo, assignee, state, }) - .then(response => response.data.filter(issue => !issue.pull_request)) + .then(issues => issues.filter(issue => !issue.pull_request)) .catch(error => { core.warning(`Failed to fetch issues from ${repo}: ${error.message}`); return []; @@ -217,13 +217,13 @@ async function getIssues(assignee, state, owner, repos, github, core) { */ async function getPullRequests(author, state, owner, repos, github, core) { const promises = repos.map(repo => - github.rest.pulls - .list({ + github + .paginate(github.rest.pulls.list, { owner, repo, state, }) - .then(response => response.data.filter(pr => pr.user.login === author)) + .then(prs => prs.filter(pr => pr.user.login === author)) .catch(error => { core.warning(`Failed to fetch pull requests from ${repo}: ${error.message}`); return [];