refactor: clean up git repo and model migration packages (#38564)

enable the golangci depguard lint rule: deny "models" and its sub
packages in "modelmigration" package.
This commit is contained in:
wxiaoguang
2026-07-23 09:22:26 +08:00
committed by GitHub
parent fa64b4627a
commit 1acf93d854
43 changed files with 243 additions and 167 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ import (
"strings"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/setting"
)
@@ -48,7 +49,7 @@ func CreateBundle(ctx context.Context, repo RepositoryFacade, commit string, out
}
defer cleanup()
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(gitcmd.RepoLocalPath(repo), "objects"))
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(gitrepo.RepoLocalPath(repo), "objects"))
gitTmpCmd := func() *gitcmd.Command {
return gitcmd.NewCommand().WithDir(tmpDir).WithEnv(env)
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"io"
"os"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/util"
)
@@ -50,7 +50,7 @@ type CatFileBatchCloser interface {
// NewBatch creates a "batch object provider (CatFileBatch)" for the given repository path to retrieve object info and content efficiently.
// The CatFileBatch and the readers create by it should only be used in the same goroutine.
func NewBatch(ctx context.Context, repo RepositoryFacade) (CatFileBatchCloser, error) {
repoPath := gitcmd.RepoLocalPath(repo)
repoPath := gitrepo.RepoLocalPath(repo)
if _, err := os.Stat(repoPath); err != nil {
return nil, util.NewNotExistErrorf("repo %q doesn't exist", repo.LogString())
}
+3 -3
View File
@@ -9,7 +9,7 @@ import (
"path/filepath"
"testing"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/test"
"github.com/stretchr/testify/assert"
@@ -26,10 +26,10 @@ func TestCatFileBatch(t *testing.T) {
func testCatFileBatch(t *testing.T) {
repo1Path, _ := filepath.Abs(filepath.Join(testReposDir, "repo1_bare"))
repo1 := gitcmd.RepositoryUnmanaged(repo1Path)
repo1 := gitrepo.RepositoryUnmanaged(repo1Path)
t.Run("CorruptedGitRepo", func(t *testing.T) {
tmpDir := t.TempDir()
batch, err := NewBatch(t.Context(), gitcmd.RepositoryUnmanaged(tmpDir))
batch, err := NewBatch(t.Context(), gitrepo.RepositoryUnmanaged(tmpDir))
// as long as the directory exists, no error, because we can't really know whether the git repo is valid until we run commands
require.NoError(t, err)
defer batch.Close()
+4 -4
View File
@@ -6,19 +6,19 @@ package git
import (
"context"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
)
// CloneExternalRepo clones an external repository to the managed repository.
func CloneExternalRepo(ctx context.Context, fromRemoteURL string, toRepo RepositoryFacade, opts CloneRepoOptions) error {
return Clone(ctx, fromRemoteURL, gitcmd.RepoLocalPath(toRepo), opts)
return Clone(ctx, fromRemoteURL, gitrepo.RepoLocalPath(toRepo), opts)
}
// CloneRepoToLocal clones a managed repository to a local path.
func CloneRepoToLocal(ctx context.Context, fromRepo RepositoryFacade, toLocalPath string, opts CloneRepoOptions) error {
return Clone(ctx, gitcmd.RepoLocalPath(fromRepo), toLocalPath, opts)
return Clone(ctx, gitrepo.RepoLocalPath(fromRepo), toLocalPath, opts)
}
func CloneManaged(ctx context.Context, fromRepo, toRepo RepositoryFacade, opts CloneRepoOptions) error {
return Clone(ctx, gitcmd.RepoLocalPath(fromRepo), gitcmd.RepoLocalPath(toRepo), opts)
return Clone(ctx, gitrepo.RepoLocalPath(fromRepo), gitrepo.RepoLocalPath(toRepo), opts)
}
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"context"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
)
// FetchRemoteCommit fetches a specific commit and its related objects from a remote
@@ -21,7 +22,7 @@ import (
func FetchRemoteCommit(ctx context.Context, repo, remoteRepo RepositoryFacade, commitID string) error {
return LockWriteAndDo(ctx, repo, func(ctx context.Context) error {
return gitcmd.NewCommand("fetch", "--no-tags").
AddDynamicArguments(gitcmd.RepoLocalPath(remoteRepo)).
AddDynamicArguments(gitrepo.RepoLocalPath(remoteRepo)).
AddDynamicArguments(commitID).
WithRepo(repo).Run(ctx)
})
+6
View File
@@ -16,6 +16,7 @@ import (
"strings"
"time"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/git/internal" //nolint:depguard // only this file can use the internal type CmdArg, other files and packages should use AddXxx functions
"gitea.dev/modules/gtprof"
"gitea.dev/modules/log"
@@ -261,6 +262,11 @@ func (c *Command) WithDir(dir string) *Command {
return c
}
func (c *Command) WithRepo(repo gitrepo.RepositoryFacade) *Command {
c.gitDir = gitrepo.RepoLocalPath(repo)
return c
}
func (c *Command) WithEnv(env []string) *Command {
c.cmdEnv = env
return c
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package gitrepo
import "strings"
func RepoCodeGitRepoRelativePath(ownerName, repoName string) string {
return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".git"
}
func RepoWikiGitRepoRelativePath(ownerName, repoName string) string {
return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".wiki.git"
}
// CodeRepoByName returns an unmanaged repository facade for the code repository of the given owner and repository name.
// Usually it is used for migration fixes or repository adoption/creation/rename/transfer.
func CodeRepoByName(ownerName, repoName string) RepositoryFacade {
return RepositoryUnmanaged(RepoCodeGitRepoRelativePath(ownerName, repoName))
}
func WikiRepoByName(ownerName, repoName string) RepositoryFacade {
return RepositoryUnmanaged(RepoWikiGitRepoRelativePath(ownerName, repoName))
}
@@ -1,7 +1,7 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package gitcmd
package gitrepo
import (
"path/filepath"
@@ -24,11 +24,6 @@ type RepositoryFacade interface {
LogString() string
}
func (c *Command) WithRepo(repo RepositoryFacade) *Command {
c.gitDir = RepoLocalPath(repo)
return c
}
// RepoLocalPath returns an absolute path for a RepositoryFacade.
// TODO: most of the calls to this function should be replaced with a "Repo FS" in the future
// to handle file accesses in the git repo (e.g.: read, write, list, remove).
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"path/filepath"
"testing"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/setting"
"gitea.dev/modules/test"
@@ -79,7 +79,7 @@ func TestGrepSearch(t *testing.T) {
assert.NoError(t, err)
assert.Empty(t, res)
nonExistingRepo := &Repository{RepositoryBase: RepositoryBase{repoFacade: gitcmd.RepositoryUnmanaged("no-such-git-repo")}}
nonExistingRepo := &Repository{RepositoryBase: RepositoryBase{repoFacade: gitrepo.RepositoryUnmanaged("no-such-git-repo")}}
res, err = GrepSearch(t.Context(), nonExistingRepo, "no-such-content", GrepOptions{})
assert.Error(t, err)
assert.Empty(t, res)
+3 -3
View File
@@ -11,7 +11,7 @@ import (
"slices"
"strings"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/util"
)
@@ -41,7 +41,7 @@ type Hook struct {
// GetHook returns a Git hook by given name and repository.
func GetHook(repo RepositoryFacade, name string) (*Hook, error) {
repoPath := gitcmd.RepoLocalPath(repo)
repoPath := gitrepo.RepoLocalPath(repo)
if !IsValidHookName(name) {
return nil, ErrNotValidHook
}
@@ -100,7 +100,7 @@ func (h *Hook) Update() error {
// ListHooks returns a list of Git hooks of given repository.
func ListHooks(repo RepositoryFacade) (_ []*Hook, err error) {
exist, err := util.IsDir(filepath.Join(gitcmd.RepoLocalPath(repo), "hooks"))
exist, err := util.IsDir(filepath.Join(gitrepo.RepoLocalPath(repo), "hooks"))
if err != nil {
return nil, err
} else if !exist {
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"path/filepath"
"runtime"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
@@ -109,7 +109,7 @@ done
// CreateDelegateHooks creates all the hooks scripts for the repo
func CreateDelegateHooks(_ context.Context, repo RepositoryFacade) (err error) {
return createDelegateHooks(filepath.Join(gitcmd.RepoLocalPath(repo), "hooks"))
return createDelegateHooks(filepath.Join(gitrepo.RepoLocalPath(repo), "hooks"))
}
func createDelegateHooks(hookDir string) (err error) {
@@ -176,7 +176,7 @@ func ensureExecutable(filename string) error {
// CheckDelegateHooks checks the hooks scripts for the repo
func CheckDelegateHooks(_ context.Context, repo RepositoryFacade) ([]string, error) {
return checkDelegateHooks(filepath.Join(gitcmd.RepoLocalPath(repo), "hooks"))
return checkDelegateHooks(filepath.Join(gitrepo.RepoLocalPath(repo), "hooks"))
}
func checkDelegateHooks(hookDir string) ([]string, error) {
+11 -11
View File
@@ -11,59 +11,59 @@ import (
"os"
"path/filepath"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/util"
)
// IsRepositoryExist returns true if the repository directory exists in the disk
func IsRepositoryExist(ctx context.Context, repo RepositoryFacade) (bool, error) {
return util.IsExist(gitcmd.RepoLocalPath(repo))
return util.IsExist(gitrepo.RepoLocalPath(repo))
}
// DeleteRepository deletes the repository directory from the disk, it will return
// nil if the repository does not exist.
func DeleteRepository(ctx context.Context, repo RepositoryFacade) error {
return util.RemoveAll(gitcmd.RepoLocalPath(repo))
return util.RemoveAll(gitrepo.RepoLocalPath(repo))
}
// RenameRepository renames a repository's name on disk
func RenameRepository(ctx context.Context, repo, newRepo RepositoryFacade) error {
dstDir := gitcmd.RepoLocalPath(newRepo)
dstDir := gitrepo.RepoLocalPath(newRepo)
if err := os.MkdirAll(filepath.Dir(dstDir), os.ModePerm); err != nil {
return fmt.Errorf("Failed to create dir %s: %w", filepath.Dir(dstDir), err)
}
if err := util.Rename(gitcmd.RepoLocalPath(repo), dstDir); err != nil {
if err := util.Rename(gitrepo.RepoLocalPath(repo), dstDir); err != nil {
return fmt.Errorf("rename repository directory: %w", err)
}
return nil
}
func InitRepository(ctx context.Context, repo RepositoryFacade, objectFormatName string) error {
return InitRepositoryLocal(ctx, gitcmd.RepoLocalPath(repo), true, objectFormatName)
return InitRepositoryLocal(ctx, gitrepo.RepoLocalPath(repo), true, objectFormatName)
}
func GetRepoFS(repo RepositoryFacade) fs.FS {
return os.DirFS(gitcmd.RepoLocalPath(repo))
return os.DirFS(gitrepo.RepoLocalPath(repo))
}
func IsRepoFileExist(ctx context.Context, repo RepositoryFacade, relativeFilePath string) (bool, error) {
absoluteFilePath := filepath.Join(gitcmd.RepoLocalPath(repo), relativeFilePath)
absoluteFilePath := filepath.Join(gitrepo.RepoLocalPath(repo), relativeFilePath)
return util.IsExist(absoluteFilePath)
}
func IsRepoDirExist(ctx context.Context, repo RepositoryFacade, relativeDirPath string) (bool, error) {
absoluteDirPath := filepath.Join(gitcmd.RepoLocalPath(repo), relativeDirPath)
absoluteDirPath := filepath.Join(gitrepo.RepoLocalPath(repo), relativeDirPath)
return util.IsDir(absoluteDirPath)
}
func RemoveRepoFileOrDir(ctx context.Context, repo RepositoryFacade, relativeFileOrDirPath string) error {
absoluteFilePath := filepath.Join(gitcmd.RepoLocalPath(repo), relativeFileOrDirPath)
absoluteFilePath := filepath.Join(gitrepo.RepoLocalPath(repo), relativeFileOrDirPath)
return util.Remove(absoluteFilePath)
}
func CreateRepoFile(ctx context.Context, repo RepositoryFacade, relativeFilePath string) (io.WriteCloser, error) {
absoluteFilePath := filepath.Join(gitcmd.RepoLocalPath(repo), relativeFilePath)
absoluteFilePath := filepath.Join(gitrepo.RepoLocalPath(repo), relativeFilePath)
if err := os.MkdirAll(filepath.Dir(absoluteFilePath), os.ModePerm); err != nil {
return nil, err
}
+3 -3
View File
@@ -7,17 +7,17 @@ import (
"path/filepath"
"testing"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
)
const testReposDir = "tests/repos/"
func mockRepository(repoPath string) gitcmd.RepositoryFacade {
func mockRepository(repoPath string) RepositoryFacade {
if !filepath.IsAbs(repoPath) {
// resolve repository path relative to the unit test fixture directory
repoPath, _ = filepath.Abs(filepath.Join(testReposDir, repoPath))
}
return gitcmd.RepositoryUnmanaged(repoPath)
return gitrepo.RepositoryUnmanaged(repoPath)
}
func TestMain(m *testing.M) {
+5 -5
View File
@@ -6,22 +6,22 @@ package git
import (
"context"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
)
// PushToExternal pushes a managed repository to an external remote.
func PushToExternal(ctx context.Context, repo RepositoryFacade, opts PushOptions) error {
return Push(ctx, gitcmd.RepoLocalPath(repo), opts)
return Push(ctx, gitrepo.RepoLocalPath(repo), opts)
}
// PushManaged pushes from one managed repository to another managed repository.
func PushManaged(ctx context.Context, fromRepo, toRepo RepositoryFacade, opts PushOptions) error {
opts.Remote = gitcmd.RepoLocalPath(toRepo)
return Push(ctx, gitcmd.RepoLocalPath(fromRepo), opts)
opts.Remote = gitrepo.RepoLocalPath(toRepo)
return Push(ctx, gitrepo.RepoLocalPath(fromRepo), opts)
}
// PushFromLocal pushes from a local path to a managed repository.
func PushFromLocal(ctx context.Context, fromLocalPath string, toRepo RepositoryFacade, opts PushOptions) error {
opts.Remote = gitcmd.RepoLocalPath(toRepo)
opts.Remote = gitrepo.RepoLocalPath(toRepo)
return Push(ctx, fromLocalPath, opts)
}
+6 -5
View File
@@ -17,12 +17,13 @@ import (
"time"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/proxy"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
type RepositoryFacade = gitcmd.RepositoryFacade
type RepositoryFacade = gitrepo.RepositoryFacade
type RepositoryBase struct {
LastCommitCache *LastCommitCache
@@ -36,7 +37,7 @@ type RepositoryBase struct {
catFileBatchInUse bool
}
var _ gitcmd.RepositoryFacade = (*Repository)(nil)
var _ RepositoryFacade = (*Repository)(nil)
func (repo *Repository) GitRepoManagedID() string {
return repo.repoFacade.GitRepoManagedID()
@@ -51,7 +52,7 @@ func (repo *Repository) LogString() string {
}
func OpenRepository(repo RepositoryFacade) (*Repository, error) {
repoPath := gitcmd.RepoLocalPath(repo)
repoPath := gitrepo.RepoLocalPath(repo)
exist, err := util.IsDir(repoPath)
if err != nil {
return nil, err
@@ -77,7 +78,7 @@ func OpenRepositoryLocal(localPath string) (_ *Repository, err error) {
return nil, err
}
}
return OpenRepository(gitcmd.RepositoryUnmanaged(localPath))
return OpenRepository(gitrepo.RepositoryUnmanaged(localPath))
}
func (repo *Repository) Close() error {
@@ -130,7 +131,7 @@ func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, o
// IsEmpty Check if repository is empty.
func (repo *Repository) IsEmpty(ctx context.Context) (bool, error) {
stdout, _, err := gitcmd.NewCommand().
AddOptionFormat("--git-dir=%s", gitcmd.RepoLocalPath(repo)). // TODO: all git commands should use "--git-dir" or "GIT_DIR=..."
AddOptionFormat("--git-dir=%s", gitrepo.RepoLocalPath(repo)). // TODO: all git commands should use "--git-dir" or "GIT_DIR=..."
AddArguments("rev-list", "-n", "1", "--all").
WithRepo(repo).
RunStdString(ctx)
+2 -2
View File
@@ -9,7 +9,7 @@ package git
import (
"path/filepath"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/setting"
"github.com/go-git/go-billy/v5"
@@ -30,7 +30,7 @@ type Repository struct {
}
func openRepositoryInternal(gitRepo *Repository) error {
repoPath := gitcmd.RepoLocalPath(gitRepo)
repoPath := gitrepo.RepoLocalPath(gitRepo)
fs := osfs.New(repoPath)
_, err := fs.Stat(".git")
if err == nil {
+2 -2
View File
@@ -10,7 +10,7 @@ import (
"os"
"path/filepath"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
"gitea.dev/modules/log"
commitgraph "github.com/go-git/go-git/v5/plumbing/format/commitgraph/v2"
@@ -19,7 +19,7 @@ import (
// CommitNodeIndex returns the index for walking commit graph
func (repo *Repository) CommitNodeIndex() (_ cgobject.CommitNodeIndex, closer func()) {
indexPath := filepath.Join(gitcmd.RepoLocalPath(repo), "objects", "info", "commit-graph")
indexPath := filepath.Join(gitrepo.RepoLocalPath(repo), "objects", "info", "commit-graph")
file, err := os.Open(indexPath)
if err == nil {
var index commitgraph.Index
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"os"
"path/filepath"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/git/gitrepo"
)
const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular
@@ -15,7 +15,7 @@ const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | o
// CalcRepositorySize returns the disk consumption for a given path
func CalcRepositorySize(repo RepositoryFacade) (int64, error) {
var size int64
err := filepath.WalkDir(gitcmd.RepoLocalPath(repo), func(_ string, entry os.DirEntry, err error) error {
err := filepath.WalkDir(gitrepo.RepoLocalPath(repo), func(_ string, entry os.DirEntry, err error) error {
if os.IsNotExist(err) { // ignore the error because some files (like temp/lock file) may be deleted during traversing.
return nil
} else if err != nil {
+1 -1
View File
@@ -19,7 +19,7 @@ type TemplateSubmoduleCommit struct {
// GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository
// This function is only for generating new repos based on existing template, the template couldn't be too large.
func GetTemplateSubmoduleCommits(ctx context.Context, repo gitcmd.RepositoryFacade) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
func GetTemplateSubmoduleCommits(ctx context.Context, repo RepositoryFacade) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
cmd := gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD")
stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe()
defer stdoutReaderClose()