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 requestreviewers #557

Merged
merged 16 commits into from
Mar 8, 2017
Merged

Add requestreviewers #557

merged 16 commits into from
Mar 8, 2017

Conversation

sevki
Copy link
Contributor

@sevki sevki commented Feb 18, 2017

this commit adds the RequestReviewers function as described here

https://developer.github.com/v3/pulls/review_requests/#create-a-review-request

btw: sorry I'm new to the codebase and followed the CONTRIBUTING to the best
of my ability, if you have any fixes I'll do my best to address them

Resolves #516.

@dmitshur
Copy link
Member

@sevki, is this meant to resolve (partially or in full) #516?

@sevki
Copy link
Contributor Author

sevki commented Feb 22, 2017

@shurcooL complete but I wanted to get something clear before I did the other two (list, delete).
I am not sure about the naming, it's not analogous to the GitHub API because PullRequestReviewRequest was already a thing. I think the request there, correct me if I'm wrong, refers to the HTTP request. and PullRequestReviewRequestRequest sounded very Java-like. So I wanted to avoid that. Are you ok with the patch as is?

@dmitshur
Copy link
Member

PullRequestReviewRequest was already a thing. I think the request there, correct me if I'm wrong, refers to the HTTP request. and PullRequestReviewRequestRequest sounded very Java-like.

We have a pattern where some structs have Request or Options suffix. Usually, Request suffix is used for methods that create new things. It's a request to create that thing. And options are usually used for other methods, like options for listing. E.g.:

// IssueRequest represents a request to create/edit an issue.
// It is separate from Issue above because otherwise Labels
// and Assignee fail to serialize to the correct JSON.
type IssueRequest struct {
// MilestoneListOptions specifies the optional parameters to the
// IssuesService.ListMilestones method.
type MilestoneListOptions struct 

So, in the case of PullRequestReviewRequest:

// PullRequestReviewRequest represents a request to create a review.
type PullRequestReviewRequest struct {

It's a request to create a PR review. It's a parameter for CreateReview and SubmitReview methods.

From what I see in https://developer.github.com/v3/pulls/review_requests/, there are 3 operations that can be done with "review requests":

  • List
  • Create
  • Delete

But review requests are basically github usernames. Both Create and Delete operations contain nothing more than an array of user logins. List operation returns an array of users.

I think we can get away without creating any structs for these 3 methods. That would be simpler.

How about something like this?

// ListReviewers lists users whose reviews have been requested on the specified pull request.
//
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests
func (s *PullRequestsService) ListReviewers(owner, repo string, number int) (*[]User, *Response, error) {
	...
}

// RequestReviewers creates a review request for the provided GitHub users for the specified pull request.
//
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request
func (s *PullRequestsService) RequestReviewers(owner, repo string, number int, reviewers []string) (*PullRequest, *Response, error) {
	...
}

// RemoveReviewers removes the review request for the provided GitHub users for the specified pull request.
//
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request
func (s *PullRequestsService) RemoveReviewers(owner, repo string, number int, reviewers []string) (*Response, error) {
	...
}

It is inspired by similar operations that can be done on issue assignees. See https://github.com/google/go-github/blob/master/github/issues_assignees.go.

@varadarajana
Copy link
Contributor

@sevki in your PR createRequest is done, please tell me if I can take up list and Delete methods or you have already finished them.

@sevki
Copy link
Contributor Author

sevki commented Feb 25, 2017

@varadarajana ah yeah they are, sorry forgot to push them.

@varadarajana
Copy link
Contributor

@sevki The build is failing here.

github/pulls_reviews_request.go:79: not enough arguments in call to s.client.Do
The command "go test -v -race ./..." exited with 2.

I think it might be due to context parameter added recently, can you please check if you have the latest version from the mainline.

Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sevki. The actual implementation is looking good, but I have some comments on improving the tests.

want := []User{
{
Login: &_login,
ID: &_id,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go style doesn't use underscores in identifier names, see https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps.

Also, these variables are not needed. This can be replaced with:

{
	Login: String("octocat"),
	ID:    Int(1),
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

})

// This returns a PR, unmarshalling of which is tested elsewhere
have, _, err := client.PullRequests.ListReviewers(context.Background(), "o", "r", 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename have to reviewers for consistency with other tests.

Alternatively, use the word got rather than have. Some other tests use got, but no one uses have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fmt.Fprintf(w, sampleResponse)
})

// This returns a PR, unmarshalling of which is tested elsewhere
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. ListReviewers returns a []*User, not *PullRequest. Is there a mistake here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

ID: &_id,
},
}
if !reflect.DeepEqual(have, &want) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it work without taking address of want, i.e.:

if !reflect.DeepEqual(have, want) {

Or would that fail? Other tests don't seem to take address of want usually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it breaks the tests.
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the error message say?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, I see that it's because ListReviewers returns *[]User and not []User. Your new version looks good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shurcooL I looked at a couple of things and saw they return pointers to arrays, is that not the consistent thing to do? if not I can change it

Reviewers: logins,
}
if !reflect.DeepEqual(have, want) {
t.Errorf("PullRequests.ListReviews returned %+v, want %+v", have, want)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading an not accurate. It says "PullRequests.ListReviews", but the method that was called was PullRequests.RemoveReviewers".

I think you should move this check directly inside mux.HandleFunc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Looks like I mixed Remove and Request 😃

type reviewers struct {
Reviewers []string `json:"reviewers,omitempty"`
}
have := reviewers{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use have here, see detailed comments below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

type reviewers struct {
Reviewers []string `json:"reviewers,omitempty"`
}
have := reviewers{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use have here either, see comments below.

"fmt"
)

// RequestReviewers submits a set of logins to be potential reviewers on a PR.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be nicer to stay closer to the language the GitHub API docs use and say that this method creates a "review request". What do you think of what I wrote earlier?

// RequestReviewers creates a review request for the provided GitHub users for the specified pull request.

That seems more consistent with the other endpoints (like the remove one).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

- changed have to reviewers, to do that I have declared a
reviewersRequest type but it's scope is limited to the test package
- checking requests are now performed inside the mux functions
Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. Some more minor suggestions, and I think that's all I have.

setup()
defer teardown()

sampleResponse := `[
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can inline this, it's used in one place. Also, make it a single line, it's short enough to be readable:

[{"login": "octocat", "id": 1}]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

@dmitshur dmitshur Feb 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You said 👍 here, but you didn't apply this change. Did you miss it?

I mean the part about "make it a single line, it's short enough to be readable".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooops.

}
if !reflect.DeepEqual(reviewers, want) {
t.Errorf("PullRequests.RemoveReviewers returned %+v, want %+v", reviewers, want)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can replace all of the above, starting with b, err := ioutil.ReadAll(r.Body), with:

testBody(t, r, `{"reviewers":["octocat","googlebot"]}`)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

func TestRemoveReviewers(t *testing.T) {
setup()
defer teardown()
logins := []string{"octocat", "googlebot"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline logins, it's used in one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
if !reflect.DeepEqual(reviewers, want) {
t.Errorf("PullRequests.RequestReviewers returned %+v, want %+v", reviewers, want)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can replace all of the above, starting with b, err := ioutil.ReadAll(r.Body), with:

testBody(t, r, `{"reviewers":["octocat","googlebot"]}`)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

setup()
defer teardown()

logins := []string{"octocat", "googlebot"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline logins, it's used in one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


type reviewersRequest struct {
Reviewers []string `json:"reviewers,omitempty"`
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you apply my suggestions below, this won't be needed, so remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
})

// This returns a PR, unmarshalling of which is tested elsewhere
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not hard to test it. You don't need to test all fields. Just include the PR number.

In the response handler above, add this at the end:

fmt.Fprint(w, `{"number":1}`)

And then do:

pull, _, err := client.PullRequests.RequestReviewers(...)
...

want := &PullRequest{Number: Int(1)}
if !reflect.DeepEqual(pull, want) {
	t.Errorf("PullRequests.RequestReviewers returned %+v, want %+v", pull, want)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if err != nil {
t.Errorf("PullRequests.RequestReviewers returned error: %v", err)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, remove the unnecessary and inconsistent blank line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypePullRequestReviewsPreview)
fmt.Fprintf(w, sampleResponse)
Copy link
Member

@dmitshur dmitshur Feb 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use fmt.Fprintf where fmt.Fprint will suffice. You don't want the extra formatting options if you're not using them, they can only cause unwanted issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request
func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo string, number int, logins []string) (*PullRequest, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number)
reviewers := struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, RemoveReviewers has a blank line between u and reviewers, but this doesn't. Please make it consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

- use testBody()
- inline logins
- fix formatting
Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're getting to the end of all issues I was able to spot. Just 3 more minor typos.

},
}
if !reflect.DeepEqual(reviewers, want) {
t.Errorf("PullRequests.ListReviews returned %+v, want %+v", reviewers, want)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/PullRequests.ListReviews/PullRequests.ListReviewers


_, err := client.PullRequests.RemoveReviewers(context.Background(), "o", "r", 1, []string{"octocat", "googlebot"})
if err != nil {
t.Errorf("PullRequests.RequestReviewers returned error: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/PullRequests.RequestReviewers/PullRequests.RemoveReviewers


reviewers, _, err := client.PullRequests.ListReviewers(context.Background(), "o", "r", 1)
if err != nil {
t.Errorf("PullRequests.ListReviewers error: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consitency with lines 34 and 50 (and elsewhere in the project), insert the word "returned":

t.Errorf("PullRequests.ListReviewers returned error: %v", err)

@sevki
Copy link
Contributor Author

sevki commented Feb 28, 2017

@shurcooL so the latest changes are going to wail because testBody() don't seem to trim whitespace. the request body seems to end with a new line but the inlined JSON doesn't. Is this an issue you are aware of or am I doing something wrong?

@dmitshur
Copy link
Member

@shurcooL so the latest changes are going to wail because testBody() don't seem to trim whitespace. the request body seems to end with a new line but the inlined JSON doesn't. Is this an issue you are aware of or am I doing something wrong?

That's fine, just add a newline to expected JSON output. See here for example:

testBody(t, r, `{"last_read_at":"2006-01-02T15:04:05Z"}`+"\n")

@sevki
Copy link
Contributor Author

sevki commented Feb 28, 2017

can I send a PR to trim whitespace when reading the testBody?

@dmitshur
Copy link
Member

dmitshur commented Feb 28, 2017

Also, @sevki, please prefer to push new commits rather than amending previous ones and force pushing. New commits make it easier to review just the changes you've done. Thanks!

@dmitshur
Copy link
Member

dmitshur commented Feb 28, 2017

can I send a PR to trim whitespace when reading the testBody?

I'd rather we don't do that, I think it's better to be explicit. If we trim whitespace in testBody, it wouldn't catch an issue where we accidentally send too much unwanted whitespace.

It's easy enough to explicitly include a newline in the expected JSON string.

- fix some typos
- add new line to test body
@sevki
Copy link
Contributor Author

sevki commented Feb 28, 2017

cool

@@ -58,12 +58,12 @@ func TestListReviewers(t *testing.T) {
mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypePullRequestReviewsPreview)
fmt.Fprint(w, `[{"login": "octocat","id": 1 }]`)
fmt.Fprint(w, `[{"login": "octocat","id":1}]`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you decided to keep the space between "login": and "octocat", but not between "id": and 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not using monospace fonts so I missed it.

Copy link
Member

@dmitshur dmitshur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sevki.

I'm not spotting any other issues.

I've edited your PR description to add "Resolves #516.", since this PR will now fully resolve that issue.

@gmlewis, can you review the API we've gone with here? It's not a direct 1:1 mapping to the names that GitHub documentation uses, because we tried to make it a cleaner API without the need for a PullRequestReviewRequestRequest struct. How does it look to you?

@sevki
Copy link
Contributor Author

sevki commented Feb 28, 2017

@shurcooL thanks for the review.

Copy link
Collaborator

@gmlewis gmlewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the requested changes, I like it.
Thank you, @sevki and @shurcooL!

// ListReviewers lists users whose reviews have been requested on the specified pull request.
//
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests
func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo string, number int) (*[]User, *Response, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to return a pointer to a slice. Just return the slice which is already a reference type.

...([]User, *Response, error) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! Yes! Where was my brain?

return nil, resp, err
}

return &users, resp, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return users, resp, nil

t.Errorf("PullRequests.ListReviewers returned error: %v", err)
}

want := &[]User{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want := []User{

Copy link
Member

@dmitshur dmitshur Mar 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on #557 (comment), this should become:

want := []*User{

want := &[]User{
{
want := []*User{
&User{
Copy link
Member

@dmitshur dmitshur Mar 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not neccessary to include &User{ here, just { as before will do.

In fact, it causes Travis to fail because we check that gofmt -s doesn't find any missed opportunities to simplify:

image

The rest of this change is perfect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@sevki
Copy link
Contributor Author

sevki commented Mar 5, 2017

@shurcooL done.

@dmitshur
Copy link
Member

dmitshur commented Mar 5, 2017

@gmlewis PTAL.

Copy link
Collaborator

@gmlewis gmlewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @sevki and @shurcooL!
LGTM.

@sevki
Copy link
Contributor Author

sevki commented Mar 6, 2017

@gmlewis my pleasure. @shurcooL did all the heavy lifting 😄

@dmitshur dmitshur merged commit cfbfe91 into google:master Mar 8, 2017
@dmitshur
Copy link
Member

dmitshur commented Mar 8, 2017

Thanks @sevki!

bubg-dev pushed a commit to bubg-dev/go-github that referenced this pull request Jun 16, 2017
Add support for an addition to the Pull Request Reviews API,
the ability to manage Review Requests.

GitHub announcement: https://developer.github.com/changes/2016-12-16-review-requests-api/
GitHub API docs: https://developer.github.com/v3/pulls/review_requests/

Resolves google#516.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for Preview Review Requests API
4 participants