mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	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:
		@@ -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 New Issue
	
	Block a user