Skip to content

Commit 62ad1b6

Browse files
authored
Merge branch 'hiero-ledger:main' into main
2 parents 329d03f + 7c1b220 commit 62ad1b6

33 files changed

+1582
-572
lines changed

.github/scripts/bot-gfi-assign-on-comment.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,29 @@ module.exports = async ({ github, context }) => {
216216
}
217217

218218
if (!commentRequestsAssignment(comment.body)) {
219+
console.log('[gfi-assign] No /assign command - evaluating reminder criteria', {
220+
issueNumber: issue?.number,
221+
commenter: comment?.user?.login,
222+
});
223+
224+
const isGFI = issueIsGoodFirstIssue(issue);
225+
const assigneeCount = issue?.assignees?.length ?? 0;
226+
const hasAssignees = assigneeCount > 0;
227+
const commenter = comment?.user?.login;
228+
229+
console.log('[gfi-assign] Reminder criteria summary:', {
230+
isGFI,
231+
hasAssignees,
232+
assigneeCount,
233+
commenter,
234+
issueNumber: issue?.number,
235+
});
236+
219237
// Only remind if:
220238
// - GFI
221239
// - unassigned
222240
// - reminder not already posted
223-
if (
224-
issueIsGoodFirstIssue(issue) &&
225-
!issue.assignees?.length
226-
) {
241+
if (isGFI && !hasAssignees) {
227242
const username = comment.user.login;
228243

229244
const isTeamMember = await isRepoCollaborator({
@@ -261,7 +276,15 @@ module.exports = async ({ github, context }) => {
261276
});
262277

263278
console.log('[gfi-assign] Posted /assign reminder');
279+
} else {
280+
console.log('[gfi-assign] Skip reminder: already posted on this issue');
264281
}
282+
} else {
283+
console.log('[gfi-assign] Skip reminder: not GFI or already assigned', {
284+
isGFI,
285+
hasAssignees,
286+
assigneeCount,
287+
});
265288
}
266289

267290
console.log('[gfi-assign] Exit: comment does not request assignment');

.github/scripts/bot-next-issue-recommendation.js

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1+
const SUPPORTED_GFI_REPOS = [
2+
'hiero-sdk-cpp',
3+
'hiero-sdk-swift',
4+
'hiero-sdk-python',
5+
'hiero-website',
6+
];
7+
18
module.exports = async ({ github, context, core }) => {
29
const { payload } = context;
3-
10+
411
// Get PR information from automatic pull_request_target trigger
512
let prNumber = payload.pull_request?.number;
613
let prBody = payload.pull_request?.body || '';
7-
14+
815
// Manual workflow_dispatch is no longer supported - inputs were removed
916
// Only automatic triggers from merged PRs will work
1017
const repoOwner = context.repo.owner;
1118
const repoName = context.repo.repo;
12-
19+
1320
if (!prNumber) {
1421
core.info('No PR number found, skipping');
1522
return;
1623
}
17-
24+
1825
core.info(`Processing PR #${prNumber}`);
19-
26+
2027
// Parse PR body to find linked issues
2128
const MAX_PR_BODY_LENGTH = 50000; // Reasonable limit for PR body
2229
if (prBody.length > MAX_PR_BODY_LENGTH) {
@@ -25,54 +32,53 @@ module.exports = async ({ github, context, core }) => {
2532
}
2633
const issueRegex = /(fixes|closes|resolves|fix|close|resolve)\s+(?:[\w-]+\/[\w-]+)?#(\d+)/gi;
2734
const matches = [...prBody.matchAll(issueRegex)];
28-
35+
2936
if (matches.length === 0) {
3037
core.info('No linked issues found in PR body');
3138
return;
3239
}
33-
40+
3441
// Get the first linked issue number
3542
const issueNumber = parseInt(matches[0][2]);
3643
core.info(`Found linked issue #${issueNumber}`);
37-
44+
3845
try {
3946
// Fetch issue details
4047
const { data: issue } = await github.rest.issues.get({
4148
owner: repoOwner,
4249
repo: repoName,
4350
issue_number: issueNumber,
4451
});
45-
52+
4653
// Normalize and check issue labels (case-insensitive)
4754
const labelNames = issue.labels.map(label => label.name.toLowerCase());
4855
const labelSet = new Set(labelNames);
4956
core.info(`Issue labels: ${labelNames.join(', ')}`);
50-
57+
5158
// Determine issue difficulty level
5259
const difficultyLevels = {
5360
beginner: labelSet.has('beginner'),
5461
goodFirstIssue: labelSet.has('good first issue'),
5562
intermediate: labelSet.has('intermediate'),
5663
advanced: labelSet.has('advanced'),
5764
};
58-
65+
5966
// Skip if intermediate or advanced
6067
if (difficultyLevels.intermediate || difficultyLevels.advanced) {
6168
core.info('Issue is intermediate or advanced level, skipping recommendation');
6269
return;
6370
}
64-
71+
6572
// Only proceed for Good First Issue or beginner issues
6673
if (!difficultyLevels.goodFirstIssue && !difficultyLevels.beginner) {
6774
core.info('Issue is not a Good First Issue or beginner issue, skipping');
6875
return;
6976
}
70-
77+
7178
let recommendedIssues = [];
7279
let recommendedLabel = null;
7380
let isFallback = false;
74-
let recommendationScope = 'repo';
75-
81+
7682
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, 'beginner');
7783
recommendedLabel = 'Beginner';
7884

@@ -82,29 +88,20 @@ module.exports = async ({ github, context, core }) => {
8288
recommendedLabel = 'Good First Issue';
8389
}
8490

85-
if (recommendedIssues.length === 0) {
86-
recommendationScope = 'org';
87-
recommendedLabel = 'Good First Issue';
88-
recommendedIssues = await github.rest.search.issuesAndPullRequests({
89-
q: `org:hiero-ledger type:issue state:open label:"good first issue" no:assignee`,
90-
per_page: 6,
91-
}).then(res => res.data.items);
92-
}
9391

9492
// Remove the issue they just solved
9593
recommendedIssues = recommendedIssues.filter(i => i.number !== issueNumber);
96-
94+
9795
// Generate and post comment
9896
const completedLabel = difficultyLevels.goodFirstIssue ? 'Good First Issue' : 'Beginner';
9997
const completedLabelText = completedLabel === 'Beginner' ? 'Beginner issue' : completedLabel;
10098
const recommendationMeta = {
10199
completedLabelText,
102100
recommendedLabel,
103101
isFallback,
104-
recommendationScope,
105102
};
106103
await generateAndPostComment(github, context, core, prNumber, recommendedIssues, recommendationMeta);
107-
104+
108105
} catch (error) {
109106
core.setFailed(`Error processing issue #${issueNumber}: ${error.message}`);
110107
}
@@ -114,12 +111,12 @@ async function searchIssues(github, core, owner, repo, label) {
114111
try {
115112
const query = `repo:${owner}/${repo} type:issue state:open label:"${label}" no:assignee`;
116113
core.info(`Searching for issues with query: ${query}`);
117-
114+
118115
const { data: searchResult } = await github.rest.search.issuesAndPullRequests({
119116
q: query,
120117
per_page: 6,
121118
});
122-
119+
123120
core.info(`Found ${searchResult.items.length} issues with label "${label}"`);
124121
return searchResult.items;
125122
} catch (error) {
@@ -128,22 +125,21 @@ async function searchIssues(github, core, owner, repo, label) {
128125
}
129126
}
130127

131-
async function generateAndPostComment(github, context, core, prNumber, recommendedIssues, { completedLabelText, recommendedLabel, isFallback, recommendationScope }) {
128+
async function generateAndPostComment(github, context, core, prNumber, recommendedIssues, { completedLabelText, recommendedLabel, isFallback}) {
132129
const marker = '<!-- next-issue-bot-marker -->';
133-
130+
134131
// Build comment content
135132
let comment = `${marker}\n\n🎉 **Nice work completing a ${completedLabelText}!**\n\n`;
136133
comment += `Thank you for your contribution to the Hiero Python SDK! We're excited to have you as part of our community.\n\n`;
137-
134+
138135
if (recommendedIssues.length > 0) {
139-
if (recommendationScope === 'org') {
140-
comment += `Here are some **Good First Issues across the Hiero organization** you might be interested in working on next:\n\n`;
141-
} else if (isFallback) {
136+
137+
if (isFallback) {
142138
comment += `Here are some **${recommendedLabel}** issues at a similar level you might be interested in working on next:\n\n`;
143139
} else {
144140
comment += `Here are some issues labeled **${recommendedLabel}** you might be interested in working on next:\n\n`;
145141
}
146-
142+
147143
// Sanitize title: escape markdown link syntax and special characters
148144
const sanitizeTitle = (title) => title
149145
.replace(/\[/g, '\\[')
@@ -168,37 +164,51 @@ async function generateAndPostComment(github, context, core, prNumber, recommend
168164
});
169165
} else {
170166
comment += `There are currently no open issues available at or near the ${completedLabelText} level in this repository.\n\n`;
171-
const orgLabel = recommendedLabel === 'Beginner' ? 'beginner' : 'good first issue';
172-
const orgLabelQuery = encodeURIComponent(`label:"${orgLabel}"`);
173-
comment += `You can check out ${recommendedLabel.toLowerCase()} issues across the entire Hiero organization: ` +
174-
`[Hiero ${recommendedLabel} Issues](https://github.com/issues?q=org%3Ahiero-ledger+type%3Aissue+state%3Aopen+${orgLabelQuery})\n\n`;
167+
comment += `You can check out **Good First Issues** in other Hiero repositories:\n\n`;
168+
const repoQuery = SUPPORTED_GFI_REPOS
169+
.map(repo => `repo:${context.repo.owner}/${repo}`)
170+
.join(' OR ');
171+
172+
const gfiSearchQuery = [
173+
'is:open',
174+
'is:issue',
175+
`org:${context.repo.owner}`,
176+
'archived:false',
177+
'no:assignee',
178+
'(label:"good first issue" OR label:"skill: good first issue")',
179+
`(${repoQuery})`,
180+
].join(' ');
181+
182+
const gfiQuery = `https://github.com/issues?q=${encodeURIComponent(gfiSearchQuery)}`;
183+
184+
comment += `[View Good First Issues across supported Hiero repositories](${gfiQuery})\n\n`;
175185
}
176-
186+
177187
comment += `🌟 **Stay connected with the project:**\n`;
178188
comment += `- ⭐ [Star this repository](https://github.com/${context.repo.owner}/${context.repo.repo}) to show your support\n`;
179189
comment += `- 👀 [Watch this repository](https://github.com/${context.repo.owner}/${context.repo.repo}/watchers) to get notified of new issues and releases\n\n`;
180-
190+
181191
comment += `We look forward to seeing more contributions from you! If you have any questions, feel free to ask in our [Discord community](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md).\n\n`;
182192
comment += `From the Hiero Python SDK Team 🚀`;
183-
193+
184194
// Check for existing comment
185195
try {
186196
const { data: comments } = await github.rest.issues.listComments({
187197
owner: context.repo.owner,
188198
repo: context.repo.repo,
189199
issue_number: prNumber,
190200
});
191-
192-
const existingComment = comments.find(comment => comment.body.includes(marker));
193-
201+
202+
const existingComment = comments.find(c => c.body.includes(marker));
203+
194204
if (existingComment) {
195205
core.info('Comment already exists, skipping');
196206
return;
197207
}
198208
} catch (error) {
199209
core.warning(`Error checking existing comments: ${error.message}`);
200210
}
201-
211+
202212
// Post the comment
203213
try {
204214
await github.rest.issues.createComment({
@@ -207,7 +217,7 @@ async function generateAndPostComment(github, context, core, prNumber, recommend
207217
issue_number: prNumber,
208218
body: comment,
209219
});
210-
220+
211221
core.info(`Successfully posted comment to PR #${prNumber}`);
212222
} catch (error) {
213223
core.setFailed(`Error posting comment: ${error.message}`);

CHANGELOG.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
66

77
## [Unreleased]
88

9-
109
### Tests
10+
- Standardize formatting of `tests/unit/entity_id_helper_test.py` using Black for consistent code style across the test suite (#1527)
11+
1112
- Added tests for ProtoBuf Training Example Implementation
1213
- Formatted `tests/unit/get_receipt_query_test.py` with black for code style consistency. (#1537)
1314
- format black `tests/unit/hbar*.py`.(#1538)
@@ -31,6 +32,8 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
3132
- Format `tests/unit/custom_fee_test.py` with black for code style consistency. (#1525)
3233

3334
### Added
35+
- Added logging in bot-gfi-assign-on-comment.js to prevent silent skips. (`#1668`)
36+
- Added `AssessedCustomFee` domain model to represent assessed custom fees. (`#1637`)
3437
- Add __repr__ method for ContractId class to improve debugging (#1714)
3538
- Added Protobuf Training guide to enhance developer understanding of proto serialization
3639
and deserialization (#1645)
@@ -140,16 +143,17 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
140143
- Added first-class support for EVM address aliases in `AccountId`, including parsing, serialization, Mirror Node population helpers.
141144
- Add automated bot to recommend next issues to contributors after their first PR merge (#1380)
142145
- Added dry-run support and refactored `.github/workflows/bot-workflows.yml` to use dedicated script `.github/scripts/bot-workflows.js` for improved maintainability and testability. (`#1288`)
146+
- Added MirrorNode based population for `ContractId`, including parsing and serialization support.
143147
- Added `/working` command to reset the inactivity timer on issues and PRs. ([#1552](https://github.com/hiero-ledger/hiero-sdk-python/issues/1552))
144148
- Added `grpc_deadline` support for transaction and query execution.
145-
146-
### Changed
149+
- Type hints to exception classes (`PrecheckError`, `MaxAttemptsError`, `ReceiptStatusError`) constructors and string methods.
147150

148151
### Documentation
149152
- Added comprehensive docstring to `compress_with_cryptography` function (#1626)
150153
- Replaced the docstring in `entity_id_helper.py` with one that is correct. (#1623)
151154

152155
### Changed
156+
- Refactored `setup_client()` in all `examples/query/` files to use `Client.from_env()` for simplified client initialization (#1449)
153157
- Updated return of to_bytes function in `src/hiero_sdk_python/transaction/transaction.py`. (#1631)
154158
- Added missing return type `src/hiero_sdk_python/utils/entity_id_helper.py`. (#1622)
155159
- Update `verify_freeze()` to treat only ACCOUNT_FROZEN_FOR_TOKEN as a successful freeze verification (#1515)
@@ -249,6 +253,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
249253
- chore: update MAINTAINERS.md to include new maintainer Manish Dait and sort maintainers by GitHub ID. (#1691)
250254

251255
### Fixed
256+
- Updated Good First Issue recommendations to supported Hiero repositories. (#1689)
252257
- Fix the next-issue recommendation bot to post the correct issue recommendation comment. (#1593)
253258
- Ensured that the GFI assignment bot skips posting `/assign` reminders for repository collaborators to avoid unnecessary notifications.(#1568).
254259
- Reduced notification spam by skipping the entire advanced qualification job for non-advanced issues and irrelevant events (#1517)

0 commit comments

Comments
 (0)