diff --git a/github/events.go b/github/events.go index 43e6137..6251997 100644 --- a/github/events.go +++ b/github/events.go @@ -23,14 +23,47 @@ type EventsService struct { // Event represents a GitHub event. type Event struct { - Type string `json:"type,omitempty"` - Public bool `json:"public"` - Payload json.RawMessage `json:"payload,omitempty"` - Repo *Repository `json:"repo,omitempty"` - Actor *User `json:"actor,omitempty"` - Org *Organization `json:"org,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Public bool `json:"public"` + RawPayload json.RawMessage `json:"payload,omitempty"` + Repo *Repository `json:"repo,omitempty"` + Actor *User `json:"actor,omitempty"` + Org *Organization `json:"org,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + ID string `json:"id,omitempty"` +} + +// Payload returns the parsed event payload. For recognized event types +// (PushEvent), a value of the corresponding struct type will be returned. +func (e *Event) Payload() (payload interface{}) { + switch e.Type { + case "PushEvent": + payload = &PushEvent{} + } + if err := json.Unmarshal(e.RawPayload, &payload); err != nil { + panic(err.Error()) + } + return payload +} + +// PushEvent represents a git push to a GitHub repository. +// +// GitHub API docs: http://developer.github.com/v3/activity/events/types/#pushevent +type PushEvent struct { + PushID int `json:"push_id,omitempty"` + Head string `json:"head,omitempty"` + Ref string `json:"ref,omitempty"` + Size int `json:"ref,omitempty"` + Commits []PushEventCommit `json:"commits,omitempty"` +} + +// PushEventCommit represents a git commit in a GitHub PushEvent. +type PushEventCommit struct { + SHA string `json:"sha,omitempty"` + Message string `json:"message,omitempty"` + Author *CommitAuthor `json:"author,omitempty"` + URL string `json:"url,omitempty"` + Distinct bool `json:"distinct"` } // ListPerformedByUser lists the events performed by a user. If publicOnly is diff --git a/github/events_test.go b/github/events_test.go index 86e25b9..d14385d 100644 --- a/github/events_test.go +++ b/github/events_test.go @@ -6,6 +6,7 @@ package github import ( + "encoding/json" "fmt" "net/http" "reflect" @@ -55,3 +56,32 @@ func TestEventsService_ListPerformedByUser_publicOnly(t *testing.T) { t.Errorf("Events.ListPerformedByUser returned %+v, want %+v", events, want) } } + +func TestEvent_Payload_typed(t *testing.T) { + raw := []byte(`{"type": "PushEvent","payload":{"push_id": 1}}`) + var event *Event + if err := json.Unmarshal(raw, &event); err != nil { + t.Fatalf("Unmarshal Event returned error: %v", err) + } + + want := &PushEvent{PushID: 1} + if !reflect.DeepEqual(event.Payload(), want) { + t.Errorf("Event Payload returned %+v, want %+v", event.Payload(), want) + } +} + +// TestEvent_Payload_untyped checks that unrecognized events are parsed to an +// interface{} value (instead of being discarded or throwing an error), for +// forward compatibility with new event types. +func TestEvent_Payload_untyped(t *testing.T) { + raw := []byte(`{"type": "UnrecognizedEvent","payload":{"field": "val"}}`) + var event *Event + if err := json.Unmarshal(raw, &event); err != nil { + t.Fatalf("Unmarshal Event returned error: %v", err) + } + + want := map[string]interface{}{"field": "val"} + if !reflect.DeepEqual(event.Payload(), want) { + t.Errorf("Event Payload returned %+v, want %+v", event.Payload(), want) + } +}