Skip to content

Commit a889d0c

Browse files
authored
Add buttons to allow loading of incomplete diffs (#16829)
This PR adds two buttons to the stats and the end of the diffs list to load the (some of) the remaining incomplete diff sections. Contains #16775 Signed-off-by: Andrew Thornton <art27@cantab.net> ## Screenshots ### Show more button at the end of the diff ![Screenshot from 2021-09-04 11-12-37](https://user-images.githubusercontent.com/1824502/132091009-b1f6113e-2c04-4be5-8a04-b8ecea56887b.png) ### Show more button at the end of the diff stats box ![Screenshot from 2021-09-04 11-14-54](https://user-images.githubusercontent.com/1824502/132091063-86da5a6d-6628-4b82-bea9-3655cd9f40f6.png)
1 parent bdfd751 commit a889d0c

File tree

12 files changed

+227
-154
lines changed

12 files changed

+227
-154
lines changed

modules/git/repo_compare.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
4646
}
4747

4848
// GetCompareInfo generates and returns compare information between base and head branches of repositories.
49-
func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison bool) (_ *CompareInfo, err error) {
49+
func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) {
5050
var (
5151
remoteBranch string
5252
tmpRemote string
@@ -87,13 +87,17 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
8787
}
8888

8989
// We have a common base - therefore we know that ... should work
90-
logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
91-
if err != nil {
92-
return nil, err
93-
}
94-
compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
95-
if err != nil {
96-
return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
90+
if !fileOnly {
91+
logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
92+
if err != nil {
93+
return nil, err
94+
}
95+
compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
96+
if err != nil {
97+
return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
98+
}
99+
} else {
100+
compareInfo.Commits = []*Commit{}
97101
}
98102
} else {
99103
compareInfo.Commits = []*Commit{}

options/locale/locale_en-US.ini

+2-1
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,8 @@ diff.file_image_height = Height
20272027
diff.file_byte_size = Size
20282028
diff.file_suppressed = File diff suppressed because it is too large
20292029
diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long
2030-
diff.too_many_files = Some files were not shown because too many files changed in this diff
2030+
diff.too_many_files = Some files were not shown because too many files have changed in this diff
2031+
diff.show_more = Show More
20312032
diff.generated = generated
20322033
diff.vendored = vendored
20332034
diff.comment.placeholder = Leave a comment

routers/api/v1/repo/pull.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
10161016
return nil, nil, nil, nil, "", ""
10171017
}
10181018

1019-
compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true)
1019+
compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true, false)
10201020
if err != nil {
10211021
headGitRepo.Close()
10221022
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
@@ -1193,9 +1193,9 @@ func GetPullRequestCommits(ctx *context.APIContext) {
11931193
}
11941194
defer baseGitRepo.Close()
11951195
if pr.HasMerged {
1196-
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true)
1196+
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false)
11971197
} else {
1198-
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true)
1198+
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
11991199
}
12001200
if err != nil {
12011201
ctx.ServerError("GetCompareInfo", err)

routers/web/repo/commit.go

+17-10
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ func Diff(ctx *context.Context) {
264264
err error
265265
)
266266

267+
fileOnly := ctx.FormBool("file-only")
268+
267269
if ctx.Data["PageIsWiki"] != nil {
268270
gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath())
269271
if err != nil {
@@ -288,16 +290,8 @@ func Diff(ctx *context.Context) {
288290
commitID = commit.ID.String()
289291
}
290292

291-
statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{})
292-
if err != nil {
293-
log.Error("GetLatestCommitStatus: %v", err)
294-
}
295-
296-
ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
297-
ctx.Data["CommitStatuses"] = statuses
298-
299293
diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo,
300-
commitID, setting.Git.MaxGitDiffLines,
294+
commitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
301295
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
302296
gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
303297
false)
@@ -333,10 +327,23 @@ func Diff(ctx *context.Context) {
333327
setCompareContext(ctx, parentCommit, commit, headTarget)
334328
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
335329
ctx.Data["Commit"] = commit
330+
ctx.Data["Diff"] = diff
331+
if fileOnly {
332+
ctx.HTML(http.StatusOK, tplDiffBox)
333+
return
334+
}
335+
336+
statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{})
337+
if err != nil {
338+
log.Error("GetLatestCommitStatus: %v", err)
339+
}
340+
341+
ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
342+
ctx.Data["CommitStatuses"] = statuses
343+
336344
verification := models.ParseCommitWithSignature(commit)
337345
ctx.Data["Verification"] = verification
338346
ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
339-
ctx.Data["Diff"] = diff
340347
ctx.Data["Parents"] = parents
341348
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
342349

routers/web/repo/compare.go

+41-32
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
const (
3232
tplCompare base.TplName = "repo/diff/compare"
3333
tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
34+
tplDiffBox base.TplName = "repo/diff/box"
3435
)
3536

3637
// setCompareContext sets context data.
@@ -161,6 +162,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
161162
baseRepo := ctx.Repo.Repository
162163
ci := &CompareInfo{}
163164

165+
fileOnly := ctx.FormBool("file-only")
166+
164167
// Get compared branches information
165168
// A full compare url is of the form:
166169
//
@@ -411,15 +414,19 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
411414
if rootRepo != nil &&
412415
rootRepo.ID != ci.HeadRepo.ID &&
413416
rootRepo.ID != baseRepo.ID {
414-
perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo)
415-
if err != nil {
416-
ctx.ServerError("GetBranchesForRepo", err)
417-
return nil
418-
}
419-
if perm {
417+
canRead := rootRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
418+
if canRead {
420419
ctx.Data["RootRepo"] = rootRepo
421-
ctx.Data["RootRepoBranches"] = branches
422-
ctx.Data["RootRepoTags"] = tags
420+
if !fileOnly {
421+
branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo)
422+
if err != nil {
423+
ctx.ServerError("GetBranchesForRepo", err)
424+
return nil
425+
}
426+
427+
ctx.Data["RootRepoBranches"] = branches
428+
ctx.Data["RootRepoTags"] = tags
429+
}
423430
}
424431
}
425432

@@ -432,15 +439,18 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
432439
ownForkRepo.ID != ci.HeadRepo.ID &&
433440
ownForkRepo.ID != baseRepo.ID &&
434441
(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
435-
perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo)
436-
if err != nil {
437-
ctx.ServerError("GetBranchesForRepo", err)
438-
return nil
439-
}
440-
if perm {
442+
canRead := ownForkRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
443+
if canRead {
441444
ctx.Data["OwnForkRepo"] = ownForkRepo
442-
ctx.Data["OwnForkRepoBranches"] = branches
443-
ctx.Data["OwnForkRepoTags"] = tags
445+
if !fileOnly {
446+
branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo)
447+
if err != nil {
448+
ctx.ServerError("GetBranchesForRepo", err)
449+
return nil
450+
}
451+
ctx.Data["OwnForkRepoBranches"] = branches
452+
ctx.Data["OwnForkRepoTags"] = tags
453+
}
444454
}
445455
}
446456

@@ -492,7 +502,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
492502
headBranchRef = git.TagPrefix + ci.HeadBranch
493503
}
494504

495-
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison)
505+
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison, fileOnly)
496506
if err != nil {
497507
ctx.ServerError("GetCompareInfo", err)
498508
return nil
@@ -545,7 +555,7 @@ func PrepareCompareDiff(
545555
}
546556

547557
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo,
548-
beforeCommitID, headCommitID, setting.Git.MaxGitDiffLines,
558+
beforeCommitID, headCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
549559
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison)
550560
if err != nil {
551561
ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
@@ -606,29 +616,22 @@ func PrepareCompareDiff(
606616
return false
607617
}
608618

609-
func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (bool, []string, []string, error) {
610-
perm, err := models.GetUserRepoPermission(repo, user)
611-
if err != nil {
612-
return false, nil, nil, err
613-
}
614-
if !perm.CanRead(models.UnitTypeCode) {
615-
return false, nil, nil, nil
616-
}
619+
func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (branches, tags []string, err error) {
617620
gitRepo, err := git.OpenRepository(repo.RepoPath())
618621
if err != nil {
619-
return false, nil, nil, err
622+
return nil, nil, err
620623
}
621624
defer gitRepo.Close()
622625

623-
branches, _, err := gitRepo.GetBranches(0, 0)
626+
branches, _, err = gitRepo.GetBranches(0, 0)
624627
if err != nil {
625-
return false, nil, nil, err
628+
return nil, nil, err
626629
}
627-
tags, err := gitRepo.GetTags(0, 0)
630+
tags, err = gitRepo.GetTags(0, 0)
628631
if err != nil {
629-
return false, nil, nil, err
632+
return nil, nil, err
630633
}
631-
return true, branches, tags, nil
634+
return branches, tags, nil
632635
}
633636

634637
// CompareDiff show different from one commit to another commit
@@ -665,6 +668,12 @@ func CompareDiff(ctx *context.Context) {
665668
}
666669
ctx.Data["Tags"] = baseTags
667670

671+
fileOnly := ctx.FormBool("file-only")
672+
if fileOnly {
673+
ctx.HTML(http.StatusOK, tplDiffBox)
674+
return
675+
}
676+
668677
headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0)
669678
if err != nil {
670679
ctx.ServerError("GetBranches", err)

routers/web/repo/pull.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
318318
ctx.Data["HasMerged"] = true
319319

320320
compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
321-
pull.MergeBase, pull.GetGitRefName(), true)
321+
pull.MergeBase, pull.GetGitRefName(), true, false)
322322
if err != nil {
323323
if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
324324
ctx.Data["IsPullRequestBroken"] = true
@@ -401,7 +401,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
401401
}
402402

403403
compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
404-
pull.MergeBase, pull.GetGitRefName(), true)
404+
pull.MergeBase, pull.GetGitRefName(), true, false)
405405
if err != nil {
406406
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
407407
ctx.Data["IsPullRequestBroken"] = true
@@ -517,7 +517,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
517517
}
518518

519519
compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
520-
git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true)
520+
git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true, false)
521521
if err != nil {
522522
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
523523
ctx.Data["IsPullRequestBroken"] = true
@@ -633,7 +633,7 @@ func ViewPullFiles(ctx *context.Context) {
633633
ctx.Data["AfterCommitID"] = endCommitID
634634

635635
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo,
636-
startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
636+
startCommitID, endCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
637637
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
638638
gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false)
639639
if err != nil {

services/gitdiff/gitdiff.go

+25-9
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int {
653653

654654
// Diff represents a difference between two git trees.
655655
type Diff struct {
656+
Start, End string
656657
NumFiles, TotalAddition, TotalDeletion int
657658
Files []*DiffFile
658659
IsIncomplete bool
@@ -719,6 +720,9 @@ parsingLoop:
719720

720721
// TODO: Handle skipping first n files
721722
if len(diff.Files) >= maxFiles {
723+
724+
lastFile := createDiffFile(diff, line)
725+
diff.End = lastFile.Name
722726
diff.IsIncomplete = true
723727
_, err := io.Copy(io.Discard, reader)
724728
if err != nil {
@@ -1217,7 +1221,7 @@ func readFileName(rd *strings.Reader) (string, bool) {
12171221
// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
12181222
// Passing the empty string as beforeCommitID returns a diff from the parent commit.
12191223
// The whitespaceBehavior is either an empty string or a git flag
1220-
func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
1224+
func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
12211225
repoPath := gitRepo.Path
12221226

12231227
commit, err := gitRepo.GetCommit(afterCommitID)
@@ -1228,31 +1232,42 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
12281232
ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second)
12291233
defer cancel()
12301234

1231-
var cmd *exec.Cmd
1235+
argsLength := 6
1236+
if len(whitespaceBehavior) > 0 {
1237+
argsLength++
1238+
}
1239+
if len(skipTo) > 0 {
1240+
argsLength++
1241+
}
1242+
1243+
diffArgs := make([]string, 0, argsLength)
12321244
if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
1233-
diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
1245+
diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
12341246
if len(whitespaceBehavior) != 0 {
12351247
diffArgs = append(diffArgs, whitespaceBehavior)
12361248
}
12371249
// append empty tree ref
12381250
diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")
12391251
diffArgs = append(diffArgs, afterCommitID)
1240-
cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
12411252
} else {
12421253
actualBeforeCommitID := beforeCommitID
12431254
if len(actualBeforeCommitID) == 0 {
12441255
parentCommit, _ := commit.Parent(0)
12451256
actualBeforeCommitID = parentCommit.ID.String()
12461257
}
1247-
diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
1258+
diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
12481259
if len(whitespaceBehavior) != 0 {
12491260
diffArgs = append(diffArgs, whitespaceBehavior)
12501261
}
12511262
diffArgs = append(diffArgs, actualBeforeCommitID)
12521263
diffArgs = append(diffArgs, afterCommitID)
1253-
cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
12541264
beforeCommitID = actualBeforeCommitID
12551265
}
1266+
if skipTo != "" {
1267+
diffArgs = append(diffArgs, "--skip-to="+skipTo)
1268+
}
1269+
cmd := exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
1270+
12561271
cmd.Dir = repoPath
12571272
cmd.Stderr = os.Stderr
12581273

@@ -1272,6 +1287,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
12721287
if err != nil {
12731288
return nil, fmt.Errorf("ParsePatch: %v", err)
12741289
}
1290+
diff.Start = skipTo
12751291

12761292
var checker *git.CheckAttributeReader
12771293

@@ -1299,7 +1315,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
12991315
log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
13001316
} else {
13011317
go func() {
1302-
err = checker.Run()
1318+
err := checker.Run()
13031319
if err != nil && err != ctx.Err() {
13041320
log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
13051321
}
@@ -1382,8 +1398,8 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
13821398

13831399
// GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID.
13841400
// The whitespaceBehavior is either an empty string or a git flag
1385-
func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
1386-
return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison)
1401+
func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
1402+
return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, skipTo, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison)
13871403
}
13881404

13891405
// CommentAsDiff returns c.Patch as *Diff

0 commit comments

Comments
 (0)