From 1f32170060210b6c4a7fea9b1c1f7f1202cea904 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Sep 2025 10:14:20 -0700 Subject: [PATCH] Move some functions to gitrepo package (#35503) --- modules/git/repo_blame.go | 25 ------------- modules/git/repo_branch.go | 64 ---------------------------------- modules/git/repo_compare.go | 51 --------------------------- modules/gitrepo/blame.go | 18 ++++++++++ modules/gitrepo/branch.go | 50 +++++++++++++++++++++++--- modules/gitrepo/command.go | 15 ++++++++ modules/gitrepo/config.go | 15 ++++---- modules/gitrepo/diff.go | 62 ++++++++++++++++++++++++++++++++ modules/gitrepo/remote.go | 6 ++-- routers/api/v1/repo/pull.go | 2 +- routers/web/repo/activity.go | 4 +-- routers/web/repo/commit.go | 2 +- routers/web/repo/compare.go | 2 +- routers/web/repo/pull.go | 4 +-- services/convert/git_commit.go | 2 +- services/convert/pull.go | 2 +- services/gitdiff/gitdiff.go | 8 ++--- services/pull/pull.go | 2 +- services/pull/review.go | 24 ++++++++++--- services/repository/branch.go | 6 ++-- services/repository/migrate.go | 12 +++---- services/wiki/wiki.go | 12 +------ 22 files changed, 190 insertions(+), 198 deletions(-) delete mode 100644 modules/git/repo_blame.go create mode 100644 modules/gitrepo/blame.go create mode 100644 modules/gitrepo/command.go create mode 100644 modules/gitrepo/diff.go diff --git a/modules/git/repo_blame.go b/modules/git/repo_blame.go deleted file mode 100644 index 04f74049aab..00000000000 --- a/modules/git/repo_blame.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package git - -import ( - "fmt" - - "code.gitea.io/gitea/modules/git/gitcmd" -) - -// LineBlame returns the latest commit at the given line -func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) { - res, _, err := gitcmd.NewCommand("blame"). - AddOptionFormat("-L %d,%d", line, line). - AddOptionValues("-p", revision). - AddDashesAndList(file).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: path}) - if err != nil { - return nil, err - } - if len(res) < 40 { - return nil, fmt.Errorf("invalid result of blame: %s", res) - } - return repo.GetCommit(res[:40]) -} diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 5d4c05bb28a..ef0f9a1e133 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -5,70 +5,12 @@ package git import ( - "context" - "errors" - "strings" - "code.gitea.io/gitea/modules/git/gitcmd" ) // BranchPrefix base dir of the branch information file store on git const BranchPrefix = "refs/heads/" -// IsReferenceExist returns true if given reference exists in the repository. -func IsReferenceExist(ctx context.Context, repoPath, name string) bool { - _, _, err := gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath}) - return err == nil -} - -// IsBranchExist returns true if given branch exists in the repository. -func IsBranchExist(ctx context.Context, repoPath, name string) bool { - return IsReferenceExist(ctx, repoPath, BranchPrefix+name) -} - -func GetDefaultBranch(ctx context.Context, repoPath string) (string, error) { - stdout, _, err := gitcmd.NewCommand("symbolic-ref", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath}) - if err != nil { - return "", err - } - stdout = strings.TrimSpace(stdout) - if !strings.HasPrefix(stdout, BranchPrefix) { - return "", errors.New("the HEAD is not a branch: " + stdout) - } - return strings.TrimPrefix(stdout, BranchPrefix), nil -} - -// DeleteBranchOptions Option(s) for delete branch -type DeleteBranchOptions struct { - Force bool -} - -// DeleteBranch delete a branch by name on repository. -func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error { - cmd := gitcmd.NewCommand("branch") - - if opts.Force { - cmd.AddArguments("-D") - } else { - cmd.AddArguments("-d") - } - - cmd.AddDashesAndList(name) - _, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path}) - - return err -} - -// CreateBranch create a new branch -func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error { - cmd := gitcmd.NewCommand("branch") - cmd.AddDashesAndList(branch, oldbranchOrCommit) - - _, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path}) - - return err -} - // AddRemote adds a new remote to repository. func (repo *Repository) AddRemote(name, url string, fetch bool) error { cmd := gitcmd.NewCommand("remote", "add") @@ -80,9 +22,3 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error { _, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path}) return err } - -// RenameBranch rename a branch -func (repo *Repository) RenameBranch(from, to string) error { - _, _, err := gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path}) - return err -} diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 69a7314d5cf..69835521ec0 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -7,14 +7,12 @@ package git import ( "bufio" "bytes" - "context" "errors" "fmt" "io" "os" "path/filepath" "regexp" - "strconv" "strings" "code.gitea.io/gitea/modules/git/gitcmd" @@ -87,57 +85,8 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis return w.numLines, nil } -// 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, repoPath string, 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.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath}) - if err != nil { - return 0, 0, 0, err - } - - return parseDiffStat(stdout) -} - -var shortStatFormat = regexp.MustCompile( - `\s*(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?`) - var patchCommits = regexp.MustCompile(`^From\s(\w+)\s`) -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 -} - // GetDiff generates and returns patch data between given revisions, optimized for human readability func (repo *Repository) GetDiff(compareArg string, w io.Writer) error { stderr := new(bytes.Buffer) diff --git a/modules/gitrepo/blame.go b/modules/gitrepo/blame.go new file mode 100644 index 00000000000..02ada581301 --- /dev/null +++ b/modules/gitrepo/blame.go @@ -0,0 +1,18 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package gitrepo + +import ( + "context" + + "code.gitea.io/gitea/modules/git/gitcmd" +) + +func LineBlame(ctx context.Context, repo Repository, revision, file string, line uint) (string, error) { + return runCmdString(ctx, repo, + gitcmd.NewCommand("blame"). + AddOptionFormat("-L %d,%d", line, line). + AddOptionValues("-p", revision). + AddDashesAndList(file)) +} diff --git a/modules/gitrepo/branch.go b/modules/gitrepo/branch.go index 4d571f583d0..b857b2ad477 100644 --- a/modules/gitrepo/branch.go +++ b/modules/gitrepo/branch.go @@ -5,6 +5,8 @@ package gitrepo import ( "context" + "errors" + "strings" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/gitcmd" @@ -34,23 +36,61 @@ func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (str // SetDefaultBranch sets default branch of repository. func SetDefaultBranch(ctx context.Context, repo Repository, name string) error { - _, _, err := gitcmd.NewCommand("symbolic-ref", "HEAD"). - AddDynamicArguments(git.BranchPrefix+name). - RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + _, err := runCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD"). + AddDynamicArguments(git.BranchPrefix+name)) return err } // GetDefaultBranch gets default branch of repository. func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) { - return git.GetDefaultBranch(ctx, repoPath(repo)) + stdout, err := runCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD")) + if err != nil { + return "", err + } + stdout = strings.TrimSpace(stdout) + if !strings.HasPrefix(stdout, git.BranchPrefix) { + return "", errors.New("the HEAD is not a branch: " + stdout) + } + return strings.TrimPrefix(stdout, git.BranchPrefix), nil } // IsReferenceExist returns true if given reference exists in the repository. func IsReferenceExist(ctx context.Context, repo Repository, name string) bool { - return git.IsReferenceExist(ctx, repoPath(repo), name) + _, err := runCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name)) + return err == nil } // IsBranchExist returns true if given branch exists in the repository. func IsBranchExist(ctx context.Context, repo Repository, name string) bool { return IsReferenceExist(ctx, repo, git.BranchPrefix+name) } + +// DeleteBranch delete a branch by name on repository. +func DeleteBranch(ctx context.Context, repo Repository, name string, force bool) error { + cmd := gitcmd.NewCommand("branch") + + if force { + cmd.AddArguments("-D") + } else { + cmd.AddArguments("-d") + } + + cmd.AddDashesAndList(name) + _, err := runCmdString(ctx, repo, cmd) + return err +} + +// CreateBranch create a new branch +func CreateBranch(ctx context.Context, repo Repository, branch, oldbranchOrCommit string) error { + cmd := gitcmd.NewCommand("branch") + cmd.AddDashesAndList(branch, oldbranchOrCommit) + + _, err := runCmdString(ctx, repo, cmd) + return err +} + +// RenameBranch rename a branch +func RenameBranch(ctx context.Context, repo Repository, from, to string) error { + _, err := runCmdString(ctx, repo, gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to)) + return err +} diff --git a/modules/gitrepo/command.go b/modules/gitrepo/command.go new file mode 100644 index 00000000000..58dee2aef0f --- /dev/null +++ b/modules/gitrepo/command.go @@ -0,0 +1,15 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package gitrepo + +import ( + "context" + + "code.gitea.io/gitea/modules/git/gitcmd" +) + +func runCmdString(ctx context.Context, repo Repository, cmd *gitcmd.Command) (string, error) { + res, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + return res, err +} diff --git a/modules/gitrepo/config.go b/modules/gitrepo/config.go index c028c6afe8f..5dfdb02b94f 100644 --- a/modules/gitrepo/config.go +++ b/modules/gitrepo/config.go @@ -12,9 +12,8 @@ import ( ) func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) { - result, _, err := gitcmd.NewCommand("config", "--get"). - AddDynamicArguments(key). - RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + result, err := runCmdString(ctx, repo, gitcmd.NewCommand("config", "--get"). + AddDynamicArguments(key)) if err != nil { return "", err } @@ -28,9 +27,8 @@ func getRepoConfigLockKey(repoStoragePath string) string { // GitConfigAdd add a git configuration key to a specific value for the given repository. func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error { return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error { - _, _, err := gitcmd.NewCommand("config", "--add"). - AddDynamicArguments(key, value). - RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + _, err := runCmdString(ctx, repo, gitcmd.NewCommand("config", "--add"). + AddDynamicArguments(key, value)) return err }) } @@ -40,9 +38,8 @@ func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error // If the key exists, it will be updated to the new value. func GitConfigSet(ctx context.Context, repo Repository, key, value string) error { return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error { - _, _, err := gitcmd.NewCommand("config"). - AddDynamicArguments(key, value). - RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + _, err := runCmdString(ctx, repo, gitcmd.NewCommand("config"). + AddDynamicArguments(key, value)) return err }) } diff --git a/modules/gitrepo/diff.go b/modules/gitrepo/diff.go new file mode 100644 index 00000000000..31a7c153b7c --- /dev/null +++ b/modules/gitrepo/diff.go @@ -0,0 +1,62 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package gitrepo + +import ( + "context" + "fmt" + "regexp" + "strconv" + + "code.gitea.io/gitea/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 Repository, 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 := runCmdString(ctx, repo, cmd) + 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 +} diff --git a/modules/gitrepo/remote.go b/modules/gitrepo/remote.go index 20d3cd21da3..f56f6d4702c 100644 --- a/modules/gitrepo/remote.go +++ b/modules/gitrepo/remote.go @@ -36,9 +36,7 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st return errors.New("unknown remote option: " + string(options[0])) } } - _, _, err := cmd. - AddDynamicArguments(remoteName, remoteURL). - RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + _, err := runCmdString(ctx, repo, cmd.AddDynamicArguments(remoteName, remoteURL)) return err }) } @@ -46,7 +44,7 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st func GitRemoteRemove(ctx context.Context, repo Repository, remoteName string) error { return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error { cmd := gitcmd.NewCommand("remote", "rm").AddDynamicArguments(remoteName) - _, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)}) + _, err := runCmdString(ctx, repo, cmd) return err }) } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index ff6ddbce2d4..22851ad2c52 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1620,7 +1620,7 @@ func GetPullRequestFiles(ctx *context.APIContext) { return } - diffShortStat, err := gitdiff.GetDiffShortStat(baseGitRepo, startCommitID, endCommitID) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, baseGitRepo, startCommitID, endCommitID) if err != nil { ctx.APIErrorInternal(err) return diff --git a/routers/web/repo/activity.go b/routers/web/repo/activity.go index 8232f0cc04b..fcede1822ae 100644 --- a/routers/web/repo/activity.go +++ b/routers/web/repo/activity.go @@ -8,7 +8,7 @@ import ( "time" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/git" + git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" @@ -56,7 +56,7 @@ func Activity(ctx *context.Context) { canReadCode := ctx.Repo.CanRead(unit.TypeCode) if canReadCode { // GetActivityStats needs to read the default branch to get some information - branchExist, _ := git.IsBranchExist(ctx, ctx.Repo.Repository.ID, ctx.Repo.Repository.DefaultBranch) + branchExist, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, ctx.Repo.Repository.DefaultBranch) if !branchExist { ctx.Data["NotFoundPrompt"] = ctx.Tr("repo.branch.default_branch_not_exist", ctx.Repo.Repository.DefaultBranch) ctx.NotFound(nil) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 0c60abcecd0..1a86a62fae1 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -324,7 +324,7 @@ func Diff(ctx *context.Context) { ctx.NotFound(err) return } - diffShortStat, err := gitdiff.GetDiffShortStat(gitRepo, "", commitID) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, gitRepo, "", commitID) if err != nil { ctx.ServerError("GetDiffShortStat", err) return diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 2e56f6934a0..9262703078a 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -631,7 +631,7 @@ func PrepareCompareDiff( ctx.ServerError("GetDiff", err) return false } - diffShortStat, err := gitdiff.GetDiffShortStat(ci.HeadGitRepo, beforeCommitID, headCommitID) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ci.HeadRepo, ci.HeadGitRepo, beforeCommitID, headCommitID) if err != nil { ctx.ServerError("GetDiffShortStat", err) return false diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 1ce2047b13d..7970c92ebb5 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -201,7 +201,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.Repo.GitRepo, mergeBaseCommitID, headCommitID) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, mergeBaseCommitID, headCommitID) if err != nil { log.Error("Failed to GetDiffShortStat: %v, repo: %v", err, ctx.Repo.Repository.FullName()) return @@ -761,7 +761,7 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) { } } - diffShortStat, err := gitdiff.GetDiffShortStat(ctx.Repo.GitRepo, beforeCommitID, afterCommitID) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, beforeCommitID, afterCommitID) if err != nil { ctx.ServerError("GetDiffShortStat", err) return diff --git a/services/convert/git_commit.go b/services/convert/git_commit.go index 3ec81b52eeb..d0228c45fb2 100644 --- a/services/convert/git_commit.go +++ b/services/convert/git_commit.go @@ -210,7 +210,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(gitRepo, "", commit.ID.String()) + diffShortStat, err := gitdiff.GetDiffShortStat(ctx, repo, gitRepo, "", commit.ID.String()) if err != nil { return nil, err } diff --git a/services/convert/pull.go b/services/convert/pull.go index 82ab0125d51..50237767e2f 100644 --- a/services/convert/pull.go +++ b/services/convert/pull.go @@ -235,7 +235,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u // Calculate diff startCommitID = pr.MergeBase - diffShortStats, err := gitdiff.GetDiffShortStat(gitRepo, startCommitID, endCommitID) + diffShortStats, err := gitdiff.GetDiffShortStat(ctx, pr.BaseRepo, gitRepo, startCommitID, endCommitID) if err != nil { log.Error("GetDiffShortStat: %v", err) } else { diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 1bb7c05ba2c..1cc5ce66f83 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -21,12 +21,14 @@ import ( git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" pull_model "code.gitea.io/gitea/models/pull" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/attribute" "code.gitea.io/gitea/modules/git/gitcmd" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -1271,9 +1273,7 @@ type DiffShortStat struct { NumFiles, TotalAddition, TotalDeletion int } -func GetDiffShortStat(gitRepo *git.Repository, beforeCommitID, afterCommitID string) (*DiffShortStat, error) { - repoPath := gitRepo.Path - +func GetDiffShortStat(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, beforeCommitID, afterCommitID string) (*DiffShortStat, error) { afterCommit, err := gitRepo.GetCommit(afterCommitID) if err != nil { return nil, err @@ -1285,7 +1285,7 @@ func GetDiffShortStat(gitRepo *git.Repository, beforeCommitID, afterCommitID str } diff := &DiffShortStat{} - diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStatByCmdArgs(gitRepo.Ctx, repoPath, nil, actualBeforeCommitID.String(), afterCommitID) + diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = gitrepo.GetDiffShortStatByCmdArgs(ctx, repo, nil, actualBeforeCommitID.String(), afterCommitID) if err != nil { return nil, err } diff --git a/services/pull/pull.go b/services/pull/pull.go index b64a846adc0..7bf13733b27 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -339,7 +339,7 @@ func checkForInvalidation(ctx context.Context, requests issues_model.PullRequest } go func() { // FIXME: graceful: We need to tell the manager we're doing something... - err := InvalidateCodeComments(ctx, requests, doer, gitRepo, branch) + err := InvalidateCodeComments(ctx, requests, doer, repo, gitRepo, branch) if err != nil { log.Error("PullRequestList.InvalidateCodeComments: %v", err) } diff --git a/services/pull/review.go b/services/pull/review.go index ee18db38599..357a816593d 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -47,11 +47,25 @@ func (err ErrDismissRequestOnClosedPR) Unwrap() error { // ErrSubmitReviewOnClosedPR represents an error when an user tries to submit an approve or reject review associated to a closed or merged PR. var ErrSubmitReviewOnClosedPR = errors.New("can't submit review for a closed or merged PR") +// LineBlame returns the latest commit at the given line +func lineBlame(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, branch, file string, line uint) (*git.Commit, error) { + sha, err := gitrepo.LineBlame(ctx, repo, branch, file, line) + if err != nil { + return nil, err + } + if len(sha) < 40 { + return nil, fmt.Errorf("invalid result of blame: %s", sha) + } + + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) + return gitRepo.GetCommit(sha[:objectFormat.FullLength()]) +} + // checkInvalidation checks if the line of code comment got changed by another commit. // If the line got changed the comment is going to be invalidated. -func checkInvalidation(ctx context.Context, c *issues_model.Comment, repo *git.Repository, branch string) error { +func checkInvalidation(ctx context.Context, c *issues_model.Comment, repo *repo_model.Repository, gitRepo *git.Repository, branch string) error { // FIXME differentiate between previous and proposed line - commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine())) + commit, err := lineBlame(ctx, repo, gitRepo, branch, c.TreePath, uint(c.UnsignedLine())) if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) { c.Invalidated = true return issues_model.UpdateCommentInvalidate(ctx, c) @@ -67,7 +81,7 @@ func checkInvalidation(ctx context.Context, c *issues_model.Comment, repo *git.R } // InvalidateCodeComments will lookup the prs for code comments which got invalidated by change -func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestList, doer *user_model.User, repo *git.Repository, branch string) error { +func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestList, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branch string) error { if len(prs) == 0 { return nil } @@ -83,7 +97,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis return fmt.Errorf("find code comments: %v", err) } for _, comment := range codeComments { - if err := checkInvalidation(ctx, comment, repo, branch); err != nil { + if err := checkInvalidation(ctx, comment, repo, gitRepo, branch); err != nil { return err } } @@ -233,7 +247,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo // FIXME validate treePath // Get latest commit referencing the commented line // No need for get commit for base branch changes - commit, err := gitRepo.LineBlame(head, gitRepo.Path, treePath, uint(line)) + commit, err := lineBlame(ctx, pr.BaseRepo, gitRepo, head, treePath, uint(line)) if err == nil { commitID = commit.ID.String() } else if !(strings.Contains(err.Error(), "exit status 128 - fatal: no such path") || notEnoughLines.MatchString(err.Error())) { diff --git a/services/repository/branch.go b/services/repository/branch.go index 1a34121d990..5d8178375e0 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -441,7 +441,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m } if err := git_model.RenameBranch(ctx, repo, from, to, func(ctx context.Context, isDefault bool) error { - err2 := gitRepo.RenameBranch(from, to) + err2 := gitrepo.RenameBranch(ctx, repo, from, to) if err2 != nil { return err2 } @@ -552,9 +552,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R return nil } - return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ - Force: true, - }) + return gitrepo.DeleteBranch(ctx, repo, branchName, true) }); err != nil { return err } diff --git a/services/repository/migrate.go b/services/repository/migrate.go index db1f020b9f8..88d83fada57 100644 --- a/services/repository/migrate.go +++ b/services/repository/migrate.go @@ -27,8 +27,8 @@ import ( "code.gitea.io/gitea/modules/util" ) -func cloneWiki(ctx context.Context, u *user_model.User, opts migration.MigrateOptions, migrateTimeout time.Duration) (string, error) { - wikiPath := repo_model.WikiPath(u.Name, opts.RepoName) +func cloneWiki(ctx context.Context, repo *repo_model.Repository, opts migration.MigrateOptions, migrateTimeout time.Duration) (string, error) { + wikiPath := repo.WikiPath() wikiRemotePath := repo_module.WikiRemoteURL(ctx, opts.CloneAddr) if wikiRemotePath == "" { return "", nil @@ -59,7 +59,7 @@ func cloneWiki(ctx context.Context, u *user_model.User, opts migration.MigrateOp return "", err } - defaultBranch, err := git.GetDefaultBranch(ctx, wikiPath) + defaultBranch, err := gitrepo.GetDefaultBranch(ctx, repo.WikiStorageRepo()) if err != nil { cleanIncompleteWikiPath() return "", fmt.Errorf("failed to get wiki repo default branch for %q, err: %w", wikiPath, err) @@ -73,7 +73,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, repo *repo_model.Repository, opts migration.MigrateOptions, httpTransport *http.Transport, ) (*repo_model.Repository, error) { - repoPath := repo_model.RepoPath(u.Name, opts.RepoName) + repoPath := repo.RepoPath() if u.IsOrganization() { t, err := organization.OrgFromUser(u).GetOwnerTeam(ctx) @@ -108,7 +108,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } if opts.Wiki { - defaultWikiBranch, err := cloneWiki(ctx, u, opts, migrateTimeout) + defaultWikiBranch, err := cloneWiki(ctx, repo, opts, migrateTimeout) if err != nil { return repo, fmt.Errorf("clone wiki error: %w", err) } @@ -137,7 +137,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, if !repo.IsEmpty { if len(repo.DefaultBranch) == 0 { // Try to get HEAD branch and set it as default branch. - headBranchName, err := git.GetDefaultBranch(ctx, repoPath) + headBranchName, err := gitrepo.GetDefaultBranch(ctx, repo) if err != nil { return repo, fmt.Errorf("GetHEADBranch: %w", err) } diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 7848e0f46da..25c33b57fc7 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -6,7 +6,6 @@ package wiki import ( "context" - "errors" "fmt" "os" "strings" @@ -22,7 +21,6 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" repo_service "code.gitea.io/gitea/services/repository" ) @@ -393,15 +391,7 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n return nil } - gitRepo, err := gitrepo.OpenRepository(ctx, repo.WikiStorageRepo()) - if errors.Is(err, util.ErrNotExist) { - return nil // no git repo on storage, no need to do anything else - } else if err != nil { - return fmt.Errorf("unable to open repository: %w", err) - } - defer gitRepo.Close() - - err = gitRepo.RenameBranch(oldDefBranch, newBranch) + err = gitrepo.RenameBranch(ctx, repo.WikiStorageRepo(), oldDefBranch, newBranch) if err != nil { return fmt.Errorf("unable to rename default branch: %w", err) }