Skip to content

Commit da1d976

Browse files
Merge branch 'main' into fix/2217-update-spam-list
2 parents 501def0 + 26a41eb commit da1d976

17 files changed

Lines changed: 324 additions & 49 deletions

.github/ISSUE_TEMPLATE/02-beginner-issue.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Beginner Issue Template
22
description: Create a beginner issue for contributors ready to learn the codebase and own a small implementation.
3-
labels: ["beginner"]
3+
labels: ["skill: beginner"]
44
assignees: []
55
body:
66
- type: markdown
@@ -227,7 +227,7 @@ body:
227227
- [Windows Setup Guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/setup_windows.md) — platform-specific installation steps
228228
- [Pylance guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/pylance.md) — inline type checking during development
229229
- [Running examples](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/examples.md)
230-
- [Browse closed beginner PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3Abeginner) — see how others did it
230+
- [Browse closed beginner PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3A%22skill%3A+beginner%22) — see how others did it
231231
232232
**References:**
233233
- [Hedera Protobufs](https://github.com/hashgraph/hedera-protobufs)

.github/ISSUE_TEMPLATE/03-intermediate-issue.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Intermediate Issue Template
22
description: Create a well-documented issue for contributors ready to own larger tasks independently
3-
labels: ["intermediate"]
3+
labels: ["skill: intermediate"]
44
assignees: []
55
body:
66
- type: markdown
@@ -248,7 +248,7 @@ body:
248248
**Project references:**
249249
- [Project structure](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/setup/project_structure.md)
250250
- [CONTRIBUTING.md](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/CONTRIBUTING.md)
251-
- [Browse closed intermediate PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3Aintermediate) — see how others did it
251+
- [Browse closed intermediate PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3A%22skill%3A+intermediate%22) — see how others did it
252252
- [Pylance guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/pylance.md)
253253
254254
**Protobuf references:**

.github/ISSUE_TEMPLATE/04-advanced-issue.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Advanced Issue Template
22
description: For expert contributors tackling architectural, multi-module, or core-logic changes.
3-
labels: ["advanced"]
3+
labels: ["skill: advanced"]
44
assignees: []
55

66
body:
@@ -145,7 +145,7 @@ body:
145145
- [Transaction Lifecycle](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/transaction_lifecycle.md)
146146
- [Executable Architecture](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/executable.md)
147147
- [Hedera Protobufs (services)](https://github.com/hashgraph/hedera-protobufs/tree/main/services)
148-
- [Browse closed advanced PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3Aadvanced) — see how others did it
148+
- [Browse closed advanced PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3A%22skill%3A+advanced%22) — see how others did it
149149
150150
**🆘 Stuck?**
151151
- [Community Calls](https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week)

.github/scripts/bot-advanced-check.sh

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ log() {
1212
# Configuration
1313
#######################################
1414
REQUIRED_INTERMEDIATE_COUNT=1
15+
INTERMEDIATE_LABEL="${INTERMEDIATE_LABEL:-skill: intermediate}"
1516

1617
#######################################
1718
# Validate required environment variables
@@ -67,20 +68,21 @@ get_intermediate_count() {
6768

6869
gh api graphql \
6970
-f query='
70-
query($owner: String!, $name: String!, $user: String!) {
71+
query($owner: String!, $name: String!, $user: String!, $labels: [String!]!) {
7172
repository(owner: $owner, name: $name) {
7273
intermediate: issues(
7374
first: 1
7475
states: CLOSED
75-
filterBy: { assignee: $user, labels: ["intermediate"] }
76+
filterBy: { assignee: $user, labels: $labels }
7677
) {
7778
totalCount
7879
}
7980
}
8081
}' \
8182
-f owner="$OWNER" \
8283
-f name="$NAME" \
83-
-f user="$user"
84+
-f user="$user" \
85+
-f "labels[]=$INTERMEDIATE_LABEL"
8486
}
8587

8688
#######################################
@@ -187,15 +189,17 @@ check_user() {
187189
###################################
188190
log "User @$user NOT qualified."
189191

190-
SUGGESTION="[intermediate issues](https://github.com/$REPO/labels/intermediate)"
192+
# URL-encode: jq @uri handles colons, spaces, and all special chars
193+
ENCODED_LABEL=$(printf '%s' "$INTERMEDIATE_LABEL" | jq -Rr @uri)
194+
SUGGESTION="[$INTERMEDIATE_LABEL issues](https://github.com/$REPO/labels/$ENCODED_LABEL)"
191195

192196
MSG="Hi @$user, I cannot assign you to this issue yet.
193197
194198
**Why?**
195199
Advanced issues involve high-risk changes to the core codebase and require prior experience in this repository.
196200
197201
**Requirement:**
198-
- Complete at least **$REQUIRED_INTERMEDIATE_COUNT** 'intermediate' issue (You have: **$INT_COUNT**)
202+
- Complete at least **$REQUIRED_INTERMEDIATE_COUNT** '$INTERMEDIATE_LABEL' issue (You have: **$INT_COUNT**)
199203
200204
Please check out our **$SUGGESTION** to build your experience first!
201205

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Parameters:
5454
*/
5555

5656
const fs = require("fs");
57+
const { BEGINNER_LABEL } = require('./shared/labels.js');
5758

5859
const SPAM_LIST_PATH = ".github/spam-list.txt";
5960
const REQUIRED_GFI_COUNT = 1;
@@ -115,9 +116,10 @@ module.exports = async ({ github, context }) => {
115116
}
116117

117118
// 2. Label Check (Fix 2: Defensive Check)
118-
const hasBeginnerLabel = Array.isArray(issue.labels) && issue.labels.some((label) => label.name === "beginner");
119+
const beginnerLabel = BEGINNER_LABEL.toLowerCase();
120+
const hasBeginnerLabel = Array.isArray(issue.labels) && issue.labels.some((label) => label.name?.toLowerCase() === beginnerLabel);
119121
if (!hasBeginnerLabel) {
120-
console.log(`[Beginner Bot] Issue #${issue.number} does not have 'beginner' label. Exiting.`);
122+
console.log(`[Beginner Bot] Issue #${issue.number} does not have '${BEGINNER_LABEL}' label. Exiting.`);
121123
return;
122124
}
123125

@@ -261,7 +263,7 @@ Please try a GFI first, then come back — we’ll be happy to assign this! 😊
261263
owner: repo.owner.login,
262264
repo: repo.name,
263265
issue_number: issue.number,
264-
body: `👋 Hi @${commenter}, thanks for your interest! This issue is already assigned to @${currentAssignee}, but we'd love your help on another one. You can find more "beginner" issues [here](https://github.com/${repo.owner.login}/${repo.name}/issues?q=is%3Aissue+is%3Aopen+label%3Abeginner+no%3Aassignee).`,
266+
body: `👋 Hi @${commenter}, thanks for your interest! This issue is already assigned to @${currentAssignee}, but we'd love your help on another one. You can find more "${BEGINNER_LABEL}" issues [here](https://github.com/${repo.owner.login}/${repo.name}/issues?q=is%3Aissue+is%3Aopen+label%3A%22${encodeURIComponent(BEGINNER_LABEL)}%22+no%3Aassignee).`,
265267
});
266268
} catch (error) {
267269
console.error("[Beginner Bot] Failed to post already-assigned message:", {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
const fs = require('fs'); // For spam list
88

9-
const GOOD_FIRST_ISSUE_LABEL = 'Good First Issue';
9+
const { GOOD_FIRST_ISSUE_LABEL } = require('./shared/labels.js');
1010
const UNASSIGNED_GFI_SEARCH_URL =
11-
'https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Good%20First%20Issue%22%20no%3Aassignee';
11+
`https://github.com/hiero-ledger/hiero-sdk-python/issues?q=${encodeURIComponent(`is:issue state:open label:"${GOOD_FIRST_ISSUE_LABEL}" no:assignee`)}`;
1212

1313
const SPAM_LIST_PATH = '.github/spam-list.txt';
1414

.github/scripts/bot-gfi-candidate-notification.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Script to notify the team when a Good First Issue Candidate is created.
22

3+
const { GOOD_FIRST_ISSUE_CANDIDATE_LABEL } = require('./shared/labels.js');
34
const marker = '<!-- GFI Candidate Notification -->';
45
const TEAM_ALIAS = '@hiero-ledger/hiero-sdk-good-first-issue-support';
56

@@ -53,7 +54,7 @@ module.exports = async ({ github, context }) => {
5354
}
5455

5556
// Only handle Good First Issue Candidate
56-
if (label.name.toLowerCase() !== 'good first issue candidate') {
57+
if (label.name.toLowerCase() !== GOOD_FIRST_ISSUE_CANDIDATE_LABEL.toLowerCase()) {
5758
return;
5859
}
5960

.github/scripts/bot-intermediate-assignment.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
const shared = require('./shared/labels.js');
12
const COMMENT_MARKER = process.env.INTERMEDIATE_COMMENT_MARKER || '<!-- Intermediate Issue Guard -->';
2-
const INTERMEDIATE_LABEL = process.env.INTERMEDIATE_LABEL?.trim() || 'intermediate';
3-
const BEGINNER_LABEL = process.env.BEGINNER_LABEL?.trim() || 'beginner';
3+
const INTERMEDIATE_LABEL = process.env.INTERMEDIATE_LABEL?.trim() || shared.INTERMEDIATE_LABEL;
4+
const BEGINNER_LABEL = process.env.BEGINNER_LABEL?.trim() || shared.BEGINNER_LABEL;
45
const EXEMPT_PERMISSION_LEVELS = (process.env.INTERMEDIATE_EXEMPT_PERMISSIONS || 'admin,maintain,write,triage')
56
.split(',')
67
.map((entry) => entry.trim().toLowerCase())
@@ -61,7 +62,7 @@ async function countCompletedBeginnerIssues(github, owner, repo, username) {
6162
!isSafeSearchToken(owner) ||
6263
!isSafeSearchToken(repo) ||
6364
!isSafeSearchToken(username) ||
64-
!isSafeSearchToken(BEGINNER_LABEL)
65+
!shared.isSafeLabel(BEGINNER_LABEL)
6566
) {
6667
console.log('Invalid search inputs', {
6768
owner,
@@ -75,7 +76,7 @@ async function countCompletedBeginnerIssues(github, owner, repo, username) {
7576
try {
7677
const searchQuery = [
7778
`repo:${owner}/${repo}`,
78-
`label:${BEGINNER_LABEL}`,
79+
`label:"${BEGINNER_LABEL}"`,
7980
'is:issue',
8081
'is:closed',
8182
`assignee:${username}`,

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
const {
2+
GOOD_FIRST_ISSUE_LABEL,
3+
BEGINNER_LABEL,
4+
INTERMEDIATE_LABEL,
5+
ADVANCED_LABEL,
6+
isSafeLabel,
7+
} = require('./shared/labels.js');
8+
9+
for (const label of [GOOD_FIRST_ISSUE_LABEL, BEGINNER_LABEL, INTERMEDIATE_LABEL, ADVANCED_LABEL]) {
10+
if (!isSafeLabel(label)) {
11+
throw new Error(`Invalid configured label: ${label}`);
12+
}
13+
}
14+
115
const SUPPORTED_GFI_REPOS = [
216
'hiero-sdk-cpp',
317
'hiero-sdk-swift',
@@ -58,10 +72,10 @@ module.exports = async ({ github, context, core }) => {
5872

5973
// Determine issue difficulty level
6074
const difficultyLevels = {
61-
beginner: labelSet.has('beginner'),
62-
goodFirstIssue: labelSet.has('good first issue'),
63-
intermediate: labelSet.has('intermediate'),
64-
advanced: labelSet.has('advanced'),
75+
beginner: labelSet.has(BEGINNER_LABEL.toLowerCase()),
76+
goodFirstIssue: labelSet.has(GOOD_FIRST_ISSUE_LABEL.toLowerCase()),
77+
intermediate: labelSet.has(INTERMEDIATE_LABEL.toLowerCase()),
78+
advanced: labelSet.has(ADVANCED_LABEL.toLowerCase()),
6579
};
6680

6781
// Skip if intermediate or advanced
@@ -80,22 +94,22 @@ module.exports = async ({ github, context, core }) => {
8094
let recommendedLabel = null;
8195
let isFallback = false;
8296

83-
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, 'beginner');
84-
recommendedLabel = 'Beginner';
97+
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, BEGINNER_LABEL);
98+
recommendedLabel = BEGINNER_LABEL;
8599

86100
if (recommendedIssues.length === 0) {
87101
isFallback = true;
88-
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, 'good first issue');
89-
recommendedLabel = 'Good First Issue';
102+
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, GOOD_FIRST_ISSUE_LABEL);
103+
recommendedLabel = GOOD_FIRST_ISSUE_LABEL;
90104
}
91105

92106

93107
// Remove the issue they just solved
94108
recommendedIssues = recommendedIssues.filter(i => i.number !== issueNumber);
95109

96110
// Generate and post comment
97-
const completedLabel = difficultyLevels.goodFirstIssue ? 'Good First Issue' : 'Beginner';
98-
const completedLabelText = completedLabel === 'Beginner' ? 'Beginner issue' : completedLabel;
111+
const completedLabel = difficultyLevels.goodFirstIssue ? GOOD_FIRST_ISSUE_LABEL : BEGINNER_LABEL;
112+
const completedLabelText = completedLabel === BEGINNER_LABEL ? `${BEGINNER_LABEL} issue` : completedLabel;
99113
const recommendationMeta = {
100114
completedLabelText,
101115
recommendedLabel,
@@ -170,7 +184,7 @@ async function generateAndPostComment(github, context, core, prNumber, recommend
170184
`org:${context.repo.owner}`,
171185
'archived:false',
172186
'no:assignee',
173-
'(label:"good first issue" OR label:"skill: good first issue")',
187+
`label:"${GOOD_FIRST_ISSUE_LABEL}"`,
174188
`(${repoQuery})`,
175189
].join(' ');
176190

.github/scripts/coderabbit_plan_trigger.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Script to trigger CodeRabbit plan for intermediate and advanced issues
22

33
const CODERABBIT_MARKER = '<!-- CodeRabbit Plan Trigger -->';
4+
const { DIFFICULTY_LABELS, GOOD_FIRST_ISSUE_LABEL } = require('./shared/labels.js');
45

56
async function triggerCodeRabbitPlan(github, owner, repo, issue, marker = CODERABBIT_MARKER) {
67
const comment = `${marker} @coderabbitai plan`;
@@ -27,13 +28,17 @@ async function triggerCodeRabbitPlan(github, owner, repo, issue, marker = CODERA
2728
}
2829

2930
function hasBeginnerOrHigherLabel(issue, label) {
30-
// Check if issue has beginner, intermediate or advanced label (case-insensitive)
31-
const allowed = ['beginner', 'intermediate', 'advanced'];
31+
// Only beginner+ labels qualify here; GFI gets its own CodeRabbit plan
32+
// trigger via the assignment bot chain (bot-gfi-assign-on-comment.js).
33+
const beginnerPlus = DIFFICULTY_LABELS
34+
.filter(d => d !== GOOD_FIRST_ISSUE_LABEL)
35+
.map(d => d.toLowerCase());
36+
const allowed = new Set(beginnerPlus);
3237

33-
const hasAllowedLabel = issue.labels?.some(l => allowed.includes(l?.name?.toLowerCase()));
38+
const hasAllowedLabel = issue.labels?.some(l => allowed.has(l?.name?.toLowerCase()));
3439

35-
// Also check if newly added label is beginner/intermediate/advanced
36-
const isNewLabelAllowed = allowed.includes(label?.name?.toLowerCase());
40+
// Also check if newly added label is a difficulty label
41+
const isNewLabelAllowed = allowed.has(label?.name?.toLowerCase());
3742

3843
return hasAllowedLabel || isNewLabelAllowed;
3944
}

0 commit comments

Comments
 (0)