Skip to content

Commit bc9d987

Browse files
committed
chore: refactor comments and jsdocs
Signed-off-by: Parv Ninama <ninamaparv@gmail.com>
1 parent 62e40ed commit bc9d987

7 files changed

Lines changed: 69 additions & 27 deletions

File tree

.github/scripts/shared/api/github-api.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const { CONFIG } = require('../config');
1616
* @param {string} repo - Repo name.
1717
* @param {string} username - GitHub login of the contributor.
1818
* @param {string} labelString - Repo-specific label string to filter by.
19-
* @param {number} cap - Maximum results to request (capped at 100).
20-
* @returns {Promise<number|null>} Count of matching issues, or null on API failure.
19+
* @param {number} cap - Maximum number of results to fetch (first page only, capped at 100).
20+
* @returns {Promise<number|null>} Number of fetched matching issues (not total count), or null on API failure.
2121
*/
2222
async function countClosedIssuesByAssignee(github, owner, repo, username, labelString, cap) {
2323
try {
@@ -38,7 +38,7 @@ async function countClosedIssuesByAssignee(github, owner, repo, username, labelS
3838
*
3939
* @param {import('@actions/github').GitHub} github
4040
* @param {object} repoConfig - Repo entry from CONFIG.repos.
41-
* @returns {Promise<Array|null>} Issue array, or null on API failure.
41+
* @returns {Promise<Array<object>|null>} Issue array, or null on API failure.
4242
*/
4343
async function fetchIssuesBatch(github, repoConfig) {
4444
try {

.github/scripts/shared/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const CONFIG = {
4747
},
4848
],
4949

50+
repositoryUrl: 'https://github.com/hiero-ledger/hiero-sdk-python',
5051
maxRecommendations: 5,
5152
fetchPerPage: 50,
5253
commentMarker: '<!-- hiero-next-issue-bot -->',

.github/scripts/shared/core/eligibility.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ const { countClosedIssuesByAssignee } = require('../api/github-api');
88

99
// Fast path: user has already completed ≥1 issue at this level or higher
1010
async function passesBypassCheck(github, homeRepo, username, candidate) {
11-
const atOrAbove = CONFIG.skillHierarchy.slice(CONFIG.skillHierarchy.indexOf(candidate));
11+
const idx = CONFIG.skillHierarchy.indexOf(candidate);
12+
if (idx === -1) return false;
13+
const atOrAbove = CONFIG.skillHierarchy.slice(idx);
1214

13-
const counts = await Promise.all(
14-
atOrAbove.map(key => countClosedIssuesByAssignee(
15+
for (const key of atOrAbove) {
16+
const count = await countClosedIssuesByAssignee(
1517
github, homeRepo.owner, homeRepo.repo, username,
1618
repoLabelFor(homeRepo, key), 1,
17-
))
18-
);
19-
20-
return counts.some(count => count !== null && count >= 1);
19+
);
20+
if (count !== null && count >= 1) return true;
21+
}
22+
return false;
2123
}
2224

2325
/**
@@ -49,7 +51,7 @@ async function passesNormalCheck(github, homeRepo, username, prereq) {
4951
* @param {object} homeRepo - Home repo entry from CONFIG.repos.
5052
* @param {string} username - GitHub login of the contributor.
5153
* @param {string} candidate - Canonical level key being evaluated.
52-
* @returns {Promise<boolean|null>} True if eligible, false if not, null on API failure.
54+
* @returns {Promise<boolean>} True if eligible, false otherwise (API failures treated as false).
5355
*/
5456
async function isEligibleFor(github, homeRepo, username, candidate) {
5557
const prereq = CONFIG.skillPrerequisites[candidate];
@@ -84,10 +86,10 @@ async function isEligibleFor(github, homeRepo, username, candidate) {
8486
async function resolveEligibleLevel(github, homeRepo, username) {
8587
for (const candidate of [...CONFIG.skillHierarchy].reverse()) {
8688
const eligible = await isEligibleFor(github, homeRepo, username, candidate);
87-
// eligible === null means API failure — skip conservatively.
89+
// false includes API failures (treated conservatively as ineligible)
8890
if (eligible === true) return candidate;
8991
}
90-
return 'gfi';
92+
return CONFIG.skillHierarchy[0];
9193
}
9294

9395
/**
@@ -131,8 +133,10 @@ function adjustEligibilityForCurrentPR(completedKey, eligibleKey) {
131133
async function detectUnlockedLevel(github, homeRepo, username, currentLevelKey) {
132134
const hierarchy = CONFIG.skillHierarchy;
133135
const currentIndex = hierarchy.indexOf(currentLevelKey);
134-
const nextKey = hierarchy[currentIndex + 1] ?? null;
135136

137+
if (currentIndex === -1) return null;
138+
139+
const nextKey = hierarchy[currentIndex + 1] ?? null;
136140
if (!nextKey) return null;
137141

138142
const nextPrereq = CONFIG.skillPrerequisites[nextKey];
@@ -144,6 +148,7 @@ async function detectUnlockedLevel(github, homeRepo, username, currentLevelKey)
144148
);
145149

146150
if (count === null) return null;
151+
// NOTE: count is derived from first-page results only; safe because requiredCount is small.
147152
return count === nextPrereq.requiredCount ? nextKey : null;
148153
}
149154

.github/scripts/shared/core/recommendation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const {
1313

1414
/**
1515
* Order: level up → same → level down (floored at beginner, capped by eligibility)
16-
*
16+
*
1717
* @param {string} completedLevelKey - Canonical key of the level just completed.
1818
* @param {string} eligibleLevelKey - Adjusted eligibility ceiling.
1919
* @returns {number[]} Deduplicated, ordered array of hierarchy indices to try.

.github/scripts/shared/helpers/comment.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,28 @@
44

55
const { CONFIG } = require('../config');
66

7-
function buildIssueListBlock(issues) {
7+
function buildIssueListBlock(issues = []) {
88
if (issues.length > 0) {
99
return [
1010
'Here are some issues you might want to explore next:',
1111
'',
12-
...issues.map(i => `- [${i.title}](${i.html_url})`),
12+
...issues.map(i => {
13+
const title = i?.title ?? 'Untitled issue';
14+
const url = i?.html_url ?? '#';
15+
return `- [${title}](${url})`;
16+
}),
1317
'',
1418
];
1519
}
1620
return ['No suitable issues are available right now — check back soon!', ''];
1721
}
1822

23+
/**
24+
* Builds a milestone banner if a new level was unlocked.
25+
*
26+
* @param {string|null} unlockedLevelKey
27+
* @returns {string[]} Lines to include in the comment.
28+
*/
1929
function buildMilestoneBlock(unlockedLevelKey) {
2030
const displayName = unlockedLevelKey
2131
? CONFIG.skillPrerequisites[unlockedLevelKey]?.displayName
@@ -43,19 +53,23 @@ function buildMilestoneBlock(unlockedLevelKey) {
4353
* @returns {string} Fully rendered comment body.
4454
*/
4555
function buildRecommendationComment(username, issues, completedDisplayName, unlockedLevelKey = null) {
56+
const repoUrl = CONFIG.repositoryUrl ?? '';
57+
const hasRepoUrl = Boolean(repoUrl);
4658
return [
4759
CONFIG.commentMarker,
4860
'',
4961
`👋 Hi @${username}! Great work completing a **${completedDisplayName}** issue! 🎉`,
5062
'',
51-
'Thank you for your contribution to the Hiero Python SDK!',
63+
'Thanks for your contribution! 🚀',
5264
'',
5365
...buildMilestoneBlock(unlockedLevelKey),
5466
...buildIssueListBlock(issues),
67+
...(hasRepoUrl ? [
5568
'🌟 **Stay connected:**',
56-
'- ⭐ [Star this repository](https://github.com/hiero-ledger/hiero-sdk-python)',
57-
'- 👀 [Watch for new issues](https://github.com/hiero-ledger/hiero-sdk-python/watchers)',
58-
'- 💬 [Join us on Discord](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md)',
69+
`- ⭐ [Star this repository](${repoUrl})`,
70+
`- 👀 [Watch for new issues](${repoUrl}/watchers)`,
71+
`- 💬 [Join us on Discord](${repoUrl}/blob/main/docs/discord.md)`,
72+
]:[]),
5973
'',
6074
'Happy coding! 🚀',
6175
'_— Hiero Python SDK Team_',

.github/scripts/shared/helpers/utils.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,51 @@
44

55
const { CONFIG } = require('../config');
66

7+
/**
8+
* Returns the repo-specific label string for a given canonical level key.
9+
*
10+
* @param {object} repoConfig - Repo config containing label mappings.
11+
* @param {string} levelKey - Canonical skill level (e.g., 'beginner').
12+
* @returns {string|null} Label string or null if not defined.
13+
*/
714
function repoLabelFor(repoConfig, levelKey) {
8-
return repoConfig.labels[levelKey];
15+
return repoConfig.labels[levelKey] ?? null;
916
}
1017

1118
function hasLabel(issue, labelName) {
19+
if (!labelName) return false;
20+
1221
const target = labelName.toLowerCase();
13-
return (issue.labels ?? []).some(l => l.name.toLowerCase() === target);
22+
return (issue.labels ?? []).some(l => l.name?.toLowerCase() === target);
1423
}
1524

25+
/**
26+
* Filters issues by a specific skill level and caps the result size.
27+
*/
1628
function filterIssuesByLevel(issues, levelKey, repoConfig) {
1729
const labelString = repoLabelFor(repoConfig, levelKey);
30+
if (!labelString) return [];
31+
1832
return issues
1933
.filter(issue => hasLabel(issue, labelString))
2034
.slice(0, CONFIG.maxRecommendations);
2135
}
2236

37+
/**
38+
* Determines the highest skill level label present on an issue.
39+
* Iterates from highest → lowest so the first match represents the ceiling.
40+
*
41+
* @param {object} issue
42+
* @param {object} repoConfig
43+
* @returns {string|null} Canonical level key or null if none found.
44+
*/
2345
function getHighestSkillLevelKey(issue, repoConfig) {
2446
return [...CONFIG.skillHierarchy]
2547
.reverse()
26-
.find(key => hasLabel(issue, repoLabelFor(repoConfig, key))) ?? null;
48+
.find(key => {
49+
const label = repoLabelFor(repoConfig, key);
50+
return label && hasLabel(issue, label);
51+
}) ?? null;
2752
}
2853

2954
module.exports = {

.github/scripts/shared/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,11 @@ const {
1414
const { CONFIG } = require('./config');
1515

1616
module.exports = {
17-
// core
1817
getRecommendedIssues,
19-
// helpers
2018
getHighestSkillLevelKey,
2119
buildRecommendationComment,
2220
postComment,
2321
alreadyCommented,
2422
extractLinkedIssueNumber,
25-
// config
2623
CONFIG,
2724
};

0 commit comments

Comments
 (0)