From 36f1fa779213695db249d2215233e9cec2d5da7c Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 3 Jul 2023 09:00:28 +0800 Subject: [PATCH] Support displaying diff stats in PR tab bar (#25387) Fix #25326 --------- Co-authored-by: silverwind --- routers/web/repo/pull.go | 54 +++++++++++++++++++++++++++--- routers/web/web.go | 3 +- services/gitdiff/gitdiff.go | 36 ++++++++++++++++++++ templates/repo/pulls/tab_menu.tmpl | 6 ++++ 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 950979a6ed..c543d90e19 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -356,12 +356,46 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink() } -// PrepareMergedViewPullInfo show meta information for a merged pull request view page -func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.CompareInfo { +// GetPullDiffStats get Pull Requests diff stats +func GetPullDiffStats(ctx *context.Context) { + issue := checkPullInfo(ctx) pull := issue.PullRequest - setMergeTarget(ctx, pull) - ctx.Data["HasMerged"] = true + mergeBaseCommitID := GetMergedBaseCommitID(ctx, issue) + + if ctx.Written() { + return + } else if mergeBaseCommitID == "" { + ctx.NotFound("PullFiles", nil) + return + } + + headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName()) + if err != nil { + ctx.ServerError("GetRefCommitID", err) + return + } + + diffOptions := &gitdiff.DiffOptions{ + BeforeCommitID: mergeBaseCommitID, + AfterCommitID: headCommitID, + MaxLines: setting.Git.MaxGitDiffLines, + MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters, + MaxFiles: setting.Git.MaxGitDiffFiles, + WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), + } + + diff, err := gitdiff.GetPullDiffStats(ctx.Repo.GitRepo, diffOptions) + if err != nil { + ctx.ServerError("GetPullDiffStats", err) + return + } + + ctx.Data["Diff"] = diff +} + +func GetMergedBaseCommitID(ctx *context.Context, issue *issues_model.Issue) string { + pull := issue.PullRequest var baseCommit string // Some migrated PR won't have any Base SHA and lose history, try to get one @@ -401,6 +435,18 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) baseCommit = pull.MergeBase } + return baseCommit +} + +// PrepareMergedViewPullInfo show meta information for a merged pull request view page +func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.CompareInfo { + pull := issue.PullRequest + + setMergeTarget(ctx, pull) + ctx.Data["HasMerged"] = true + + baseCommit := GetMergedBaseCommitID(ctx, issue) + compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), baseCommit, pull.GetGitRefName(), false, false) if err != nil { diff --git a/routers/web/web.go b/routers/web/web.go index 5dd7be120d..45c374e9c0 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1277,9 +1277,10 @@ func registerRoutes(m *web.Route) { }) m.Group("/pulls/{index}", func() { + m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue) m.Get(".diff", repo.DownloadPullDiff) m.Get(".patch", repo.DownloadPullPatch) - m.Get("/commits", context.RepoRef(), repo.ViewPullCommits) + m.Get("/commits", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits) m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest) m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest) m.Post("/update", repo.UpdatePullRequest) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 9adf3b9400..38283680ae 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1229,6 +1229,42 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff return diff, nil } +type PullDiffStats struct { + TotalAddition, TotalDeletion int +} + +// GetPullDiffStats +func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStats, error) { + repoPath := gitRepo.Path + + diff := &PullDiffStats{} + + separator := "..." + if opts.DirectComparison { + separator = ".." + } + + diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} + if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA { + diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID} + } + + var err error + + _, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...) + if err != nil && strings.Contains(err.Error(), "no merge base") { + // git >= 2.28 now returns an error if base and head have become unrelated. + // previously it would return the results of git diff --shortstat base head so let's try that... + diffPaths = []string{opts.BeforeCommitID, opts.AfterCommitID} + _, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...) + } + if err != nil { + return nil, err + } + + return diff, nil +} + // SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set // Additionally, the database asynchronously is updated if files have changed since the last review func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) { diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index f44968c775..6c121bdd1f 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -14,4 +14,10 @@ {{$.locale.Tr "repo.pulls.tab_files"}} {{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}} + + {{if .Diff.TotalAddition}}+{{.Diff.TotalAddition}}{{end}} {{if .Diff.TotalDeletion}}-{{.Diff.TotalDeletion}}{{end}} + +
+
+