Move some functions into services/repository (#17677)

This commit is contained in:
Lunny Xiao 2021-11-17 23:17:31 +08:00 committed by GitHub
parent 750a8465f5
commit 5233051e64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 283 additions and 285 deletions

View file

@ -85,7 +85,7 @@ func registerRepositoryUpdateHook() {
RunAtStart: false,
Schedule: "@every 72h",
}, func(ctx context.Context, _ *models.User, _ Config) error {
return repo_module.SyncRepositoryHooks(ctx)
return repo_service.SyncRepositoryHooks(ctx)
})
}

View file

@ -333,7 +333,7 @@ func runSync(ctx context.Context, m *models.Mirror) ([]*mirrorSyncResult, bool)
}
log.Trace("SyncMirrors [repo: %-v]: invalidating mirror branch caches...", m.Repo)
branches, _, err := repo_module.GetBranches(m.Repo, 0, 0)
branches, _, err := git.GetBranchesByPath(m.Repo.RepoPath(), 0, 0)
if err != nil {
log.Error("GetBranches: %v", err)
return nil, false

View file

@ -6,6 +6,7 @@ package repository
import (
"errors"
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
@ -15,6 +16,95 @@ import (
pull_service "code.gitea.io/gitea/services/pull"
)
// CreateNewBranch creates a new repository branch
func CreateNewBranch(doer *models.User, repo *models.Repository, oldBranchName, branchName string) (err error) {
// Check if branch name can be used
if err := checkBranchName(repo, branchName); err != nil {
return err
}
if !git.IsBranchExist(repo.RepoPath(), oldBranchName) {
return models.ErrBranchDoesNotExist{
BranchName: oldBranchName,
}
}
if err := git.Push(repo.RepoPath(), git.PushOptions{
Remote: repo.RepoPath(),
Branch: fmt.Sprintf("%s:%s%s", oldBranchName, git.BranchPrefix, branchName),
Env: models.PushingEnvironment(doer, repo),
}); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
return err
}
return fmt.Errorf("Push: %v", err)
}
return nil
}
// GetBranches returns branches from the repository, skipping skip initial branches and
// returning at most limit branches, or all branches if limit is 0.
func GetBranches(repo *models.Repository, skip, limit int) ([]*git.Branch, int, error) {
return git.GetBranchesByPath(repo.RepoPath(), skip, limit)
}
// checkBranchName validates branch name with existing repository branches
func checkBranchName(repo *models.Repository, name string) error {
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
return err
}
defer gitRepo.Close()
branches, _, err := GetBranches(repo, 0, 0)
if err != nil {
return err
}
for _, branch := range branches {
if branch.Name == name {
return models.ErrBranchAlreadyExists{
BranchName: branch.Name,
}
} else if (len(branch.Name) < len(name) && branch.Name+"/" == name[0:len(branch.Name)+1]) ||
(len(branch.Name) > len(name) && name+"/" == branch.Name[0:len(name)+1]) {
return models.ErrBranchNameConflict{
BranchName: branch.Name,
}
}
}
if _, err := gitRepo.GetTag(name); err == nil {
return models.ErrTagAlreadyExists{
TagName: name,
}
}
return nil
}
// CreateNewBranchFromCommit creates a new repository branch
func CreateNewBranchFromCommit(doer *models.User, repo *models.Repository, commit, branchName string) (err error) {
// Check if branch name can be used
if err := checkBranchName(repo, branchName); err != nil {
return err
}
if err := git.Push(repo.RepoPath(), git.PushOptions{
Remote: repo.RepoPath(),
Branch: fmt.Sprintf("%s:%s%s", commit, git.BranchPrefix, branchName),
Env: models.PushingEnvironment(doer, repo),
}); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
return err
}
return fmt.Errorf("Push: %v", err)
}
return nil
}
// RenameBranch rename a branch
func RenameBranch(repo *models.Repository, doer *models.User, gitRepo *git.Repository, from, to string) (string, error) {
if from == to {

View file

@ -0,0 +1,48 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repository
import (
"context"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
)
func getRefName(fullRefName string) string {
if strings.HasPrefix(fullRefName, git.TagPrefix) {
return fullRefName[len(git.TagPrefix):]
} else if strings.HasPrefix(fullRefName, git.BranchPrefix) {
return fullRefName[len(git.BranchPrefix):]
}
return ""
}
// CacheRef cachhe last commit information of the branch or the tag
func CacheRef(ctx context.Context, repo *models.Repository, gitRepo *git.Repository, fullRefName string) error {
if !setting.CacheService.LastCommit.Enabled {
return nil
}
commit, err := gitRepo.GetCommit(fullRefName)
if err != nil {
return err
}
commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(getRefName(fullRefName), true), commit.CommitsCount)
if err != nil {
return err
}
if commitsCount < setting.CacheService.LastCommit.CommitsCount {
return nil
}
commitCache := git.NewLastCommitCache(repo.FullName(), gitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache())
return commitCache.CacheCommit(ctx, commit)
}

View file

@ -0,0 +1,52 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repository
import (
"context"
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"xorm.io/builder"
)
// SyncRepositoryHooks rewrites all repositories' pre-receive, update and post-receive hooks
// to make sure the binary and custom conf path are up-to-date.
func SyncRepositoryHooks(ctx context.Context) error {
log.Trace("Doing: SyncRepositoryHooks")
if err := db.Iterate(
db.DefaultContext,
new(models.Repository),
builder.Gt{"id": 0},
func(idx int, bean interface{}) error {
repo := bean.(*models.Repository)
select {
case <-ctx.Done():
return db.ErrCancelledf("before sync repository hooks for %s", repo.FullName())
default:
}
if err := repo_module.CreateDelegateHooks(repo.RepoPath()); err != nil {
return fmt.Errorf("SyncRepositoryHook: %v", err)
}
if repo.HasWiki() {
if err := repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("SyncRepositoryHook: %v", err)
}
}
return nil
},
); err != nil {
return err
}
log.Trace("Finished: SyncRepositoryHooks")
return nil
}

View file

@ -5,8 +5,10 @@
package repository
import (
"context"
"errors"
"fmt"
"strings"
"time"
"code.gitea.io/gitea/models"
@ -20,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/repofiles"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
pull_service "code.gitea.io/gitea/services/pull"
)
@ -210,7 +213,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
// Cache for big repository
if err := repo_module.CacheRef(graceful.GetManager().HammerContext(), repo, gitRepo, opts.RefFullName); err != nil {
if err := CacheRef(graceful.GetManager().HammerContext(), repo, gitRepo, opts.RefFullName); err != nil {
log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err)
}
} else {
@ -229,7 +232,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
log.Trace("Non-tag and non-branch commits pushed.")
}
}
if err := repo_module.PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil {
if err := PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil {
return fmt.Errorf("PushUpdateAddDeleteTags: %v", err)
}
@ -240,3 +243,122 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
return nil
}
// PushUpdateAddDeleteTags updates a number of added and delete tags
func PushUpdateAddDeleteTags(repo *models.Repository, gitRepo *git.Repository, addTags, delTags []string) error {
return db.WithTx(func(ctx context.Context) error {
if err := models.PushUpdateDeleteTagsContext(ctx, repo, delTags); err != nil {
return err
}
return pushUpdateAddTags(ctx, repo, gitRepo, addTags)
})
}
// pushUpdateAddTags updates a number of add tags
func pushUpdateAddTags(ctx context.Context, repo *models.Repository, gitRepo *git.Repository, tags []string) error {
if len(tags) == 0 {
return nil
}
lowerTags := make([]string, 0, len(tags))
for _, tag := range tags {
lowerTags = append(lowerTags, strings.ToLower(tag))
}
releases, err := models.GetReleasesByRepoIDAndNames(ctx, repo.ID, lowerTags)
if err != nil {
return fmt.Errorf("GetReleasesByRepoIDAndNames: %v", err)
}
relMap := make(map[string]*models.Release)
for _, rel := range releases {
relMap[rel.LowerTagName] = rel
}
newReleases := make([]*models.Release, 0, len(lowerTags)-len(relMap))
emailToUser := make(map[string]*models.User)
for i, lowerTag := range lowerTags {
tag, err := gitRepo.GetTag(tags[i])
if err != nil {
return fmt.Errorf("GetTag: %v", err)
}
commit, err := tag.Commit()
if err != nil {
return fmt.Errorf("Commit: %v", err)
}
sig := tag.Tagger
if sig == nil {
sig = commit.Author
}
if sig == nil {
sig = commit.Committer
}
var author *models.User
var createdAt = time.Unix(1, 0)
if sig != nil {
var ok bool
author, ok = emailToUser[sig.Email]
if !ok {
author, err = models.GetUserByEmailContext(ctx, sig.Email)
if err != nil && !models.IsErrUserNotExist(err) {
return fmt.Errorf("GetUserByEmail: %v", err)
}
if author != nil {
emailToUser[sig.Email] = author
}
}
createdAt = sig.When
}
commitsCount, err := commit.CommitsCount()
if err != nil {
return fmt.Errorf("CommitsCount: %v", err)
}
rel, has := relMap[lowerTag]
if !has {
rel = &models.Release{
RepoID: repo.ID,
Title: "",
TagName: tags[i],
LowerTagName: lowerTag,
Target: "",
Sha1: commit.ID.String(),
NumCommits: commitsCount,
Note: "",
IsDraft: false,
IsPrerelease: false,
IsTag: true,
CreatedUnix: timeutil.TimeStamp(createdAt.Unix()),
}
if author != nil {
rel.PublisherID = author.ID
}
newReleases = append(newReleases, rel)
} else {
rel.Sha1 = commit.ID.String()
rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
rel.NumCommits = commitsCount
rel.IsDraft = false
if rel.IsTag && author != nil {
rel.PublisherID = author.ID
}
if err = models.UpdateRelease(ctx, rel); err != nil {
return fmt.Errorf("Update: %v", err)
}
}
}
if len(newReleases) > 0 {
if err = models.InsertReleasesContext(ctx, newReleases); err != nil {
return fmt.Errorf("Insert: %v", err)
}
}
return nil
}