Skip to content
Merged
9 changes: 5 additions & 4 deletions .github/ISSUE_TEMPLATE/01_good_first_issue_candidate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,9 @@ body:
EDIT OR EXPAND THE CHECKLIST ON WHAT IS REQUIRED TO BE ABLE TO MERGE A PULL REQUEST FOR THIS ISSUE
value: |
To be able to merge a pull request for this issue, we need:
- [ ] **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))
- [ ] **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))
- [ ] **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)
- [ ] **Changelog Entry:** Correct changelog entry [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md)
- [ ] **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)
- [ ] **All Tests Pass:** our workflow checks like unit and integration tests must pass
- [ ] **Issue is Solved:** The implementation fully addresses the issue requirements as described above
- [ ] **No Further Changes are Made:** Code review feedback has been addressed and no further changes are requested
Expand All @@ -253,14 +254,14 @@ body:
value: |
If you have never contributed to an open source project at GitHub, the following step-by-step guide will introduce you to the workflow.

- [ ] **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.
- [ ] **Wait for assignment:** A community member with the given rights will add you as an assignee of the issue
- [ ] **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)
- [ ] **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).
- [ ] **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)
- [ ] **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.
- [ ] **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).
- [ ] **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 ❤️

***IMPORTANT*** You will ONLY be assigned to the issue if you comment: `/assign`
***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.
validations:
required: true
Expand Down
9 changes: 5 additions & 4 deletions .github/ISSUE_TEMPLATE/04_good_first_issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,9 @@ body:
EDIT OR EXPAND THE CHECKLIST ON WHAT IS REQUIRED TO BE ABLE TO MERGE A PULL REQUEST FOR THIS ISSUE
value: |
To be able to merge a pull request for this issue, we need:
- [ ] **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))
- [ ] **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))
- [ ] **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)
- [ ] **Changelog Entry:** Correct changelog entry [see guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md)
- [ ] **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)
- [ ] **All Tests Pass:** our workflow checks like unit and integration tests must pass
- [ ] **Issue is Solved:** The implementation fully addresses the issue requirements as described above
- [ ] **No Further Changes are Made:** Code review feedback has been addressed and no further changes are requested
Expand All @@ -245,14 +246,14 @@ body:
value: |
If you have never contributed to an open source project at GitHub, the following step-by-step guide will introduce you to the workflow.

- [ ] **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.
- [ ] **Wait for assignment:** A community member with the given rights will add you as an assignee of the issue
- [ ] **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)
- [ ] **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).
- [ ] **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)
- [ ] **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.
- [ ] **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).
- [ ] **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 ❤️

***IMPORTANT*** You will ONLY be assigned to the issue if you comment: `/assign`
***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.
validations:
required: true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Script to notify the team when a GFI issue receives its first human comment.
// Replaced by automatic GFI assignment

const marker = '<!-- GFI Issue Notification -->';
const TEAM_ALIAS = '@hiero-ledger/hiero-sdk-good-first-issue-support';
Expand Down
213 changes: 213 additions & 0 deletions .github/scripts/bot-gfi-assign-on-comment.js
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,
});

// 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;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ jobs:
'Good First Issue'
)


concurrency:
group: gfi-notify-issue-${{ github.event.issue.number }}
cancel-in-progress: false

steps:
- name: Harden the runner
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
Expand All @@ -40,4 +39,4 @@ jobs:
with:
script: |
const script = require('./.github/scripts/gfi_notify_team.js');
await script({ github, context});
await script({ github, context});
38 changes: 38 additions & 0 deletions .github/workflows/bot-gfi-assign-on-comment.yml
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

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 });
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
## [Unreleased]

### Added
- Enable auto assignment to good first issues (#1312), archived good first issue support team notification. Changed templates with new assign instruction.
- Added unit test for 'endpoint.py' to increase coverage.
- 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)
- Added Hbar object support for TransferTransaction HBAR transfers:
Expand Down
14 changes: 8 additions & 6 deletions docs/sdk_developers/training/workflow/04_assigning_issues.md
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.