diff --git a/github/github-accessors.go b/github/github-accessors.go index 1c17384eac0..61eb48070ca 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -4692,6 +4692,142 @@ func (h *HookConfig) GetURL() string { return *h.URL } +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetAction() string { + if h == nil || h.Action == nil { + return "" + } + return *h.Action +} + +// GetDeliveredAt returns the DeliveredAt field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetDeliveredAt() Timestamp { + if h == nil || h.DeliveredAt == nil { + return Timestamp{} + } + return *h.DeliveredAt +} + +// GetDuration returns the Duration field. +func (h *HookDelivery) GetDuration() *float64 { + if h == nil { + return nil + } + return h.Duration +} + +// GetEvent returns the Event field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetEvent() string { + if h == nil || h.Event == nil { + return "" + } + return *h.Event +} + +// GetGUID returns the GUID field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetGUID() string { + if h == nil || h.GUID == nil { + return "" + } + return *h.GUID +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetID() int64 { + if h == nil || h.ID == nil { + return 0 + } + return *h.ID +} + +// GetInstallationID returns the InstallationID field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetInstallationID() string { + if h == nil || h.InstallationID == nil { + return "" + } + return *h.InstallationID +} + +// GetRedelivery returns the Redelivery field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetRedelivery() bool { + if h == nil || h.Redelivery == nil { + return false + } + return *h.Redelivery +} + +// GetRepositoryID returns the RepositoryID field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetRepositoryID() int64 { + if h == nil || h.RepositoryID == nil { + return 0 + } + return *h.RepositoryID +} + +// GetRequest returns the Request field. +func (h *HookDelivery) GetRequest() *HookRequest { + if h == nil { + return nil + } + return h.Request +} + +// GetResponse returns the Response field. +func (h *HookDelivery) GetResponse() *HookResponse { + if h == nil { + return nil + } + return h.Response +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetStatus() string { + if h == nil || h.Status == nil { + return "" + } + return *h.Status +} + +// GetStatusCode returns the StatusCode field if it's non-nil, zero value otherwise. +func (h *HookDelivery) GetStatusCode() int { + if h == nil || h.StatusCode == nil { + return 0 + } + return *h.StatusCode +} + +// GetHeaders returns the Headers map if it's non-nil, an empty map otherwise. +func (h *HookRequest) GetHeaders() map[string]string { + if h == nil || h.Headers == nil { + return map[string]string{} + } + return h.Headers +} + +// GetRawPayload returns the RawPayload field if it's non-nil, zero value otherwise. +func (h *HookRequest) GetRawPayload() json.RawMessage { + if h == nil || h.RawPayload == nil { + return json.RawMessage{} + } + return *h.RawPayload +} + +// GetHeaders returns the Headers map if it's non-nil, an empty map otherwise. +func (h *HookResponse) GetHeaders() map[string]string { + if h == nil || h.Headers == nil { + return map[string]string{} + } + return h.Headers +} + +// GetRawPayload returns the RawPayload field if it's non-nil, zero value otherwise. +func (h *HookResponse) GetRawPayload() json.RawMessage { + if h == nil || h.RawPayload == nil { + return json.RawMessage{} + } + return *h.RawPayload +} + // GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise. func (h *HookStats) GetActiveHooks() int { if h == nil || h.ActiveHooks == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 750c6a40f8f..7d70caf1b43 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -5524,6 +5524,167 @@ func TestHookConfig_GetURL(tt *testing.T) { h.GetURL() } +func TestHookDelivery_GetAction(tt *testing.T) { + var zeroValue string + h := &HookDelivery{Action: &zeroValue} + h.GetAction() + h = &HookDelivery{} + h.GetAction() + h = nil + h.GetAction() +} + +func TestHookDelivery_GetDeliveredAt(tt *testing.T) { + var zeroValue Timestamp + h := &HookDelivery{DeliveredAt: &zeroValue} + h.GetDeliveredAt() + h = &HookDelivery{} + h.GetDeliveredAt() + h = nil + h.GetDeliveredAt() +} + +func TestHookDelivery_GetDuration(tt *testing.T) { + h := &HookDelivery{} + h.GetDuration() + h = nil + h.GetDuration() +} + +func TestHookDelivery_GetEvent(tt *testing.T) { + var zeroValue string + h := &HookDelivery{Event: &zeroValue} + h.GetEvent() + h = &HookDelivery{} + h.GetEvent() + h = nil + h.GetEvent() +} + +func TestHookDelivery_GetGUID(tt *testing.T) { + var zeroValue string + h := &HookDelivery{GUID: &zeroValue} + h.GetGUID() + h = &HookDelivery{} + h.GetGUID() + h = nil + h.GetGUID() +} + +func TestHookDelivery_GetID(tt *testing.T) { + var zeroValue int64 + h := &HookDelivery{ID: &zeroValue} + h.GetID() + h = &HookDelivery{} + h.GetID() + h = nil + h.GetID() +} + +func TestHookDelivery_GetInstallationID(tt *testing.T) { + var zeroValue string + h := &HookDelivery{InstallationID: &zeroValue} + h.GetInstallationID() + h = &HookDelivery{} + h.GetInstallationID() + h = nil + h.GetInstallationID() +} + +func TestHookDelivery_GetRedelivery(tt *testing.T) { + var zeroValue bool + h := &HookDelivery{Redelivery: &zeroValue} + h.GetRedelivery() + h = &HookDelivery{} + h.GetRedelivery() + h = nil + h.GetRedelivery() +} + +func TestHookDelivery_GetRepositoryID(tt *testing.T) { + var zeroValue int64 + h := &HookDelivery{RepositoryID: &zeroValue} + h.GetRepositoryID() + h = &HookDelivery{} + h.GetRepositoryID() + h = nil + h.GetRepositoryID() +} + +func TestHookDelivery_GetRequest(tt *testing.T) { + h := &HookDelivery{} + h.GetRequest() + h = nil + h.GetRequest() +} + +func TestHookDelivery_GetResponse(tt *testing.T) { + h := &HookDelivery{} + h.GetResponse() + h = nil + h.GetResponse() +} + +func TestHookDelivery_GetStatus(tt *testing.T) { + var zeroValue string + h := &HookDelivery{Status: &zeroValue} + h.GetStatus() + h = &HookDelivery{} + h.GetStatus() + h = nil + h.GetStatus() +} + +func TestHookDelivery_GetStatusCode(tt *testing.T) { + var zeroValue int + h := &HookDelivery{StatusCode: &zeroValue} + h.GetStatusCode() + h = &HookDelivery{} + h.GetStatusCode() + h = nil + h.GetStatusCode() +} + +func TestHookRequest_GetHeaders(tt *testing.T) { + zeroValue := map[string]string{} + h := &HookRequest{Headers: zeroValue} + h.GetHeaders() + h = &HookRequest{} + h.GetHeaders() + h = nil + h.GetHeaders() +} + +func TestHookRequest_GetRawPayload(tt *testing.T) { + var zeroValue json.RawMessage + h := &HookRequest{RawPayload: &zeroValue} + h.GetRawPayload() + h = &HookRequest{} + h.GetRawPayload() + h = nil + h.GetRawPayload() +} + +func TestHookResponse_GetHeaders(tt *testing.T) { + zeroValue := map[string]string{} + h := &HookResponse{Headers: zeroValue} + h.GetHeaders() + h = &HookResponse{} + h.GetHeaders() + h = nil + h.GetHeaders() +} + +func TestHookResponse_GetRawPayload(tt *testing.T) { + var zeroValue json.RawMessage + h := &HookResponse{RawPayload: &zeroValue} + h.GetRawPayload() + h = &HookResponse{} + h.GetRawPayload() + h = nil + h.GetRawPayload() +} + func TestHookStats_GetActiveHooks(tt *testing.T) { var zeroValue int h := &HookStats{ActiveHooks: &zeroValue} diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go index cf0c7ebe817..589febf9f56 100644 --- a/github/github-stringify_test.go +++ b/github/github-stringify_test.go @@ -544,6 +544,28 @@ func TestHook_String(t *testing.T) { } } +func TestHookDelivery_String(t *testing.T) { + v := HookDelivery{ + ID: Int64(0), + GUID: String(""), + DeliveredAt: &Timestamp{}, + Redelivery: Bool(false), + Duration: Float64(0.0), + Status: String(""), + StatusCode: Int(0), + Event: String(""), + Action: String(""), + InstallationID: String(""), + RepositoryID: Int64(0), + Request: &HookRequest{}, + Response: &HookResponse{}, + } + want := `github.HookDelivery{ID:0, GUID:"", DeliveredAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Redelivery:false, Duration:0, Status:"", StatusCode:0, Event:"", Action:"", InstallationID:"", RepositoryID:0, Request:github.HookRequest{}, Response:github.HookResponse{}}` + if got := v.String(); got != want { + t.Errorf("HookDelivery.String = %v, want %v", got, want) + } +} + func TestHookStats_String(t *testing.T) { v := HookStats{ TotalHooks: Int(0), diff --git a/github/github.go b/github/github.go index efde8f8dbab..1748c6372c8 100644 --- a/github/github.go +++ b/github/github.go @@ -212,6 +212,9 @@ type ListCursorOptions struct { // A cursor, as given in the Link header. If specified, the query only searches for events before this cursor. Before string `url:"before,omitempty"` + + // A cursor, as given in the Link header. If specified, the query continues the search using this cursor. + Cursor string `url:"cursor,omitempty"` } // UploadOptions specifies the parameters to methods that support uploads. @@ -445,6 +448,11 @@ type Response struct { // calling the endpoint again. NextPageToken string + // For APIs that support cursor pagination, such as RepositoryService.ListRepositoryHookDeliveries, + // the following field will be populated to point to the next page. + // Set ListCursorOptions.Cursor to this value when calling the endpoint again. + Cursor string + // Explicitly specify the Rate type so Rate's String() receiver doesn't // propagate to Response. Rate Rate @@ -481,7 +489,21 @@ func (r *Response) populatePageValues() { if err != nil { continue } - page := url.Query().Get("page") + + q := url.Query() + + if cursor := q.Get("cursor"); cursor != "" { + for _, segment := range segments[1:] { + switch strings.TrimSpace(segment) { + case `rel="next"`: + r.Cursor = cursor + } + } + + continue + } + + page := q.Get("page") if page == "" { continue } @@ -499,7 +521,6 @@ func (r *Response) populatePageValues() { case `rel="last"`: r.LastPage, _ = strconv.Atoi(page) } - } } } diff --git a/github/github_test.go b/github/github_test.go index 828898fd0e9..6b4aacbf62e 100644 --- a/github/github_test.go +++ b/github/github_test.go @@ -635,6 +635,20 @@ func TestResponse_cursorPagination(t *testing.T) { if got, want := response.NextPageToken, "url-encoded-next-page-token"; want != got { t.Errorf("response.NextPageToken: %v, want %v", got, want) } + + // cursor-based pagination with "cursor" param + r = http.Response{ + Header: http.Header{ + "Link": { + `; rel="next"`, + }, + }, + } + + response = newResponse(&r) + if got, want := response.Cursor, "v1_12345678"; got != want { + t.Errorf("response.Cursor: %v, want %v", got, want) + } } func TestResponse_populatePageValues_invalid(t *testing.T) { diff --git a/github/orgs_hooks_deliveries.go b/github/orgs_hooks_deliveries.go new file mode 100644 index 00000000000..6ab2d7aa244 --- /dev/null +++ b/github/orgs_hooks_deliveries.go @@ -0,0 +1,54 @@ +// Copyright 2021 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ListHookDeliveries lists webhook deliveries for a webhook configured in an organization. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/orgs#list-deliveries-for-an-organization-webhook +func (s *OrganizationsService) ListHookDeliveries(ctx context.Context, org string, id int64, opts *ListCursorOptions) ([]*HookDelivery, *Response, error) { + u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries", org, id) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + deliveries := []*HookDelivery{} + resp, err := s.client.Do(ctx, req, &deliveries) + if err != nil { + return nil, resp, err + } + + return deliveries, resp, nil +} + +// GetHookDelivery returns a delivery for a webhook configured in an organization. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/orgs#get-a-webhook-delivery-for-an-organization-webhook +func (s *OrganizationsService) GetHookDelivery(ctx context.Context, owner string, hookID, deliveryID int64) (*HookDelivery, *Response, error) { + u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries/%v", owner, hookID, deliveryID) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + h := new(HookDelivery) + resp, err := s.client.Do(ctx, req, h) + if err != nil { + return nil, resp, err + } + + return h, resp, nil +} diff --git a/github/orgs_hooks_deliveries_test.go b/github/orgs_hooks_deliveries_test.go new file mode 100644 index 00000000000..c1efc527aa8 --- /dev/null +++ b/github/orgs_hooks_deliveries_test.go @@ -0,0 +1,106 @@ +// Copyright 2021 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_ListHookDeliveries(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/hooks/1/deliveries", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"cursor": "v1_12077215967"}) + fmt.Fprint(w, `[{"id":1}, {"id":2}]`) + }) + + opt := &ListCursorOptions{Cursor: "v1_12077215967"} + + ctx := context.Background() + hooks, _, err := client.Organizations.ListHookDeliveries(ctx, "o", 1, opt) + if err != nil { + t.Errorf("Organizations.ListHookDeliveries returned error: %v", err) + } + + want := []*HookDelivery{{ID: Int64(1)}, {ID: Int64(2)}} + if d := cmp.Diff(hooks, want); d != "" { + t.Errorf("Organizations.ListHooks want (-), got (+):\n%s", d) + } + + const methodName = "ListHookDeliveries" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.ListHookDeliveries(ctx, "\n", -1, opt) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.ListHookDeliveries(ctx, "o", 1, opt) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_ListHookDeliveries_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + ctx := context.Background() + _, _, err := client.Organizations.ListHookDeliveries(ctx, "%", 1, nil) + testURLParseError(t, err) +} + +func TestOrganizationsService_GetHookDelivery(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/hooks/1/deliveries/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"id":1}`) + }) + + ctx := context.Background() + hook, _, err := client.Organizations.GetHookDelivery(ctx, "o", 1, 1) + if err != nil { + t.Errorf("Organizations.GetHookDelivery returned error: %v", err) + } + + want := &HookDelivery{ID: Int64(1)} + if !cmp.Equal(hook, want) { + t.Errorf("Organizations.GetHookDelivery returned %+v, want %+v", hook, want) + } + + const methodName = "GetHookDelivery" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.GetHookDelivery(ctx, "\n", -1, -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetHookDelivery(ctx, "o", 1, 1) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_GetHookDelivery_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + ctx := context.Background() + _, _, err := client.Organizations.GetHookDelivery(ctx, "%", 1, 1) + testURLParseError(t, err) +} diff --git a/github/repos_hooks_deliveries.go b/github/repos_hooks_deliveries.go new file mode 100644 index 00000000000..122674463ae --- /dev/null +++ b/github/repos_hooks_deliveries.go @@ -0,0 +1,117 @@ +// Copyright 2021 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "encoding/json" + "fmt" +) + +// HookDelivery represents the data that is received from GitHub's Webhook Delivery API +// +// GitHub API docs: +// - https://docs.github.com/en/rest/reference/repos#list-deliveries-for-a-repository-webhook +// - https://docs.github.com/en/rest/reference/repos#get-a-delivery-for-a-repository-webhook +type HookDelivery struct { + ID *int64 `json:"id"` + GUID *string `json:"guid"` + DeliveredAt *Timestamp `json:"delivered_at"` + Redelivery *bool `json:"redelivery"` + Duration *float64 `json:"duration"` + Status *string `json:"status"` + StatusCode *int `json:"status_code"` + Event *string `json:"event"` + Action *string `json:"action"` + InstallationID *string `json:"installation_id"` + RepositoryID *int64 `json:"repository_id"` + + // Request is populated by GetHookDelivery. + Request *HookRequest `json:"request,omitempty"` + // Response is populated by GetHookDelivery. + Response *HookResponse `json:"response,omitempty"` +} + +func (d HookDelivery) String() string { + return Stringify(d) +} + +// HookRequest is a part of HookDelivery that contains +// the HTTP headers and the JSON payload of the webhook request. +type HookRequest struct { + Headers map[string]string `json:"headers,omitempty"` + RawPayload *json.RawMessage `json:"payload,omitempty"` +} + +func (r HookRequest) String() string { + return Stringify(r) +} + +// HookResponse is a part of HookDelivery that contains +// the HTTP headers and the response body served by the webhook endpoint. +type HookResponse struct { + Headers map[string]string `json:"headers,omitempty"` + RawPayload *json.RawMessage `json:"payload,omitempty"` +} + +func (r HookResponse) String() string { + return Stringify(r) +} + +// ListHookDeliveries lists webhook deliveries for a webhook configured in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/repos#list-deliveries-for-a-repository-webhook +func (s *RepositoriesService) ListHookDeliveries(ctx context.Context, owner, repo string, id int64, opts *ListCursorOptions) ([]*HookDelivery, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/hooks/%v/deliveries", owner, repo, id) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + deliveries := []*HookDelivery{} + resp, err := s.client.Do(ctx, req, &deliveries) + if err != nil { + return nil, resp, err + } + + return deliveries, resp, nil +} + +// GetHookDelivery returns a delivery for a webhook configured in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/repos#get-a-delivery-for-a-repository-webhook +func (s *RepositoriesService) GetHookDelivery(ctx context.Context, owner, repo string, hookID, deliveryID int64) (*HookDelivery, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/hooks/%v/deliveries/%v", owner, repo, hookID, deliveryID) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + h := new(HookDelivery) + resp, err := s.client.Do(ctx, req, h) + if err != nil { + return nil, resp, err + } + + return h, resp, nil +} + +// ParseRequestPayload parses the request payload. For recognized event types, +// a value of the corresponding struct type will be returned. +func (d *HookDelivery) ParseRequestPayload() (interface{}, error) { + eType, ok := eventTypeMapping[*d.Event] + if !ok { + return nil, fmt.Errorf("unsupported event type %q", *d.Event) + } + + e := &Event{Type: &eType, RawPayload: d.Request.RawPayload} + return e.ParsePayload() +} diff --git a/github/repos_hooks_deliveries_test.go b/github/repos_hooks_deliveries_test.go new file mode 100644 index 00000000000..5c6fb86d7eb --- /dev/null +++ b/github/repos_hooks_deliveries_test.go @@ -0,0 +1,220 @@ +// Copyright 2021 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestRepositoriesService_ListHookDeliveries(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/hooks/1/deliveries", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"cursor": "v1_12077215967"}) + fmt.Fprint(w, `[{"id":1}, {"id":2}]`) + }) + + opt := &ListCursorOptions{Cursor: "v1_12077215967"} + + ctx := context.Background() + hooks, _, err := client.Repositories.ListHookDeliveries(ctx, "o", "r", 1, opt) + if err != nil { + t.Errorf("Repositories.ListHookDeliveries returned error: %v", err) + } + + want := []*HookDelivery{{ID: Int64(1)}, {ID: Int64(2)}} + if d := cmp.Diff(hooks, want); d != "" { + t.Errorf("Repositories.ListHooks want (-), got (+):\n%s", d) + } + + const methodName = "ListHookDeliveries" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ListHookDeliveries(ctx, "\n", "\n", -1, opt) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ListHookDeliveries(ctx, "o", "r", 1, opt) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestRepositoriesService_ListHookDeliveries_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + ctx := context.Background() + _, _, err := client.Repositories.ListHookDeliveries(ctx, "%", "%", 1, nil) + testURLParseError(t, err) +} + +func TestRepositoriesService_GetHookDelivery(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/hooks/1/deliveries/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"id":1}`) + }) + + ctx := context.Background() + hook, _, err := client.Repositories.GetHookDelivery(ctx, "o", "r", 1, 1) + if err != nil { + t.Errorf("Repositories.GetHookDelivery returned error: %v", err) + } + + want := &HookDelivery{ID: Int64(1)} + if !cmp.Equal(hook, want) { + t.Errorf("Repositories.GetHookDelivery returned %+v, want %+v", hook, want) + } + + const methodName = "GetHookDelivery" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetHookDelivery(ctx, "\n", "\n", -1, -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetHookDelivery(ctx, "o", "r", 1, 1) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestRepositoriesService_GetHookDelivery_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + ctx := context.Background() + _, _, err := client.Repositories.GetHookDelivery(ctx, "%", "%", 1, 1) + testURLParseError(t, err) +} + +var hookDeliveryPayloadTypeToStruct = map[string]interface{}{ + "check_run": &CheckRunEvent{}, + "check_suite": &CheckSuiteEvent{}, + "commit_comment": &CommitCommentEvent{}, + "content_reference": &ContentReferenceEvent{}, + "create": &CreateEvent{}, + "delete": &DeleteEvent{}, + "deploy_key": &DeployKeyEvent{}, + "deployment": &DeploymentEvent{}, + "deployment_status": &DeploymentStatusEvent{}, + "fork": &ForkEvent{}, + "github_app_authorization": &GitHubAppAuthorizationEvent{}, + "gollum": &GollumEvent{}, + "installation": &InstallationEvent{}, + "installation_repositories": &InstallationRepositoriesEvent{}, + "issue_comment": &IssueCommentEvent{}, + "issues": &IssuesEvent{}, + "label": &LabelEvent{}, + "marketplace_purchase": &MarketplacePurchaseEvent{}, + "member": &MemberEvent{}, + "membership": &MembershipEvent{}, + "meta": &MetaEvent{}, + "milestone": &MilestoneEvent{}, + "organization": &OrganizationEvent{}, + "org_block": &OrgBlockEvent{}, + "package": &PackageEvent{}, + "page_build": &PageBuildEvent{}, + "ping": &PingEvent{}, + "project": &ProjectEvent{}, + "project_card": &ProjectCardEvent{}, + "project_column": &ProjectColumnEvent{}, + "public": &PublicEvent{}, + "pull_request": &PullRequestEvent{}, + "pull_request_review": &PullRequestReviewEvent{}, + "pull_request_review_comment": &PullRequestReviewCommentEvent{}, + "pull_request_target": &PullRequestTargetEvent{}, + "push": &PushEvent{}, + "release": &ReleaseEvent{}, + "repository": &RepositoryEvent{}, + "repository_dispatch": &RepositoryDispatchEvent{}, + "repository_vulnerability_alert": &RepositoryVulnerabilityAlertEvent{}, + "star": &StarEvent{}, + "status": &StatusEvent{}, + "team": &TeamEvent{}, + "team_add": &TeamAddEvent{}, + "user": &UserEvent{}, + "watch": &WatchEvent{}, + "workflow_dispatch": &WorkflowDispatchEvent{}, + "workflow_run": &WorkflowRunEvent{}, +} + +func TestHookDelivery_ParsePayload(t *testing.T) { + for evt, obj := range hookDeliveryPayloadTypeToStruct { + t.Run(evt, func(t *testing.T) { + bs, err := json.Marshal(obj) + if err != nil { + t.Fatal(err) + } + + p := json.RawMessage(bs) + + d := &HookDelivery{ + Event: String(evt), + Request: &HookRequest{ + RawPayload: &p, + }, + } + + got, err := d.ParseRequestPayload() + if err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(obj, got) { + t.Errorf("want %T %v, got %T %v", obj, obj, got, got) + } + }) + } +} + +func TestHookDelivery_ParsePayload_invalidEvent(t *testing.T) { + p := json.RawMessage(nil) + + d := &HookDelivery{ + Event: String("some_invalid_event"), + Request: &HookRequest{ + RawPayload: &p, + }, + } + + _, err := d.ParseRequestPayload() + if err == nil || err.Error() != `unsupported event type "some_invalid_event"` { + t.Errorf("unexpected error: %v", err) + } +} + +func TestHookDelivery_ParsePayload_invalidPayload(t *testing.T) { + p := json.RawMessage([]byte(`{"check_run":{"id":"invalid"}}`)) + + d := &HookDelivery{ + Event: String("check_run"), + Request: &HookRequest{ + RawPayload: &p, + }, + } + + _, err := d.ParseRequestPayload() + if err == nil || err.Error() != "json: cannot unmarshal string into Go struct field CheckRun.check_run.id of type int64" { + t.Errorf("unexpected error: %v", err) + } +}