Skip to content

Commit e4e1ce0

Browse files
authored
Merge pull request #73 from nf-core/fix-labelling
Vibe code (Claude Sonnet 4) label updating code to just replace status labels and not replace entirely all labels
2 parents 23a1b6c + 047bdd2 commit e4e1ce0

File tree

3 files changed

+108
-10
lines changed

3 files changed

+108
-10
lines changed

.github/workflows/lib/approval.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,28 +59,44 @@ class ApprovalManager {
5959

6060
// Helper to update issue status and labels
6161
async updateIssueStatus(status) {
62-
const labels = [];
62+
// Get current issue to preserve existing labels
63+
const issue = await this.github.rest.issues.get({
64+
owner: this.org,
65+
repo: this.repo,
66+
issue_number: this.issueNumber,
67+
});
68+
69+
// Filter out existing status labels
70+
const statusLabels = ["accepted", "turned-down", "timed-out", "proposed"];
71+
const existingLabels = issue.data.labels
72+
.map((label) => (typeof label === "string" ? label : label.name))
73+
.filter((label) => !statusLabels.includes(label));
6374

75+
// Determine new status label
76+
let newStatusLabel;
6477
switch (status) {
6578
case "✅ Approved":
66-
labels.push("accepted");
79+
newStatusLabel = "accepted";
6780
break;
6881
case "❌ Rejected":
69-
labels.push("turned-down");
82+
newStatusLabel = "turned-down";
7083
break;
7184
case "⏰ Timed Out":
72-
labels.push("timed-out");
85+
newStatusLabel = "timed-out";
7386
break;
7487
default:
75-
labels.push("proposed");
88+
newStatusLabel = "proposed";
7689
}
7790

91+
// Combine existing non-status labels with new status label
92+
const updatedLabels = [...existingLabels, newStatusLabel];
93+
7894
// Update labels
7995
await this.github.rest.issues.update({
8096
owner: this.org,
8197
repo: this.repo,
8298
issue_number: this.issueNumber,
83-
labels: labels,
99+
labels: updatedLabels,
84100
});
85101
}
86102

.github/workflows/lib/approval.test.js

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const mockGithub = {
77
rest: {
88
issues: {
99
listComments: jest.fn(),
10+
get: jest.fn(),
1011
update: jest.fn(),
1112
updateComment: jest.fn(),
1213
createComment: jest.fn(),
@@ -108,47 +109,106 @@ describe("ApprovalManager", () => {
108109
});
109110

110111
describe("updateIssueStatus", () => {
112+
beforeEach(() => {
113+
// Mock the get method to return an issue with existing labels
114+
mockGithub.rest.issues.get.mockResolvedValue({
115+
data: {
116+
labels: [
117+
{ name: "bug" },
118+
{ name: "proposed" }, // This should be replaced
119+
{ name: "enhancement" },
120+
],
121+
},
122+
});
123+
});
124+
111125
it("should add accepted label for approved status", async () => {
112126
await approvalManager.updateIssueStatus("✅ Approved");
113127

128+
expect(mockGithub.rest.issues.get).toHaveBeenCalledWith({
129+
owner: mockOrg,
130+
repo: mockRepo,
131+
issue_number: mockIssueNumber,
132+
});
133+
114134
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
115135
owner: mockOrg,
116136
repo: mockRepo,
117137
issue_number: mockIssueNumber,
118-
labels: ["accepted"],
138+
labels: ["bug", "enhancement", "accepted"],
119139
});
120140
});
121141

122142
it("should add turned-down label for rejected status", async () => {
123143
await approvalManager.updateIssueStatus("❌ Rejected");
124144

145+
expect(mockGithub.rest.issues.get).toHaveBeenCalledWith({
146+
owner: mockOrg,
147+
repo: mockRepo,
148+
issue_number: mockIssueNumber,
149+
});
150+
125151
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
126152
owner: mockOrg,
127153
repo: mockRepo,
128154
issue_number: mockIssueNumber,
129-
labels: ["turned-down"],
155+
labels: ["bug", "enhancement", "turned-down"],
130156
});
131157
});
132158

133159
it("should add timed-out label for timed out status", async () => {
134160
await approvalManager.updateIssueStatus("⏰ Timed Out");
135161

162+
expect(mockGithub.rest.issues.get).toHaveBeenCalledWith({
163+
owner: mockOrg,
164+
repo: mockRepo,
165+
issue_number: mockIssueNumber,
166+
});
167+
136168
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
137169
owner: mockOrg,
138170
repo: mockRepo,
139171
issue_number: mockIssueNumber,
140-
labels: ["timed-out"],
172+
labels: ["bug", "enhancement", "timed-out"],
141173
});
142174
});
143175

144176
it("should add proposed label for pending status", async () => {
145177
await approvalManager.updateIssueStatus("🕐 Pending");
146178

179+
expect(mockGithub.rest.issues.get).toHaveBeenCalledWith({
180+
owner: mockOrg,
181+
repo: mockRepo,
182+
issue_number: mockIssueNumber,
183+
});
184+
185+
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
186+
owner: mockOrg,
187+
repo: mockRepo,
188+
issue_number: mockIssueNumber,
189+
labels: ["bug", "enhancement", "proposed"],
190+
});
191+
});
192+
193+
it("should preserve existing labels when updating status", async () => {
194+
// Set up a different set of existing labels
195+
mockGithub.rest.issues.get.mockResolvedValueOnce({
196+
data: {
197+
labels: [
198+
{ name: "documentation" },
199+
{ name: "accepted" }, // This should be replaced with turned-down
200+
{ name: "priority-high" },
201+
],
202+
},
203+
});
204+
205+
await approvalManager.updateIssueStatus("❌ Rejected");
206+
147207
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
148208
owner: mockOrg,
149209
repo: mockRepo,
150210
issue_number: mockIssueNumber,
151-
labels: ["proposed"],
211+
labels: ["documentation", "priority-high", "turned-down"],
152212
});
153213
});
154214
});

.github/workflows/lib/workflow-integration.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const mockGithub = {
77
rest: {
88
issues: {
99
listComments: jest.fn(),
10+
get: jest.fn(),
1011
update: jest.fn(),
1112
updateComment: jest.fn(),
1213
createComment: jest.fn(),
@@ -38,6 +39,13 @@ describe("Workflow Integration Tests", () => {
3839
// Mock empty comments initially
3940
mockGithub.paginate.mockResolvedValue([]);
4041

42+
// Mock issues.get to return an issue with no existing labels
43+
mockGithub.rest.issues.get.mockResolvedValue({
44+
data: {
45+
labels: [],
46+
},
47+
});
48+
4149
approvalManager = await new ApprovalManager(mockGithub, mockOrg, mockRepo, mockIssueNumber).initialize();
4250
});
4351

@@ -184,6 +192,13 @@ describe("Workflow Integration Tests", () => {
184192

185193
mockGithub.paginate.mockResolvedValue([]);
186194

195+
// Mock issues.get to return an issue with no existing labels
196+
mockGithub.rest.issues.get.mockResolvedValue({
197+
data: {
198+
labels: [],
199+
},
200+
});
201+
187202
approvalManager = await new ApprovalManager(mockGithub, mockOrg, mockRepo, mockIssueNumber).initialize();
188203
});
189204

@@ -328,6 +343,13 @@ describe("Workflow Integration Tests", () => {
328343

329344
mockGithub.paginate.mockResolvedValue([]);
330345

346+
// Mock issues.get to return an issue with no existing labels
347+
mockGithub.rest.issues.get.mockResolvedValue({
348+
data: {
349+
labels: [],
350+
},
351+
});
352+
331353
approvalManager = await new ApprovalManager(mockGithub, "org", "repo", 123).initialize();
332354
});
333355

0 commit comments

Comments
 (0)