@@ -3,10 +3,11 @@ package githubapi
import (
"context"
"fmt"
"log"
"sort"
"strings"
"dmitri.shuralyov.com/changes"
"github.com/google/go-github/github"
"github.com/shurcooL/githubql"
@@ -331,26 +332,32 @@ func (s service) ListTimeline(ctx context.Context, rs string, id uint64, opt *ch
OID string
URL string
}
MergeRefName string
} `graphql:"...on MergedEvent"`
PullRequestReview struct {
Author githubqlActor
CreatedAt githubql.DateTime
State githubql.PullRequestReviewState
} `graphql:"...on PullRequestReview"`
}
} `graphql:"timeline(first:100)"` // TODO: Pagination...
// Need to use PullRequest.Reviews rather than PullRequest.Timeline.PullRequestReview,
// because the latter is missing single-inline-reply reviews (as of 2018-02-08).
Reviews struct {
Nodes []struct {
DatabaseID uint64
Author githubqlActor
PublishedAt githubql.DateTime
LastEditedAt *githubql.DateTime
Editor *githubqlActor
State githubql.PullRequestReviewState
Body string
ViewerCanUpdate bool
Comments struct {
Nodes []struct {
Path string
OriginalPosition int
Body string
}
} `graphql:"comments(first:100)"` // TODO: Pagination... Figure out how to make pagination across 2 resource types work...
}
} `graphql:"reviews(first:100)"` // TODO: Pagination... Figure out how to make pagination across 2 resource types work...
} `graphql:"pullRequest(number:$prNumber)"`
} `graphql:"repository(owner:$repositoryOwner,name:$repositoryName)"`
}
@@ -412,27 +419,40 @@ func (s service) ListTimeline(ctx context.Context, rs string, id uint64, opt *ch
Reactions: reactions,
Editable: comment.ViewerCanUpdate,
})
}
for _, review := range q.Repository.PullRequest.Reviews.Nodes {
if review.Body == "" {
continue
}
var edited *changes.Edited
if review.LastEditedAt != nil {
edited = &changes.Edited{
By: ghActor(*review.Editor),
At: review.LastEditedAt.Time,
}
}
timeline = append(timeline, changes.Comment{
var cs []changes.InlineComment
for _, comment := range review.Comments.Nodes {
cs = append(cs, changes.InlineComment{
File: comment.Path,
Line: comment.OriginalPosition,
Body: comment.Body,
})
}
sort.Slice(cs, func(i, j int) bool {
if cs[i].File == cs[j].File {
return cs[i].Line < cs[j].Line
}
return cs[i].File < cs[j].File
})
timeline = append(timeline, changes.Review{
ID: review.DatabaseID,
User: ghActor(review.Author),
CreatedAt: review.PublishedAt.Time,
Edited: edited,
State: ghPRReviewState(review.State),
Body: review.Body,
Editable: review.ViewerCanUpdate,
Comments: cs,
})
}
for _, event := range q.Repository.PullRequest.Timeline.Nodes {
e := changes.TimelineItem{
//ID: 0, // TODO.
@@ -493,23 +513,10 @@ func (s service) ListTimeline(ctx context.Context, rs string, id uint64, opt *ch
e.Payload = changes.MergedEvent{
CommitID: event.MergedEvent.Commit.OID,
CommitHTMLURL: event.MergedEvent.Commit.URL,
RefName: event.MergedEvent.MergeRefName,
}
case "PullRequestReview":
switch event.PullRequestReview.State {
case githubql.PullRequestReviewStateApproved:
// TODO: Make this a thing that ListComments returns, etc. After all, it can have a non-empty body.
e.Payload = changes.ApprovedEvent{}
case githubql.PullRequestReviewStateChangesRequested:
// TODO: Make this a thing that ListComments returns, etc. After all, it can have a non-empty body.
e.Payload = changes.ChangesRequestedEvent{}
default:
continue
}
e.Actor = ghActor(event.PullRequestReview.Author)
e.CreatedAt = event.PullRequestReview.CreatedAt.Time
default:
continue
}
timeline = append(timeline, e)
}
@@ -634,10 +641,28 @@ func ghPRState(state githubql.PullRequestState) changes.State {
default:
panic("unreachable")
}
}
// ghPRReviewState converts a GitHub PullRequestReviewState to changes.ReviewState.
func ghPRReviewState(state githubql.PullRequestReviewState) changes.ReviewState {
switch state {
case githubql.PullRequestReviewStateApproved:
return changes.Approved
case githubql.PullRequestReviewStateCommented:
return changes.Commented
case githubql.PullRequestReviewStateChangesRequested:
return changes.ChangesRequested
case githubql.PullRequestReviewStatePending:
panic("PullRequestReviewStatePending not implemented") // TODO.
case githubql.PullRequestReviewStateDismissed:
panic("PullRequestReviewStateDismissed not implemented") // TODO.
default:
panic("unreachable")
}
}
// ghColor converts a GitHub color hex string like "ff0000"
// into an issues.RGB value.
func ghColor(hex string) issues.RGB {
var c issues.RGB
fmt.Sscanf(hex, "%02x%02x%02x", &c.R, &c.G, &c.B)