1package gitlab
2
3import (
4 "fmt"
5 "sort"
6 "strings"
7 "time"
8
9 "github.com/MichaelMure/git-bug/util/text"
10 "github.com/xanzy/go-gitlab"
11)
12
13// Event represents a unified GitLab event (note, label or state event).
14type Event interface {
15 ID() string
16 UserID() int
17 Kind() EventKind
18 CreatedAt() time.Time
19}
20
21type EventKind int
22
23const (
24 EventUnknown EventKind = iota
25 EventError
26 EventComment
27 EventTitleChanged
28 EventDescriptionChanged
29 EventClosed
30 EventReopened
31 EventLocked
32 EventUnlocked
33 EventChangedDuedate
34 EventRemovedDuedate
35 EventAssigned
36 EventUnassigned
37 EventChangedMilestone
38 EventRemovedMilestone
39 EventAddLabel
40 EventRemoveLabel
41 EventMentionedInIssue
42 EventMentionedInMergeRequest
43)
44
45type NoteEvent struct{ gitlab.Note }
46
47func (n NoteEvent) ID() string { return fmt.Sprintf("%d", n.Note.ID) }
48func (n NoteEvent) UserID() int { return n.Author.ID }
49func (n NoteEvent) CreatedAt() time.Time { return *n.Note.CreatedAt }
50func (n NoteEvent) Kind() EventKind {
51
52 switch {
53 case !n.System:
54 return EventComment
55
56 case n.Body == "closed":
57 return EventClosed
58
59 case n.Body == "reopened":
60 return EventReopened
61
62 case n.Body == "changed the description":
63 return EventDescriptionChanged
64
65 case n.Body == "locked this issue":
66 return EventLocked
67
68 case n.Body == "unlocked this issue":
69 return EventUnlocked
70
71 case strings.HasPrefix(n.Body, "changed title from"):
72 return EventTitleChanged
73
74 case strings.HasPrefix(n.Body, "changed due date to"):
75 return EventChangedDuedate
76
77 case n.Body == "removed due date":
78 return EventRemovedDuedate
79
80 case strings.HasPrefix(n.Body, "assigned to @"):
81 return EventAssigned
82
83 case strings.HasPrefix(n.Body, "unassigned @"):
84 return EventUnassigned
85
86 case strings.HasPrefix(n.Body, "changed milestone to %"):
87 return EventChangedMilestone
88
89 case strings.HasPrefix(n.Body, "removed milestone"):
90 return EventRemovedMilestone
91
92 case strings.HasPrefix(n.Body, "mentioned in issue"):
93 return EventMentionedInIssue
94
95 case strings.HasPrefix(n.Body, "mentioned in merge request"):
96 return EventMentionedInMergeRequest
97
98 default:
99 return EventUnknown
100 }
101
102}
103
104func (n NoteEvent) Title() string {
105 if n.Kind() == EventTitleChanged {
106 return getNewTitle(n.Body)
107 }
108 return text.CleanupOneLine(n.Body)
109}
110
111type LabelEvent struct{ gitlab.LabelEvent }
112
113func (l LabelEvent) ID() string { return fmt.Sprintf("%d", l.LabelEvent.ID) }
114func (l LabelEvent) UserID() int { return l.User.ID }
115func (l LabelEvent) CreatedAt() time.Time { return *l.LabelEvent.CreatedAt }
116func (l LabelEvent) Kind() EventKind {
117 switch l.Action {
118 case "add":
119 return EventAddLabel
120 case "remove":
121 return EventRemoveLabel
122 default:
123 return EventUnknown
124 }
125}
126
127type StateEvent struct{ gitlab.StateEvent }
128
129func (s StateEvent) ID() string { return fmt.Sprintf("%d", s.StateEvent.ID) }
130func (s StateEvent) UserID() int { return s.User.ID }
131func (s StateEvent) CreatedAt() time.Time { return *s.StateEvent.CreatedAt }
132func (s StateEvent) Kind() EventKind {
133 switch s.State {
134 case "closed":
135 return EventClosed
136 case "opened", "reopened":
137 return EventReopened
138 default:
139 return EventUnknown
140 }
141}
142
143type ErrorEvent struct {
144 Err error
145 Time time.Time
146}
147
148func (e ErrorEvent) ID() string { return "" }
149func (e ErrorEvent) UserID() int { return -1 }
150func (e ErrorEvent) CreatedAt() time.Time { return e.Time }
151func (e ErrorEvent) Kind() EventKind { return EventError }
152
153// SortedEvents consumes an Event-channel and returns an event slice, sorted by creation date, using CreatedAt-method.
154func SortedEvents(c <-chan Event) []Event {
155 var events []Event
156 for e := range c {
157 events = append(events, e)
158 }
159 sort.Sort(eventsByCreation(events))
160 return events
161}
162
163type eventsByCreation []Event
164
165func (e eventsByCreation) Len() int {
166 return len(e)
167}
168
169func (e eventsByCreation) Less(i, j int) bool {
170 return e[i].CreatedAt().Before(e[j].CreatedAt())
171}
172
173func (e eventsByCreation) Swap(i, j int) {
174 e[i], e[j] = e[j], e[i]
175}
176
177// getNewTitle parses body diff given by gitlab api and return it final form
178// examples: "changed title from **fourth issue** to **fourth issue{+ changed+}**"
179// "changed title from **fourth issue{- changed-}** to **fourth issue**"
180// because Gitlab
181func getNewTitle(diff string) string {
182 newTitle := strings.Split(diff, "** to **")[1]
183 newTitle = strings.Replace(newTitle, "{+", "", -1)
184 newTitle = strings.Replace(newTitle, "+}", "", -1)
185 return strings.TrimSuffix(newTitle, "**")
186}