From 0c0445c97a9219f7a9f7f2afd618b31bf958e14f Mon Sep 17 00:00:00 2001 From: Chester Liu Date: Tue, 19 Jan 2021 12:07:38 +0800 Subject: [PATCH] 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 Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: silverwind --- custom/conf/app.example.ini | 4 + .../doc/advanced/config-cheat-sheet.en-us.md | 2 + modules/git/repo_commit.go | 3 + modules/setting/git.go | 7 + routers/repo/branch.go | 231 +++++++++++------- templates/repo/branch/list.tmpl | 1 + 6 files changed, 160 insertions(+), 88 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 3920f5112..8921e3a5d 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1098,6 +1098,10 @@ MAX_GIT_DIFF_LINES = 1000 MAX_GIT_DIFF_LINE_CHARACTERS = 5000 ; Max number of files shown in diff view 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" ; see more on http://git-scm.com/docs/git-gc/ GC_ARGS = diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 5b86cadd4..50d6a0722 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -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_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. +- `COMMITS_RANGE_SIZE`: **50**: Set the default commits range size +- `BRANCHES_RANGE_SIZE`: **20**: Set the default branches range size - `GC_ARGS`: **\**: 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 - `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) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index c31f41662..f02fdde5a 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -110,6 +110,9 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) { // CommitsRangeSize the default commits range size var CommitsRangeSize = 50 +// BranchesRangeSize the default branches range size +var BranchesRangeSize = 20 + func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) (*list.List, error) { stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize), "--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path) diff --git a/modules/setting/git.go b/modules/setting/git.go index 80170e37b..308d94894 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -19,6 +19,8 @@ var ( MaxGitDiffLines int MaxGitDiffLineCharacters int MaxGitDiffFiles int + CommitsRangeSize int + BranchesRangeSize int VerbosePush bool VerbosePushDelay time.Duration GCArgs []string `ini:"GC_ARGS" delim:" "` @@ -37,6 +39,8 @@ var ( MaxGitDiffLines: 1000, MaxGitDiffLineCharacters: 5000, MaxGitDiffFiles: 100, + CommitsRangeSize: 50, + BranchesRangeSize: 20, VerbosePush: true, VerbosePushDelay: 5 * time.Second, GCArgs: []string{}, @@ -91,5 +95,8 @@ func newGit() { args = append(args, "Version 2") // for focus color } + git.CommitsRangeSize = Git.CommitsRangeSize + git.BranchesRangeSize = Git.BranchesRangeSize + log.Info(format, args...) } diff --git a/routers/repo/branch.go b/routers/repo/branch.go index 81e8916af..bf9f2e6a3 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -52,7 +52,25 @@ func Branches(ctx *context.Context) { ctx.Data["PageIsViewCode"] = 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) } @@ -176,17 +194,25 @@ func deleteBranch(ctx *context.Context, branchName string) error { 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) if err != nil { ctx.ServerError("GetBranches", err) - return nil + return nil, 0 } protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches() if err != nil { ctx.ServerError("GetProtectedBranches", err) - return nil + return nil, 0 } repoIDToRepo := map[int64]*models.Repository{} @@ -195,100 +221,129 @@ func loadBranches(ctx *context.Context) []*Branch { repoIDToGitRepo := map[int64]*git.Repository{} repoIDToGitRepo[ctx.Repo.Repository.ID] = ctx.Repo.GitRepo - branches := make([]*Branch, len(rawBranches)) - for i := range rawBranches { - commit, err := rawBranches[i].GetCommit() - if err != nil { - 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 totalNumOfBranches = len(rawBranches) + var startIndex = (page - 1) * pageSize + if startIndex > totalNumOfBranches { + startIndex = totalNumOfBranches - 1 } + 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) { deletedBranches, err := getDeletedBranches(ctx) if err != nil { ctx.ServerError("getDeletedBranches", err) - return nil + return nil, 0 } 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) { diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index cf7c22462..8176738ff 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -127,6 +127,7 @@ + {{template "base/paginate" .}} {{end}}