From 7c0f2b9843f67ec49ea0038692648a531138a055 Mon Sep 17 00:00:00 2001
From: Mario Lubenka <mario.lubenka@googlemail.com>
Date: Thu, 27 Jun 2019 16:15:30 +0200
Subject: [PATCH] Show Pull Request button or status of latest PR in branch
 list (#6990)

* Show Pull Request button or status of latest PR in branch list

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Do not show pull request button on deleted branches

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Do not show commit divergence on deleted branches

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Use XORMs Get instead of limit

* Links pull request ID and use smaller labels for displaying the pull request status

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Handle error when getting latest pull request

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Indent template

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Check error when loading issue

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
---
 models/pull.go                  | 14 ++++++++++++
 routers/repo/branch.go          | 38 ++++++++++++++++++++++-----------
 templates/repo/branch/list.tmpl | 25 ++++++++++++++++++++--
 3 files changed, 63 insertions(+), 14 deletions(-)

diff --git a/models/pull.go b/models/pull.go
index 2f5412651..eac36235b 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -776,6 +776,20 @@ func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequ
 		Find(&prs)
 }
 
+// GetLatestPullRequestByHeadInfo returns the latest pull request (regardless of its status)
+// by given head information (repo and branch).
+func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, error) {
+	pr := new(PullRequest)
+	has, err := x.
+		Where("head_repo_id = ? AND head_branch = ?", repoID, branch).
+		OrderBy("id DESC").
+		Get(pr)
+	if !has {
+		return nil, err
+	}
+	return pr, err
+}
+
 // GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged
 // by given base information (repo and branch).
 func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) {
diff --git a/routers/repo/branch.go b/routers/repo/branch.go
index 05d64fb4c..708b33be0 100644
--- a/routers/repo/branch.go
+++ b/routers/repo/branch.go
@@ -24,13 +24,14 @@ const (
 
 // Branch contains the branch information
 type Branch struct {
-	Name          string
-	Commit        *git.Commit
-	IsProtected   bool
-	IsDeleted     bool
-	DeletedBranch *models.DeletedBranch
-	CommitsAhead  int
-	CommitsBehind int
+	Name              string
+	Commit            *git.Commit
+	IsProtected       bool
+	IsDeleted         bool
+	DeletedBranch     *models.DeletedBranch
+	CommitsAhead      int
+	CommitsBehind     int
+	LatestPullRequest *models.PullRequest
 }
 
 // Branches render repository branch page
@@ -181,12 +182,25 @@ func loadBranches(ctx *context.Context) []*Branch {
 			return nil
 		}
 
+		pr, err := models.GetLatestPullRequestByHeadInfo(ctx.Repo.Repository.ID, branchName)
+		if err != nil {
+			ctx.ServerError("GetLatestPullRequestByHeadInfo", err)
+			return nil
+		}
+		if pr != nil {
+			if err := pr.LoadIssue(); err != nil {
+				ctx.ServerError("pr.LoadIssue", err)
+				return nil
+			}
+		}
+
 		branches[i] = &Branch{
-			Name:          branchName,
-			Commit:        commit,
-			IsProtected:   isProtected,
-			CommitsAhead:  divergence.Ahead,
-			CommitsBehind: divergence.Behind,
+			Name:              branchName,
+			Commit:            commit,
+			IsProtected:       isProtected,
+			CommitsAhead:      divergence.Ahead,
+			CommitsBehind:     divergence.Behind,
+			LatestPullRequest: pr,
 		}
 	}
 
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index 58e77f2c1..a2fb5c206 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -26,7 +26,8 @@
 				<table class="ui very basic striped fixed table single line">
 					<thead>
 						<tr>
-							<th class="seven wide">{{.i18n.Tr "repo.branch.name"}}</th>
+							<th class="six wide">{{.i18n.Tr "repo.branch.name"}}</th>
+							<th class="two wide"></th>
 							<th class="two wide"></th>
 							{{if and $.IsWriter (not $.IsMirror)}}
 								<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
@@ -44,9 +45,10 @@
 									{{else}}
 										<a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a>
 										<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
-									</td>
 									{{end}}
+									</td>
 									<td class="ui">
+										{{if not .IsDeleted}}
 										<div class="commit-divergence">
 											<div class="bar-group">
 												<div class="count count-behind">{{.CommitsBehind}}</div>
@@ -57,6 +59,25 @@
                                             	<div class="bar bar-ahead" style="width: {{percentage .CommitsAhead .CommitsBehind .CommitsAhead}}%"></div>
 											</div>
 										</div>
+										{{end}}
+									</td>
+									<td class="right aligned">
+										{{if not .LatestPullRequest}}
+											{{if not .IsDeleted}}
+											<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
+												<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
+											</a>
+											{{end}}
+										{{else}}
+											<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}">#{{.LatestPullRequest.Issue.Index}}</a>
+											{{if .LatestPullRequest.HasMerged}}
+												<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui purple small label"><i class="octicon octicon-git-pull-request"></i> {{$.i18n.Tr "repo.pulls.merged"}}</a>
+											{{else if .LatestPullRequest.Issue.IsClosed}}
+												<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui red small label"><i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.closed_title"}}</a>
+											{{else}}
+												<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui green small label"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.open_title"}}</a>
+											{{end}}
+										{{end}}
 									</td>
 									{{if and $.IsWriter (not $.IsMirror)}}
 										<td class="right aligned">