Skip to content

Commit 2e07d0f

Browse files
desprestonmislav
andauthored
pr status: show number of approvals (cli#4240)
If the base branch has no minimum approval requirements, show "N Approved" reviews. Otherwise, show "N/X Approved". Co-authored-by: Mislav Marohnić <mislav@github.com>
1 parent d307646 commit 2e07d0f

File tree

6 files changed

+71
-4
lines changed

6 files changed

+71
-4
lines changed

api/export_pr.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ func (pr *PullRequest) ExportData(fields []string) map[string]interface{} {
7575
data[f] = pr.ProjectCards.Nodes
7676
case "reviews":
7777
data[f] = pr.Reviews.Nodes
78+
case "latestReviews":
79+
data[f] = pr.LatestReviews.Nodes
7880
case "files":
7981
data[f] = pr.Files.Nodes
8082
case "reviewRequests":

api/queries_pr.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ type PullRequest struct {
6464

6565
BaseRef struct {
6666
BranchProtectionRule struct {
67-
RequiresStrictStatusChecks bool
67+
RequiresStrictStatusChecks bool
68+
RequiredApprovingReviewCount int
6869
}
6970
}
7071

@@ -108,6 +109,7 @@ type PullRequest struct {
108109
Comments Comments
109110
ReactionGroups ReactionGroups
110111
Reviews PullRequestReviews
112+
LatestReviews PullRequestReviews
111113
ReviewRequests ReviewRequests
112114
}
113115

@@ -405,6 +407,11 @@ func PullRequestStatus(client *Client, repo ghrepo.Interface, options StatusOpti
405407
}
406408
pullRequest(number: $number) {
407409
...prWithReviews
410+
baseRef {
411+
branchProtectionRule {
412+
requiredApprovingReviewCount
413+
}
414+
}
408415
}
409416
}
410417
`
@@ -519,7 +526,7 @@ func pullRequestFragment(httpClient *http.Client, hostname string) (string, erro
519526

520527
var reviewFields []string
521528
if prFeatures.HasReviewDecision {
522-
reviewFields = append(reviewFields, "reviewDecision")
529+
reviewFields = append(reviewFields, "reviewDecision", "latestReviews")
523530
}
524531

525532
fragments := fmt.Sprintf(`

api/query_builder.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ var prReviews = shortenQuery(`
8282
}
8383
`)
8484

85+
var prLatestReviews = shortenQuery(`
86+
latestReviews(first: 100) {
87+
nodes {
88+
author{login},
89+
authorAssociation,
90+
submittedAt,
91+
body,
92+
state
93+
}
94+
}
95+
`)
96+
8597
var prFiles = shortenQuery(`
8698
files(first: 100) {
8799
nodes {
@@ -180,6 +192,7 @@ var PullRequestFields = append(IssueFields,
180192
"headRepositoryOwner",
181193
"isCrossRepository",
182194
"isDraft",
195+
"latestReviews",
183196
"maintainerCanModify",
184197
"mergeable",
185198
"mergeCommit",
@@ -229,6 +242,8 @@ func PullRequestGraphQL(fields []string) string {
229242
q = append(q, prReviewRequests)
230243
case "reviews":
231244
q = append(q, prReviews)
245+
case "latestReviews":
246+
q = append(q, prLatestReviews)
232247
case "files":
233248
q = append(q, prFiles)
234249
case "commits":

pkg/cmd/pr/status/fixtures/prStatusChecks.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,33 @@
4444
"url": "https://github.com/cli/cli/pull/7",
4545
"headRefName": "banananana",
4646
"reviewDecision": "APPROVED",
47+
"baseRef": {
48+
"branchProtectionRule": {
49+
"requiredApprovingReviewCount": 0
50+
}
51+
},
52+
"latestReviews": {
53+
"nodes": [
54+
{
55+
"author": {
56+
"login": "bob"
57+
},
58+
"state": "APPROVED"
59+
},
60+
{
61+
"author": {
62+
"login": "stella"
63+
},
64+
"state": "CHANGES_REQUESTED"
65+
},
66+
{
67+
"author": {
68+
"login": "alice"
69+
},
70+
"state": "APPROVED"
71+
}
72+
]
73+
},
4774
"statusCheckRollup": {
4875
"nodes": [
4976
{

pkg/cmd/pr/status/status.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ func prSelectorForCurrentBranch(baseRepo ghrepo.Interface, prHeadRef string, rem
199199
return
200200
}
201201

202+
func totalApprovals(pr *api.PullRequest) int {
203+
approvals := 0
204+
for _, review := range pr.LatestReviews.Nodes {
205+
if review.State == "APPROVED" {
206+
approvals++
207+
}
208+
}
209+
return approvals
210+
}
211+
202212
func printPrs(io *iostreams.IOStreams, totalCount int, prs ...api.PullRequest) {
203213
w := io.Out
204214
cs := io.ColorScheme()
@@ -246,7 +256,13 @@ func printPrs(io *iostreams.IOStreams, totalCount int, prs ...api.PullRequest) {
246256
} else if reviews.ReviewRequired {
247257
fmt.Fprint(w, cs.Yellow("- Review required"))
248258
} else if reviews.Approved {
249-
fmt.Fprint(w, cs.Green("✓ Approved"))
259+
numRequiredApprovals := pr.BaseRef.BranchProtectionRule.RequiredApprovingReviewCount
260+
gotApprovals := totalApprovals(&pr)
261+
s := fmt.Sprintf("%d", gotApprovals)
262+
if numRequiredApprovals > 0 {
263+
s = fmt.Sprintf("%d/%d", gotApprovals, numRequiredApprovals)
264+
}
265+
fmt.Fprint(w, cs.Green(fmt.Sprintf("✓ %s Approved", s)))
250266
}
251267

252268
if pr.BaseRef.BranchProtectionRule.RequiresStrictStatusChecks {

pkg/cmd/pr/status/status_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func TestPRStatus_reviewsAndChecks(t *testing.T) {
112112

113113
expected := []string{
114114
"✓ Checks passing + Changes requested",
115-
"- Checks pending ✓ Approved",
115+
"- Checks pending ✓ 2 Approved",
116116
"× 1/3 checks failing - Review required",
117117
}
118118

0 commit comments

Comments
 (0)