]> source.dussan.org Git - gitea.git/commitdiff
Move some functions into services/repository (#17677)
authorLunny Xiao <xiaolunwen@gmail.com>
Wed, 17 Nov 2021 15:17:31 +0000 (23:17 +0800)
committerGitHub <noreply@github.com>
Wed, 17 Nov 2021 15:17:31 +0000 (23:17 +0800)
16 files changed:
cmd/admin.go
integrations/api_repo_get_contents_list_test.go
integrations/api_repo_get_contents_test.go
modules/repository/branch.go
modules/repository/cache.go [deleted file]
modules/repository/hooks.go
modules/repository/update.go [deleted file]
routers/api/v1/repo/branch.go
routers/init.go
routers/web/repo/branch.go
services/cron/tasks_extended.go
services/mirror/mirror_pull.go
services/repository/branch.go
services/repository/cache.go [new file with mode: 0644]
services/repository/hooks.go [new file with mode: 0644]
services/repository/push.go

index 64106f506019c6cf9ff03ccf7b7e96e7097f2529..858498ed376b810a5c2bba97bda3892c055baff4 100644 (file)
@@ -25,6 +25,7 @@ import (
        "code.gitea.io/gitea/modules/storage"
        auth_service "code.gitea.io/gitea/services/auth"
        "code.gitea.io/gitea/services/auth/source/oauth2"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/urfave/cli"
 )
@@ -612,7 +613,7 @@ func runRegenerateHooks(_ *cli.Context) error {
        if err := initDB(ctx); err != nil {
                return err
        }
-       return repo_module.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
+       return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
 }
 
 func runRegenerateKeys(_ *cli.Context) error {
index c35a345e81bbc419ab0b319a72c8a49b65d4133a..823a72c726aeb5008f7185037b86a99f435a72be 100644 (file)
@@ -13,9 +13,9 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/modules/git"
-       repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/stretchr/testify/assert"
 )
@@ -72,7 +72,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 
        // Make a new branch in repo1
        newBranch := "test_branch"
-       err := repo_module.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch)
+       err := repo_service.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch)
        assert.NoError(t, err)
        // Get the commit ID of the default branch
        gitRepo, err := git.OpenRepository(repo1.RepoPath())
index 243ee229dc4dd3ffb8cf8618d1f95a26c98b2562..67ec02b7b0803726c2fa1b2bbe3dbc58d2f4556d 100644 (file)
@@ -12,9 +12,9 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/modules/git"
-       repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/stretchr/testify/assert"
 )
@@ -73,7 +73,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 
        // Make a new branch in repo1
        newBranch := "test_branch"
-       err := repo_module.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch)
+       err := repo_service.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch)
        assert.NoError(t, err)
        // Get the commit ID of the default branch
        gitRepo, err := git.OpenRepository(repo1.RepoPath())
index 275bae91e3f9b7795c2d5700603ce2c66fd370fb..dcd82554d53197bdd8ffa33c131530ccd21e678c 100644 (file)
@@ -24,92 +24,3 @@ func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) {
 
        return gitRepo.GetBranch(branch)
 }
-
-// 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
-}
-
-// 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
-}
-
-// 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
-}
diff --git a/modules/repository/cache.go b/modules/repository/cache.go
deleted file mode 100644 (file)
index e574f1a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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)
-}
index 23eee8897dc82ad94e873acdb91098f7bc678f8b..bd77423afc960dd2b65f9148084d430b99cbabd4 100644 (file)
@@ -5,19 +5,13 @@
 package repository
 
 import (
-       "context"
        "fmt"
        "os"
        "path/filepath"
 
-       "code.gitea.io/gitea/models"
-       "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/git"
-       "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
-
-       "xorm.io/builder"
 )
 
 func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) {
@@ -240,38 +234,3 @@ func CheckDelegateHooks(repoPath string) ([]string, error) {
        }
        return results, nil
 }
-
-// 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 := createDelegateHooks(repo.RepoPath()); err != nil {
-                               return fmt.Errorf("SyncRepositoryHook: %v", err)
-                       }
-                       if repo.HasWiki() {
-                               if err := createDelegateHooks(repo.WikiPath()); err != nil {
-                                       return fmt.Errorf("SyncRepositoryHook: %v", err)
-                               }
-                       }
-                       return nil
-               },
-       ); err != nil {
-               return err
-       }
-
-       log.Trace("Finished: SyncRepositoryHooks")
-       return nil
-}
diff --git a/modules/repository/update.go b/modules/repository/update.go
deleted file mode 100644 (file)
index b9a5db2..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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"
-       "fmt"
-       "strings"
-       "time"
-
-       "code.gitea.io/gitea/models"
-       "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/git"
-       "code.gitea.io/gitea/modules/timeutil"
-)
-
-// 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
-}
index c57075e3b84cdb834782351afb651ae5a8bec2c9..2e08b568266de0529b64bf44b86255e9b3e5a425 100644 (file)
@@ -176,7 +176,7 @@ func CreateBranch(ctx *context.APIContext) {
                opt.OldBranchName = ctx.Repo.Repository.DefaultBranch
        }
 
-       err := repo_module.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName)
+       err := repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName)
 
        if err != nil {
                if models.IsErrBranchDoesNotExist(err) {
@@ -257,7 +257,7 @@ func ListBranches(ctx *context.APIContext) {
 
        listOptions := utils.GetListOptions(ctx)
        skip, _ := listOptions.GetStartEnd()
-       branches, totalNumOfBranches, err := repo_module.GetBranches(ctx.Repo.Repository, skip, listOptions.PageSize)
+       branches, totalNumOfBranches, err := repo_service.GetBranches(ctx.Repo.Repository, skip, listOptions.PageSize)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, "GetBranches", err)
                return
index 0f19e7f732d82e01700579c1d6a00f650bec9658..762508cee52b23948ef78ba8fe3c666ffc79ea91 100644 (file)
@@ -25,7 +25,6 @@ import (
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/external"
        "code.gitea.io/gitea/modules/notification"
-       repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/ssh"
        "code.gitea.io/gitea/modules/storage"
@@ -45,7 +44,7 @@ import (
        repo_migrations "code.gitea.io/gitea/services/migrations"
        mirror_service "code.gitea.io/gitea/services/mirror"
        pull_service "code.gitea.io/gitea/services/pull"
-       "code.gitea.io/gitea/services/repository"
+       repo_service "code.gitea.io/gitea/services/repository"
        "code.gitea.io/gitea/services/webhook"
 
        "gitea.com/go-chi/session"
@@ -73,7 +72,7 @@ func mustInitCtx(ctx context.Context, fn func(ctx context.Context) error) {
 func InitGitServices() {
        setting.NewServices()
        mustInit(storage.Init)
-       mustInit(repository.NewContext)
+       mustInit(repo_service.NewContext)
 }
 
 func syncAppPathForGit(ctx context.Context) error {
@@ -85,7 +84,7 @@ func syncAppPathForGit(ctx context.Context) error {
                log.Info("AppPath changed from '%s' to '%s'", runtimeState.LastAppPath, setting.AppPath)
 
                log.Info("re-sync repository hooks ...")
-               mustInitCtx(ctx, repo_module.SyncRepositoryHooks)
+               mustInitCtx(ctx, repo_service.SyncRepositoryHooks)
 
                log.Info("re-write ssh public keys ...")
                mustInit(models.RewriteAllPublicKeys)
index 991beeace2af7169099535fd0607d5c352210f3a..10557ff3db088057ff3241c48f259089083f1e18 100644 (file)
@@ -171,7 +171,7 @@ func loadBranches(ctx *context.Context, skip, limit int) ([]*Branch, int) {
                return nil, 0
        }
 
-       rawBranches, totalNumOfBranches, err := repo_module.GetBranches(ctx.Repo.Repository, skip, limit)
+       rawBranches, totalNumOfBranches, err := repo_service.GetBranches(ctx.Repo.Repository, skip, limit)
        if err != nil {
                log.Error("GetBranches: %v", err)
                ctx.ServerError("GetBranches", err)
@@ -350,11 +350,11 @@ func CreateBranch(ctx *context.Context) {
                        err = release_service.CreateNewTag(ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName, "")
                }
        } else if ctx.Repo.IsViewBranch {
-               err = repo_module.CreateNewBranch(ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
+               err = repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
        } else if ctx.Repo.IsViewTag {
-               err = repo_module.CreateNewBranchFromCommit(ctx.User, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName)
+               err = repo_service.CreateNewBranchFromCommit(ctx.User, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName)
        } else {
-               err = repo_module.CreateNewBranchFromCommit(ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
+               err = repo_service.CreateNewBranchFromCommit(ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
        }
        if err != nil {
                if models.IsErrTagAlreadyExists(err) {
index 4ddcd44537ed84c6effbc63fcd78fac201941c1c..1f115de43a38fb49c4987a2a84816351f4ed2360 100644 (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)
        })
 }
 
index 2dee49f710234694a50f1d63a409ad8a7c219f78..84644145f78626a6645fe11706fbde52ca58bc31 100644 (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
index 5e246cbec67ca4b80d0d39b8b94b8ccea8b53310..83980c5bd994f85799409df93cd4c0b6207ed505 100644 (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 {
diff --git a/services/repository/cache.go b/services/repository/cache.go
new file mode 100644 (file)
index 0000000..e574f1a
--- /dev/null
@@ -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)
+}
diff --git a/services/repository/hooks.go b/services/repository/hooks.go
new file mode 100644 (file)
index 0000000..a50853f
--- /dev/null
@@ -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
+}
index ab1b404609740ea7ccc1bdcc58fc9d5d8048329a..a98cfb1758377c5ad5b31f87f0abd0c3efdb006a 100644 (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
+}