mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-07 02:59:00 +02:00
refactor: GetDiffShortStat and fix panic caused by inconsistent "changed file number" (#39248)
This commit is contained in:
@@ -330,3 +330,11 @@ func GetAffectedFiles(ctx context.Context, repo *Repository, branchName, oldComm
|
||||
|
||||
return affectedFiles, err
|
||||
}
|
||||
|
||||
// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
|
||||
func GetReverseRawDiff(ctx context.Context, repo RepositoryFacade, commitID string, writer io.Writer) error {
|
||||
return gitcmd.NewCommand("show", "--pretty=format:revert %H%n", "-R").
|
||||
AddDynamicArguments(commitID).
|
||||
WithStdoutCopy(writer).
|
||||
WithRepo(repo).RunWithStderr(ctx)
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"gitea.dev/modules/git/gitcmd"
|
||||
)
|
||||
|
||||
// GetDiffShortStatByCmdArgs counts number of changed files, number of additions and deletions
|
||||
// TODO: it can be merged with another "GetDiffShortStat" in the future
|
||||
func GetDiffShortStatByCmdArgs(ctx context.Context, repo RepositoryFacade, trustedArgs gitcmd.TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
|
||||
// Now if we call:
|
||||
// $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875
|
||||
// we get:
|
||||
// " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
|
||||
cmd := gitcmd.NewCommand("diff", "--shortstat").AddArguments(trustedArgs...).AddDynamicArguments(dynamicArgs...)
|
||||
stdout, _, err := cmd.WithRepo(repo).RunStdString(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
return parseDiffStat(stdout)
|
||||
}
|
||||
|
||||
var shortStatFormat = regexp.MustCompile(
|
||||
`\s*(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?`)
|
||||
|
||||
func parseDiffStat(stdout string) (numFiles, totalAdditions, totalDeletions int, err error) {
|
||||
if len(stdout) == 0 || stdout == "\n" {
|
||||
return 0, 0, 0, nil
|
||||
}
|
||||
groups := shortStatFormat.FindStringSubmatch(stdout)
|
||||
if len(groups) != 4 {
|
||||
return 0, 0, 0, fmt.Errorf("unable to parse shortstat: %s groups: %s", stdout, groups)
|
||||
}
|
||||
|
||||
numFiles, err = strconv.Atoi(groups[1])
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unable to parse shortstat: %s. Error parsing NumFiles %w", stdout, err)
|
||||
}
|
||||
|
||||
if len(groups[2]) != 0 {
|
||||
totalAdditions, err = strconv.Atoi(groups[2])
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unable to parse shortstat: %s. Error parsing NumAdditions %w", stdout, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(groups[3]) != 0 {
|
||||
totalDeletions, err = strconv.Atoi(groups[3])
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unable to parse shortstat: %s. Error parsing NumDeletions %w", stdout, err)
|
||||
}
|
||||
}
|
||||
return numFiles, totalAdditions, totalDeletions, err
|
||||
}
|
||||
|
||||
// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
|
||||
func GetReverseRawDiff(ctx context.Context, repo RepositoryFacade, commitID string, writer io.Writer) error {
|
||||
return gitcmd.NewCommand("show", "--pretty=format:revert %H%n", "-R").
|
||||
AddDynamicArguments(commitID).
|
||||
WithStdoutCopy(writer).
|
||||
WithRepo(repo).RunWithStderr(ctx)
|
||||
}
|
||||
@@ -35,7 +35,8 @@ type FastImportCommit struct {
|
||||
func ForceFastImportWithInit(ctx context.Context, repoLocalPath string, commits []FastImportCommit, initOpts ...FastImportInit) (RepositoryFacade, error) {
|
||||
repo := gitrepo.RepositoryUnmanaged(repoLocalPath)
|
||||
initOpt := util.OptionalArg(initOpts, FastImportInit{Bare: true})
|
||||
if exist, _ := IsRepositoryExist(ctx, repo); !exist {
|
||||
dirEntries, err := os.ReadDir(repoLocalPath)
|
||||
if os.IsNotExist(err) || (err == nil && len(dirEntries) == 0) {
|
||||
_ = os.MkdirAll(repoLocalPath, 0o755)
|
||||
err := InitRepositoryLocal(ctx, repoLocalPath, initOpt.Bare, util.IfZero(initOpt.ObjectFormat, "sha1"))
|
||||
if err != nil {
|
||||
|
||||
@@ -37,10 +37,8 @@ type Sha1ObjectFormatImpl struct{}
|
||||
|
||||
var (
|
||||
emptySha1ObjectID = &Sha1Hash{}
|
||||
emptySha1Tree = &Sha1Hash{
|
||||
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
||||
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
||||
}
|
||||
// emptySha1Tree: 4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
emptySha1Tree = &Sha1Hash{0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04}
|
||||
)
|
||||
|
||||
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
||||
|
||||
+13
-12
@@ -1580,39 +1580,40 @@ func GetPullRequestFiles(ctx *context.APIContext) {
|
||||
maxLines := setting.Git.MaxGitDiffLines
|
||||
|
||||
// FIXME: If there are too many files in the repo, may cause some unpredictable issues.
|
||||
diffCommonOptions := gitdiff.DiffCommonOptions{
|
||||
BeforeCommitID: startCommitID,
|
||||
AfterCommitID: endCommitID,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
}
|
||||
diff, err := gitdiff.GetDiffForAPI(ctx, baseGitRepo,
|
||||
&gitdiff.DiffOptions{
|
||||
BeforeCommitID: startCommitID,
|
||||
AfterCommitID: endCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1, // GetDiff() will return all files
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
||||
DiffCommonOptions: diffCommonOptions,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: -1, // GetDiff() will return all files
|
||||
})
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, baseGitRepo, startCommitID, endCommitID)
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, baseGitRepo, &diffCommonOptions)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
listOptions := utils.GetListOptions(ctx)
|
||||
totalNumberOfFiles := diffShortStat.NumFiles
|
||||
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
||||
|
||||
start, limit := listOptions.GetSkipTake()
|
||||
|
||||
limit = min(limit, totalNumberOfFiles-start)
|
||||
|
||||
limit = max(limit, 0)
|
||||
|
||||
apiFiles := make([]*api.ChangedFile, 0, limit)
|
||||
for i := start; i < start+limit; i++ {
|
||||
for i := start; i < start+limit && i < len(diff.Files); i++ {
|
||||
// refs/pull/1/head stores the HEAD commit ID, allowing all related commits to be found in the base repository.
|
||||
// The head repository might have been deleted, so we should not rely on it here.
|
||||
apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.BaseRepo, endCommitID))
|
||||
|
||||
@@ -318,19 +318,22 @@ func Diff(ctx *context.Context) {
|
||||
maxLines, maxFiles = -1, -1
|
||||
}
|
||||
|
||||
diff, err := gitdiff.GetDiffForRender(ctx, ctx.Repo.RepoLink, gitRepo, &gitdiff.DiffOptions{
|
||||
AfterCommitID: commitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
diffCommonOptions := gitdiff.DiffCommonOptions{
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(GetWhitespaceBehavior(ctx)),
|
||||
AfterCommitID: commitID,
|
||||
}
|
||||
diff, err := gitdiff.GetDiffForRender(ctx, ctx.Repo.RepoLink, gitRepo, &gitdiff.DiffOptions{
|
||||
DiffCommonOptions: diffCommonOptions,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
}, files...)
|
||||
if err != nil {
|
||||
ctx.NotFound(err)
|
||||
return
|
||||
}
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, gitRepo, "", commitID)
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, gitRepo, &diffCommonOptions)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffShortStat", err)
|
||||
return
|
||||
|
||||
+11
-10
@@ -409,23 +409,24 @@ func (cpi *comparePageInfoType) prepareCompareDiff(ctx *context.Context, whitesp
|
||||
}
|
||||
|
||||
fileOnly := ctx.FormBool("file-only")
|
||||
|
||||
diffCommonOptions := gitdiff.DiffCommonOptions{
|
||||
BeforeCommitID: beforeCommitID,
|
||||
AfterCommitID: headCommitID,
|
||||
WhitespaceBehavior: whitespaceBehavior,
|
||||
}
|
||||
diff, err := gitdiff.GetDiffForRender(ctx, ci.HeadRepo.Link(), ci.HeadGitRepo,
|
||||
&gitdiff.DiffOptions{
|
||||
BeforeCommitID: beforeCommitID,
|
||||
AfterCommitID: headCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
WhitespaceBehavior: whitespaceBehavior,
|
||||
DirectComparison: ci.DirectComparison(),
|
||||
DiffCommonOptions: diffCommonOptions,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
}, ctx.FormStrings("files")...)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiff", err)
|
||||
return
|
||||
}
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ci.HeadGitRepo, beforeCommitID, headCommitID)
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ci.HeadGitRepo, &diffCommonOptions)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffShortStat", err)
|
||||
return
|
||||
|
||||
@@ -203,7 +203,7 @@ func GetPullDiffStats(ctx *context.Context) {
|
||||
log.Error("Failed to GetRefCommitID: %v, repo: %v", err, ctx.Repo.Repository.FullName())
|
||||
return
|
||||
}
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.GitRepo, mergeBaseCommitID, headCommitID)
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.GitRepo, &gitdiff.DiffCommonOptions{BeforeCommitID: mergeBaseCommitID, AfterCommitID: headCommitID})
|
||||
if err != nil {
|
||||
log.Error("Failed to GetDiffShortStat: %v, repo: %v", err, ctx.Repo.Repository.FullName())
|
||||
return
|
||||
@@ -770,15 +770,18 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) {
|
||||
maxLines, maxFiles = -1, -1
|
||||
}
|
||||
|
||||
diffOptions := &gitdiff.DiffOptions{
|
||||
diffCommonOptions := gitdiff.DiffCommonOptions{
|
||||
BeforeCommitID: beforeCommitID,
|
||||
AfterCommitID: afterCommitID,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(GetWhitespaceBehavior(ctx)),
|
||||
}
|
||||
diffOptions := &gitdiff.DiffOptions{
|
||||
DiffCommonOptions: diffCommonOptions,
|
||||
SkipTo: ctx.FormString("skip-to"),
|
||||
MaxLines: maxLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
}
|
||||
|
||||
diff, err := gitdiff.GetDiffForRender(ctx, ctx.Repo.RepoLink, gitRepo, diffOptions, files...)
|
||||
if err != nil {
|
||||
@@ -803,7 +806,7 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) {
|
||||
}
|
||||
}
|
||||
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.GitRepo, beforeCommitID, afterCommitID)
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.GitRepo, &diffCommonOptions)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffShortStat", err)
|
||||
return
|
||||
|
||||
@@ -209,7 +209,7 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
|
||||
|
||||
// Get diff stats for commit
|
||||
if opts.Stat {
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, gitRepo, "", commit.ID.String())
|
||||
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, gitRepo, &gitdiff.DiffCommonOptions{AfterCommitID: commit.ID.String()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
|
||||
// Calculate diff
|
||||
startCommitID = pr.MergeBase
|
||||
|
||||
diffShortStats, err := gitdiff.GetDiffShortStat(ctx, gitRepo, startCommitID, endCommitID)
|
||||
diffShortStats, err := gitdiff.GetDiffShortStat(ctx, gitRepo, &gitdiff.DiffCommonOptions{BeforeCommitID: startCommitID, AfterCommitID: endCommitID})
|
||||
if err != nil {
|
||||
log.Error("GetDiffShortStat: %v", err)
|
||||
} else {
|
||||
|
||||
+49
-29
@@ -15,6 +15,7 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -1293,36 +1294,45 @@ func readFileName(rd *strings.Reader) (string, bool) {
|
||||
return name[2:], ambiguity
|
||||
}
|
||||
|
||||
// DiffOptions represents the options for a DiffRange
|
||||
type DiffOptions struct {
|
||||
type DiffCommonOptions struct {
|
||||
BeforeCommitID string
|
||||
AfterCommitID string
|
||||
SkipTo string
|
||||
MaxLines int
|
||||
MaxLineCharacters int
|
||||
MaxFiles int
|
||||
WhitespaceBehavior gitcmd.TrustedCmdArgs
|
||||
DirectComparison bool
|
||||
}
|
||||
|
||||
func guessBeforeCommitForDiff(ctx context.Context, gitRepo *git.Repository, beforeCommitID string, afterCommit *git.Commit) (actualBeforeCommit *git.Commit, actualBeforeCommitID git.ObjectID, err error) {
|
||||
commitObjectFormat := afterCommit.ID.Type()
|
||||
isBeforeCommitIDEmpty := beforeCommitID == "" || beforeCommitID == commitObjectFormat.EmptyObjectID().String()
|
||||
type DiffOptions struct {
|
||||
DiffCommonOptions
|
||||
SkipTo string
|
||||
MaxLines int
|
||||
MaxLineCharacters int
|
||||
MaxFiles int
|
||||
}
|
||||
|
||||
// prepareDiffCommits prepares the before and after commits for a diff operation based on the provided options.
|
||||
// The "before commit" can be nil (the empty tree ID is used) if there is no "before commit" can be determined.
|
||||
func prepareDiffCommits(ctx context.Context, gitRepo *git.Repository, opts *DiffCommonOptions) (actualBeforeCommit *git.Commit, actualBeforeCommitID git.ObjectID, afterCommit *git.Commit, err error) {
|
||||
afterCommit, err = gitRepo.GetCommit(ctx, opts.AfterCommitID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
commitObjectFormat := afterCommit.ID.Type()
|
||||
isBeforeCommitIDEmpty := opts.BeforeCommitID == "" || opts.BeforeCommitID == commitObjectFormat.EmptyObjectID().String()
|
||||
if isBeforeCommitIDEmpty && afterCommit.ParentCount() == 0 {
|
||||
// "git diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 after-commit" can work with tree ID as before commit ID
|
||||
actualBeforeCommitID = commitObjectFormat.EmptyTree()
|
||||
} else {
|
||||
if isBeforeCommitIDEmpty {
|
||||
actualBeforeCommit, err = afterCommit.Parent(ctx, gitRepo, 0)
|
||||
} else {
|
||||
actualBeforeCommit, err = gitRepo.GetCommit(ctx, beforeCommitID)
|
||||
actualBeforeCommit, err = gitRepo.GetCommit(ctx, opts.BeforeCommitID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
actualBeforeCommitID = actualBeforeCommit.ID
|
||||
}
|
||||
return actualBeforeCommit, actualBeforeCommitID, nil
|
||||
return actualBeforeCommit, actualBeforeCommitID, afterCommit, nil
|
||||
}
|
||||
|
||||
// getDiffBasic builds a Diff between two commits of a repository.
|
||||
@@ -1330,12 +1340,7 @@ func guessBeforeCommitForDiff(ctx context.Context, gitRepo *git.Repository, befo
|
||||
// The whitespaceBehavior is either an empty string or a git flag
|
||||
// Returned beforeCommit could be nil if the afterCommit doesn't have parent commit
|
||||
func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, files ...string) (_ *Diff, beforeCommit, afterCommit *git.Commit, err error) {
|
||||
afterCommit, err = gitRepo.GetCommit(ctx, opts.AfterCommitID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
beforeCommit, beforeCommitID, err := guessBeforeCommitForDiff(ctx, gitRepo, opts.BeforeCommitID, afterCommit)
|
||||
beforeCommit, beforeCommitID, afterCommit, err := prepareDiffCommits(ctx, gitRepo, &opts.DiffCommonOptions)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -1494,26 +1499,41 @@ func highlightCodeLines(name, lang string, sections []*DiffSection, isLeft bool,
|
||||
}
|
||||
|
||||
type DiffShortStat struct {
|
||||
NumFiles, TotalAddition, TotalDeletion int
|
||||
NumFiles, TotalAddition, TotalDeletion int // these fields are used in templates directly
|
||||
}
|
||||
|
||||
func GetDiffShortStat(ctx context.Context, gitRepo *git.Repository, beforeCommitID, afterCommitID string) (*DiffShortStat, error) {
|
||||
afterCommit, err := gitRepo.GetCommit(ctx, afterCommitID)
|
||||
func GetDiffShortStat(ctx context.Context, gitRepo *git.Repository, opts *DiffCommonOptions) (*DiffShortStat, error) {
|
||||
_, actualBeforeCommitID, afterCommit, err := prepareDiffCommits(ctx, gitRepo, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, actualBeforeCommitID, err := guessBeforeCommitForDiff(ctx, gitRepo, beforeCommitID, afterCommit)
|
||||
stat := &DiffShortStat{}
|
||||
cmd := gitcmd.NewCommand("diff", "--shortstat").
|
||||
AddArguments(opts.WhitespaceBehavior...).
|
||||
AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold).
|
||||
AddDynamicArguments(actualBeforeCommitID.String(), afterCommit.ID.String())
|
||||
// output: " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
|
||||
stdout, _, err := cmd.WithRepo(gitRepo).RunStdString(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
diff := &DiffShortStat{}
|
||||
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStatByCmdArgs(ctx, gitRepo, nil, actualBeforeCommitID.String(), afterCommitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
stdout = strings.TrimSpace(stdout)
|
||||
for field := range strings.SplitSeq(stdout, ",") {
|
||||
field = strings.TrimSpace(field)
|
||||
num, suffix, ok := strings.Cut(field, " ")
|
||||
switch {
|
||||
case strings.Contains(suffix, "file") && strings.Contains(suffix, "change"):
|
||||
stat.NumFiles, _ = strconv.Atoi(num)
|
||||
case strings.Contains(suffix, "insertion"):
|
||||
stat.TotalAddition, _ = strconv.Atoi(num)
|
||||
case strings.Contains(suffix, "deletion"):
|
||||
stat.TotalDeletion, _ = strconv.Atoi(num)
|
||||
case ok:
|
||||
setting.PanicInDevOrTesting("unexpected diff shortstat output: %s", stdout)
|
||||
}
|
||||
}
|
||||
return diff, nil
|
||||
return stat, nil
|
||||
}
|
||||
|
||||
// SyncUserSpecificDiff inserts user-specific data such as which files the user has already viewed on the given diff
|
||||
|
||||
@@ -1308,3 +1308,37 @@ D test10.txt`
|
||||
assert.Equal(t, thirdReviewUpdatedFiles, thirdReview.UpdatedFiles)
|
||||
assert.Equal(t, 1, thirdReview.GetViewedFileCount())
|
||||
}
|
||||
|
||||
func TestGetDiffShortStatWithOptions(t *testing.T) {
|
||||
repo, err := git.ForceFastImportWithInit(t.Context(), t.TempDir(), []git.FastImportCommit{
|
||||
{Ref: "refs/heads/base", Files: []git.FastImportFile{
|
||||
{Path: "real.txt", Content: "a1\na2\n"},
|
||||
{Path: "whitespace.txt", Content: "b\n"},
|
||||
}},
|
||||
{Ref: "refs/heads/head", Files: []git.FastImportFile{
|
||||
{Path: "real.txt", Content: "A1\nA2\nA3\n"},
|
||||
{Path: "whitespace.txt", Content: "b \n"},
|
||||
}},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
gitRepo, err := git.OpenRepository(t.Context(), repo)
|
||||
require.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
t.Run("NoParent", func(t *testing.T) {
|
||||
stat, err := GetDiffShortStat(t.Context(), gitRepo, &DiffCommonOptions{AfterCommitID: "refs/heads/head"})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &DiffShortStat{NumFiles: 2, TotalAddition: 4, TotalDeletion: 0}, stat)
|
||||
})
|
||||
diffOptions := DiffCommonOptions{BeforeCommitID: "refs/heads/base", AfterCommitID: "refs/heads/head"}
|
||||
t.Run("NormalDiff", func(t *testing.T) {
|
||||
stat, err := GetDiffShortStat(t.Context(), gitRepo, &diffOptions)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &DiffShortStat{NumFiles: 2, TotalAddition: 4, TotalDeletion: 3}, stat)
|
||||
})
|
||||
t.Run("IgnoreSpace", func(t *testing.T) {
|
||||
diffOptions.WhitespaceBehavior = GetWhitespaceFlag("ignore-all")
|
||||
stat, err := GetDiffShortStat(t.Context(), gitRepo, &diffOptions)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &DiffShortStat{NumFiles: 1, TotalAddition: 3, TotalDeletion: 2}, stat)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package pull
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.dev/modules/git"
|
||||
@@ -97,7 +96,7 @@ func TestAddCommitMessageTailer(t *testing.T) {
|
||||
|
||||
func TestResolveMergeMessageTemplate(t *testing.T) {
|
||||
t.Run("NoDefault", func(t *testing.T) {
|
||||
repo, err := git.ForceFastImportWithInit(t.Context(), filepath.Join(t.TempDir(), "test-repo"), []git.FastImportCommit{
|
||||
repo, err := git.ForceFastImportWithInit(t.Context(), t.TempDir(), []git.FastImportCommit{
|
||||
{Ref: "refs/heads/master", Files: []git.FastImportFile{
|
||||
{Path: ".gitea/default_merge_message/REBASE_TEMPLATE.md", Content: "rebase template"},
|
||||
}},
|
||||
@@ -117,7 +116,7 @@ func TestResolveMergeMessageTemplate(t *testing.T) {
|
||||
assert.Equal(t, "rebase template", tmpl)
|
||||
})
|
||||
t.Run("WithDefault", func(t *testing.T) {
|
||||
repo, err := git.ForceFastImportWithInit(t.Context(), filepath.Join(t.TempDir(), "test-repo"), []git.FastImportCommit{
|
||||
repo, err := git.ForceFastImportWithInit(t.Context(), t.TempDir(), []git.FastImportCommit{
|
||||
{Ref: "refs/heads/master", Files: []git.FastImportFile{
|
||||
{Path: ".gitea/default_merge_message/DEFAULT_TEMPLATE.md", Content: "default template"},
|
||||
{Path: ".gitea/default_merge_message/REBASE_TEMPLATE.md", Content: "rebase template"},
|
||||
|
||||
Reference in New Issue
Block a user