Add pager to the branches page (#14202)

* Add pager to the branches page

* override pageSize if bigger than max

* Make branches commit range configurable

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
Chester Liu 2021-01-19 12:07:38 +08:00 committed by GitHub
parent 8d0e331c0a
commit 0c0445c97a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 160 additions and 88 deletions

View file

@ -1098,6 +1098,10 @@ MAX_GIT_DIFF_LINES = 1000
MAX_GIT_DIFF_LINE_CHARACTERS = 5000 MAX_GIT_DIFF_LINE_CHARACTERS = 5000
; Max number of files shown in diff view ; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100 MAX_GIT_DIFF_FILES = 100
; Set the default commits range size
COMMITS_RANGE_SIZE = 50
; Set the default branches range size
BRANCHES_RANGE_SIZE = 20
; Arguments for command 'git gc', e.g. "--aggressive --auto" ; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/ ; see more on http://git-scm.com/docs/git-gc/
GC_ARGS = GC_ARGS =

View file

@ -752,6 +752,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
- `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view. - `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view.
- `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view. - `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view.
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
- `COMMITS_RANGE_SIZE`: **50**: Set the default commits range size
- `BRANCHES_RANGE_SIZE`: **20**: Set the default branches range size
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/ - `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1 - `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
- `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled) - `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)

View file

@ -110,6 +110,9 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
// CommitsRangeSize the default commits range size // CommitsRangeSize the default commits range size
var CommitsRangeSize = 50 var CommitsRangeSize = 50
// BranchesRangeSize the default branches range size
var BranchesRangeSize = 20
func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) (*list.List, error) { func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) (*list.List, error) {
stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize), stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path) "--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path)

View file

@ -19,6 +19,8 @@ var (
MaxGitDiffLines int MaxGitDiffLines int
MaxGitDiffLineCharacters int MaxGitDiffLineCharacters int
MaxGitDiffFiles int MaxGitDiffFiles int
CommitsRangeSize int
BranchesRangeSize int
VerbosePush bool VerbosePush bool
VerbosePushDelay time.Duration VerbosePushDelay time.Duration
GCArgs []string `ini:"GC_ARGS" delim:" "` GCArgs []string `ini:"GC_ARGS" delim:" "`
@ -37,6 +39,8 @@ var (
MaxGitDiffLines: 1000, MaxGitDiffLines: 1000,
MaxGitDiffLineCharacters: 5000, MaxGitDiffLineCharacters: 5000,
MaxGitDiffFiles: 100, MaxGitDiffFiles: 100,
CommitsRangeSize: 50,
BranchesRangeSize: 20,
VerbosePush: true, VerbosePush: true,
VerbosePushDelay: 5 * time.Second, VerbosePushDelay: 5 * time.Second,
GCArgs: []string{}, GCArgs: []string{},
@ -91,5 +95,8 @@ func newGit() {
args = append(args, "Version 2") // for focus color args = append(args, "Version 2") // for focus color
} }
git.CommitsRangeSize = Git.CommitsRangeSize
git.BranchesRangeSize = Git.BranchesRangeSize
log.Info(format, args...) log.Info(format, args...)
} }

View file

@ -52,7 +52,25 @@ func Branches(ctx *context.Context) {
ctx.Data["PageIsViewCode"] = true ctx.Data["PageIsViewCode"] = true
ctx.Data["PageIsBranches"] = true ctx.Data["PageIsBranches"] = true
ctx.Data["Branches"] = loadBranches(ctx) page := ctx.QueryInt("page")
if page <= 1 {
page = 1
}
pageSize := ctx.QueryInt("limit")
if pageSize <= 0 || pageSize > git.BranchesRangeSize {
pageSize = git.BranchesRangeSize
}
branches, branchesCount := loadBranches(ctx, page, pageSize)
if ctx.Written() {
return
}
ctx.Data["Branches"] = branches
pager := context.NewPagination(int(branchesCount), git.BranchesRangeSize, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
ctx.HTML(200, tplBranch) ctx.HTML(200, tplBranch)
} }
@ -176,17 +194,25 @@ func deleteBranch(ctx *context.Context, branchName string) error {
return nil return nil
} }
func loadBranches(ctx *context.Context) []*Branch { // loadBranches loads branches from the repository limited by page & pageSize.
// NOTE: May write to context on error. page & pageSize must be > 0
func loadBranches(ctx *context.Context, page, pageSize int) ([]*Branch, int) {
defaultBranch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch)
if err != nil {
ctx.ServerError("GetDefaultBranch", err)
return nil, 0
}
rawBranches, err := repo_module.GetBranches(ctx.Repo.Repository) rawBranches, err := repo_module.GetBranches(ctx.Repo.Repository)
if err != nil { if err != nil {
ctx.ServerError("GetBranches", err) ctx.ServerError("GetBranches", err)
return nil return nil, 0
} }
protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches() protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
if err != nil { if err != nil {
ctx.ServerError("GetProtectedBranches", err) ctx.ServerError("GetProtectedBranches", err)
return nil return nil, 0
} }
repoIDToRepo := map[int64]*models.Repository{} repoIDToRepo := map[int64]*models.Repository{}
@ -195,100 +221,129 @@ func loadBranches(ctx *context.Context) []*Branch {
repoIDToGitRepo := map[int64]*git.Repository{} repoIDToGitRepo := map[int64]*git.Repository{}
repoIDToGitRepo[ctx.Repo.Repository.ID] = ctx.Repo.GitRepo repoIDToGitRepo[ctx.Repo.Repository.ID] = ctx.Repo.GitRepo
branches := make([]*Branch, len(rawBranches)) var totalNumOfBranches = len(rawBranches)
for i := range rawBranches { var startIndex = (page - 1) * pageSize
commit, err := rawBranches[i].GetCommit() if startIndex > totalNumOfBranches {
if err != nil { startIndex = totalNumOfBranches - 1
ctx.ServerError("GetCommit", err)
return nil
}
var isProtected bool
branchName := rawBranches[i].Name
for _, b := range protectedBranches {
if b.BranchName == branchName {
isProtected = true
break
}
}
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, git.BranchPrefix+branchName)
if divergenceError != nil {
ctx.ServerError("CountDivergingCommits", divergenceError)
return nil
}
pr, err := models.GetLatestPullRequestByHeadInfo(ctx.Repo.Repository.ID, branchName)
if err != nil {
ctx.ServerError("GetLatestPullRequestByHeadInfo", err)
return nil
}
headCommit := commit.ID.String()
mergeMovedOn := false
if pr != nil {
pr.HeadRepo = ctx.Repo.Repository
if err := pr.LoadIssue(); err != nil {
ctx.ServerError("pr.LoadIssue", err)
return nil
}
if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok {
pr.BaseRepo = repo
} else if err := pr.LoadBaseRepo(); err != nil {
ctx.ServerError("pr.LoadBaseRepo", err)
return nil
} else {
repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
}
pr.Issue.Repo = pr.BaseRepo
if pr.HasMerged {
baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
if !ok {
baseGitRepo, err = git.OpenRepository(pr.BaseRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
}
defer baseGitRepo.Close()
repoIDToGitRepo[pr.BaseRepoID] = baseGitRepo
}
pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("GetBranchCommitID", err)
return nil
}
if err == nil && headCommit != pullCommit {
// the head has moved on from the merge - we shouldn't delete
mergeMovedOn = true
}
}
}
isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName
branches[i] = &Branch{
Name: branchName,
Commit: commit,
IsProtected: isProtected,
IsIncluded: isIncluded,
CommitsAhead: divergence.Ahead,
CommitsBehind: divergence.Behind,
LatestPullRequest: pr,
MergeMovedOn: mergeMovedOn,
}
} }
var endIndex = startIndex + pageSize
if endIndex > totalNumOfBranches {
endIndex = totalNumOfBranches - 1
}
var branches []*Branch
for i := startIndex; i < endIndex; i++ {
var branch = loadOneBranch(ctx, rawBranches[i], protectedBranches, repoIDToRepo, repoIDToGitRepo)
if branch == nil {
return nil, 0
}
if branch.Name == ctx.Repo.Repository.DefaultBranch {
// Skip default branch
continue
}
branches = append(branches, branch)
}
// Always add the default branch
branches = append(branches, loadOneBranch(ctx, defaultBranch, protectedBranches, repoIDToRepo, repoIDToGitRepo))
if ctx.Repo.CanWrite(models.UnitTypeCode) { if ctx.Repo.CanWrite(models.UnitTypeCode) {
deletedBranches, err := getDeletedBranches(ctx) deletedBranches, err := getDeletedBranches(ctx)
if err != nil { if err != nil {
ctx.ServerError("getDeletedBranches", err) ctx.ServerError("getDeletedBranches", err)
return nil return nil, 0
} }
branches = append(branches, deletedBranches...) branches = append(branches, deletedBranches...)
} }
return branches return branches, len(rawBranches) - 1
}
func loadOneBranch(ctx *context.Context, rawBranch *git.Branch, protectedBranches []*models.ProtectedBranch,
repoIDToRepo map[int64]*models.Repository,
repoIDToGitRepo map[int64]*git.Repository) *Branch {
commit, err := rawBranch.GetCommit()
if err != nil {
ctx.ServerError("GetCommit", err)
return nil
}
branchName := rawBranch.Name
var isProtected bool
for _, b := range protectedBranches {
if b.BranchName == branchName {
isProtected = true
break
}
}
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, git.BranchPrefix+branchName)
if divergenceError != nil {
ctx.ServerError("CountDivergingCommits", divergenceError)
return nil
}
pr, err := models.GetLatestPullRequestByHeadInfo(ctx.Repo.Repository.ID, branchName)
if err != nil {
ctx.ServerError("GetLatestPullRequestByHeadInfo", err)
return nil
}
headCommit := commit.ID.String()
mergeMovedOn := false
if pr != nil {
pr.HeadRepo = ctx.Repo.Repository
if err := pr.LoadIssue(); err != nil {
ctx.ServerError("pr.LoadIssue", err)
return nil
}
if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok {
pr.BaseRepo = repo
} else if err := pr.LoadBaseRepo(); err != nil {
ctx.ServerError("pr.LoadBaseRepo", err)
return nil
} else {
repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
}
pr.Issue.Repo = pr.BaseRepo
if pr.HasMerged {
baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
if !ok {
baseGitRepo, err = git.OpenRepository(pr.BaseRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
}
defer baseGitRepo.Close()
repoIDToGitRepo[pr.BaseRepoID] = baseGitRepo
}
pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("GetBranchCommitID", err)
return nil
}
if err == nil && headCommit != pullCommit {
// the head has moved on from the merge - we shouldn't delete
mergeMovedOn = true
}
}
}
isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName
return &Branch{
Name: branchName,
Commit: commit,
IsProtected: isProtected,
IsIncluded: isIncluded,
CommitsAhead: divergence.Ahead,
CommitsBehind: divergence.Behind,
LatestPullRequest: pr,
MergeMovedOn: mergeMovedOn,
}
} }
func getDeletedBranches(ctx *context.Context) ([]*Branch, error) { func getDeletedBranches(ctx *context.Context) ([]*Branch, error) {

View file

@ -127,6 +127,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{{template "base/paginate" .}}
{{end}} {{end}}
</div> </div>
</div> </div>