package gitlab
import (
"fmt"
"sort"
"strings"
"time"
"github.com/MichaelMure/git-bug/util/text"
"github.com/xanzy/go-gitlab"
)
// Event represents a unified GitLab event (note, label or state event).
type Event interface {
ID() string
UserID() int
Kind() EventKind
CreatedAt() time.Time
}
type EventKind int
const (
EventUnknown EventKind = iota
EventError
EventComment
EventTitleChanged
EventDescriptionChanged
EventClosed
EventReopened
EventLocked
EventUnlocked
EventChangedDuedate
EventRemovedDuedate
EventAssigned
EventUnassigned
EventChangedMilestone
EventRemovedMilestone
EventAddLabel
EventRemoveLabel
EventMentionedInIssue
EventMentionedInMergeRequest
)
type NoteEvent struct{ gitlab.Note }
func (n NoteEvent) ID() string { return fmt.Sprintf("%d", n.Note.ID) }
func (n NoteEvent) UserID() int { return n.Author.ID }
func (n NoteEvent) CreatedAt() time.Time { return *n.Note.CreatedAt }
func (n NoteEvent) Kind() EventKind {
switch {
case !n.System:
return EventComment
case n.Body == "closed":
return EventClosed
case n.Body == "reopened":
return EventReopened
case n.Body == "changed the description":
return EventDescriptionChanged
case n.Body == "locked this issue":
return EventLocked
case n.Body == "unlocked this issue":
return EventUnlocked
case strings.HasPrefix(n.Body, "changed title from"):
return EventTitleChanged
case strings.HasPrefix(n.Body, "changed due date to"):
return EventChangedDuedate
case n.Body == "removed due date":
return EventRemovedDuedate
case strings.HasPrefix(n.Body, "assigned to @"):
return EventAssigned
case strings.HasPrefix(n.Body, "unassigned @"):
return EventUnassigned
case strings.HasPrefix(n.Body, "changed milestone to %"):
return EventChangedMilestone
case strings.HasPrefix(n.Body, "removed milestone"):
return EventRemovedMilestone
case strings.HasPrefix(n.Body, "mentioned in issue"):
return EventMentionedInIssue
case strings.HasPrefix(n.Body, "mentioned in merge request"):
return EventMentionedInMergeRequest
default:
return EventUnknown
}
}
func (n NoteEvent) Title() string {
if n.Kind() == EventTitleChanged {
return getNewTitle(n.Body)
}
return text.CleanupOneLine(n.Body)
}
type LabelEvent struct{ gitlab.LabelEvent }
func (l LabelEvent) ID() string { return fmt.Sprintf("%d", l.LabelEvent.ID) }
func (l LabelEvent) UserID() int { return l.User.ID }
func (l LabelEvent) CreatedAt() time.Time { return *l.LabelEvent.CreatedAt }
func (l LabelEvent) Kind() EventKind {
switch l.Action {
case "add":
return EventAddLabel
case "remove":
return EventRemoveLabel
default:
return EventUnknown
}
}
type StateEvent struct{ gitlab.StateEvent }
func (s StateEvent) ID() string { return fmt.Sprintf("%d", s.StateEvent.ID) }
func (s StateEvent) UserID() int { return s.User.ID }
func (s StateEvent) CreatedAt() time.Time { return *s.StateEvent.CreatedAt }
func (s StateEvent) Kind() EventKind {
switch s.State {
case "closed":
return EventClosed
case "opened", "reopened":
return EventReopened
default:
return EventUnknown
}
}
type ErrorEvent struct {
Err error
Time time.Time
}
func (e ErrorEvent) ID() string { return "" }
func (e ErrorEvent) UserID() int { return -1 }
func (e ErrorEvent) CreatedAt() time.Time { return e.Time }
func (e ErrorEvent) Kind() EventKind { return EventError }
// SortedEvents consumes an Event-channel and returns an event slice, sorted by creation date, using CreatedAt-method.
func SortedEvents(c <-chan Event) []Event {
var events []Event
for e := range c {
events = append(events, e)
}
sort.Sort(eventsByCreation(events))
return events
}
type eventsByCreation []Event
func (e eventsByCreation) Len() int {
return len(e)
}
func (e eventsByCreation) Less(i, j int) bool {
return e[i].CreatedAt().Before(e[j].CreatedAt())
}
func (e eventsByCreation) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}
// getNewTitle parses body diff given by gitlab api and return it final form
// examples: "changed title from **fourth issue** to **fourth issue{+ changed+}**"
// "changed title from **fourth issue{- changed-}** to **fourth issue**"
// because Gitlab
func getNewTitle(diff string) string {
newTitle := strings.Split(diff, "** to **")[1]
newTitle = strings.Replace(newTitle, "{+", "", -1)
newTitle = strings.Replace(newTitle, "+}", "", -1)
return strings.TrimSuffix(newTitle, "**")
}