@@ -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)