Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add system hook events #714

Merged
merged 2 commits into from Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
116 changes: 115 additions & 1 deletion event_parsing.go
Expand Up @@ -18,6 +18,7 @@ const (
EventTypeNote EventType = "Note Hook"
EventTypePipeline EventType = "Pipeline Hook"
EventTypePush EventType = "Push Hook"
EventTypeSystemHook EventType = "System Hook"
EventTypeTagPush EventType = "Tag Push Hook"
EventTypeWikiPage EventType = "Wiki Page Hook"
)
Expand All @@ -38,6 +39,119 @@ type noteEvent struct {

const eventTypeHeader = "X-Gitlab-Event"

// HookEventType returns the event type for the given request.
func HookEventType(r *http.Request) EventType {
return EventType(r.Header.Get(eventTypeHeader))
}

// ParseHook tries to parse both web- and system hooks.
//
// Example usage:
//
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// payload, err := ioutil.ReadAll(r.Body)
// if err != nil { ... }
// event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload)
// if err != nil { ... }
// switch event := event.(type) {
// case *gitlab.PushEvent:
// processPushEvent(event)
// case *gitlab.MergeEvent:
// processMergeEvent(event)
// ...
// }
// }
//
func ParseHook(eventType EventType, payload []byte) (event interface{}, err error) {
switch eventType {
case EventTypeSystemHook:
return ParseSystemhook(payload)
default:
return ParseWebhook(eventType, payload)
}
}

// ParseSystemhook parses the event payload. For recognized event types, a
// value of the corresponding struct type will be returned. An error will be
// returned for unrecognized event types.
//
// Example usage:
//
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// payload, err := ioutil.ReadAll(r.Body)
// if err != nil { ... }
// event, err := gitlab.ParseSystemhook(payload)
// if err != nil { ... }
// switch event := event.(type) {
// case *gitlab.PushSystemEvent:
// processPushSystemEvent(event)
// case *gitlab.MergeSystemEvent:
// processMergeSystemEvent(event)
// ...
// }
// }
//
func ParseSystemhook(payload []byte) (event interface{}, err error) {
e := &systemHookEvent{}
err = json.Unmarshal(payload, e)
if err != nil {
return nil, err
}

switch e.EventName {
case "push":
event = &PushSystemEvent{}
case "tag_push":
event = &TagPushSystemEvent{}
case "repository_update":
event = &RepositoryUpdateSystemEvent{}
case
"project_create",
"project_update",
"project_destroy",
"project_transfer",
"project_rename":
event = &ProjectSystemEvent{}
case
"group_create",
"group_destroy",
"group_rename":
event = &GroupSystemEvent{}
case
"key_create",
"key_destroy":
event = &KeySystemEvent{}
case
"user_create",
"user_destroy",
"user_rename":
event = &UserSystemEvent{}
case
"user_add_to_group",
"user_remove_from_group",
"user_update_for_group":
event = &UserGroupSystemEvent{}
case
"user_add_to_team",
"user_remove_from_team",
"user_update_for_team":
event = &UserTeamSystemEvent{}
default:
switch e.ObjectKind {
case "merge_request":
event = &MergeEvent{}
default:
return nil, fmt.Errorf("unexpected system hook type %s", e.EventName)
}
}

if err := json.Unmarshal(payload, event); err != nil {
return nil, err
}

return event, nil
}

// WebhookEventType returns the event type for the given request.
func WebhookEventType(r *http.Request) EventType {
return EventType(r.Header.Get(eventTypeHeader))
Expand All @@ -52,7 +166,7 @@ func WebhookEventType(r *http.Request) EventType {
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// payload, err := ioutil.ReadAll(r.Body)
// if err != nil { ... }
// event, err := gitlab.ParseWebhook(gitlab.WebhookEventType(r), payload)
// event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload)
// if err != nil { ... }
// switch event := event.(type) {
// case *gitlab.PushEvent:
Expand Down
201 changes: 201 additions & 0 deletions event_parsing_systemhook_test.go
@@ -0,0 +1,201 @@
package gitlab

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestParseSystemhookPush(t *testing.T) {
payload := loadFixture("testdata/systemhooks/push.json")

parsedEvent, err := ParseSystemhook(payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}

event, ok := parsedEvent.(*PushSystemEvent)
if !ok {
t.Errorf("Expected PushSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, "push", event.EventName)
}

func TestParseSystemhookTagPush(t *testing.T) {
payload := loadFixture("testdata/systemhooks/tag_push.json")

parsedEvent, err := ParseSystemhook(payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}

event, ok := parsedEvent.(*TagPushSystemEvent)
if !ok {
t.Errorf("Expected TagPushSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, "tag_push", event.EventName)
}

func TestParseSystemhookMergeRequest(t *testing.T) {
payload := loadFixture("testdata/systemhooks/merge_request.json")

parsedEvent, err := ParseSystemhook(payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}

event, ok := parsedEvent.(*MergeEvent)
if !ok {
t.Errorf("Expected MergeRequestSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, "merge_request", event.ObjectKind)
}

func TestParseSystemhookRepositoryUpdate(t *testing.T) {
payload := loadFixture("testdata/systemhooks/repository_update.json")

parsedEvent, err := ParseSystemhook(payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}

event, ok := parsedEvent.(*RepositoryUpdateSystemEvent)
if !ok {
t.Errorf("Expected RepositoryUpdateSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, "repository_update", event.EventName)
}

func TestParseSystemhookProject(t *testing.T) {
var tests = []struct {
event string
payload []byte
}{
{"project_create", loadFixture("testdata/systemhooks/project_create.json")},
{"project_update", loadFixture("testdata/systemhooks/project_update.json")},
{"project_destroy", loadFixture("testdata/systemhooks/project_destroy.json")},
{"project_transfer", loadFixture("testdata/systemhooks/project_transfer.json")},
{"project_rename", loadFixture("testdata/systemhooks/project_rename.json")},
}
for _, tc := range tests {
t.Run(tc.event, func(t *testing.T) {
parsedEvent, err := ParseSystemhook(tc.payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
event, ok := parsedEvent.(*ProjectSystemEvent)
if !ok {
t.Errorf("Expected ProjectSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, tc.event, event.EventName)
})
}
}

func TestParseSystemhookGroup(t *testing.T) {
var tests = []struct {
event string
payload []byte
}{
{"group_create", loadFixture("testdata/systemhooks/group_create.json")},
{"group_destroy", loadFixture("testdata/systemhooks/group_destroy.json")},
{"group_rename", loadFixture("testdata/systemhooks/group_rename.json")},
}
for _, tc := range tests {
t.Run(tc.event, func(t *testing.T) {
parsedEvent, err := ParseSystemhook(tc.payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
event, ok := parsedEvent.(*GroupSystemEvent)
if !ok {
t.Errorf("Expected GroupSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, tc.event, event.EventName)
})
}
}

func TestParseSystemhookUser(t *testing.T) {
var tests = []struct {
event string
payload []byte
}{
{"user_create", loadFixture("testdata/systemhooks/user_create.json")},
{"user_destroy", loadFixture("testdata/systemhooks/user_destroy.json")},
{"user_rename", loadFixture("testdata/systemhooks/user_rename.json")},
}
for _, tc := range tests {
t.Run(tc.event, func(t *testing.T) {
parsedEvent, err := ParseSystemhook(tc.payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
event, ok := parsedEvent.(*UserSystemEvent)
if !ok {
t.Errorf("Expected UserSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, tc.event, event.EventName)
})
}
}

func TestParseSystemhookUserGroup(t *testing.T) {
var tests = []struct {
event string
payload []byte
}{
{"user_add_to_group", loadFixture("testdata/systemhooks/user_add_to_group.json")},
{"user_remove_from_group", loadFixture("testdata/systemhooks/user_remove_from_group.json")},
{"user_update_for_group", loadFixture("testdata/systemhooks/user_update_for_group.json")},
}
for _, tc := range tests {
t.Run(tc.event, func(t *testing.T) {
parsedEvent, err := ParseSystemhook(tc.payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
event, ok := parsedEvent.(*UserGroupSystemEvent)
if !ok {
t.Errorf("Expected UserGroupSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, tc.event, event.EventName)
})
}
}

func TestParseSystemhookUserTeam(t *testing.T) {
var tests = []struct {
event string
payload []byte
}{
{"user_add_to_team", loadFixture("testdata/systemhooks/user_add_to_team.json")},
{"user_remove_from_team", loadFixture("testdata/systemhooks/user_remove_from_team.json")},
{"user_update_for_team", loadFixture("testdata/systemhooks/user_update_for_team.json")},
}
for _, tc := range tests {
t.Run(tc.event, func(t *testing.T) {
parsedEvent, err := ParseSystemhook(tc.payload)
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
event, ok := parsedEvent.(*UserTeamSystemEvent)
if !ok {
t.Errorf("Expected UserTeamSystemHookEvent, but parsing produced %T", parsedEvent)
}
assert.Equal(t, tc.event, event.EventName)
})
}
}

func TestParseHookSystemHook(t *testing.T) {
parsedEvent1, err := ParseHook("System Hook", loadFixture("testdata/systemhooks/merge_request.json"))
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
parsedEvent2, err := ParseSystemhook(loadFixture("testdata/systemhooks/merge_request.json"))
if err != nil {
t.Errorf("Error parsing build hook: %s", err)
}
assert.Equal(t, parsedEvent1, parsedEvent2)
}