aboutsummaryrefslogblamecommitdiffstats
path: root/bridge/gitlab/event.go
blob: 0653269d81c8136c884c3cc8ff8467477ca28d07 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



              


                 
                                    

                                                  

 







                                                                        





















                                     
                              

 

                          




















































                                                                                


                                                              












                                          

                           















                                                                                       

                           















                                                                                       

                           









                                                               











































                                                                                                                                


                                                                            


                                                                          





                                                          
package gitlab

import (
	"fmt"
	"strings"
	"time"

	"github.com/xanzy/go-gitlab"

	"github.com/MichaelMure/git-bug/util/text"
)

// 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
	EventMentionedInCommit
)

var _ Event = &NoteEvent{}

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

	case strings.HasPrefix(n.Body, "mentioned in commit"):
		return EventMentionedInCommit

	default:
		return EventUnknown
	}

}

func (n NoteEvent) Title() string {
	if n.Kind() == EventTitleChanged {
		return getNewTitle(n.Body)
	}
	return text.CleanupOneLine(n.Body)
}

var _ Event = &LabelEvent{}

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
	}
}

var _ Event = &StateEvent{}

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
	}
}

var _ Event = &ErrorEvent{}

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 fan-in some Event-channels into one, sorted by creation date, using CreatedAt-method.
// This function assume that each channel is pre-ordered.
func SortedEvents(inputs ...<-chan Event) chan Event {
	out := make(chan Event)

	go func() {
		defer close(out)

		heads := make([]Event, len(inputs))

		// pre-fill the head view
		for i, input := range inputs {
			if event, ok := <-input; ok {
				heads[i] = event
			}
		}

		for {
			var earliestEvent Event
			var originChannel int

			// pick the earliest event of the heads
			for i, head := range heads {
				if head != nil && (earliestEvent == nil || head.CreatedAt().Before(earliestEvent.CreatedAt())) {
					earliestEvent = head
					originChannel = i
				}
			}

			if earliestEvent == nil {
				// no event anymore, we are done
				return
			}

			// we have an event: consume it and replace it if possible
			heads[originChannel] = nil
			if event, ok := <-inputs[originChannel]; ok {
				heads[originChannel] = event
			}
			out <- earliestEvent
		}
	}()

	return out
}

// 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**"
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, "**")
}