Repository: palantir/policy-bot (go)

Issue:
FR: Handle approvals embedded in GHE review comments
Sometimes a user will make a slightly weird, but otherwise correct review, and we'll see something like 

User1 reviewed with a comment:
```
 👍 
```

Policybot looks at the comment text and the result of the github approval, but not the _text_ of the github approval. I believe this is covered in the slightly different [reviews api](https://developer.github.com/v3/pulls/reviews/), so these types of "approvals" aren't counted.

Pull request description:
Add support for handling review comments
This PR adds support for handling review comments like regular comments, thus allowing users to approve or disapprove without switching back to the "Conversation" tab of the pull request whilst reviewing the changes.

Fixes #51.

Patch:
diff --git a/pull/github.go b/pull/github.go
index 01cc8f2..b690183 100644
--- a/pull/github.go
+++ b/pull/github.go
@@ -519,7 +519,7 @@ func (ghc *GitHubContext) loadPagedData() error {
 				Reviews struct {
 					PageInfo v4PageInfo
 					Nodes    []v4PullRequestReview
-				} `graphql:"reviews(first: 100, after: $reviewCursor, states: [APPROVED, CHANGES_REQUESTED])"`
+				} `graphql:"reviews(first: 100, after: $reviewCursor, states: [APPROVED, CHANGES_REQUESTED, COMMENTED])"`
 			} `graphql:"pullRequest(number: $number)"`
 		} `graphql:"repository(owner: $owner, name: $name)"`
 	}
@@ -548,7 +548,12 @@ func (ghc *GitHubContext) loadPagedData() error {
 		}
 
 		for _, r := range q.Repository.PullRequest.Reviews.Nodes {
-			reviews = append(reviews, r.ToReview())
+			switch r.State {
+			case "COMMENTED":
+				comments = append(comments, r.ToComment())
+			case "APPROVED", "CHANGES_REQUESTED":
+				reviews = append(reviews, r.ToReview())
+			}
 		}
 		if !q.Repository.PullRequest.Reviews.PageInfo.UpdateCursor(qvars, "reviewCursor") {
 			complete++
@@ -784,6 +789,14 @@ func (r *v4PullRequestReview) ToReview() *Review {
 	}
 }
 
+func (r *v4PullRequestReview) ToComment() *Comment {
+	return &Comment{
+		CreatedAt: r.SubmittedAt,
+		Author:    r.Author.GetV3Login(),
+		Body:      r.Body,
+	}
+}
+
 type v4IssueComment struct {
 	Author    v4Actor
 	Body      string


Test patch:
diff --git a/pull/github_test.go b/pull/github_test.go
index 2a09c42..689c3d2 100644
--- a/pull/github_test.go
+++ b/pull/github_test.go
@@ -241,7 +241,7 @@ func TestComments(t *testing.T) {
 	comments, err := ctx.Comments()
 	require.NoError(t, err)
 
-	require.Len(t, comments, 2, "incorrect number of comments")
+	require.Len(t, comments, 3, "incorrect number of comments")
 	assert.Equal(t, 2, dataRule.Count, "no http request was made")
 
 	expectedTime, err := time.Parse(time.RFC3339, "2018-06-27T20:28:22Z")
@@ -255,11 +255,15 @@ func TestComments(t *testing.T) {
 	assert.Equal(t, expectedTime.Add(time.Minute), comments[1].CreatedAt)
 	assert.Equal(t, "I merge!", comments[1].Body)
 
+	assert.Equal(t, "jgiannuzzi", comments[2].Author)
+	assert.Equal(t, expectedTime.Add(10*time.Minute), comments[2].CreatedAt)
+	assert.Equal(t, "A review comment", comments[2].Body)
+
 	// verify that the commit list is cached
 	comments, err = ctx.Comments()
 	require.NoError(t, err)
 
-	require.Len(t, comments, 2, "incorrect number of comments")
+	require.Len(t, comments, 3, "incorrect number of comments")
 	assert.Equal(t, 2, dataRule.Count, "cached comments were not used")
 }
 
@@ -359,7 +363,7 @@ func TestMixedReviewCommentPaging(t *testing.T) {
 	require.NoError(t, err)
 
 	assert.Equal(t, 2, dataRule.Count, "cached values were not used")
-	assert.Len(t, comments, 2, "incorrect number of comments")
+	assert.Len(t, comments, 3, "incorrect number of comments")
 	assert.Len(t, reviews, 2, "incorrect number of reviews")
 }
 
diff --git a/pull/testdata/responses/pull_comments.yml b/pull/testdata/responses/pull_comments.yml
index 83cdd80..44871b4 100644
--- a/pull/testdata/responses/pull_comments.yml
+++ b/pull/testdata/responses/pull_comments.yml
@@ -20,6 +20,22 @@
                   "createdAt": "2018-06-27T20:28:22Z"
                 }
               ]
+            },
+            "reviews": {
+              "pageInfo": {
+                "endCursor": "2",
+                "hasNextPage": true
+              },
+              "nodes": [
+                {
+                  "author": {
+                    "login": "mhaypenny"
+                  },
+                  "state": "CHANGES_REQUESTED",
+                  "body": "",
+                  "submittedAt": "2018-06-27T20:33:26Z"
+                }
+              ]
             }
           }
         }
@@ -47,6 +63,30 @@
                   "createdAt": "2018-06-27T20:29:22Z"
                 }
               ]
+            },
+            "reviews": {
+              "pageInfo": {
+                "endCursor": "3",
+                "hasNextPage": false
+              },
+              "nodes": [
+                {
+                  "author": {
+                    "login": "bkeyes"
+                  },
+                  "state": "APPROVED",
+                  "body": "the body",
+                  "submittedAt": "2018-06-27T20:33:27Z"
+                },
+                {
+                  "author": {
+                    "login": "jgiannuzzi"
+                  },
+                  "state": "COMMENTED",
+                  "body": "A review comment",
+                  "submittedAt": "2018-06-27T20:38:22Z"
+                }
+              ]
             }
           }
         }
diff --git a/pull/testdata/responses/pull_reviews.yml b/pull/testdata/responses/pull_reviews.yml
index 80de094..173372e 100644
--- a/pull/testdata/responses/pull_reviews.yml
+++ b/pull/testdata/responses/pull_reviews.yml
@@ -45,6 +45,14 @@
                   "state": "APPROVED",
                   "body": "the body",
                   "submittedAt": "2018-06-27T20:33:27Z"
+                },
+                {
+                  "author": {
+                    "login": "jgiannuzzi"
+                  },
+                  "state": "COMMENTED",
+                  "body": "A review comment",
+                  "submittedAt": "2018-06-27T20:38:22Z"
                 }
               ]
             }
diff --git a/pull/testdata/responses/pull_reviews_comments.yml b/pull/testdata/responses/pull_reviews_comments.yml
index b2e975e..b538626 100644
--- a/pull/testdata/responses/pull_reviews_comments.yml
+++ b/pull/testdata/responses/pull_reviews_comments.yml
@@ -76,6 +76,14 @@
                   "state": "APPROVED",
                   "body": "the body",
                   "submittedAt": "2018-06-27T20:33:27Z"
+                },
+                {
+                  "author": {
+                    "login": "jgiannuzzi"
+                  },
+                  "state": "COMMENTED",
+                  "body": "A review comment",
+                  "submittedAt": "2018-06-27T20:38:22Z"
                 }
               ]
             }