Skip to content

Commit f64711c

Browse files
committed
Prevent mentor self-match and duplicate notifications
Signed-off-by: Mounil <[email protected]>
1 parent d044d83 commit f64711c

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

.github/scripts/bot-mentor-assignment.js

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,25 @@ function loadMentorRoster() {
3636
}
3737
}
3838

39-
function selectMentor(roster) {
39+
function selectMentor(roster, mentee) {
4040
if (!Array.isArray(roster) || roster.length === 0) {
4141
throw new Error('Mentor roster must contain at least one entry.');
4242
}
4343

4444
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
4545
const dayNumber = Math.floor(Date.now() / MILLISECONDS_PER_DAY); // UTC day index
46-
const index = dayNumber % roster.length;
46+
const baseIndex = dayNumber % roster.length;
47+
const normalizedMentee = typeof mentee === 'string' ? mentee.toLowerCase() : null;
4748

48-
return roster[index];
49+
for (let offset = 0; offset < roster.length; offset += 1) {
50+
const candidate = roster[(baseIndex + offset) % roster.length];
51+
52+
if (!normalizedMentee || candidate.toLowerCase() !== normalizedMentee) {
53+
return candidate;
54+
}
55+
}
56+
57+
return null;
4958
}
5059

5160
function hasGoodFirstIssueLabel(issue) {
@@ -55,6 +64,41 @@ function hasGoodFirstIssueLabel(issue) {
5564
});
5665
}
5766

67+
async function hasActiveMentorAssignment(github, owner, repo, mentee, currentIssueNumber) {
68+
try {
69+
const assignedIssues = await github.paginate(
70+
github.rest.issues.listForRepo,
71+
{
72+
owner,
73+
repo,
74+
assignee: mentee,
75+
state: 'open',
76+
per_page: 100,
77+
},
78+
(response) =>
79+
(response.data || []).filter((issue) => issue?.number && issue.number !== currentIssueNumber),
80+
);
81+
82+
for (const assignedIssue of assignedIssues) {
83+
const comments = await github.paginate(github.rest.issues.listComments, {
84+
owner,
85+
repo,
86+
issue_number: assignedIssue.number,
87+
per_page: 100,
88+
});
89+
90+
if (comments.some((comment) => comment.body?.includes(COMMENT_MARKER))) {
91+
return true;
92+
}
93+
}
94+
} catch (error) {
95+
const message = error instanceof Error ? error.message : String(error);
96+
console.log(`Unable to detect existing mentor assignments for ${mentee}: ${message}`);
97+
}
98+
99+
return false;
100+
}
101+
58102
async function isNewContributor(github, owner, repo, login) {
59103
const query = `repo:${owner}/${repo} type:pr state:closed is:merged author:${login}`;
60104

@@ -132,19 +176,44 @@ module.exports = async ({ github, context }) => {
132176
return console.log(`${mentee} already has merged contributions. Skipping mentor assignment.`);
133177
}
134178

179+
if (await hasActiveMentorAssignment(github, owner, repo, mentee, issue.number)) {
180+
return console.log(`${mentee} already has an active mentor assignment comment on another issue. Skipping.`);
181+
}
182+
135183
const roster = loadMentorRoster();
136-
const mentor = selectMentor(roster);
184+
const mentor = selectMentor(roster, mentee);
185+
186+
if (!mentor) {
187+
return console.log(`No eligible mentor (excluding mentee ${mentee}) found. Skipping mentor assignment.`);
188+
}
137189

138190
console.log(`Assigning mentor @${mentor} to mentee @${mentee} for issue #${issue.number}.`);
139191

140192
const comment = buildComment({ mentee, mentor, owner, repo });
141193

142-
await github.rest.issues.createComment({
143-
owner,
144-
repo,
145-
issue_number: issue.number,
146-
body: comment,
147-
});
194+
try {
195+
await github.rest.issues.createComment({
196+
owner,
197+
repo,
198+
issue_number: issue.number,
199+
body: comment,
200+
});
201+
} catch (error) {
202+
const message = error instanceof Error ? error.message : String(error);
203+
204+
const freshComments = await github.paginate(github.rest.issues.listComments, {
205+
owner,
206+
repo,
207+
issue_number: issue.number,
208+
per_page: 100,
209+
});
210+
211+
if (freshComments.some((existing) => existing.body?.includes(COMMENT_MARKER))) {
212+
return console.log(`Mentor assignment comment already exists on issue #${issue.number} after concurrent run. Skipping. (${message})`);
213+
}
214+
215+
throw error;
216+
}
148217
} catch (error) {
149218
const message = error instanceof Error ? error.message : String(error);
150219
console.log(`❌ Mentor assignment failed: ${message}`);

.github/workflows/bot-mentor-assignment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ permissions:
1212

1313
jobs:
1414
assign-mentor:
15+
if: contains(github.event.issue.labels.*.name, 'Good First Issue')
1516
runs-on: ubuntu-latest
1617
steps:
1718
- name: Harden the runner

0 commit comments

Comments
 (0)