Skip to content

Commit 3c751f0

Browse files
authored
Merge pull request #68 from exploreriii/auto-assignment-GFIs
feat(ci): auto assignment gfis
2 parents 8980910 + 84baa92 commit 3c751f0

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// .github/scripts/gfi_assign_on_comment.js
2+
//
3+
// Assigns human user to Good First Issue when they comment "/assign".
4+
// Posts a comment if the issue is already assigned.
5+
// All other validation and additional GFI comments are handled by other existing bots which can be refactored with time.
6+
7+
const GOOD_FIRST_ISSUE_LABEL = 'Good First Issue';
8+
const UNASSIGNED_GFI_SEARCH_URL =
9+
'https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Good%20First%20Issue%22%20no%3Aassignee';
10+
11+
/// HELPERS FOR ASSIGNING ///
12+
13+
/**
14+
* Returns true if /assign appears at the start of a line or comment
15+
* Optionally preceded or followed by whitespace
16+
*/
17+
function commentRequestsAssignment(body) {
18+
return typeof body === 'string' &&
19+
/(^|\n)\s*\/assign(\s|$)/i.test(body);
20+
}
21+
22+
/**
23+
* Returns true if the issue has the good first issue label.
24+
*/
25+
function issueIsGoodFirstIssue(issue) {
26+
return issue?.labels?.some(label => label.name === GOOD_FIRST_ISSUE_LABEL);
27+
}
28+
29+
/// HELPERS FOR COMMENTING ///
30+
31+
/**
32+
* Returns a formatted @username for the current assignee of the issue.
33+
*/
34+
function getCurrentAssigneeMention(issue) {
35+
const login = issue?.assignees?.[0]?.login;
36+
return login ? `@${login}` : 'someone';
37+
}
38+
39+
/**
40+
* Builds a comment explaining that the issue is already assigned.
41+
* Requester username is passed from main
42+
*/
43+
function commentAlreadyAssigned(requesterUsername, issue) {
44+
return (
45+
`Hi @${requesterUsername} — this issue is already assigned to ${getCurrentAssigneeMention(issue)}, so I can’t assign it again.
46+
47+
👉 **Choose a different Good First Issue to work on next:**
48+
[Browse unassigned Good First Issues](${UNASSIGNED_GFI_SEARCH_URL})
49+
50+
Once you find one you like, comment \`/assign\` to get started.`
51+
);
52+
}
53+
54+
55+
/// START OF SCRIPT ///
56+
module.exports = async ({ github, context }) => {
57+
const { issue, comment } = context.payload;
58+
const { owner, repo } = context.repo;
59+
60+
// Reject if issue, comment or comment user is missing, reject bots, or if no /assign message
61+
if (
62+
!issue?.number ||
63+
!comment?.body ||
64+
!comment?.user?.login ||
65+
comment.user.type === 'Bot' ||
66+
!commentRequestsAssignment(comment.body)
67+
) {
68+
return;
69+
}
70+
// Reject if issue is not a Good First Issue
71+
if (!issueIsGoodFirstIssue(issue)) return;
72+
73+
// Get requester username and issue number to enable comments and assignments
74+
const requesterUsername = comment.user.login;
75+
const issueNumber = issue.number;
76+
77+
// Reject if issue is already assigned
78+
// Comment failure to the requester
79+
if (issue.assignees?.length > 0) {
80+
await github.rest.issues.createComment({
81+
owner,
82+
repo,
83+
issue_number: issueNumber,
84+
body: commentAlreadyAssigned(requesterUsername, issue),
85+
});
86+
return;
87+
}
88+
89+
// All validations passed and user has requested assignment on a GFI
90+
// Assign the issue to the requester
91+
// Do not comment on success
92+
await github.rest.issues.addAssignees({
93+
owner,
94+
repo,
95+
issue_number: issueNumber,
96+
assignees: [requesterUsername],
97+
});
98+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: GFI Assign on /assign
2+
3+
on:
4+
issue_comment:
5+
types:
6+
- created
7+
8+
permissions:
9+
issues: write
10+
contents: read
11+
12+
jobs:
13+
gfi-assign:
14+
# Only run on issue comments (not PR comments)
15+
if: github.event.issue.pull_request == null
16+
17+
runs-on: ubuntu-latest
18+
19+
# Prevent race conditions: always wait for the first assignment request to finish processing
20+
concurrency:
21+
group: gfi-assign-${{ github.event.issue.number }}
22+
cancel-in-progress: false
23+
24+
steps:
25+
- name: Harden runner
26+
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
27+
with:
28+
egress-policy: audit
29+
30+
- name: Checkout repository
31+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
32+
33+
- name: Run GFI /assign handler
34+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
35+
with:
36+
script: |
37+
const script = require('./.github/scripts/bot-gfi-assign-on-comment.js');
38+
await script({ github, context });

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
77
## [Unreleased]
88

99
### Added
10+
- Enable auto assignment to good first issues (#1312)
1011
- Added unit test for 'endpoint.py' to increase coverage.
1112
- Automated assignment guard for `advanced` issues; requires completion of at least one `good first issue` and one `intermediate` issue before assignment (exempts maintainers, committers, and triage members). (#1142)
1213
- Added Hbar object support for TransferTransaction HBAR transfers:

0 commit comments

Comments
 (0)