Number of commits ahead/behind in branch overview (#6695)
* Call Git API to determine divergence of a branch and its base branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show commit divergance in branch list Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds missing comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds test for diverging commits Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Try comparing commits instead of branches Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes test as CI can't run it Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjusts signature of percentage function to allow providing multiple integers as numerator Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves CountDivergingCommits function into repofiles module Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
This commit is contained in:
parent
c1da790cee
commit
55a8e12d85
7 changed files with 132 additions and 6 deletions
|
@ -9,9 +9,11 @@ import (
|
|||
"bytes"
|
||||
"container/list"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -306,3 +308,40 @@ func GetLatestCommitTime(repoPath string) (time.Time, error) {
|
|||
commitTime := strings.TrimSpace(stdout)
|
||||
return time.Parse(GitTimeLayout, commitTime)
|
||||
}
|
||||
|
||||
// DivergeObject represents commit count diverging commits
|
||||
type DivergeObject struct {
|
||||
Ahead int
|
||||
Behind int
|
||||
}
|
||||
|
||||
func checkDivergence(repoPath string, baseBranch string, targetBranch string) (int, error) {
|
||||
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
|
||||
cmd := NewCommand("rev-list", "--count", branches)
|
||||
stdout, err := cmd.RunInDir(repoPath)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
outInteger, errInteger := strconv.Atoi(strings.Trim(stdout, "\n"))
|
||||
if errInteger != nil {
|
||||
return -1, errInteger
|
||||
}
|
||||
return outInteger, nil
|
||||
}
|
||||
|
||||
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
|
||||
func GetDivergingCommits(repoPath string, baseBranch string, targetBranch string) (DivergeObject, error) {
|
||||
// $(git rev-list --count master..feature) commits ahead of master
|
||||
ahead, errorAhead := checkDivergence(repoPath, baseBranch, targetBranch)
|
||||
if errorAhead != nil {
|
||||
return DivergeObject{}, errorAhead
|
||||
}
|
||||
|
||||
// $(git rev-list --count feature..master) commits behind master
|
||||
behind, errorBehind := checkDivergence(repoPath, targetBranch, baseBranch)
|
||||
if errorBehind != nil {
|
||||
return DivergeObject{}, errorBehind
|
||||
}
|
||||
|
||||
return DivergeObject{ahead, behind}, nil
|
||||
}
|
||||
|
|
19
modules/repofiles/commit.go
Normal file
19
modules/repofiles/commit.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repofiles
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
)
|
||||
|
||||
// CountDivergingCommits determines how many commits a branch is ahead or behind the repository's base branch
|
||||
func CountDivergingCommits(repo *models.Repository, branch string) (*git.DivergeObject, error) {
|
||||
divergence, err := git.GetDivergingCommits(repo.RepoPath(), repo.DefaultBranch, branch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &divergence, nil
|
||||
}
|
|
@ -223,6 +223,13 @@ func NewFuncMap() []template.FuncMap {
|
|||
}
|
||||
return dict, nil
|
||||
},
|
||||
"percentage": func(n int, values ...int) float32 {
|
||||
var sum = 0
|
||||
for i := 0; i < len(values); i++ {
|
||||
sum += values[i]
|
||||
}
|
||||
return float32(n) * 100 / float32(sum)
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -963,6 +963,42 @@
|
|||
margin-top: 1px!important;
|
||||
}
|
||||
|
||||
&.branches {
|
||||
.commit-divergence {
|
||||
.bar-group {
|
||||
position: relative;
|
||||
float: left;
|
||||
padding-bottom: 6px;
|
||||
width: 90px;
|
||||
|
||||
&:last-child {
|
||||
border-left: 1px solid #b4b4b4;
|
||||
}
|
||||
}
|
||||
.count {
|
||||
margin: 0 3px;
|
||||
&.count-ahead {
|
||||
text-align: left;
|
||||
}
|
||||
&.count-behind {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.bar {
|
||||
height: 4px;
|
||||
position: absolute;
|
||||
background-color: #d4d4d5;
|
||||
|
||||
&.bar-behind {
|
||||
right: 0;
|
||||
}
|
||||
&.bar-ahead {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.commits {
|
||||
.header {
|
||||
.search {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
|
@ -28,6 +29,8 @@ type Branch struct {
|
|||
IsProtected bool
|
||||
IsDeleted bool
|
||||
DeletedBranch *models.DeletedBranch
|
||||
CommitsAhead int
|
||||
CommitsBehind int
|
||||
}
|
||||
|
||||
// Branches render repository branch page
|
||||
|
@ -168,16 +171,25 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||
return nil
|
||||
}
|
||||
|
||||
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(rawBranches[i].Name, ctx.User)
|
||||
branchName := rawBranches[i].Name
|
||||
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsProtectedBranch", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
|
||||
if divergenceError != nil {
|
||||
ctx.ServerError("CountDivergingCommits", divergenceError)
|
||||
return nil
|
||||
}
|
||||
|
||||
branches[i] = &Branch{
|
||||
Name: rawBranches[i].Name,
|
||||
Commit: commit,
|
||||
IsProtected: isProtected,
|
||||
Name: branchName,
|
||||
Commit: commit,
|
||||
IsProtected: isProtected,
|
||||
CommitsAhead: divergence.Ahead,
|
||||
CommitsBehind: divergence.Behind,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
<table class="ui very basic striped fixed table single line">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="nine wide">{{.i18n.Tr "repo.branch.name"}}</th>
|
||||
<th class="seven wide">{{.i18n.Tr "repo.branch.name"}}</th>
|
||||
<th class="two wide"></th>
|
||||
{{if and $.IsWriter (not $.IsMirror)}}
|
||||
<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
|
||||
{{end}}
|
||||
|
@ -45,6 +46,18 @@
|
|||
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="ui">
|
||||
<div class="commit-divergence">
|
||||
<div class="bar-group">
|
||||
<div class="count count-behind">{{.CommitsBehind}}</div>
|
||||
<div class="bar bar-behind" style="width: {{percentage .CommitsBehind .CommitsBehind .CommitsAhead}}%"></div>
|
||||
</div>
|
||||
<div class="bar-group">
|
||||
<div class="count count-ahead">{{.CommitsAhead}}</div>
|
||||
<div class="bar bar-ahead" style="width: {{percentage .CommitsAhead .CommitsBehind .CommitsAhead}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{{if and $.IsWriter (not $.IsMirror)}}
|
||||
<td class="right aligned">
|
||||
{{if .IsProtected}}
|
||||
|
|
Reference in a new issue