Skip to content

Commit d61d4a9

Browse files
committed
refactor: centralize Good First Issue labels and remove migration script
Signed-off-by: DeathGun44 <krishnamewara841@gmail.com>
1 parent 3ef0b1e commit d61d4a9

9 files changed

Lines changed: 87 additions & 114 deletions

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
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 =
1111
'https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Good%20First%20Issue%22%20no%3Aassignee';
1212

.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-next-issue-recommendation.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { BEGINNER_LABEL, INTERMEDIATE_LABEL, ADVANCED_LABEL } = require('./shared/labels.js');
1+
const { GOOD_FIRST_ISSUE_LABEL, BEGINNER_LABEL, INTERMEDIATE_LABEL, ADVANCED_LABEL } = require('./shared/labels.js');
22

33
const SUPPORTED_GFI_REPOS = [
44
'hiero-sdk-cpp',
@@ -61,7 +61,7 @@ module.exports = async ({ github, context, core }) => {
6161
// Determine issue difficulty level
6262
const difficultyLevels = {
6363
beginner: labelSet.has(BEGINNER_LABEL.toLowerCase()),
64-
goodFirstIssue: labelSet.has('good first issue'),
64+
goodFirstIssue: labelSet.has(GOOD_FIRST_ISSUE_LABEL.toLowerCase()),
6565
intermediate: labelSet.has(INTERMEDIATE_LABEL.toLowerCase()),
6666
advanced: labelSet.has(ADVANCED_LABEL.toLowerCase()),
6767
};
@@ -87,8 +87,8 @@ module.exports = async ({ github, context, core }) => {
8787

8888
if (recommendedIssues.length === 0) {
8989
isFallback = true;
90-
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, 'good first issue');
91-
recommendedLabel = 'Good First Issue';
90+
recommendedIssues = await searchIssues(github, core, repoOwner, repoName, GOOD_FIRST_ISSUE_LABEL);
91+
recommendedLabel = GOOD_FIRST_ISSUE_LABEL;
9292
}
9393

9494

.github/scripts/coderabbit_plan_trigger.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +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 } = require('./shared/labels.js');
4+
const { DIFFICULTY_LABELS, GOOD_FIRST_ISSUE_LABEL } = require('./shared/labels.js');
55

66
async function triggerCodeRabbitPlan(github, owner, repo, issue, marker = CODERABBIT_MARKER, isDryRun = false) {
77
const comment = `${marker} @coderabbitai plan`;
@@ -33,8 +33,12 @@ async function triggerCodeRabbitPlan(github, owner, repo, issue, marker = CODERA
3333
}
3434

3535
function hasBeginnerOrHigherLabel(issue, label) {
36-
// Check if issue has a difficulty label (case-insensitive)
37-
const allowed = new Set(DIFFICULTY_LABELS.map(d => d.toLowerCase()));
36+
// Only beginner+ labels qualify here; GFI gets its own CodeRabbit plan
37+
// trigger via the assignment bot chain (bot-gfi-assign-on-comment.js).
38+
const beginnerPlus = DIFFICULTY_LABELS
39+
.filter(d => d !== GOOD_FIRST_ISSUE_LABEL)
40+
.map(d => d.toLowerCase());
41+
const allowed = new Set(beginnerPlus);
3842

3943
const hasAllowedLabel = issue.labels?.some(l => allowed.has(l?.name?.toLowerCase()));
4044

.github/scripts/cron-admin-update-spam-list.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
const fs = require('fs').promises;
11+
const { GOOD_FIRST_ISSUE_LABEL } = require('./shared/labels.js');
1112

1213
const SPAM_LIST_PATH = '.github/spam-list.txt';
1314
const dryRun = (process.env.DRY_RUN || 'false').toString().toLowerCase() === 'true';
@@ -137,7 +138,7 @@ module.exports = async ({github, context, core}) => {
137138
},
138139
{
139140
name: 'rehabilitated PRs',
140-
query: `repo:${owner}/${repo} is:pr is:merged label:"Good First Issue"`,
141+
query: `repo:${owner}/${repo} is:pr is:merged label:"${GOOD_FIRST_ISSUE_LABEL}"`,
141142
process: async (pr) => {
142143
if (!pr.user?.login) {
143144
console.log(`Skipping PR #${pr.number}: user account unavailable`);

.github/scripts/migrate-skill-labels.sh

Lines changed: 0 additions & 89 deletions
This file was deleted.

.github/scripts/shared/labels.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,28 @@
88
* corresponding workflow YAML `if:` conditions (which cannot import JS).
99
*
1010
* Environment variable overrides are supported for per-workflow customization:
11+
* GOOD_FIRST_ISSUE_LABEL, GOOD_FIRST_ISSUE_CANDIDATE_LABEL,
1112
* BEGINNER_LABEL, INTERMEDIATE_LABEL, ADVANCED_LABEL
1213
*/
1314

14-
const BEGINNER_LABEL = process.env.BEGINNER_LABEL?.trim() || 'skill: beginner';
15-
const INTERMEDIATE_LABEL = process.env.INTERMEDIATE_LABEL?.trim() || 'skill: intermediate';
16-
const ADVANCED_LABEL = process.env.ADVANCED_LABEL?.trim() || 'skill: advanced';
15+
const GOOD_FIRST_ISSUE_LABEL = process.env.GOOD_FIRST_ISSUE_LABEL?.trim() || 'Good First Issue';
16+
const GOOD_FIRST_ISSUE_CANDIDATE_LABEL = process.env.GOOD_FIRST_ISSUE_CANDIDATE_LABEL?.trim() || 'Good First Issue Candidate';
17+
const BEGINNER_LABEL = process.env.BEGINNER_LABEL?.trim() || 'skill: beginner';
18+
const INTERMEDIATE_LABEL = process.env.INTERMEDIATE_LABEL?.trim() || 'skill: intermediate';
19+
const ADVANCED_LABEL = process.env.ADVANCED_LABEL?.trim() || 'skill: advanced';
1720

1821
/**
19-
* All difficulty labels as an array, for scripts that need to check
20-
* whether an issue has *any* difficulty label (e.g. coderabbit_plan_trigger).
22+
* All difficulty labels as an array, ordered by ascending difficulty.
23+
*
24+
* Scripts that need to check whether an issue has *any* difficulty label
25+
* (e.g. coderabbit_plan_trigger) should test against this array.
2126
*/
22-
const DIFFICULTY_LABELS = [BEGINNER_LABEL, INTERMEDIATE_LABEL, ADVANCED_LABEL];
27+
const DIFFICULTY_LABELS = [
28+
GOOD_FIRST_ISSUE_LABEL,
29+
BEGINNER_LABEL,
30+
INTERMEDIATE_LABEL,
31+
ADVANCED_LABEL,
32+
];
2333

2434
/**
2535
* Validates a label string for safe use in API queries.
@@ -39,6 +49,8 @@ function isSafeLabel(value) {
3949
}
4050

4151
module.exports = {
52+
GOOD_FIRST_ISSUE_LABEL,
53+
GOOD_FIRST_ISSUE_CANDIDATE_LABEL,
4254
BEGINNER_LABEL,
4355
INTERMEDIATE_LABEL,
4456
ADVANCED_LABEL,

.github/scripts/shared/labels.test.js

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,22 @@ describe('labels.js — default exports', () => {
2121

2222
beforeEach(() => {
2323
// Clear any env overrides from previous tests
24+
delete process.env.GOOD_FIRST_ISSUE_LABEL;
25+
delete process.env.GOOD_FIRST_ISSUE_CANDIDATE_LABEL;
2426
delete process.env.BEGINNER_LABEL;
2527
delete process.env.INTERMEDIATE_LABEL;
2628
delete process.env.ADVANCED_LABEL;
2729
labels = freshRequire();
2830
});
2931

32+
it('exports correct default GOOD_FIRST_ISSUE_LABEL', () => {
33+
assert.equal(labels.GOOD_FIRST_ISSUE_LABEL, 'Good First Issue');
34+
});
35+
36+
it('exports correct default GOOD_FIRST_ISSUE_CANDIDATE_LABEL', () => {
37+
assert.equal(labels.GOOD_FIRST_ISSUE_CANDIDATE_LABEL, 'Good First Issue Candidate');
38+
});
39+
3040
it('exports correct default BEGINNER_LABEL', () => {
3141
assert.equal(labels.BEGINNER_LABEL, 'skill: beginner');
3242
});
@@ -39,24 +49,48 @@ describe('labels.js — default exports', () => {
3949
assert.equal(labels.ADVANCED_LABEL, 'skill: advanced');
4050
});
4151

42-
it('exports DIFFICULTY_LABELS array with all three', () => {
43-
assert.equal(labels.DIFFICULTY_LABELS.length, 3);
52+
it('exports DIFFICULTY_LABELS array with all four difficulty tiers', () => {
53+
assert.equal(labels.DIFFICULTY_LABELS.length, 4);
54+
assert.ok(labels.DIFFICULTY_LABELS.includes('Good First Issue'));
4455
assert.ok(labels.DIFFICULTY_LABELS.includes('skill: beginner'));
4556
assert.ok(labels.DIFFICULTY_LABELS.includes('skill: intermediate'));
4657
assert.ok(labels.DIFFICULTY_LABELS.includes('skill: advanced'));
4758
});
59+
60+
it('orders DIFFICULTY_LABELS by ascending difficulty', () => {
61+
assert.deepEqual(labels.DIFFICULTY_LABELS, [
62+
'Good First Issue',
63+
'skill: beginner',
64+
'skill: intermediate',
65+
'skill: advanced',
66+
]);
67+
});
68+
69+
it('does not include GOOD_FIRST_ISSUE_CANDIDATE_LABEL in DIFFICULTY_LABELS', () => {
70+
assert.ok(!labels.DIFFICULTY_LABELS.includes('Good First Issue Candidate'));
71+
});
4872
});
4973

5074
describe('labels.js — isSafeLabel', () => {
5175
let isSafeLabel;
5276

5377
beforeEach(() => {
78+
delete process.env.GOOD_FIRST_ISSUE_LABEL;
79+
delete process.env.GOOD_FIRST_ISSUE_CANDIDATE_LABEL;
5480
delete process.env.BEGINNER_LABEL;
5581
delete process.env.INTERMEDIATE_LABEL;
5682
delete process.env.ADVANCED_LABEL;
5783
isSafeLabel = freshRequire().isSafeLabel;
5884
});
5985

86+
it('accepts "Good First Issue"', () => {
87+
assert.ok(isSafeLabel('Good First Issue'));
88+
});
89+
90+
it('accepts "Good First Issue Candidate"', () => {
91+
assert.ok(isSafeLabel('Good First Issue Candidate'));
92+
});
93+
6094
it('accepts "skill: beginner"', () => {
6195
assert.ok(isSafeLabel('skill: beginner'));
6296
});
@@ -69,10 +103,6 @@ describe('labels.js — isSafeLabel', () => {
69103
assert.ok(isSafeLabel('skill: advanced'));
70104
});
71105

72-
it('accepts "Good First Issue"', () => {
73-
assert.ok(isSafeLabel('Good First Issue'));
74-
});
75-
76106
it('accepts simple alphanumeric labels', () => {
77107
assert.ok(isSafeLabel('beginner'));
78108
assert.ok(isSafeLabel('scope/CI'));
@@ -102,6 +132,21 @@ describe('labels.js — isSafeLabel', () => {
102132
});
103133

104134
describe('labels.js — environment variable overrides', () => {
135+
it('overrides GOOD_FIRST_ISSUE_LABEL from env', () => {
136+
process.env.GOOD_FIRST_ISSUE_LABEL = 'custom: gfi';
137+
const labels = freshRequire();
138+
assert.equal(labels.GOOD_FIRST_ISSUE_LABEL, 'custom: gfi');
139+
assert.ok(labels.DIFFICULTY_LABELS.includes('custom: gfi'));
140+
delete process.env.GOOD_FIRST_ISSUE_LABEL;
141+
});
142+
143+
it('overrides GOOD_FIRST_ISSUE_CANDIDATE_LABEL from env', () => {
144+
process.env.GOOD_FIRST_ISSUE_CANDIDATE_LABEL = 'custom: gfi candidate';
145+
const labels = freshRequire();
146+
assert.equal(labels.GOOD_FIRST_ISSUE_CANDIDATE_LABEL, 'custom: gfi candidate');
147+
delete process.env.GOOD_FIRST_ISSUE_CANDIDATE_LABEL;
148+
});
149+
105150
it('overrides BEGINNER_LABEL from env', () => {
106151
process.env.BEGINNER_LABEL = 'custom: beginner';
107152
const labels = freshRequire();

.github/workflows/bot-coderabbit-plan-trigger.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# This workflow automatically triggers CodeRabbit's plan feature for intermediate and advanced issues.
2-
# Fix for #1427: Only triggers when a beginner/intermediate/advanced label is specifically added,
3-
# preventing duplicate runs when other labels are added to the same issue.
1+
# Triggers CodeRabbit's plan feature when a difficulty label is added to an issue.
2+
# Only fires for skill: beginner/intermediate/advanced labels, preventing duplicate runs.
43
name: CodeRabbit Plan Trigger
54
on:
65
issues:

0 commit comments

Comments
 (0)