From 09a37d57ac99a8938444e44375db8660c2184696 Mon Sep 17 00:00:00 2001 From: Glenn Lewis Date: Fri, 13 May 2016 14:42:02 -0700 Subject: [PATCH] add support for Reactions API Fixes #356. Change-Id: Iecc8d7d7c11a8ce9ed38c6d024683815495cb8b4 --- github/github.go | 5 + github/issues.go | 10 ++ github/issues_comments.go | 9 ++ github/issues_comments_test.go | 3 + github/issues_test.go | 5 + github/pulls_comments.go | 7 + github/pulls_comments_test.go | 3 + github/reactions.go | 272 +++++++++++++++++++++++++++++++++ github/reactions_test.go | 200 ++++++++++++++++++++++++ github/repos_comments.go | 10 ++ github/repos_comments_test.go | 3 + 11 files changed, 527 insertions(+) create mode 100644 github/reactions.go create mode 100644 github/reactions_test.go diff --git a/github/github.go b/github/github.go index a9772ac..01e573d 100644 --- a/github/github.go +++ b/github/github.go @@ -69,6 +69,9 @@ const ( // https://developer.github.com/changes/2016-02-19-source-import-preview-api/ mediaTypeImportPreview = "application/vnd.github.barred-rock-preview" + + // https://developer.github.com/changes/2016-05-12-reactions-api-preview/ + mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview" ) // A Client manages communication with the GitHub API. @@ -107,6 +110,7 @@ type Client struct { Users *UsersService Licenses *LicensesService Migrations *MigrationService + Reactions *ReactionsService } // ListOptions specifies the optional parameters to various List methods that @@ -171,6 +175,7 @@ func NewClient(httpClient *http.Client) *Client { c.Users = &UsersService{client: c} c.Licenses = &LicensesService{client: c} c.Migrations = &MigrationService{client: c} + c.Reactions = &ReactionsService{client: c} return c } diff --git a/github/issues.go b/github/issues.go index 58a3a69..d380dd3 100644 --- a/github/issues.go +++ b/github/issues.go @@ -36,6 +36,7 @@ type Issue struct { Milestone *Milestone `json:"milestone,omitempty"` PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"` Repository *Repository `json:"repository,omitempty"` + Reactions *Reactions `json:"reactions,omitempty"` // TextMatches is only populated from search results that request text matches // See: search.go and https://developer.github.com/v3/search/#text-match-metadata @@ -131,6 +132,9 @@ func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]Issue, *R return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + issues := new([]Issue) resp, err := s.client.Do(req, issues) if err != nil { @@ -195,6 +199,9 @@ func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRe return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + issues := new([]Issue) resp, err := s.client.Do(req, issues) if err != nil { @@ -214,6 +221,9 @@ func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, *Res return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + issue := new(Issue) resp, err := s.client.Do(req, issue) if err != nil { diff --git a/github/issues_comments.go b/github/issues_comments.go index db48e14..6dbc31e 100644 --- a/github/issues_comments.go +++ b/github/issues_comments.go @@ -15,6 +15,7 @@ type IssueComment struct { ID *int `json:"id,omitempty"` Body *string `json:"body,omitempty"` User *User `json:"user,omitempty"` + Reactions *Reactions `json:"reactions,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` URL *string `json:"url,omitempty"` @@ -61,6 +62,10 @@ func (s *IssuesService) ListComments(owner string, repo string, number int, opt if err != nil { return nil, nil, err } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comments := new([]IssueComment) resp, err := s.client.Do(req, comments) if err != nil { @@ -80,6 +85,10 @@ func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueCom if err != nil { return nil, nil, err } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comment := new(IssueComment) resp, err := s.client.Do(req, comment) if err != nil { diff --git a/github/issues_comments_test.go b/github/issues_comments_test.go index 697f438..280fbd3 100644 --- a/github/issues_comments_test.go +++ b/github/issues_comments_test.go @@ -20,6 +20,7 @@ func TestIssuesService_ListComments_allIssues(t *testing.T) { mux.HandleFunc("/repos/o/r/issues/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{ "sort": "updated", "direction": "desc", @@ -52,6 +53,7 @@ func TestIssuesService_ListComments_specificIssue(t *testing.T) { mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `[{"id":1}]`) }) @@ -77,6 +79,7 @@ func TestIssuesService_GetComment(t *testing.T) { mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `{"id":1}`) }) diff --git a/github/issues_test.go b/github/issues_test.go index 46183f4..657e060 100644 --- a/github/issues_test.go +++ b/github/issues_test.go @@ -20,6 +20,7 @@ func TestIssuesService_List_all(t *testing.T) { mux.HandleFunc("/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{ "filter": "all", "state": "closed", @@ -56,6 +57,7 @@ func TestIssuesService_List_owned(t *testing.T) { mux.HandleFunc("/user/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `[{"number":1}]`) }) @@ -76,6 +78,7 @@ func TestIssuesService_ListByOrg(t *testing.T) { mux.HandleFunc("/orgs/o/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `[{"number":1}]`) }) @@ -101,6 +104,7 @@ func TestIssuesService_ListByRepo(t *testing.T) { mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{ "milestone": "*", "state": "closed", @@ -142,6 +146,7 @@ func TestIssuesService_Get(t *testing.T) { mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `{"number":1, "labels": [{"url": "u", "name": "n", "color": "c"}]}`) }) diff --git a/github/pulls_comments.go b/github/pulls_comments.go index 0b7e13b..247f179 100644 --- a/github/pulls_comments.go +++ b/github/pulls_comments.go @@ -22,6 +22,7 @@ type PullRequestComment struct { CommitID *string `json:"commit_id,omitempty"` OriginalCommitID *string `json:"original_commit_id,omitempty"` User *User `json:"user,omitempty"` + Reactions *Reactions `json:"reactions,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` URL *string `json:"url,omitempty"` @@ -70,6 +71,9 @@ func (s *PullRequestsService) ListComments(owner string, repo string, number int return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comments := new([]PullRequestComment) resp, err := s.client.Do(req, comments) if err != nil { @@ -89,6 +93,9 @@ func (s *PullRequestsService) GetComment(owner string, repo string, number int) return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comment := new(PullRequestComment) resp, err := s.client.Do(req, comment) if err != nil { diff --git a/github/pulls_comments_test.go b/github/pulls_comments_test.go index 7885ab1..8882456 100644 --- a/github/pulls_comments_test.go +++ b/github/pulls_comments_test.go @@ -20,6 +20,7 @@ func TestPullRequestsService_ListComments_allPulls(t *testing.T) { mux.HandleFunc("/repos/o/r/pulls/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{ "sort": "updated", "direction": "desc", @@ -53,6 +54,7 @@ func TestPullRequestsService_ListComments_specificPull(t *testing.T) { mux.HandleFunc("/repos/o/r/pulls/1/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `[{"id":1}]`) }) @@ -79,6 +81,7 @@ func TestPullRequestsService_GetComment(t *testing.T) { mux.HandleFunc("/repos/o/r/pulls/comments/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `{"id":1}`) }) diff --git a/github/reactions.go b/github/reactions.go new file mode 100644 index 0000000..283938a --- /dev/null +++ b/github/reactions.go @@ -0,0 +1,272 @@ +// Copyright 2016 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 "fmt" + +// ReactionsService provides access to the reactions-related functions in the +// GitHub API. +// +// GitHub API docs: https://developer.github.com/v3/reactions/ +type ReactionsService struct { + client *Client +} + +// Reaction represents a GitHub reaction. +type Reaction struct { + // ID is the Reaction ID. + ID *int `json:"id,omitempty"` + UserID *int `json:"user_id,omitempty"` + // Content is the type of reaction. + // Possible values are: + // "+1", "-1", "laugh", "confused", "heart", "hooray". + Content *string `json:"content,omitempty"` +} + +// Reactions represents a summary of GitHub reactions. +type Reactions struct { + TotalCount *int `json:"total_count,omitempty"` + PlusOne *int `json:"+1,omitempty"` + MinusOne *int `json:"-1,omitempty"` + Laugh *int `json:"laugh,omitempty"` + Confused *int `json:"confused,omitempty"` + Heart *int `json:"heart,omitempty"` + Hooray *int `json:"hooray,omitempty"` + URL *string `json:"url,omitempty"` +} + +func (r Reaction) String() string { + return Stringify(r) +} + +// ListCommentReactions lists the reactions for a commit comment. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment +func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// CreateCommentReaction creates a reaction for a commit comment. +// Note that if you have already created a reaction of type content, the +// previously created reaction will be returned with Status: 200 OK. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment +func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + req, err := s.client.NewRequest("POST", u, body) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// ListIssueReactions lists the reactions for an issue. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue +func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// CreateIssueReaction creates a reaction for an issue. +// Note that if you have already created a reaction of type content, the +// previously created reaction will be returned with Status: 200 OK. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue +func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) + + body := &Reaction{Content: String(content)} + req, err := s.client.NewRequest("POST", u, body) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// ListIssueCommentReactions lists the reactions for an issue comment. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment +func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// CreateIssueCommentReaction creates a reaction for an issue comment. +// Note that if you have already created a reaction of type content, the +// previously created reaction will be returned with Status: 200 OK. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment +func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + req, err := s.client.NewRequest("POST", u, body) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// ListPullRequestCommentReactions lists the reactions for a pull request review comment. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment +func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// CreatePullRequestCommentReaction creates a reaction for a pull request review comment. +// Note that if you have already created a reaction of type content, the +// previously created reaction will be returned with Status: 200 OK. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment +func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + req, err := s.client.NewRequest("POST", u, body) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// DeleteReaction deletes a reaction. +// +// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive +func (s *ReactionsService) DeleteReaction(id int) (*Response, error) { + u := fmt.Sprintf("/reactions/%v", id) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + return s.client.Do(req, nil) +} diff --git a/github/reactions_test.go b/github/reactions_test.go new file mode 100644 index 0000000..010cb8c --- /dev/null +++ b/github/reactions_test.go @@ -0,0 +1,200 @@ +// Copyright 2016 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 ( + "net/http" + "reflect" + "testing" +) + +func TestReactionsService_ListCommentReactions(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`[{"id":1,"user_id":2,"content":"+1"}]`)) + }) + + got, _, err := client.Reactions.ListCommentReactions("o", "r", 1, nil) + if err != nil { + t.Errorf("ListCommentReactions returned error: %v", err) + } + if want := []*Reaction{{ID: Int(1), UserID: Int(2), Content: String("+1")}}; !reflect.DeepEqual(got, want) { + t.Errorf("ListCommentReactions = %+v, want %+v", got, want) + } +} + +func TestReactionsService_CreateCommentReaction(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"id":1,"user_id":2,"content":"+1"}`)) + }) + + got, _, err := client.Reactions.CreateCommentReaction("o", "r", 1, "+1") + if err != nil { + t.Errorf("CreateCommentReaction returned error: %v", err) + } + want := &Reaction{ID: Int(1), UserID: Int(2), Content: String("+1")} + if !reflect.DeepEqual(got, want) { + t.Errorf("CreateCommentReaction = %+v, want %+v", got, want) + } +} + +func TestReactionsService_ListIssueReactions(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`[{"id":1,"user_id":2,"content":"+1"}]`)) + }) + + got, _, err := client.Reactions.ListIssueReactions("o", "r", 1, nil) + if err != nil { + t.Errorf("ListIssueReactions returned error: %v", err) + } + if want := []*Reaction{{ID: Int(1), UserID: Int(2), Content: String("+1")}}; !reflect.DeepEqual(got, want) { + t.Errorf("ListIssueReactions = %+v, want %+v", got, want) + } +} + +func TestReactionsService_CreateIssueReaction(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"id":1,"user_id":2,"content":"+1"}`)) + }) + + got, _, err := client.Reactions.CreateIssueReaction("o", "r", 1, "+1") + if err != nil { + t.Errorf("CreateIssueReaction returned error: %v", err) + } + want := &Reaction{ID: Int(1), UserID: Int(2), Content: String("+1")} + if !reflect.DeepEqual(got, want) { + t.Errorf("CreateIssueReaction = %+v, want %+v", got, want) + } +} + +func TestReactionsService_ListIssueCommentReactions(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`[{"id":1,"user_id":2,"content":"+1"}]`)) + }) + + got, _, err := client.Reactions.ListIssueCommentReactions("o", "r", 1, nil) + if err != nil { + t.Errorf("ListIssueCommentReactions returned error: %v", err) + } + if want := []*Reaction{{ID: Int(1), UserID: Int(2), Content: String("+1")}}; !reflect.DeepEqual(got, want) { + t.Errorf("ListIssueCommentReactions = %+v, want %+v", got, want) + } +} + +func TestReactionsService_CreateIssueCommentReaction(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"id":1,"user_id":2,"content":"+1"}`)) + }) + + got, _, err := client.Reactions.CreateIssueCommentReaction("o", "r", 1, "+1") + if err != nil { + t.Errorf("CreateIssueCommentReaction returned error: %v", err) + } + want := &Reaction{ID: Int(1), UserID: Int(2), Content: String("+1")} + if !reflect.DeepEqual(got, want) { + t.Errorf("CreateIssueCommentReaction = %+v, want %+v", got, want) + } +} + +func TestReactionsService_ListPullRequestCommentReactions(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/pulls/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`[{"id":1,"user_id":2,"content":"+1"}]`)) + }) + + got, _, err := client.Reactions.ListPullRequestCommentReactions("o", "r", 1, nil) + if err != nil { + t.Errorf("ListPullRequestCommentReactions returned error: %v", err) + } + if want := []*Reaction{{ID: Int(1), UserID: Int(2), Content: String("+1")}}; !reflect.DeepEqual(got, want) { + t.Errorf("ListPullRequestCommentReactions = %+v, want %+v", got, want) + } +} + +func TestReactionsService_CreatePullRequestCommentReaction(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/pulls/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"id":1,"user_id":2,"content":"+1"}`)) + }) + + got, _, err := client.Reactions.CreatePullRequestCommentReaction("o", "r", 1, "+1") + if err != nil { + t.Errorf("CreatePullRequestCommentReaction returned error: %v", err) + } + want := &Reaction{ID: Int(1), UserID: Int(2), Content: String("+1")} + if !reflect.DeepEqual(got, want) { + t.Errorf("CreatePullRequestCommentReaction = %+v, want %+v", got, want) + } +} + +func TestReactionsService_DeleteReaction(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/reactions/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) + + w.WriteHeader(http.StatusNoContent) + }) + + if _, err := client.Reactions.DeleteReaction(1); err != nil { + t.Errorf("DeleteReaction returned error: %v", err) + } +} diff --git a/github/repos_comments.go b/github/repos_comments.go index 2d090bb..bba0fe7 100644 --- a/github/repos_comments.go +++ b/github/repos_comments.go @@ -17,6 +17,7 @@ type RepositoryComment struct { ID *int `json:"id,omitempty"` CommitID *string `json:"commit_id,omitempty"` User *User `json:"user,omitempty"` + Reactions *Reactions `json:"reactions,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` @@ -46,6 +47,9 @@ func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comments := new([]RepositoryComment) resp, err := s.client.Do(req, comments) if err != nil { @@ -70,6 +74,9 @@ func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *L return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comments := new([]RepositoryComment) resp, err := s.client.Do(req, comments) if err != nil { @@ -109,6 +116,9 @@ func (s *RepositoriesService) GetComment(owner, repo string, id int) (*Repositor return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + c := new(RepositoryComment) resp, err := s.client.Do(req, c) if err != nil { diff --git a/github/repos_comments_test.go b/github/repos_comments_test.go index b5a8786..ddede06 100644 --- a/github/repos_comments_test.go +++ b/github/repos_comments_test.go @@ -19,6 +19,7 @@ func TestRepositoriesService_ListComments(t *testing.T) { mux.HandleFunc("/repos/o/r/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{"page": "2"}) fmt.Fprint(w, `[{"id":1}, {"id":2}]`) }) @@ -46,6 +47,7 @@ func TestRepositoriesService_ListCommitComments(t *testing.T) { mux.HandleFunc("/repos/o/r/commits/s/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) testFormValues(t, r, values{"page": "2"}) fmt.Fprint(w, `[{"id":1}, {"id":2}]`) }) @@ -107,6 +109,7 @@ func TestRepositoriesService_GetComment(t *testing.T) { mux.HandleFunc("/repos/o/r/comments/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeReactionsPreview) fmt.Fprint(w, `{"id":1}`) })