* Move PushUpdateAddDeleteTags to repository module from models * Fix deadlock on sqlitetags/v1.10.5
@@ -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) | |||
} | |||
} |