"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"
)
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 {
"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"
)
// 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())
"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"
)
// 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())
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
-}
+++ /dev/null
-// 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)
-}
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) {
}
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
-}
+++ /dev/null
-// 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
-}
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) {
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
"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"
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"
func InitGitServices() {
setting.NewServices()
mustInit(storage.Init)
- mustInit(repository.NewContext)
+ mustInit(repo_service.NewContext)
}
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)
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)
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) {
RunAtStart: false,
Schedule: "@every 72h",
}, func(ctx context.Context, _ *models.User, _ Config) error {
- return repo_module.SyncRepositoryHooks(ctx)
+ return repo_service.SyncRepositoryHooks(ctx)
})
}
}
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
import (
"errors"
+ "fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
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 {
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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
+}
package repository
import (
+ "context"
"errors"
"fmt"
+ "strings"
"time"
"code.gitea.io/gitea/models"
"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"
)
}
// 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 {
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)
}
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
+}