-
Notifications
You must be signed in to change notification settings - Fork 145
feat(ci): enable auto-assignment for good first issues #1315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
exploreriii
merged 13 commits into
hiero-ledger:main
from
exploreriii:enable-gfi-auto-assign
Jan 3, 2026
+273
−17
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
b27f48a
feat: auto assign for GFIs
exploreriii 84baa92
chore: changelog entry
exploreriii 4d3c046
chore: add logs for debugging
exploreriii 9ea2c4b
fix: loosening the regex
exploreriii 8493831
fix: the regex
exploreriii faf4567
chore: assignment to templates
exploreriii 7a0b93f
chore: add assign reminder feature
exploreriii 0ce176d
chore: archive unused bu useful workflow
exploreriii 88a48ff
fix: URLs
exploreriii 8fe6b17
chore: changelog entry
exploreriii d93a8f5
fix: remove reundant wait for assignment instruction
exploreriii 3ebe6dd
fix: formatting fails
exploreriii bcb9373
chore: try catch
exploreriii File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
.github/scripts/gfi_notify_team.js → .github/scripts/archive/gfi_notify_team.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| // .github/scripts/bot-gfi_assign_on_comment.js | ||
| // | ||
| // Assigns human user to Good First Issue when they comment "/assign". | ||
| // Posts a comment if the issue is already assigned. | ||
| // All other validation and additional GFI comments are handled by other existing bots which can be refactored with time. | ||
|
|
||
| const GOOD_FIRST_ISSUE_LABEL = 'Good First Issue'; | ||
| const UNASSIGNED_GFI_SEARCH_URL = | ||
| 'https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Good%20First%20Issue%22%20no%3Aassignee'; | ||
|
|
||
| /// HELPERS FOR ASSIGNING /// | ||
|
|
||
| /** | ||
| * Returns true if /assign appears as a standalone command in the comment | ||
| */ | ||
| function commentRequestsAssignment(body) { | ||
| const matches = | ||
| typeof body === 'string' && | ||
| /(^|\s)\/assign(\s|$)/i.test(body); | ||
|
|
||
| console.log('[gfi-assign] commentRequestsAssignment:', { | ||
| body, | ||
| matches, | ||
| }); | ||
|
|
||
| return matches; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the issue has the good first issue label. | ||
| */ | ||
| function issueIsGoodFirstIssue(issue) { | ||
| const labels = issue?.labels?.map(label => label.name) ?? []; | ||
| const isGfi = labels.includes(GOOD_FIRST_ISSUE_LABEL); | ||
|
|
||
| console.log('[gfi-assign] issueIsGoodFirstIssue:', { | ||
| labels, | ||
| expected: GOOD_FIRST_ISSUE_LABEL, | ||
| isGfi, | ||
| }); | ||
|
|
||
| return isGfi; | ||
| } | ||
| /// HELPERS FOR COMMENTING /// | ||
|
|
||
| /** | ||
| * Returns a formatted @username for the current assignee of the issue. | ||
| */ | ||
| function getCurrentAssigneeMention(issue) { | ||
| const login = issue?.assignees?.[0]?.login; | ||
| return login ? `@${login}` : 'someone'; | ||
| } | ||
|
|
||
| /** | ||
| * Builds a comment explaining that the issue is already assigned. | ||
| * Requester username is passed from main | ||
| */ | ||
| function commentAlreadyAssigned(requesterUsername, issue) { | ||
| return ( | ||
| `Hi @${requesterUsername} — this issue is already assigned to ${getCurrentAssigneeMention(issue)}, so I can’t assign it again. | ||
|
|
||
| 👉 **Choose a different Good First Issue to work on next:** | ||
| [Browse unassigned Good First Issues](${UNASSIGNED_GFI_SEARCH_URL}) | ||
|
|
||
| Once you find one you like, comment \`/assign\` to get started.` | ||
| ); | ||
| } | ||
|
|
||
| // HELPERS FOR PEOPLE THAT WANT TO BE ASSIGNED BUT DID NOT READ INSTRUCTIONS | ||
| const ASSIGN_REMINDER_MARKER = '<!-- GFI assign reminder -->'; | ||
|
|
||
| function buildAssignReminder(username) { | ||
| return `${ASSIGN_REMINDER_MARKER} | ||
| 👋 Hi @${username}! | ||
|
|
||
| If you’d like to work on this **Good First Issue**, just comment: | ||
|
|
||
| \`\`\` | ||
| /assign | ||
| \`\`\` | ||
|
|
||
| and you’ll be automatically assigned. Feel free to ask questions here if anything is unclear!`; | ||
| } | ||
|
|
||
| /// START OF SCRIPT /// | ||
| module.exports = async ({ github, context }) => { | ||
| try { | ||
| const { issue, comment } = context.payload; | ||
| const { owner, repo } = context.repo; | ||
|
|
||
| console.log('[gfi-assign] Payload snapshot:', { | ||
| issueNumber: issue?.number, | ||
| commenter: comment?.user?.login, | ||
| commenterType: comment?.user?.type, | ||
| commentBody: comment?.body, | ||
| }); | ||
exploreriii marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Reject if issue, comment or comment user is missing, reject bots, or if no /assign message | ||
| if (!issue?.number) { | ||
| console.log('[gfi-assign] Exit: missing issue number'); | ||
| return; | ||
| } | ||
|
|
||
| if (!comment?.body) { | ||
| console.log('[gfi-assign] Exit: missing comment body'); | ||
| return; | ||
| } | ||
|
|
||
| if (!comment?.user?.login) { | ||
| console.log('[gfi-assign] Exit: missing comment user login'); | ||
| return; | ||
| } | ||
|
|
||
| if (comment.user.type === 'Bot') { | ||
| console.log('[gfi-assign] Exit: comment authored by bot'); | ||
| return; | ||
| } | ||
|
|
||
| if (!commentRequestsAssignment(comment.body)) { | ||
| // Only remind if: | ||
| // - GFI | ||
| // - unassigned | ||
| // - reminder not already posted | ||
| if ( | ||
| issueIsGoodFirstIssue(issue) && | ||
| !issue.assignees?.length | ||
| ) { | ||
| const comments = await github.paginate( | ||
| github.rest.issues.listComments, | ||
| { | ||
| owner, | ||
| repo, | ||
| issue_number: issue.number, | ||
| per_page: 100, | ||
| } | ||
| ); | ||
|
|
||
| const reminderAlreadyPosted = comments.some(c => | ||
| c.body?.includes(ASSIGN_REMINDER_MARKER) | ||
| ); | ||
|
|
||
| if (!reminderAlreadyPosted) { | ||
| await github.rest.issues.createComment({ | ||
| owner, | ||
| repo, | ||
| issue_number: issue.number, | ||
| body: buildAssignReminder(comment.user.login), | ||
| }); | ||
|
|
||
| console.log('[gfi-assign] Posted /assign reminder'); | ||
| } | ||
| } | ||
|
|
||
| console.log('[gfi-assign] Exit: comment does not request assignment'); | ||
| return; | ||
| } | ||
|
|
||
| console.log('[gfi-assign] Assignment command detected'); | ||
|
|
||
| // Reject if issue is not a Good First Issue | ||
| if (!issueIsGoodFirstIssue(issue)) { | ||
| console.log('[gfi-assign] Exit: issue is not a Good First Issue'); | ||
| return; | ||
| } | ||
|
|
||
| console.log('[gfi-assign] Issue is labeled Good First Issue'); | ||
|
|
||
| // Get requester username and issue number to enable comments and assignments | ||
| const requesterUsername = comment.user.login; | ||
| const issueNumber = issue.number; | ||
|
|
||
| console.log('[gfi-assign] Requester:', requesterUsername); | ||
| console.log('[gfi-assign] Current assignees:', issue.assignees?.map(a => a.login)); | ||
|
|
||
| // Reject if issue is already assigned | ||
| // Comment failure to the requester | ||
| if (issue.assignees?.length > 0) { | ||
| console.log('[gfi-assign] Exit: issue already assigned'); | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner, | ||
| repo, | ||
| issue_number: issueNumber, | ||
| body: commentAlreadyAssigned(requesterUsername, issue), | ||
| }); | ||
|
|
||
| console.log('[gfi-assign] Posted already-assigned comment'); | ||
| return; | ||
| } | ||
|
|
||
| console.log('[gfi-assign] Assigning issue to requester'); | ||
|
|
||
| // All validations passed and user has requested assignment on a GFI | ||
| // Assign the issue to the requester | ||
| // Do not comment on success | ||
| await github.rest.issues.addAssignees({ | ||
| owner, | ||
| repo, | ||
| issue_number: issueNumber, | ||
| assignees: [requesterUsername], | ||
| }); | ||
|
|
||
| console.log('[gfi-assign] Assignment completed successfully'); | ||
| } catch (error) { | ||
| console.error('[gfi-assign] Error:', { | ||
| message: error.message, | ||
| status: error.status, | ||
| issueNumber: context.payload.issue?.number, | ||
| commenter: context.payload.comment?.user?.login, | ||
| }); | ||
| throw error; | ||
| } | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| name: GFI Assign on /assign | ||
|
|
||
| on: | ||
| issue_comment: | ||
| types: | ||
| - created | ||
|
|
||
| permissions: | ||
| issues: write | ||
| contents: read | ||
|
|
||
exploreriii marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| jobs: | ||
| gfi-assign: | ||
| # Only run on issue comments (not PR comments) | ||
| if: github.event.issue.pull_request == null | ||
|
|
||
| runs-on: ubuntu-latest | ||
|
|
||
| # Prevent race conditions: always wait for the first assignment request to finish processing | ||
| concurrency: | ||
| group: gfi-assign-${{ github.event.issue.number }} | ||
| cancel-in-progress: false | ||
|
|
||
| steps: | ||
| - name: Harden runner | ||
| uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Checkout repository | ||
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | ||
|
|
||
| - name: Run GFI /assign handler | ||
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0 | ||
| with: | ||
| script: | | ||
| const script = require('./.github/scripts/bot-gfi-assign-on-comment.js'); | ||
| await script({ github, context }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 8 additions & 6 deletions
14
docs/sdk_developers/training/workflow/04_assigning_issues.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| ## Getting Assigned to an Issue | ||
|
|
||
| It is important to be assigned an issue before starting work on it or creating a pull request. | ||
| Claim an issue as yours to work on by commenting on a good first issue with exactly: /assign | ||
|
|
||
| We recommend Good First Issues for developers new to the Python SDK. These are easier and better documented tasks. | ||
|
|
||
| To do that, | ||
| 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) | ||
| 2. Write a comment at the bottom of the issue page asking "I want to be assigned to this issue" | ||
| 3. A maintainer will shortly assign you to the issue | ||
| Key steps: | ||
| 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) | ||
| 2. Write a comment replying to the issue with: `/assign` | ||
| 3. You'll be automatically assigned | ||
|
|
||
| Congratulations! You are assigned and can now get started on the work. | ||
| Congratulations! You have claimed the issue and can now get started on the work. | ||
|
|
||
| Intermediate and advanced issues require team approval to be assigned. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.