mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 10:56:10 +01:00 
			
		
		
		
	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  ### Show more button at the end of the diff stats box 
This commit is contained in:
		| @@ -46,7 +46,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin | |||||||
| } | } | ||||||
|  |  | ||||||
| // GetCompareInfo generates and returns compare information between base and head branches of repositories. | // GetCompareInfo generates and returns compare information between base and head branches of repositories. | ||||||
| func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison bool) (_ *CompareInfo, err error) { | func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) { | ||||||
| 	var ( | 	var ( | ||||||
| 		remoteBranch string | 		remoteBranch string | ||||||
| 		tmpRemote    string | 		tmpRemote    string | ||||||
| @@ -87,6 +87,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// We have a common base - therefore we know that ... should work | 		// We have a common base - therefore we know that ... should work | ||||||
|  | 		if !fileOnly { | ||||||
| 			logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) | 			logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, err | 				return nil, err | ||||||
| @@ -95,6 +96,9 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, | |||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) | 				return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) | ||||||
| 			} | 			} | ||||||
|  | 		} else { | ||||||
|  | 			compareInfo.Commits = []*Commit{} | ||||||
|  | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		compareInfo.Commits = []*Commit{} | 		compareInfo.Commits = []*Commit{} | ||||||
| 		compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) | 		compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) | ||||||
|   | |||||||
| @@ -2027,7 +2027,8 @@ diff.file_image_height = Height | |||||||
| diff.file_byte_size = Size | diff.file_byte_size = Size | ||||||
| diff.file_suppressed = File diff suppressed because it is too large | diff.file_suppressed = File diff suppressed because it is too large | ||||||
| diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long | diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long | ||||||
| diff.too_many_files = Some files were not shown because too many files changed in this diff | diff.too_many_files = Some files were not shown because too many files have changed in this diff | ||||||
|  | diff.show_more = Show More | ||||||
| diff.generated = generated | diff.generated = generated | ||||||
| diff.vendored = vendored | diff.vendored = vendored | ||||||
| diff.comment.placeholder = Leave a comment | diff.comment.placeholder = Leave a comment | ||||||
|   | |||||||
| @@ -1016,7 +1016,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) | |||||||
| 		return nil, nil, nil, nil, "", "" | 		return nil, nil, nil, nil, "", "" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true) | 	compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true, false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		headGitRepo.Close() | 		headGitRepo.Close() | ||||||
| 		ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err) | 		ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err) | ||||||
| @@ -1193,9 +1193,9 @@ func GetPullRequestCommits(ctx *context.APIContext) { | |||||||
| 	} | 	} | ||||||
| 	defer baseGitRepo.Close() | 	defer baseGitRepo.Close() | ||||||
| 	if pr.HasMerged { | 	if pr.HasMerged { | ||||||
| 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true) | 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false) | ||||||
| 	} else { | 	} else { | ||||||
| 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true) | 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false) | ||||||
| 	} | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetCompareInfo", err) | 		ctx.ServerError("GetCompareInfo", err) | ||||||
|   | |||||||
| @@ -264,6 +264,8 @@ func Diff(ctx *context.Context) { | |||||||
| 		err     error | 		err     error | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
|  | 	fileOnly := ctx.FormBool("file-only") | ||||||
|  |  | ||||||
| 	if ctx.Data["PageIsWiki"] != nil { | 	if ctx.Data["PageIsWiki"] != nil { | ||||||
| 		gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath()) | 		gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -288,16 +290,8 @@ func Diff(ctx *context.Context) { | |||||||
| 		commitID = commit.ID.String() | 		commitID = commit.ID.String() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Error("GetLatestCommitStatus: %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses) |  | ||||||
| 	ctx.Data["CommitStatuses"] = statuses |  | ||||||
|  |  | ||||||
| 	diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo, | 	diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo, | ||||||
| 		commitID, setting.Git.MaxGitDiffLines, | 		commitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, | ||||||
| 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, | 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, | ||||||
| 		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), | 		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), | ||||||
| 		false) | 		false) | ||||||
| @@ -333,10 +327,23 @@ func Diff(ctx *context.Context) { | |||||||
| 	setCompareContext(ctx, parentCommit, commit, headTarget) | 	setCompareContext(ctx, parentCommit, commit, headTarget) | ||||||
| 	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID) | 	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID) | ||||||
| 	ctx.Data["Commit"] = commit | 	ctx.Data["Commit"] = commit | ||||||
|  | 	ctx.Data["Diff"] = diff | ||||||
|  | 	if fileOnly { | ||||||
|  | 		ctx.HTML(http.StatusOK, tplDiffBox) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Error("GetLatestCommitStatus: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses) | ||||||
|  | 	ctx.Data["CommitStatuses"] = statuses | ||||||
|  |  | ||||||
| 	verification := models.ParseCommitWithSignature(commit) | 	verification := models.ParseCommitWithSignature(commit) | ||||||
| 	ctx.Data["Verification"] = verification | 	ctx.Data["Verification"] = verification | ||||||
| 	ctx.Data["Author"] = models.ValidateCommitWithEmail(commit) | 	ctx.Data["Author"] = models.ValidateCommitWithEmail(commit) | ||||||
| 	ctx.Data["Diff"] = diff |  | ||||||
| 	ctx.Data["Parents"] = parents | 	ctx.Data["Parents"] = parents | ||||||
| 	ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 | 	ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ import ( | |||||||
| const ( | const ( | ||||||
| 	tplCompare     base.TplName = "repo/diff/compare" | 	tplCompare     base.TplName = "repo/diff/compare" | ||||||
| 	tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" | 	tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" | ||||||
|  | 	tplDiffBox     base.TplName = "repo/diff/box" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // setCompareContext sets context data. | // setCompareContext sets context data. | ||||||
| @@ -161,6 +162,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { | |||||||
| 	baseRepo := ctx.Repo.Repository | 	baseRepo := ctx.Repo.Repository | ||||||
| 	ci := &CompareInfo{} | 	ci := &CompareInfo{} | ||||||
|  |  | ||||||
|  | 	fileOnly := ctx.FormBool("file-only") | ||||||
|  |  | ||||||
| 	// Get compared branches information | 	// Get compared branches information | ||||||
| 	// A full compare url is of the form: | 	// A full compare url is of the form: | ||||||
| 	// | 	// | ||||||
| @@ -411,17 +414,21 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { | |||||||
| 	if rootRepo != nil && | 	if rootRepo != nil && | ||||||
| 		rootRepo.ID != ci.HeadRepo.ID && | 		rootRepo.ID != ci.HeadRepo.ID && | ||||||
| 		rootRepo.ID != baseRepo.ID { | 		rootRepo.ID != baseRepo.ID { | ||||||
| 		perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo) | 		canRead := rootRepo.CheckUnitUser(ctx.User, models.UnitTypeCode) | ||||||
|  | 		if canRead { | ||||||
|  | 			ctx.Data["RootRepo"] = rootRepo | ||||||
|  | 			if !fileOnly { | ||||||
|  | 				branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					ctx.ServerError("GetBranchesForRepo", err) | 					ctx.ServerError("GetBranchesForRepo", err) | ||||||
| 					return nil | 					return nil | ||||||
| 				} | 				} | ||||||
| 		if perm { |  | ||||||
| 			ctx.Data["RootRepo"] = rootRepo |  | ||||||
| 				ctx.Data["RootRepoBranches"] = branches | 				ctx.Data["RootRepoBranches"] = branches | ||||||
| 				ctx.Data["RootRepoTags"] = tags | 				ctx.Data["RootRepoTags"] = tags | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// If we have a ownForkRepo and it's different from: | 	// If we have a ownForkRepo and it's different from: | ||||||
| 	// 1. The computed base | 	// 1. The computed base | ||||||
| @@ -432,17 +439,20 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { | |||||||
| 		ownForkRepo.ID != ci.HeadRepo.ID && | 		ownForkRepo.ID != ci.HeadRepo.ID && | ||||||
| 		ownForkRepo.ID != baseRepo.ID && | 		ownForkRepo.ID != baseRepo.ID && | ||||||
| 		(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) { | 		(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) { | ||||||
| 		perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo) | 		canRead := ownForkRepo.CheckUnitUser(ctx.User, models.UnitTypeCode) | ||||||
|  | 		if canRead { | ||||||
|  | 			ctx.Data["OwnForkRepo"] = ownForkRepo | ||||||
|  | 			if !fileOnly { | ||||||
|  | 				branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					ctx.ServerError("GetBranchesForRepo", err) | 					ctx.ServerError("GetBranchesForRepo", err) | ||||||
| 					return nil | 					return nil | ||||||
| 				} | 				} | ||||||
| 		if perm { |  | ||||||
| 			ctx.Data["OwnForkRepo"] = ownForkRepo |  | ||||||
| 				ctx.Data["OwnForkRepoBranches"] = branches | 				ctx.Data["OwnForkRepoBranches"] = branches | ||||||
| 				ctx.Data["OwnForkRepoTags"] = tags | 				ctx.Data["OwnForkRepoTags"] = tags | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Check if head branch is valid. | 	// Check if head branch is valid. | ||||||
| 	headIsCommit := ci.HeadGitRepo.IsCommitExist(ci.HeadBranch) | 	headIsCommit := ci.HeadGitRepo.IsCommitExist(ci.HeadBranch) | ||||||
| @@ -492,7 +502,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { | |||||||
| 		headBranchRef = git.TagPrefix + ci.HeadBranch | 		headBranchRef = git.TagPrefix + ci.HeadBranch | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison) | 	ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison, fileOnly) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetCompareInfo", err) | 		ctx.ServerError("GetCompareInfo", err) | ||||||
| 		return nil | 		return nil | ||||||
| @@ -545,7 +555,7 @@ func PrepareCompareDiff( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo, | 	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo, | ||||||
| 		beforeCommitID, headCommitID, setting.Git.MaxGitDiffLines, | 		beforeCommitID, headCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, | ||||||
| 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison) | 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err) | 		ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err) | ||||||
| @@ -606,29 +616,22 @@ func PrepareCompareDiff( | |||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
|  |  | ||||||
| func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (bool, []string, []string, error) { | func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (branches, tags []string, err error) { | ||||||
| 	perm, err := models.GetUserRepoPermission(repo, user) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, nil, nil, err |  | ||||||
| 	} |  | ||||||
| 	if !perm.CanRead(models.UnitTypeCode) { |  | ||||||
| 		return false, nil, nil, nil |  | ||||||
| 	} |  | ||||||
| 	gitRepo, err := git.OpenRepository(repo.RepoPath()) | 	gitRepo, err := git.OpenRepository(repo.RepoPath()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| 	defer gitRepo.Close() | 	defer gitRepo.Close() | ||||||
|  |  | ||||||
| 	branches, _, err := gitRepo.GetBranches(0, 0) | 	branches, _, err = gitRepo.GetBranches(0, 0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| 	tags, err := gitRepo.GetTags(0, 0) | 	tags, err = gitRepo.GetTags(0, 0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| 	return true, branches, tags, nil | 	return branches, tags, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // CompareDiff show different from one commit to another commit | // CompareDiff show different from one commit to another commit | ||||||
| @@ -665,6 +668,12 @@ func CompareDiff(ctx *context.Context) { | |||||||
| 	} | 	} | ||||||
| 	ctx.Data["Tags"] = baseTags | 	ctx.Data["Tags"] = baseTags | ||||||
|  |  | ||||||
|  | 	fileOnly := ctx.FormBool("file-only") | ||||||
|  | 	if fileOnly { | ||||||
|  | 		ctx.HTML(http.StatusOK, tplDiffBox) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0) | 	headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetBranches", err) | 		ctx.ServerError("GetBranches", err) | ||||||
|   | |||||||
| @@ -318,7 +318,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C | |||||||
| 	ctx.Data["HasMerged"] = true | 	ctx.Data["HasMerged"] = true | ||||||
|  |  | ||||||
| 	compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), | 	compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), | ||||||
| 		pull.MergeBase, pull.GetGitRefName(), true) | 		pull.MergeBase, pull.GetGitRefName(), true, false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") { | 		if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") { | ||||||
| 			ctx.Data["IsPullRequestBroken"] = true | 			ctx.Data["IsPullRequestBroken"] = true | ||||||
| @@ -401,7 +401,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), | 		compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), | ||||||
| 			pull.MergeBase, pull.GetGitRefName(), true) | 			pull.MergeBase, pull.GetGitRefName(), true, false) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if strings.Contains(err.Error(), "fatal: Not a valid object name") { | 			if strings.Contains(err.Error(), "fatal: Not a valid object name") { | ||||||
| 				ctx.Data["IsPullRequestBroken"] = true | 				ctx.Data["IsPullRequestBroken"] = true | ||||||
| @@ -517,7 +517,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), | 	compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), | ||||||
| 		git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true) | 		git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true, false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if strings.Contains(err.Error(), "fatal: Not a valid object name") { | 		if strings.Contains(err.Error(), "fatal: Not a valid object name") { | ||||||
| 			ctx.Data["IsPullRequestBroken"] = true | 			ctx.Data["IsPullRequestBroken"] = true | ||||||
| @@ -633,7 +633,7 @@ func ViewPullFiles(ctx *context.Context) { | |||||||
| 	ctx.Data["AfterCommitID"] = endCommitID | 	ctx.Data["AfterCommitID"] = endCommitID | ||||||
|  |  | ||||||
| 	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo, | 	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo, | ||||||
| 		startCommitID, endCommitID, setting.Git.MaxGitDiffLines, | 		startCommitID, endCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, | ||||||
| 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, | 		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, | ||||||
| 		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false) | 		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -653,6 +653,7 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int { | |||||||
|  |  | ||||||
| // Diff represents a difference between two git trees. | // Diff represents a difference between two git trees. | ||||||
| type Diff struct { | type Diff struct { | ||||||
|  | 	Start, End                             string | ||||||
| 	NumFiles, TotalAddition, TotalDeletion int | 	NumFiles, TotalAddition, TotalDeletion int | ||||||
| 	Files                                  []*DiffFile | 	Files                                  []*DiffFile | ||||||
| 	IsIncomplete                           bool | 	IsIncomplete                           bool | ||||||
| @@ -719,6 +720,9 @@ parsingLoop: | |||||||
|  |  | ||||||
| 		// TODO: Handle skipping first n files | 		// TODO: Handle skipping first n files | ||||||
| 		if len(diff.Files) >= maxFiles { | 		if len(diff.Files) >= maxFiles { | ||||||
|  |  | ||||||
|  | 			lastFile := createDiffFile(diff, line) | ||||||
|  | 			diff.End = lastFile.Name | ||||||
| 			diff.IsIncomplete = true | 			diff.IsIncomplete = true | ||||||
| 			_, err := io.Copy(io.Discard, reader) | 			_, err := io.Copy(io.Discard, reader) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -1217,7 +1221,7 @@ func readFileName(rd *strings.Reader) (string, bool) { | |||||||
| // GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository. | // GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository. | ||||||
| // Passing the empty string as beforeCommitID returns a diff from the parent commit. | // Passing the empty string as beforeCommitID returns a diff from the parent commit. | ||||||
| // The whitespaceBehavior is either an empty string or a git flag | // The whitespaceBehavior is either an empty string or a git flag | ||||||
| func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { | func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { | ||||||
| 	repoPath := gitRepo.Path | 	repoPath := gitRepo.Path | ||||||
|  |  | ||||||
| 	commit, err := gitRepo.GetCommit(afterCommitID) | 	commit, err := gitRepo.GetCommit(afterCommitID) | ||||||
| @@ -1228,31 +1232,42 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, | |||||||
| 	ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second) | 	ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second) | ||||||
| 	defer cancel() | 	defer cancel() | ||||||
|  |  | ||||||
| 	var cmd *exec.Cmd | 	argsLength := 6 | ||||||
|  | 	if len(whitespaceBehavior) > 0 { | ||||||
|  | 		argsLength++ | ||||||
|  | 	} | ||||||
|  | 	if len(skipTo) > 0 { | ||||||
|  | 		argsLength++ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	diffArgs := make([]string, 0, argsLength) | ||||||
| 	if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 { | 	if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 { | ||||||
| 		diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"} | 		diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M") | ||||||
| 		if len(whitespaceBehavior) != 0 { | 		if len(whitespaceBehavior) != 0 { | ||||||
| 			diffArgs = append(diffArgs, whitespaceBehavior) | 			diffArgs = append(diffArgs, whitespaceBehavior) | ||||||
| 		} | 		} | ||||||
| 		// append empty tree ref | 		// append empty tree ref | ||||||
| 		diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904") | 		diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904") | ||||||
| 		diffArgs = append(diffArgs, afterCommitID) | 		diffArgs = append(diffArgs, afterCommitID) | ||||||
| 		cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...) |  | ||||||
| 	} else { | 	} else { | ||||||
| 		actualBeforeCommitID := beforeCommitID | 		actualBeforeCommitID := beforeCommitID | ||||||
| 		if len(actualBeforeCommitID) == 0 { | 		if len(actualBeforeCommitID) == 0 { | ||||||
| 			parentCommit, _ := commit.Parent(0) | 			parentCommit, _ := commit.Parent(0) | ||||||
| 			actualBeforeCommitID = parentCommit.ID.String() | 			actualBeforeCommitID = parentCommit.ID.String() | ||||||
| 		} | 		} | ||||||
| 		diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"} | 		diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M") | ||||||
| 		if len(whitespaceBehavior) != 0 { | 		if len(whitespaceBehavior) != 0 { | ||||||
| 			diffArgs = append(diffArgs, whitespaceBehavior) | 			diffArgs = append(diffArgs, whitespaceBehavior) | ||||||
| 		} | 		} | ||||||
| 		diffArgs = append(diffArgs, actualBeforeCommitID) | 		diffArgs = append(diffArgs, actualBeforeCommitID) | ||||||
| 		diffArgs = append(diffArgs, afterCommitID) | 		diffArgs = append(diffArgs, afterCommitID) | ||||||
| 		cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...) |  | ||||||
| 		beforeCommitID = actualBeforeCommitID | 		beforeCommitID = actualBeforeCommitID | ||||||
| 	} | 	} | ||||||
|  | 	if skipTo != "" { | ||||||
|  | 		diffArgs = append(diffArgs, "--skip-to="+skipTo) | ||||||
|  | 	} | ||||||
|  | 	cmd := exec.CommandContext(ctx, git.GitExecutable, diffArgs...) | ||||||
|  |  | ||||||
| 	cmd.Dir = repoPath | 	cmd.Dir = repoPath | ||||||
| 	cmd.Stderr = os.Stderr | 	cmd.Stderr = os.Stderr | ||||||
|  |  | ||||||
| @@ -1272,6 +1287,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("ParsePatch: %v", err) | 		return nil, fmt.Errorf("ParsePatch: %v", err) | ||||||
| 	} | 	} | ||||||
|  | 	diff.Start = skipTo | ||||||
|  |  | ||||||
| 	var checker *git.CheckAttributeReader | 	var checker *git.CheckAttributeReader | ||||||
|  |  | ||||||
| @@ -1299,7 +1315,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, | |||||||
| 				log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) | 				log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) | ||||||
| 			} else { | 			} else { | ||||||
| 				go func() { | 				go func() { | ||||||
| 					err = checker.Run() | 					err := checker.Run() | ||||||
| 					if err != nil && err != ctx.Err() { | 					if err != nil && err != ctx.Err() { | ||||||
| 						log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) | 						log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) | ||||||
| 					} | 					} | ||||||
| @@ -1382,8 +1398,8 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, | |||||||
|  |  | ||||||
| // GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID. | // GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID. | ||||||
| // The whitespaceBehavior is either an empty string or a git flag | // The whitespaceBehavior is either an empty string or a git flag | ||||||
| func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { | func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { | ||||||
| 	return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison) | 	return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, skipTo, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison) | ||||||
| } | } | ||||||
|  |  | ||||||
| // CommentAsDiff returns c.Patch as *Diff | // CommentAsDiff returns c.Patch as *Diff | ||||||
|   | |||||||
| @@ -522,7 +522,7 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 	defer gitRepo.Close() | 	defer gitRepo.Close() | ||||||
| 	for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} { | 	for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} { | ||||||
| 		diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", | 		diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", "", | ||||||
| 			setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false) | 			setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false) | ||||||
| 		assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior)) | 		assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior)) | ||||||
| 		for _, f := range diffs.Files { | 		for _, f := range diffs.Files { | ||||||
|   | |||||||
| @@ -80,7 +80,7 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6 | |||||||
| 	defer baseGitRepo.Close() | 	defer baseGitRepo.Close() | ||||||
|  |  | ||||||
| 	compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), | 	compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), | ||||||
| 		git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true) | 		git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true, false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -42,17 +42,25 @@ | |||||||
| 					<a class="file mono" href="#diff-{{.Index}}">{{.Name}}</a> | 					<a class="file mono" href="#diff-{{.Index}}">{{.Name}}</a> | ||||||
| 				</li> | 				</li> | ||||||
| 			{{end}} | 			{{end}} | ||||||
|  | 			{{if .Diff.IsIncomplete}} | ||||||
|  | 				<li id="diff-too-many-files-stats" class="pt-2"> | ||||||
|  | 					<span class="file df ac sb">{{$.i18n.Tr "repo.diff.too_many_files"}} | ||||||
|  | 						<a class="ui basic tiny button" id="diff-show-more-files-stats" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.i18n.Tr "repo.diff.show_more"}}</a> | ||||||
|  | 					</span> | ||||||
|  | 				</li> | ||||||
|  | 			{{end}} | ||||||
| 		</ol> | 		</ol> | ||||||
|  | 		<div id="diff-file-boxes"> | ||||||
| 			{{range $i, $file := .Diff.Files}} | 			{{range $i, $file := .Diff.Files}} | ||||||
| 				{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} | 				{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} | ||||||
| 				{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} | 				{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} | ||||||
| 				{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} | 				{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} | ||||||
| 				{{$isCsv := (call $.IsCsvFile $file)}} | 				{{$isCsv := (call $.IsCsvFile $file)}} | ||||||
| 				{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} | 				{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} | ||||||
| 			<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}" {{if $file.IsGenerated}}data-folded="true"{{end}}> | 				<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if $file.IsGenerated}}data-folded="true"{{end}}> | ||||||
| 					<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb"> | 					<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb"> | ||||||
| 						<div class="fold-file df ac"> | 						<div class="fold-file df ac"> | ||||||
| 						<a role="button" class="chevron muted mr-2"> | 							<a role="button" class="fold-file muted mr-2"> | ||||||
| 								{{if $file.IsGenerated}} | 								{{if $file.IsGenerated}} | ||||||
| 									{{svg "octicon-chevron-right" 18}} | 									{{svg "octicon-chevron-right" 18}} | ||||||
| 								{{else}} | 								{{else}} | ||||||
| @@ -135,12 +143,14 @@ | |||||||
| 			{{end}} | 			{{end}} | ||||||
|  |  | ||||||
| 			{{if .Diff.IsIncomplete}} | 			{{if .Diff.IsIncomplete}} | ||||||
| 			<div class="diff-file-box diff-box file-content mt-3"> | 				<div class="diff-file-box diff-box file-content mt-3" id="diff-incomplete"> | ||||||
| 				<h4 class="ui top attached normal header"> | 					<h4 class="ui top attached normal header df ac sb"> | ||||||
| 						{{$.i18n.Tr "repo.diff.too_many_files"}} | 						{{$.i18n.Tr "repo.diff.too_many_files"}} | ||||||
|  | 						<a class="ui basic tiny button" id="diff-show-more-files" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.i18n.Tr "repo.diff.show_more"}}</a> | ||||||
| 					</h4> | 					</h4> | ||||||
| 				</div> | 				</div> | ||||||
| 			{{end}} | 			{{end}} | ||||||
|  | 		</div> | ||||||
|  |  | ||||||
| 		{{if not $.Repository.IsArchived}} | 		{{if not $.Repository.IsArchived}} | ||||||
| 			<div class="hide" id="edit-content-form"> | 			<div class="hide" id="edit-content-form"> | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								web_src/js/features/diff.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web_src/js/features/diff.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | export function initDiffShowMore() { | ||||||
|  |   $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => { | ||||||
|  |     e.preventDefault(); | ||||||
|  |  | ||||||
|  |     if ($(e.target).hasClass('disabled')) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled'); | ||||||
|  |  | ||||||
|  |     const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href'); | ||||||
|  |     $.ajax({ | ||||||
|  |       type: 'GET', | ||||||
|  |       url, | ||||||
|  |     }).done((resp) => { | ||||||
|  |       if (!resp || resp.html === '' || resp.empty) { | ||||||
|  |         $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       $('#diff-too-many-files-stats').remove(); | ||||||
|  |       $('#diff-files').append($(resp).find('#diff-files li')); | ||||||
|  |       $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children()); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
| @@ -27,6 +27,7 @@ import {initNotificationsTable, initNotificationCount} from './features/notifica | |||||||
| import {initLastCommitLoader} from './features/lastcommitloader.js'; | import {initLastCommitLoader} from './features/lastcommitloader.js'; | ||||||
| import {initIssueContentHistory} from './features/issue-content-history.js'; | import {initIssueContentHistory} from './features/issue-content-history.js'; | ||||||
| import {initStopwatch} from './features/stopwatch.js'; | import {initStopwatch} from './features/stopwatch.js'; | ||||||
|  | import {initDiffShowMore} from './features/diff.js'; | ||||||
| import {showLineButton} from './code/linebutton.js'; | import {showLineButton} from './code/linebutton.js'; | ||||||
| import {initMarkupContent, initCommentContent} from './markup/content.js'; | import {initMarkupContent, initCommentContent} from './markup/content.js'; | ||||||
| import {stripTags, mqBinarySearch} from './utils.js'; | import {stripTags, mqBinarySearch} from './utils.js'; | ||||||
| @@ -2881,6 +2882,7 @@ $(document).ready(async () => { | |||||||
|   initFileViewToggle(); |   initFileViewToggle(); | ||||||
|   initReleaseEditor(); |   initReleaseEditor(); | ||||||
|   initRelease(); |   initRelease(); | ||||||
|  |   initDiffShowMore(); | ||||||
|   initIssueContentHistory(); |   initIssueContentHistory(); | ||||||
|   initAdminUserListSearchForm(); |   initAdminUserListSearchForm(); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user