Skip to content

Commit ec903c7

Browse files
authored
feat(ci): enable auto-assignment for good first issues (#1315)
Signed-off-by: exploreriii <[email protected]>
1 parent 6ce63da commit ec903c7

File tree

8 files changed

+273
-17
lines changed

8 files changed

+273
-17
lines changed

.github/ISSUE_TEMPLATE/01_good_first_issue_candidate.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,9 @@ body:
237237
EDIT OR EXPAND THE CHECKLIST ON WHAT IS REQUIRED TO BE ABLE TO MERGE A PULL REQUEST FOR THIS ISSUE
238238
value: |
239239
To be able to merge a pull request for this issue, we need:
240-
- [ ] **Changelog Entry:** Correct changelog entry (please link to the documentation - [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md))
241-
- [ ] **Signed commits:** commits must be DCO and GPG key signed ([see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md))
240+
- [ ] **Assignment:** You must be assigned to the issue, comment: `/assign` in the issue to get assigned [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/04_assigning_issues.md)
241+
- [ ] **Changelog Entry:** Correct changelog entry [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md)
242+
- [ ] **Signed commits:** commits must be DCO and GPG key signed [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md)
242243
- [ ] **All Tests Pass:** our workflow checks like unit and integration tests must pass
243244
- [ ] **Issue is Solved:** The implementation fully addresses the issue requirements as described above
244245
- [ ] **No Further Changes are Made:** Code review feedback has been addressed and no further changes are requested
@@ -253,14 +254,14 @@ body:
253254
value: |
254255
If you have never contributed to an open source project at GitHub, the following step-by-step guide will introduce you to the workflow.
255256
256-
- [ ] **Claim this issue:** Comment below that you are interested in working on the issue. Without assignment, your pull requests might be closed and the issue given to another developer.
257-
- [ ] **Wait for assignment:** A community member with the given rights will add you as an assignee of the issue
257+
- [ ] **Assignment:** You must be assigned to the issue, comment: `/assign` in the issue to get assigned [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/04_assigning_issues.md)
258258
- [ ] **Fork, Branch and Work on the issue:** Create a copy of the repository, create a branch for the issue and solve the problem. For instructions, please read our [Contributing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/CONTRIBUTING.md) file. Further help can be found at [Set-up Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/setup) and [Workflow Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/workflow).
259259
- [ ] **DCO and GPG key sign each commit :** each commit must be -s and -S signed. An explanation on how to do this is at [Signing Guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md)
260260
- [ ] **Add a Changelog Entry :** your pull request will require a changelog. Read [Changelog Entry Guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md) to learn how.
261261
- [ ] **Push and Create a Pull Request :** Once your issue is resolved, and your commits are signed, and you have a changelog entry, push your changes and create a pull request. Detailed instructions can be found at [Submit PR Training](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/11_submit_pull_request.md), part of [Workflow Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/workflow).
262262
- [ ] **You did it 🎉:** A maintainer or committer will review your pull request and provide feedback. If approved, we will merge the fix in the main branch. Thanks for being part of the Hiero community as an open-source contributor ❤️
263263
264+
***IMPORTANT*** You will ONLY be assigned to the issue if you comment: `/assign`
264265
***IMPORTANT*** Your pull request CANNOT BE MERGED until you add a changelog entry AND sign your commits each with `git commit -S -s -m "chore: your commit message"` with a GPG key setup.
265266
validations:
266267
required: true

.github/ISSUE_TEMPLATE/04_good_first_issue.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,9 @@ body:
229229
EDIT OR EXPAND THE CHECKLIST ON WHAT IS REQUIRED TO BE ABLE TO MERGE A PULL REQUEST FOR THIS ISSUE
230230
value: |
231231
To be able to merge a pull request for this issue, we need:
232-
- [ ] **Changelog Entry:** Correct changelog entry (please link to the documentation - [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md))
233-
- [ ] **Signed commits:** commits must be DCO and GPG key signed ([see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md))
232+
- [ ] **Assignment:** You must be assigned to the issue, comment: `/assign` in the issue to get assigned [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/04_assigning_issues.md)
233+
- [ ] **Changelog Entry:** Correct changelog entry [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md)
234+
- [ ] **Signed commits:** commits must be DCO and GPG key signed [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md)
234235
- [ ] **All Tests Pass:** our workflow checks like unit and integration tests must pass
235236
- [ ] **Issue is Solved:** The implementation fully addresses the issue requirements as described above
236237
- [ ] **No Further Changes are Made:** Code review feedback has been addressed and no further changes are requested
@@ -245,14 +246,14 @@ body:
245246
value: |
246247
If you have never contributed to an open source project at GitHub, the following step-by-step guide will introduce you to the workflow.
247248
248-
- [ ] **Claim this issue:** Comment below that you are interested in working on the issue. Without assignment, your pull requests might be closed and the issue given to another developer.
249-
- [ ] **Wait for assignment:** A community member with the given rights will add you as an assignee of the issue
249+
- [ ] **Assignment:** You must be assigned to the issue, comment: `/assign` in the issue to get assigned [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/04_assigning_issues.md)
250250
- [ ] **Fork, Branch and Work on the issue:** Create a copy of the repository, create a branch for the issue and solve the problem. For instructions, please read our [Contributing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/CONTRIBUTING.md) file. Further help can be found at [Set-up Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/setup) and [Workflow Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/workflow).
251251
- [ ] **DCO and GPG key sign each commit :** each commit must be -s and -S signed. An explanation on how to do this is at [Signing Guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md)
252252
- [ ] **Add a Changelog Entry :** your pull request will require a changelog. Read [Changelog Entry Guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md) to learn how.
253253
- [ ] **Push and Create a Pull Request :** Once your issue is resolved, and your commits are signed, and you have a changelog entry, push your changes and create a pull request. Detailed instructions can be found at [Submit PR Training](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/11_submit_pull_request.md), part of [Workflow Training](https://github.com/hiero-ledger/hiero-sdk-python/tree/main/docs/sdk_developers/training/workflow).
254254
- [ ] **You did it 🎉:** A maintainer or committer will review your pull request and provide feedback. If approved, we will merge the fix in the main branch. Thanks for being part of the Hiero community as an open-source contributor ❤️
255255
256+
***IMPORTANT*** You will ONLY be assigned to the issue if you comment: `/assign`
256257
***IMPORTANT*** Your pull request CANNOT BE MERGED until you add a changelog entry AND sign your commits each with `git commit -S -s -m "chore: your commit message"` with a GPG key setup.
257258
validations:
258259
required: true

.github/scripts/gfi_notify_team.js renamed to .github/scripts/archive/gfi_notify_team.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Script to notify the team when a GFI issue receives its first human comment.
2+
// Replaced by automatic GFI assignment
23

34
const marker = '<!-- GFI Issue Notification -->';
45
const TEAM_ALIAS = '@hiero-ledger/hiero-sdk-good-first-issue-support';
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// .github/scripts/bot-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 as a standalone command in the comment
15+
*/
16+
function commentRequestsAssignment(body) {
17+
const matches =
18+
typeof body === 'string' &&
19+
/(^|\s)\/assign(\s|$)/i.test(body);
20+
21+
console.log('[gfi-assign] commentRequestsAssignment:', {
22+
body,
23+
matches,
24+
});
25+
26+
return matches;
27+
}
28+
29+
/**
30+
* Returns true if the issue has the good first issue label.
31+
*/
32+
function issueIsGoodFirstIssue(issue) {
33+
const labels = issue?.labels?.map(label => label.name) ?? [];
34+
const isGfi = labels.includes(GOOD_FIRST_ISSUE_LABEL);
35+
36+
console.log('[gfi-assign] issueIsGoodFirstIssue:', {
37+
labels,
38+
expected: GOOD_FIRST_ISSUE_LABEL,
39+
isGfi,
40+
});
41+
42+
return isGfi;
43+
}
44+
/// HELPERS FOR COMMENTING ///
45+
46+
/**
47+
* Returns a formatted @username for the current assignee of the issue.
48+
*/
49+
function getCurrentAssigneeMention(issue) {
50+
const login = issue?.assignees?.[0]?.login;
51+
return login ? `@${login}` : 'someone';
52+
}
53+
54+
/**
55+
* Builds a comment explaining that the issue is already assigned.
56+
* Requester username is passed from main
57+
*/
58+
function commentAlreadyAssigned(requesterUsername, issue) {
59+
return (
60+
`Hi @${requesterUsername} — this issue is already assigned to ${getCurrentAssigneeMention(issue)}, so I can’t assign it again.
61+
62+
👉 **Choose a different Good First Issue to work on next:**
63+
[Browse unassigned Good First Issues](${UNASSIGNED_GFI_SEARCH_URL})
64+
65+
Once you find one you like, comment \`/assign\` to get started.`
66+
);
67+
}
68+
69+
// HELPERS FOR PEOPLE THAT WANT TO BE ASSIGNED BUT DID NOT READ INSTRUCTIONS
70+
const ASSIGN_REMINDER_MARKER = '<!-- GFI assign reminder -->';
71+
72+
function buildAssignReminder(username) {
73+
return `${ASSIGN_REMINDER_MARKER}
74+
👋 Hi @${username}!
75+
76+
If you’d like to work on this **Good First Issue**, just comment:
77+
78+
\`\`\`
79+
/assign
80+
\`\`\`
81+
82+
and you’ll be automatically assigned. Feel free to ask questions here if anything is unclear!`;
83+
}
84+
85+
/// START OF SCRIPT ///
86+
module.exports = async ({ github, context }) => {
87+
try {
88+
const { issue, comment } = context.payload;
89+
const { owner, repo } = context.repo;
90+
91+
console.log('[gfi-assign] Payload snapshot:', {
92+
issueNumber: issue?.number,
93+
commenter: comment?.user?.login,
94+
commenterType: comment?.user?.type,
95+
commentBody: comment?.body,
96+
});
97+
98+
// Reject if issue, comment or comment user is missing, reject bots, or if no /assign message
99+
if (!issue?.number) {
100+
console.log('[gfi-assign] Exit: missing issue number');
101+
return;
102+
}
103+
104+
if (!comment?.body) {
105+
console.log('[gfi-assign] Exit: missing comment body');
106+
return;
107+
}
108+
109+
if (!comment?.user?.login) {
110+
console.log('[gfi-assign] Exit: missing comment user login');
111+
return;
112+
}
113+
114+
if (comment.user.type === 'Bot') {
115+
console.log('[gfi-assign] Exit: comment authored by bot');
116+
return;
117+
}
118+
119+
if (!commentRequestsAssignment(comment.body)) {
120+
// Only remind if:
121+
// - GFI
122+
// - unassigned
123+
// - reminder not already posted
124+
if (
125+
issueIsGoodFirstIssue(issue) &&
126+
!issue.assignees?.length
127+
) {
128+
const comments = await github.paginate(
129+
github.rest.issues.listComments,
130+
{
131+
owner,
132+
repo,
133+
issue_number: issue.number,
134+
per_page: 100,
135+
}
136+
);
137+
138+
const reminderAlreadyPosted = comments.some(c =>
139+
c.body?.includes(ASSIGN_REMINDER_MARKER)
140+
);
141+
142+
if (!reminderAlreadyPosted) {
143+
await github.rest.issues.createComment({
144+
owner,
145+
repo,
146+
issue_number: issue.number,
147+
body: buildAssignReminder(comment.user.login),
148+
});
149+
150+
console.log('[gfi-assign] Posted /assign reminder');
151+
}
152+
}
153+
154+
console.log('[gfi-assign] Exit: comment does not request assignment');
155+
return;
156+
}
157+
158+
console.log('[gfi-assign] Assignment command detected');
159+
160+
// Reject if issue is not a Good First Issue
161+
if (!issueIsGoodFirstIssue(issue)) {
162+
console.log('[gfi-assign] Exit: issue is not a Good First Issue');
163+
return;
164+
}
165+
166+
console.log('[gfi-assign] Issue is labeled Good First Issue');
167+
168+
// Get requester username and issue number to enable comments and assignments
169+
const requesterUsername = comment.user.login;
170+
const issueNumber = issue.number;
171+
172+
console.log('[gfi-assign] Requester:', requesterUsername);
173+
console.log('[gfi-assign] Current assignees:', issue.assignees?.map(a => a.login));
174+
175+
// Reject if issue is already assigned
176+
// Comment failure to the requester
177+
if (issue.assignees?.length > 0) {
178+
console.log('[gfi-assign] Exit: issue already assigned');
179+
180+
await github.rest.issues.createComment({
181+
owner,
182+
repo,
183+
issue_number: issueNumber,
184+
body: commentAlreadyAssigned(requesterUsername, issue),
185+
});
186+
187+
console.log('[gfi-assign] Posted already-assigned comment');
188+
return;
189+
}
190+
191+
console.log('[gfi-assign] Assigning issue to requester');
192+
193+
// All validations passed and user has requested assignment on a GFI
194+
// Assign the issue to the requester
195+
// Do not comment on success
196+
await github.rest.issues.addAssignees({
197+
owner,
198+
repo,
199+
issue_number: issueNumber,
200+
assignees: [requesterUsername],
201+
});
202+
203+
console.log('[gfi-assign] Assignment completed successfully');
204+
} catch (error) {
205+
console.error('[gfi-assign] Error:', {
206+
message: error.message,
207+
status: error.status,
208+
issueNumber: context.payload.issue?.number,
209+
commenter: context.payload.comment?.user?.login,
210+
});
211+
throw error;
212+
}
213+
};

.github/workflows/bot-gfi-notify-team.yml renamed to .github/workflows/archive/bot-gfi-notify-team.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ jobs:
1919
'Good First Issue'
2020
)
2121
22-
2322
concurrency:
2423
group: gfi-notify-issue-${{ github.event.issue.number }}
2524
cancel-in-progress: false
26-
25+
2726
steps:
2827
- name: Harden the runner
2928
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
@@ -40,4 +39,4 @@ jobs:
4039
with:
4140
script: |
4241
const script = require('./.github/scripts/gfi_notify_team.js');
43-
await script({ github, context});
42+
await script({ github, context});
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), archived good first issue support team notification. Changed templates with new assign instruction.
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:
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
## Getting Assigned to an Issue
22

3-
It is important to be assigned an issue before starting work on it or creating a pull request.
3+
Claim an issue as yours to work on by commenting on a good first issue with exactly: /assign
44

55
We recommend Good First Issues for developers new to the Python SDK. These are easier and better documented tasks.
66

7-
To do that,
8-
1. Select a `Good First Issue` that interests you and is not yet assigned at [Python SDK Issues](https://github.com/hiero-ledger/hiero-sdk-python/issues)
9-
2. Write a comment at the bottom of the issue page asking "I want to be assigned to this issue"
10-
3. A maintainer will shortly assign you to the issue
7+
Key steps:
8+
1. Find an available `Good First Issue` that interests you and is not yet assigned at [Python SDK Good First Issues](https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Good%20First%20Issue%22%20no%3Aassignee)
9+
2. Write a comment replying to the issue with: `/assign`
10+
3. You'll be automatically assigned
1111

12-
Congratulations! You are assigned and can now get started on the work.
12+
Congratulations! You have claimed the issue and can now get started on the work.
13+
14+
Intermediate and advanced issues require team approval to be assigned.

0 commit comments

Comments
 (0)