1 package list
2
3 import (
4 "context"
5 "fmt"
6 "strconv"
7 "strings"
8
9 "github.com/google/go-github/v47/github"
10
11 "edge-infra.dev/pkg/f8n/devinfra/jack/constants"
12 guestservices "edge-infra.dev/pkg/f8n/devinfra/jack/guest_services"
13 "edge-infra.dev/pkg/f8n/devinfra/jack/plugin"
14 "edge-infra.dev/pkg/lib/logging"
15 )
16
17
18 func addIssue(hp plugin.HandlerParams, event AddRemoveEvent, commands []string, isParent bool) error {
19 log := hp.Log
20 ctx := hp.Ctx
21 client := hp.Client
22 log.Info("Adding a list of issues")
23
24 epicNumber := event.EpicNumber
25 repoOwner := event.RepoOwner
26 repoName := event.RepoName
27
28 log.Info(fmt.Sprintf("%+v", commands))
29
30 hasParentLabel := false
31 for _, v := range event.Labels {
32 if guestservices.IsParentLabel(v.GetName()) {
33 log.Info(v.GetName())
34 hasParentLabel = true
35 log.Info("Issue already has a parent label")
36 }
37 }
38
39 isEpic := guestservices.HasEpicLabel(event.Labels)
40
41 if isEpic && isParent {
42 log.Info("Epics cant have parents silly goose")
43 msg := fmt.Sprintf("%s `%s`\n%s `%s` `%s` `%s`\n___\n%s",
44 "Cannot add parents to issues labeled with",
45 string(constants.Epic),
46 "Use a different parent label such as:",
47 string(constants.Capability),
48 string(constants.Feature),
49 string(constants.Story),
50 "[Check the docs for more info](https://docs.edge-infra.dev/dev/project/#hierarchy)")
51 issueComment := github.IssueComment{Body: &msg}
52
53 if _, _, err := client.Issues().CreateComment(ctx, repoOwner, repoName, epicNumber, &issueComment); err != nil {
54 log.Error(err, "Failed to comment on issue")
55 return err
56 }
57 return nil
58 }
59
60
61 errorList, newParentBody := iterateOverListOfIssues(ctx, log, client, event, commands, isParent)
62
63 if !hasParentLabel && !isParent {
64 log.Info("adding epic label to new parent")
65 labels := []string{string(constants.Epic)}
66
67 var fl []*github.Label
68 fl = append(fl, &github.Label{Name: github.String(string(constants.Epic))})
69
70 newParent := guestservices.ParentChild{}
71 newParent.New(newParentBody, fl, constants.Preamble, constants.Postamble, event.RepoID)
72
73 githubIssueBody := &github.IssueRequest{Body: github.String(newParent.ToString()), Labels: &labels}
74 _, _, err := client.Issues().Edit(ctx, repoOwner, repoName, epicNumber, githubIssueBody)
75 if err != nil {
76 return err
77 }
78 return nil
79
80
81
82
83
84 }
85
86 githubIssueBody := &github.IssueRequest{Body: github.String(newParentBody)}
87
88 _, _, err := client.Issues().Edit(ctx, repoOwner, repoName, epicNumber, githubIssueBody)
89 if err != nil {
90 log.Error(err, "Failed to update epic desc")
91 return err
92 }
93
94 if len(errorList) > 0 {
95 errorString := strings.Join(errorList, "\n")
96
97 log.Info("Commenting on epic that some issues were not added")
98 log.Info(fmt.Sprintf("%s\n%s", "Some issues could not be added:", errorString))
99
100 msg := fmt.Sprintf("%s\n%s", "Some issues could not be added:", errorString)
101 issueComment := github.IssueComment{Body: &msg}
102
103 if _, _, err := client.Issues().CreateComment(ctx, repoOwner, repoName, epicNumber, &issueComment); err != nil {
104 log.Error(err, "Failed to comment on issue")
105 return err
106 }
107 }
108 return nil
109 }
110
111 func iterateOverListOfIssues(ctx context.Context, log logging.EdgeLogger, client plugin.GithubClientInterface, event AddRemoveEvent,
112 commands []string, isParent bool) ([]string, string) {
113 epicTitle := event.EpicTitle
114 epicNumber := event.EpicNumber
115 labels := event.Labels
116 repoOwner := event.RepoOwner
117 repoName := event.RepoName
118 repoID := event.RepoID
119
120 pc := guestservices.ParentChild{}
121 pc.New(event.EpicBody, labels, constants.Preamble, constants.Postamble, repoID)
122 log.Info(pc.ToString())
123
124 errorList := []string{}
125
126 for _, v := range commands {
127 log.Info(v)
128
129 issueNumberRegex, err := strconv.Atoi(v)
130 if err != nil {
131 log.Info("#" + v + " - Failed to convert issue number to an int")
132 errorList = append(errorList, "#"+v+" - failed to convert issue number to an int")
133 continue
134 }
135
136
137 if epicNumber == issueNumberRegex {
138 log.Info("#" + v + " - cannot add an issue to itself")
139 errorList = append(errorList, "#"+v+" - cannot add an issue to itself")
140 continue
141 }
142
143
144 foundIssue, _, err := client.Issues().Get(ctx, repoOwner, repoName, issueNumberRegex)
145 if err != nil {
146 log.Error(err, "Failed to get issues")
147 errorList = append(errorList, "failed to get issue #"+v)
148 continue
149 }
150
151
152 if foundIssue.IsPullRequest() {
153 log.Info("#" + v + " references a pull request")
154 errorList = append(errorList, "#"+v+" - pull requests cannot be linked to issues")
155 continue
156 }
157
158 foundIssueNumber := foundIssue.GetNumber()
159 foundIssueTitle := foundIssue.GetTitle()
160 foundIssueBody := foundIssue.GetBody()
161 foundLabels := foundIssue.Labels
162
163 secondPC := &guestservices.ParentChild{}
164 secondPC.New(foundIssueBody, foundLabels, constants.Preamble, constants.Postamble, repoID)
165
166 log.Info(fmt.Sprintf("Adding epic %v to issue %v", epicNumber, foundIssueNumber))
167
168
169 foundParentIndex := pc.FindParent(foundIssueNumber, repoID)
170 foundChildIndex := pc.FindChild(foundIssueNumber, repoID)
171
172
173 if foundParentIndex != -1 && !isParent {
174 log.Info(fmt.Sprintf("This issue was already added to the parent list #%d", epicNumber))
175 log.Info(fmt.Sprintf("attempting to swap child to parent %d", foundIssueNumber))
176 success := pc.SwapParentToChild(foundIssueNumber, repoID)
177 if success == -1 {
178 log.Info(fmt.Sprintf("failed to swap #%d from parent to child on upstream list", foundIssueNumber))
179 }
180
181 success = secondPC.SwapChildToParent(epicNumber, repoID)
182 if success == -1 {
183 log.Info(fmt.Sprintf("failed to swap #%d from child to parent on downstream list", epicNumber))
184 }
185 }
186
187
188 p, _ := guestservices.CheckForParentLabel("", foundIssue.Labels)
189 if foundChildIndex != -1 && isParent && p {
190 log.Info(fmt.Sprintf("This issue was already added to the child list on #%d", epicNumber))
191 log.Info(fmt.Sprintf("attempting to swap child to parent %d", foundIssueNumber))
192 success := pc.SwapChildToParent(foundIssueNumber, repoID)
193 if success == -1 {
194 log.Info(fmt.Sprintf("failed to swap #%d from child to parent on upstream list", foundIssueNumber))
195 }
196 log.Info(fmt.Sprintf("attempting to swap parent to child %d %d", foundIssueNumber, epicNumber))
197 success = secondPC.SwapParentToChild(epicNumber, repoID)
198 if success == -1 {
199 log.Info(fmt.Sprintf("failed to swap #%d from parent to child on downstream list", epicNumber))
200 }
201 }
202
203
204 if foundChildIndex == -1 && foundParentIndex == -1 {
205
206 epicString := guestservices.ListItem{Number: epicNumber, Title: epicTitle, RepoID: repoID}
207
208 if isParent {
209 secondPC.AddChildItem(epicString)
210 } else {
211 secondPC.AddParentItem(epicString)
212 }
213
214 issueString := guestservices.ListItem{Number: foundIssueNumber, Title: foundIssueTitle, RepoID: repoID}
215 if isParent {
216 pc.AddParentItem(issueString)
217 } else {
218 pc.AddChildItem(issueString)
219 }
220 }
221
222 newIssueBody := secondPC.ToString()
223
224
225 githubIssueBody := &github.IssueRequest{Body: github.String(newIssueBody)}
226 _, _, err = client.Issues().Edit(ctx, repoOwner, repoName, foundIssueNumber, githubIssueBody)
227 if err != nil {
228 log.Error(err, "Failed to update issue body")
229 errorList = append(errorList, "#"+v+" - failed to update issue body")
230 continue
231 }
232
233 log.Info(fmt.Sprintf("Added issue %v to epic %v", foundIssueNumber, epicNumber))
234 }
235
236 return errorList, pc.ToString()
237 }
238
239
240 func removeIssue(hp plugin.HandlerParams, event AddRemoveEvent, commands []string, isParent bool) error {
241 log := hp.Log
242 ctx := hp.Ctx
243 client := hp.Client
244
245 log.Info("Removing a list of issues")
246
247 repoOwner := event.RepoOwner
248 repoName := event.RepoName
249 repoID := event.RepoID
250 senderNumber := event.EpicNumber
251 senderBody := event.EpicBody
252 senderLabels := event.Labels
253
254 sender := guestservices.ParentChild{}
255 sender.New(senderBody, senderLabels, constants.Preamble, constants.Postamble, repoID)
256
257 errorList := []string{}
258 for _, v := range commands {
259 issueNumberRegex, err := strconv.Atoi(v)
260 if err != nil {
261 log.Info(v + " Failed to convert issue number to an int")
262 errorList = append(errorList, "#"+v+" - failed to convert issue number to an int")
263 continue
264 }
265
266
267 receivingIssue, _, err := client.Issues().Get(ctx, repoOwner, repoName, issueNumberRegex)
268 if err != nil {
269 log.Error(err, "Failed to get issues")
270 errorList = append(errorList, "#"+v+" - failed to retrieve issue")
271 continue
272 }
273
274 if receivingIssue.IsPullRequest() {
275 log.Info("#" + v + " references a pull request")
276 errorList = append(errorList, "#"+v+" - pull requests cannot be linked to issues")
277 continue
278 }
279
280 log.Info("Removing an epic from an issues list")
281
282 receiverNumber := receivingIssue.GetNumber()
283 receiverBody := receivingIssue.GetBody()
284 receiverLabels := receivingIssue.Labels
285
286 log.Info(fmt.Sprintf("Removing epic %v from issue %v", senderNumber, receiverNumber))
287
288 receiver := guestservices.ParentChild{}
289 receiver.New(receiverBody, receiverLabels, constants.Preamble, constants.Postamble, repoID)
290
291 if isParent {
292 receiver.RemoveChild(senderNumber, repoID)
293 } else {
294 receiver.RemoveParent(senderNumber, repoID)
295 }
296 newReceiverBody := receiver.ToString()
297
298
299 githubIssueBody := &github.IssueRequest{Body: github.String(newReceiverBody)}
300 _, _, err = client.Issues().Edit(ctx, repoOwner, repoName, receiverNumber, githubIssueBody)
301 if err != nil {
302 log.Error(err, "Failed to update issue body")
303 errorList = append(errorList, "#"+v+" - failed to update issue body")
304 continue
305 }
306 if isParent {
307 sender.RemoveParent(receiverNumber, repoID)
308 } else {
309 sender.RemoveChild(receiverNumber, repoID)
310 }
311 log.Info(fmt.Sprintf("Removed issue %v from epic %v", receiverNumber, senderNumber))
312 }
313
314 newSenderBody := sender.ToString()
315 githubIssueBody := &github.IssueRequest{Body: github.String(newSenderBody)}
316 _, _, err := client.Issues().Edit(ctx, repoOwner, repoName, senderNumber, githubIssueBody)
317 if err != nil {
318 log.Error(err, "Failed to update epic desc")
319 return err
320 }
321
322
323 if len(errorList) > 0 {
324 errorString := strings.Join(errorList, "\n")
325
326 log.Info("Commenting on epic that some issues were not removed")
327 log.Info(fmt.Sprintf("%s\n%s", "Some issues could not be removed:", errorString))
328
329 msg := fmt.Sprintf("%s\n%s", "Some issues could not be removed:", errorString)
330 issueComment := github.IssueComment{Body: &msg}
331
332 if _, _, err := client.Issues().CreateComment(ctx, repoOwner, repoName, senderNumber, &issueComment); err != nil {
333 log.Error(err, "Failed to comment on issue")
334 return err
335 }
336 }
337
338 return nil
339 }
340
View as plain text