* Move PushUpdateAddDeleteTags to repository module from models * Fix deadlock on sqlitetags/v1.21.12.1
| @@ -10,6 +10,19 @@ import ( | |||
| "strings" | |||
| ) | |||
| // env keys for git hooks need | |||
| const ( | |||
| EnvRepoName = "GITEA_REPO_NAME" | |||
| EnvRepoUsername = "GITEA_REPO_USER_NAME" | |||
| EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" | |||
| EnvPusherName = "GITEA_PUSHER_NAME" | |||
| EnvPusherEmail = "GITEA_PUSHER_EMAIL" | |||
| EnvPusherID = "GITEA_PUSHER_ID" | |||
| EnvKeyID = "GITEA_KEY_ID" | |||
| EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" | |||
| EnvIsInternal = "GITEA_INTERNAL_PUSH" | |||
| ) | |||
| // InternalPushingEnvironment returns an os environment to switch off hooks on push | |||
| // It is recommended to avoid using this unless you are pushing within a transaction | |||
| // or if you absolutely are sure that post-receive and pre-receive will do nothing | |||
| @@ -119,9 +119,15 @@ func InsertRelease(rel *Release) error { | |||
| return err | |||
| } | |||
| // InsertReleasesContext insert releases | |||
| func InsertReleasesContext(ctx DBContext, rels []*Release) error { | |||
| _, err := ctx.e.Insert(rels) | |||
| return err | |||
| } | |||
| // UpdateRelease updates all columns of a release | |||
| func UpdateRelease(rel *Release) error { | |||
| _, err := x.ID(rel.ID).AllCols().Update(rel) | |||
| func UpdateRelease(ctx DBContext, rel *Release) error { | |||
| _, err := ctx.e.ID(rel.ID).AllCols().Update(rel) | |||
| return err | |||
| } | |||
| @@ -212,10 +218,10 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er | |||
| } | |||
| // GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames. | |||
| func GetReleasesByRepoIDAndNames(repoID int64, tagNames []string) (rels []*Release, err error) { | |||
| err = x. | |||
| Desc("created_unix"). | |||
| func GetReleasesByRepoIDAndNames(ctx DBContext, repoID int64, tagNames []string) (rels []*Release, err error) { | |||
| err = ctx.e. | |||
| In("tag_name", tagNames). | |||
| Desc("created_unix"). | |||
| Find(&rels, Release{RepoID: repoID}) | |||
| return rels, err | |||
| } | |||
| @@ -7,42 +7,8 @@ package models | |||
| import ( | |||
| "fmt" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| // env keys for git hooks need | |||
| const ( | |||
| EnvRepoName = "GITEA_REPO_NAME" | |||
| EnvRepoUsername = "GITEA_REPO_USER_NAME" | |||
| EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" | |||
| EnvPusherName = "GITEA_PUSHER_NAME" | |||
| EnvPusherEmail = "GITEA_PUSHER_EMAIL" | |||
| EnvPusherID = "GITEA_PUSHER_ID" | |||
| EnvKeyID = "GITEA_KEY_ID" | |||
| EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" | |||
| EnvIsInternal = "GITEA_INTERNAL_PUSH" | |||
| ) | |||
| // PushUpdateAddDeleteTags updates a number of added and delete tags | |||
| func PushUpdateAddDeleteTags(repo *Repository, gitRepo *git.Repository, addTags, delTags []string) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err) | |||
| } | |||
| if err := pushUpdateDeleteTags(sess, repo, delTags); err != nil { | |||
| return err | |||
| } | |||
| if err := pushUpdateAddTags(sess, repo, gitRepo, addTags); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| // PushUpdateDeleteTags updates a number of delete tags | |||
| func PushUpdateDeleteTags(repo *Repository, tags []string) error { | |||
| sess := x.NewSession() | |||
| @@ -57,6 +23,11 @@ func PushUpdateDeleteTags(repo *Repository, tags []string) error { | |||
| return sess.Commit() | |||
| } | |||
| // PushUpdateDeleteTagsContext updates a number of delete tags with context | |||
| func PushUpdateDeleteTagsContext(ctx DBContext, repo *Repository, tags []string) error { | |||
| return pushUpdateDeleteTags(ctx.e, repo, tags) | |||
| } | |||
| func pushUpdateDeleteTags(e Engine, repo *Repository, tags []string) error { | |||
| if len(tags) == 0 { | |||
| return nil | |||
| @@ -111,125 +82,6 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error { | |||
| return nil | |||
| } | |||
| // PushUpdateAddTags updates a number of add tags | |||
| func PushUpdateAddTags(repo *Repository, gitRepo *git.Repository, tags []string) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return fmt.Errorf("Unable to begin sess in PushUpdateAddTags: %v", err) | |||
| } | |||
| if err := pushUpdateAddTags(sess, repo, gitRepo, tags); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func pushUpdateAddTags(e Engine, repo *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 := make([]Release, 0, len(tags)) | |||
| if err := e.Where("repo_id = ?", repo.ID). | |||
| In("lower_tag_name", lowerTags).Find(&releases); err != nil { | |||
| return fmt.Errorf("GetRelease: %v", err) | |||
| } | |||
| relMap := make(map[string]*Release) | |||
| for _, rel := range releases { | |||
| relMap[rel.LowerTagName] = &rel | |||
| } | |||
| newReleases := make([]*Release, 0, len(lowerTags)-len(relMap)) | |||
| emailToUser := make(map[string]*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 *User | |||
| var createdAt = time.Unix(1, 0) | |||
| if sig != nil { | |||
| var ok bool | |||
| author, ok = emailToUser[sig.Email] | |||
| if !ok { | |||
| author, err = GetUserByEmail(sig.Email) | |||
| if err != nil && !IsErrUserNotExist(err) { | |||
| return fmt.Errorf("GetUserByEmail: %v", err) | |||
| } | |||
| } | |||
| createdAt = sig.When | |||
| } | |||
| commitsCount, err := commit.CommitsCount() | |||
| if err != nil { | |||
| return fmt.Errorf("CommitsCount: %v", err) | |||
| } | |||
| rel, has := relMap[lowerTag] | |||
| if !has { | |||
| rel = &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 = e.ID(rel.ID).AllCols().Update(rel); err != nil { | |||
| return fmt.Errorf("Update: %v", err) | |||
| } | |||
| } | |||
| } | |||
| if len(newReleases) > 0 { | |||
| if _, err := e.Insert(newReleases); err != nil { | |||
| return fmt.Errorf("Insert: %v", err) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // SaveOrUpdateTag must be called for any push actions to add tag | |||
| func SaveOrUpdateTag(repo *Repository, newRel *Release) error { | |||
| rel, err := GetRelease(repo.ID, newRel.TagName) | |||
| @@ -1452,6 +1452,11 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List { | |||
| // GetUserByEmail returns the user object by given e-mail if exists. | |||
| func GetUserByEmail(email string) (*User, error) { | |||
| return GetUserByEmailContext(DefaultDBContext(), email) | |||
| } | |||
| // GetUserByEmailContext returns the user object by given e-mail if exists with db context | |||
| func GetUserByEmailContext(ctx DBContext, email string) (*User, error) { | |||
| if len(email) == 0 { | |||
| return nil, ErrUserNotExist{0, email, 0} | |||
| } | |||
| @@ -1459,7 +1464,7 @@ func GetUserByEmail(email string) (*User, error) { | |||
| email = strings.ToLower(email) | |||
| // First try to find the user by primary email | |||
| user := &User{Email: email} | |||
| has, err := x.Get(user) | |||
| has, err := ctx.e.Get(user) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -1469,19 +1474,19 @@ func GetUserByEmail(email string) (*User, error) { | |||
| // Otherwise, check in alternative list for activated email addresses | |||
| emailAddress := &EmailAddress{Email: email, IsActivated: true} | |||
| has, err = x.Get(emailAddress) | |||
| has, err = ctx.e.Get(emailAddress) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if has { | |||
| return GetUserByID(emailAddress.UID) | |||
| return getUserByID(ctx.e, emailAddress.UID) | |||
| } | |||
| // Finally, if email address is the protected email address: | |||
| if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | |||
| username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | |||
| user := &User{LowerName: username} | |||
| has, err := x.Get(user) | |||
| has, err := ctx.e.Get(user) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -732,7 +732,7 @@ func createCommitRepoActions(repo *models.Repository, gitRepo *git.Repository, o | |||
| Commits: commits, | |||
| }) | |||
| } | |||
| if err := models.PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil { | |||
| if err := repo_module.PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil { | |||
| return nil, fmt.Errorf("PushUpdateAddDeleteTags: %v", err) | |||
| } | |||
| return actions, nil | |||
| @@ -0,0 +1,134 @@ | |||
| // 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 ( | |||
| "fmt" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "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 models.WithTx(func(ctx models.DBContext) 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 models.DBContext, 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 | |||
| } | |||
| @@ -420,7 +420,7 @@ func RedirectDownload(ctx *context.Context) { | |||
| ) | |||
| tagNames := []string{vTag} | |||
| curRepo := ctx.Repo.Repository | |||
| releases, err := models.GetReleasesByRepoIDAndNames(curRepo.ID, tagNames) | |||
| releases, err := models.GetReleasesByRepoIDAndNames(models.DefaultDBContext(), curRepo.ID, tagNames) | |||
| if err != nil { | |||
| if models.IsErrAttachmentNotExist(err) { | |||
| ctx.Error(404) | |||
| @@ -102,7 +102,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea | |||
| } | |||
| rel.LowerTagName = strings.ToLower(rel.TagName) | |||
| if err = models.UpdateRelease(rel); err != nil { | |||
| if err = models.UpdateRelease(models.DefaultDBContext(), rel); err != nil { | |||
| return err | |||
| } | |||
| @@ -145,7 +145,7 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error { | |||
| rel.Title = "" | |||
| rel.Note = "" | |||
| if err = models.UpdateRelease(rel); err != nil { | |||
| if err = models.UpdateRelease(models.DefaultDBContext(), rel); err != nil { | |||
| return fmt.Errorf("Update: %v", err) | |||
| } | |||
| } | |||