@@ -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 { |
@@ -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()) |
@@ -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()) |
@@ -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 | |||
} |
@@ -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 | |||
} |
@@ -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 | |||
} |
@@ -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 |
@@ -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) |
@@ -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) { |
@@ -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) | |||
}) | |||
} | |||
@@ -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 |
@@ -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 { |
@@ -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 | |||
} |
@@ -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 | |||
} |