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"
|
"bytes"
|
||||||
"container/list"
|
"container/list"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -306,3 +308,40 @@ func GetLatestCommitTime(repoPath string) (time.Time, error) {
|
||||||
commitTime := strings.TrimSpace(stdout)
|
commitTime := strings.TrimSpace(stdout)
|
||||||
return time.Parse(GitTimeLayout, commitTime)
|
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
|
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;
|
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 {
|
&.commits {
|
||||||
.header {
|
.header {
|
||||||
.search {
|
.search {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/repofiles"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +29,8 @@ type Branch struct {
|
||||||
IsProtected bool
|
IsProtected bool
|
||||||
IsDeleted bool
|
IsDeleted bool
|
||||||
DeletedBranch *models.DeletedBranch
|
DeletedBranch *models.DeletedBranch
|
||||||
|
CommitsAhead int
|
||||||
|
CommitsBehind int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branches render repository branch page
|
// Branches render repository branch page
|
||||||
|
@ -168,16 +171,25 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||||
return nil
|
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 {
|
if err != nil {
|
||||||
ctx.ServerError("IsProtectedBranch", err)
|
ctx.ServerError("IsProtectedBranch", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
|
||||||
|
if divergenceError != nil {
|
||||||
|
ctx.ServerError("CountDivergingCommits", divergenceError)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
branches[i] = &Branch{
|
branches[i] = &Branch{
|
||||||
Name: rawBranches[i].Name,
|
Name: branchName,
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
IsProtected: isProtected,
|
IsProtected: isProtected,
|
||||||
|
CommitsAhead: divergence.Ahead,
|
||||||
|
CommitsBehind: divergence.Behind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
<table class="ui very basic striped fixed table single line">
|
<table class="ui very basic striped fixed table single line">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<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)}}
|
{{if and $.IsWriter (not $.IsMirror)}}
|
||||||
<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
|
<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -45,6 +46,18 @@
|
||||||
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
|
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{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)}}
|
{{if and $.IsWriter (not $.IsMirror)}}
|
||||||
<td class="right aligned">
|
<td class="right aligned">
|
||||||
{{if .IsProtected}}
|
{{if .IsProtected}}
|
||||||
|
|
Reference in a new issue