gitea source for verification 2026-05-22
This commit is contained in:
56
modules/gitrepo/branch.go
Normal file
56
modules/gitrepo/branch.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
)
|
||||
|
||||
// GetBranchesByPath returns a branch by its path
|
||||
// if limit = 0 it will not limit
|
||||
func GetBranchesByPath(ctx context.Context, repo Repository, skip, limit int) ([]string, int, error) {
|
||||
gitRepo, err := OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
return gitRepo.GetBranchNames(skip, limit)
|
||||
}
|
||||
|
||||
func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (string, error) {
|
||||
gitRepo, err := OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
return gitRepo.GetBranchCommitID(branch)
|
||||
}
|
||||
|
||||
// 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)})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDefaultBranch gets default branch of repository.
|
||||
func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {
|
||||
return git.GetDefaultBranch(ctx, repoPath(repo))
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
48
modules/gitrepo/config.go
Normal file
48
modules/gitrepo/config.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
"code.gitea.io/gitea/modules/globallock"
|
||||
)
|
||||
|
||||
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)})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(result), nil
|
||||
}
|
||||
|
||||
func getRepoConfigLockKey(repoStoragePath string) string {
|
||||
return "repo-config:" + repoStoragePath
|
||||
}
|
||||
|
||||
// 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)})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// GitConfigSet updates a git configuration key to a specific value for the given repository.
|
||||
// If the key does not exist, it will be created.
|
||||
// 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)})
|
||||
return err
|
||||
})
|
||||
}
|
||||
16
modules/gitrepo/fsck.go
Normal file
16
modules/gitrepo/fsck.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
)
|
||||
|
||||
// Fsck verifies the connectivity and validity of the objects in the database
|
||||
func Fsck(ctx context.Context, repo Repository, timeout time.Duration, args gitcmd.TrustedCmdArgs) error {
|
||||
return gitcmd.NewCommand("fsck").AddArguments(args...).Run(ctx, &gitcmd.RunOpts{Timeout: timeout, Dir: repoPath(repo)})
|
||||
}
|
||||
88
modules/gitrepo/gitrepo.go
Normal file
88
modules/gitrepo/gitrepo.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/reqctx"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// Repository represents a git repository which stored in a disk
|
||||
type Repository interface {
|
||||
RelativePath() string // We don't assume how the directory structure of the repository is, so we only need the relative path
|
||||
}
|
||||
|
||||
// RelativePath should be an unix style path like username/reponame.git
|
||||
// This method should change it according to the current OS.
|
||||
func repoPath(repo Repository) string {
|
||||
return filepath.Join(setting.RepoRootPath, filepath.FromSlash(repo.RelativePath()))
|
||||
}
|
||||
|
||||
// OpenRepository opens the repository at the given relative path with the provided context.
|
||||
func OpenRepository(ctx context.Context, repo Repository) (*git.Repository, error) {
|
||||
return git.OpenRepository(ctx, repoPath(repo))
|
||||
}
|
||||
|
||||
// contextKey is a value for use with context.WithValue.
|
||||
type contextKey struct {
|
||||
repoPath string
|
||||
}
|
||||
|
||||
// RepositoryFromContextOrOpen attempts to get the repository from the context or just opens it
|
||||
// The caller must call "defer gitRepo.Close()"
|
||||
func RepositoryFromContextOrOpen(ctx context.Context, repo Repository) (*git.Repository, io.Closer, error) {
|
||||
reqCtx := reqctx.FromContext(ctx)
|
||||
if reqCtx != nil {
|
||||
gitRepo, err := RepositoryFromRequestContextOrOpen(reqCtx, repo)
|
||||
return gitRepo, util.NopCloser{}, err
|
||||
}
|
||||
gitRepo, err := OpenRepository(ctx, repo)
|
||||
return gitRepo, gitRepo, err
|
||||
}
|
||||
|
||||
// RepositoryFromRequestContextOrOpen opens the repository at the given relative path in the provided request context.
|
||||
// Caller shouldn't close the git repo manually, the git repo will be automatically closed when the request context is done.
|
||||
func RepositoryFromRequestContextOrOpen(ctx reqctx.RequestContext, repo Repository) (*git.Repository, error) {
|
||||
ck := contextKey{repoPath: repoPath(repo)}
|
||||
if gitRepo, ok := ctx.Value(ck).(*git.Repository); ok {
|
||||
return gitRepo, nil
|
||||
}
|
||||
gitRepo, err := git.OpenRepository(ctx, ck.repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.AddCloser(gitRepo)
|
||||
ctx.SetContextValue(ck, gitRepo)
|
||||
return gitRepo, nil
|
||||
}
|
||||
|
||||
// IsRepositoryExist returns true if the repository directory exists in the disk
|
||||
func IsRepositoryExist(ctx context.Context, repo Repository) (bool, error) {
|
||||
return util.IsExist(repoPath(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 Repository) error {
|
||||
return util.RemoveAll(repoPath(repo))
|
||||
}
|
||||
|
||||
// RenameRepository renames a repository's name on disk
|
||||
func RenameRepository(ctx context.Context, repo, newRepo Repository) error {
|
||||
if err := util.Rename(repoPath(repo), repoPath(newRepo)); err != nil {
|
||||
return fmt.Errorf("rename repository directory: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitRepository(ctx context.Context, repo Repository, objectFormatName string) error {
|
||||
return git.InitRepository(ctx, repoPath(repo), true, objectFormatName)
|
||||
}
|
||||
240
modules/gitrepo/hooks.go
Normal file
240
modules/gitrepo/hooks.go
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) {
|
||||
hookNames = []string{"pre-receive", "update", "post-receive"}
|
||||
hookTpls = []string{
|
||||
// for pre-receive
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
data=$(cat)
|
||||
exitcodes=""
|
||||
hookname=$(basename $0)
|
||||
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||
|
||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||
test -x "${hook}" && test -f "${hook}" || continue
|
||||
echo "${data}" | "${hook}"
|
||||
exitcodes="${exitcodes} $?"
|
||||
done
|
||||
|
||||
for i in ${exitcodes}; do
|
||||
[ ${i} -eq 0 ] || exit ${i}
|
||||
done
|
||||
`, setting.ScriptType),
|
||||
|
||||
// for update
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
exitcodes=""
|
||||
hookname=$(basename $0)
|
||||
GIT_DIR=${GIT_DIR:-$(dirname $0/..)}
|
||||
|
||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||
test -x "${hook}" && test -f "${hook}" || continue
|
||||
"${hook}" $1 $2 $3
|
||||
exitcodes="${exitcodes} $?"
|
||||
done
|
||||
|
||||
for i in ${exitcodes}; do
|
||||
[ ${i} -eq 0 ] || exit ${i}
|
||||
done
|
||||
`, setting.ScriptType),
|
||||
|
||||
// for post-receive
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
data=$(cat)
|
||||
exitcodes=""
|
||||
hookname=$(basename $0)
|
||||
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||
|
||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||
test -x "${hook}" && test -f "${hook}" || continue
|
||||
echo "${data}" | "${hook}"
|
||||
exitcodes="${exitcodes} $?"
|
||||
done
|
||||
|
||||
for i in ${exitcodes}; do
|
||||
[ ${i} -eq 0 ] || exit ${i}
|
||||
done
|
||||
`, setting.ScriptType),
|
||||
}
|
||||
|
||||
giteaHookTpls = []string{
|
||||
// for pre-receive
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
%s hook --config=%s pre-receive
|
||||
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),
|
||||
|
||||
// for update
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
%s hook --config=%s update $1 $2 $3
|
||||
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),
|
||||
|
||||
// for post-receive
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
%s hook --config=%s post-receive
|
||||
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),
|
||||
}
|
||||
|
||||
// although only new git (>=2.29) supports proc-receive, it's still good to create its hook, in case the user upgrades git
|
||||
hookNames = append(hookNames, "proc-receive")
|
||||
hookTpls = append(hookTpls,
|
||||
fmt.Sprintf(`#!/usr/bin/env %s
|
||||
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||
%s hook --config=%s proc-receive
|
||||
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)))
|
||||
giteaHookTpls = append(giteaHookTpls, "")
|
||||
|
||||
return hookNames, hookTpls, giteaHookTpls
|
||||
}
|
||||
|
||||
// CreateDelegateHooks creates all the hooks scripts for the repo
|
||||
func CreateDelegateHooks(_ context.Context, repo Repository) (err error) {
|
||||
return createDelegateHooks(filepath.Join(repoPath(repo), "hooks"))
|
||||
}
|
||||
|
||||
func createDelegateHooks(hookDir string) (err error) {
|
||||
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
|
||||
|
||||
for i, hookName := range hookNames {
|
||||
oldHookPath := filepath.Join(hookDir, hookName)
|
||||
newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(hookDir, hookName+".d"), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("create hooks dir '%s': %w", filepath.Join(hookDir, hookName+".d"), err)
|
||||
}
|
||||
|
||||
// WARNING: This will override all old server-side hooks
|
||||
if err = util.Remove(oldHookPath); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("unable to pre-remove old hook file '%s' prior to rewriting: %w ", oldHookPath, err)
|
||||
}
|
||||
if err = os.WriteFile(oldHookPath, []byte(hookTpls[i]), 0o777); err != nil {
|
||||
return fmt.Errorf("write old hook file '%s': %w", oldHookPath, err)
|
||||
}
|
||||
|
||||
if err = ensureExecutable(oldHookPath); err != nil {
|
||||
return fmt.Errorf("Unable to set %s executable. Error %w", oldHookPath, err)
|
||||
}
|
||||
|
||||
if err = util.Remove(newHookPath); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %w", newHookPath, err)
|
||||
}
|
||||
if err = os.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0o777); err != nil {
|
||||
return fmt.Errorf("write new hook file '%s': %w", newHookPath, err)
|
||||
}
|
||||
|
||||
if err = ensureExecutable(newHookPath); err != nil {
|
||||
return fmt.Errorf("Unable to set %s executable. Error %w", oldHookPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkExecutable(filename string) bool {
|
||||
// windows has no concept of a executable bit
|
||||
if runtime.GOOS == "windows" {
|
||||
return true
|
||||
}
|
||||
fileInfo, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return (fileInfo.Mode() & 0o100) > 0
|
||||
}
|
||||
|
||||
func ensureExecutable(filename string) error {
|
||||
fileInfo, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (fileInfo.Mode() & 0o100) > 0 {
|
||||
return nil
|
||||
}
|
||||
mode := fileInfo.Mode() | 0o100
|
||||
return os.Chmod(filename, mode)
|
||||
}
|
||||
|
||||
// CheckDelegateHooks checks the hooks scripts for the repo
|
||||
func CheckDelegateHooks(_ context.Context, repo Repository) ([]string, error) {
|
||||
return checkDelegateHooks(filepath.Join(repoPath(repo), "hooks"))
|
||||
}
|
||||
|
||||
func checkDelegateHooks(hookDir string) ([]string, error) {
|
||||
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
|
||||
|
||||
results := make([]string, 0, 10)
|
||||
|
||||
for i, hookName := range hookNames {
|
||||
oldHookPath := filepath.Join(hookDir, hookName)
|
||||
newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")
|
||||
|
||||
cont := false
|
||||
isExist, err := util.IsExist(oldHookPath)
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath, err))
|
||||
}
|
||||
if err == nil && !isExist {
|
||||
results = append(results, fmt.Sprintf("old hook file %s does not exist", oldHookPath))
|
||||
cont = true
|
||||
}
|
||||
isExist, err = util.IsExist(oldHookPath + ".d")
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath+".d", err))
|
||||
}
|
||||
if err == nil && !isExist {
|
||||
results = append(results, fmt.Sprintf("hooks directory %s does not exist", oldHookPath+".d"))
|
||||
cont = true
|
||||
}
|
||||
isExist, err = util.IsExist(newHookPath)
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", newHookPath, err))
|
||||
}
|
||||
if err == nil && !isExist {
|
||||
results = append(results, fmt.Sprintf("new hook file %s does not exist", newHookPath))
|
||||
cont = true
|
||||
}
|
||||
if cont {
|
||||
continue
|
||||
}
|
||||
contents, err := os.ReadFile(oldHookPath)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
if string(contents) != hookTpls[i] {
|
||||
results = append(results, fmt.Sprintf("old hook file %s is out of date", oldHookPath))
|
||||
}
|
||||
if !checkExecutable(oldHookPath) {
|
||||
results = append(results, fmt.Sprintf("old hook file %s is not executable", oldHookPath))
|
||||
}
|
||||
contents, err = os.ReadFile(newHookPath)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
if string(contents) != giteaHookTpls[i] {
|
||||
results = append(results, fmt.Sprintf("new hook file %s is out of date", newHookPath))
|
||||
}
|
||||
if !checkExecutable(newHookPath) {
|
||||
results = append(results, fmt.Sprintf("new hook file %s is not executable", newHookPath))
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
21
modules/gitrepo/ref.go
Normal file
21
modules/gitrepo/ref.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
)
|
||||
|
||||
func UpdateRef(ctx context.Context, repo Repository, refName, newCommitID string) error {
|
||||
_, _, err := gitcmd.NewCommand("update-ref").AddDynamicArguments(refName, newCommitID).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||
return err
|
||||
}
|
||||
|
||||
func RemoveRef(ctx context.Context, repo Repository, refName string) error {
|
||||
_, _, err := gitcmd.NewCommand("update-ref", "--no-deref", "-d").
|
||||
AddDynamicArguments(refName).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||
return err
|
||||
}
|
||||
86
modules/gitrepo/remote.go
Normal file
86
modules/gitrepo/remote.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
giturl "code.gitea.io/gitea/modules/git/url"
|
||||
"code.gitea.io/gitea/modules/globallock"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
type RemoteOption string
|
||||
|
||||
const (
|
||||
RemoteOptionMirrorPush RemoteOption = "--mirror=push"
|
||||
RemoteOptionMirrorFetch RemoteOption = "--mirror=fetch"
|
||||
)
|
||||
|
||||
func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL string, options ...RemoteOption) error {
|
||||
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
||||
cmd := gitcmd.NewCommand("remote", "add")
|
||||
if len(options) > 0 {
|
||||
switch options[0] {
|
||||
case RemoteOptionMirrorPush:
|
||||
cmd.AddArguments("--mirror=push")
|
||||
case RemoteOptionMirrorFetch:
|
||||
cmd.AddArguments("--mirror=fetch")
|
||||
default:
|
||||
return errors.New("unknown remote option: " + string(options[0]))
|
||||
}
|
||||
}
|
||||
_, _, err := cmd.
|
||||
AddDynamicArguments(remoteName, remoteURL).
|
||||
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
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)})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// GitRemoteGetURL returns the url of a specific remote of the repository.
|
||||
func GitRemoteGetURL(ctx context.Context, repo Repository, remoteName string) (*giturl.GitURL, error) {
|
||||
addr, err := git.GetRemoteAddress(ctx, repoPath(repo), remoteName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if addr == "" {
|
||||
return nil, util.NewNotExistErrorf("remote '%s' does not exist", remoteName)
|
||||
}
|
||||
return giturl.ParseGitURL(addr)
|
||||
}
|
||||
|
||||
// GitRemotePrune prunes the remote branches that no longer exist in the remote repository.
|
||||
func GitRemotePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
||||
return gitcmd.NewCommand("remote", "prune").AddDynamicArguments(remoteName).
|
||||
Run(ctx, &gitcmd.RunOpts{
|
||||
Timeout: timeout,
|
||||
Dir: repoPath(repo),
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
})
|
||||
}
|
||||
|
||||
// GitRemoteUpdatePrune updates the remote branches and prunes the ones that no longer exist in the remote repository.
|
||||
func GitRemoteUpdatePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
||||
return gitcmd.NewCommand("remote", "update", "--prune").AddDynamicArguments(remoteName).
|
||||
Run(ctx, &gitcmd.RunOpts{
|
||||
Timeout: timeout,
|
||||
Dir: repoPath(repo),
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
})
|
||||
}
|
||||
15
modules/gitrepo/tag.go
Normal file
15
modules/gitrepo/tag.go
Normal file
@@ -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"
|
||||
)
|
||||
|
||||
// IsTagExist returns true if given tag exists in the repository.
|
||||
func IsTagExist(ctx context.Context, repo Repository, name string) bool {
|
||||
return IsReferenceExist(ctx, repo, git.TagPrefix+name)
|
||||
}
|
||||
8
modules/gitrepo/url.go
Normal file
8
modules/gitrepo/url.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitrepo
|
||||
|
||||
func RepoGitURL(repo Repository) string {
|
||||
return repoPath(repo)
|
||||
}
|
||||
36
modules/gitrepo/walk_gogit.go
Normal file
36
modules/gitrepo/walk_gogit.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build gogit
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
// refname is empty, ObjectTag or ObjectBranch. All other values should be treated as equivalent to empty.
|
||||
func WalkReferences(ctx context.Context, repo Repository, walkfn func(sha1, refname string) error) (int, error) {
|
||||
gitRepo, closer, err := RepositoryFromContextOrOpen(ctx, repo)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
i := 0
|
||||
iter, err := gitRepo.GoGitRepo().References()
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
defer iter.Close()
|
||||
|
||||
err = iter.ForEach(func(ref *plumbing.Reference) error {
|
||||
err := walkfn(ref.Hash().String(), string(ref.Name()))
|
||||
i++
|
||||
return err
|
||||
})
|
||||
return i, err
|
||||
}
|
||||
17
modules/gitrepo/walk_nogogit.go
Normal file
17
modules/gitrepo/walk_nogogit.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build !gogit
|
||||
|
||||
package gitrepo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
)
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
func WalkReferences(ctx context.Context, repo Repository, walkfn func(sha1, refname string) error) (int, error) {
|
||||
return git.WalkShowRef(ctx, repoPath(repo), nil, 0, 0, walkfn)
|
||||
}
|
||||
Reference in New Issue
Block a user