Skip to content

Commit 0dcf31a

Browse files
kolaentelafriks
authored andcommitted
Show review summary in pull requests (#5132)
1 parent cef0f12 commit 0dcf31a

File tree

8 files changed

+179
-2
lines changed

8 files changed

+179
-2
lines changed

models/fixtures/review.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,43 @@
3030
content: "Pending Review"
3131
updated_unix: 946684810
3232
created_unix: 946684810
33+
-
34+
id: 5
35+
type: 2
36+
reviewer_id: 1
37+
issue_id: 3
38+
content: "New review 1"
39+
updated_unix: 946684810
40+
created_unix: 946684810
41+
-
42+
id: 6
43+
type: 0
44+
reviewer_id: 2
45+
issue_id: 3
46+
content: "New review 3"
47+
updated_unix: 946684810
48+
created_unix: 946684810
49+
-
50+
id: 7
51+
type: 3
52+
reviewer_id: 3
53+
issue_id: 3
54+
content: "New review 4"
55+
updated_unix: 946684810
56+
created_unix: 946684810
57+
-
58+
id: 8
59+
type: 1
60+
reviewer_id: 4
61+
issue_id: 3
62+
content: "New review 5"
63+
updated_unix: 946684810
64+
created_unix: 946684810
65+
-
66+
id: 9
67+
type: 3
68+
reviewer_id: 2
69+
issue_id: 3
70+
content: "New review 3 rejected"
71+
updated_unix: 946684810
72+
created_unix: 946684810

models/review.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,36 @@ func UpdateReview(r *Review) error {
255255
}
256256
return nil
257257
}
258+
259+
// PullReviewersWithType represents the type used to display a review overview
260+
type PullReviewersWithType struct {
261+
User `xorm:"extends"`
262+
Type ReviewType
263+
ReviewUpdatedUnix util.TimeStamp `xorm:"review_updated_unix"`
264+
}
265+
266+
// GetReviewersByPullID gets all reviewers for a pull request with the statuses
267+
func GetReviewersByPullID(pullID int64) (issueReviewers []*PullReviewersWithType, err error) {
268+
irs := []*PullReviewersWithType{}
269+
err = x.Select("`user`.*, review.type, max(review.updated_unix) as review_updated_unix").
270+
Table("review").
271+
Join("INNER", "`user`", "review.reviewer_id = `user`.id").
272+
Where("review.issue_id = ? AND (review.type = ? OR review.type = ?)", pullID, ReviewTypeApprove, ReviewTypeReject).
273+
GroupBy("`user`.id, review.type").
274+
OrderBy("review_updated_unix DESC").
275+
Find(&irs)
276+
277+
// We need to group our results by user id _and_ review type, otherwise the query fails when using postgresql.
278+
// But becaus we're doing this, we need to manually filter out multiple reviews of different types by the
279+
// same person because we only want to show the newest review grouped by user. Thats why we're using a map here.
280+
issueReviewers = []*PullReviewersWithType{}
281+
usersInArray := make(map[int64]bool)
282+
for _, ir := range irs {
283+
if !usersInArray[ir.ID] {
284+
issueReviewers = append(issueReviewers, ir)
285+
usersInArray[ir.ID] = true
286+
}
287+
}
288+
289+
return
290+
}

models/review_test.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func TestGetCurrentReview(t *testing.T) {
7474
assert.Equal(t, ReviewTypePending, review.Type)
7575
assert.Equal(t, "Pending Review", review.Content)
7676

77-
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
77+
user2 := AssertExistsAndLoadBean(t, &User{ID: 7}).(*User)
7878
review2, err := GetCurrentReview(user2, issue)
7979
assert.Error(t, err)
8080
assert.True(t, IsErrReviewNotExist(err))
@@ -105,3 +105,33 @@ func TestUpdateReview(t *testing.T) {
105105
assert.NoError(t, UpdateReview(review))
106106
AssertExistsAndLoadBean(t, &Review{ID: 1, Content: "Updated Review"})
107107
}
108+
109+
func TestGetReviewersByPullID(t *testing.T) {
110+
assert.NoError(t, PrepareTestDatabase())
111+
112+
issue := AssertExistsAndLoadBean(t, &Issue{ID: 3}).(*Issue)
113+
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
114+
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
115+
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
116+
117+
expectedReviews := []*PullReviewersWithType{}
118+
expectedReviews = append(expectedReviews, &PullReviewersWithType{
119+
User: *user2,
120+
Type: ReviewTypeReject,
121+
ReviewUpdatedUnix: 946684810,
122+
},
123+
&PullReviewersWithType{
124+
User: *user3,
125+
Type: ReviewTypeReject,
126+
ReviewUpdatedUnix: 946684810,
127+
},
128+
&PullReviewersWithType{
129+
User: *user4,
130+
Type: ReviewTypeApprove,
131+
ReviewUpdatedUnix: 946684810,
132+
})
133+
134+
allReviews, err := GetReviewersByPullID(issue.ID)
135+
assert.NoError(t, err)
136+
assert.Equal(t, expectedReviews, allReviews)
137+
}

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ issues.review.content.empty = You need to leave a comment indicating the request
832832
issues.review.reject = "rejected these changes %s"
833833
issues.review.pending = Pending
834834
issues.review.review = Review
835+
issues.review.reviewers = Reviewers
835836
issues.review.show_outdated = Show outdated
836837
issues.review.hide_outdated = Hide outdated
837838

public/css/index.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/less/_repository.less

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,38 @@
556556
margin-top: 10px;
557557
}
558558
}
559+
.review-item {
560+
561+
.avatar, .type-icon{
562+
float: none;
563+
display: inline-block;
564+
text-align: center;
565+
vertical-align: middle;
566+
567+
.octicon {
568+
width: 23px;
569+
font-size: 23px;
570+
margin-top: 0.45em;
571+
}
572+
}
573+
574+
.text {
575+
margin: .3em 0 .5em .5em
576+
}
577+
578+
.type-icon{
579+
float: right;
580+
margin-right: 1em;
581+
}
582+
583+
.divider{
584+
margin: .5rem 0;
585+
}
586+
587+
.review-content {
588+
padding: 1em 0 1em 3.8em;
589+
}
590+
}
559591
}
560592
.comment-list {
561593
&:before {

routers/repo/issue.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,12 @@ func ViewIssue(ctx *context.Context) {
802802
}
803803
}
804804
ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch)
805+
806+
ctx.Data["PullReviewersWithType"], err = models.GetReviewersByPullID(issue.ID)
807+
if err != nil {
808+
ctx.ServerError("GetReviewersByPullID", err)
809+
return
810+
}
805811
}
806812

807813
// Get Dependencies

templates/repo/issue/view_content/pull.tmpl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
{{if gt (len .PullReviewersWithType) 0}}
2+
<div class="comment box">
3+
<div class="content">
4+
<div class="ui segment">
5+
<h4>{{$.i18n.Tr "repo.issues.review.reviewers"}}</h4>
6+
{{range .PullReviewersWithType}}
7+
{{ $createdStr:= TimeSinceUnix .ReviewUpdatedUnix $.Lang }}
8+
<div class="ui divider"></div>
9+
<div class="review-item">
10+
<span class="type-icon text {{if eq .Type 1}}green
11+
{{else if eq .Type 2}}grey
12+
{{else if eq .Type 3}}red
13+
{{else}}grey{{end}}">
14+
<span class="octicon octicon-{{.Type.Icon}}"></span>
15+
</span>
16+
<a class="ui avatar image" href="{{.HomeLink}}">
17+
<img src="{{.RelAvatarLink}}">
18+
</a>
19+
<span class="text grey"><a href="{{.HomeLink}}">{{.Name}}</a>
20+
{{if eq .Type 1}}
21+
{{$.i18n.Tr "repo.issues.review.approve" $createdStr | Safe}}
22+
{{else if eq .Type 2}}
23+
{{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}}
24+
{{else if eq .Type 3}}
25+
{{$.i18n.Tr "repo.issues.review.reject" $createdStr | Safe}}
26+
{{else}}
27+
{{$.i18n.Tr "repo.issues.review.comment" $createdStr | Safe}}
28+
{{end}}
29+
</span>
30+
</div>
31+
{{end}}
32+
</div>
33+
</div>
34+
</div>
35+
{{end}}
136
<div class="comment merge box">
237
<a class="avatar text
338
{{if .Issue.PullRequest.HasMerged}}purple

0 commit comments

Comments
 (0)