summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2022-06-06 16:01:49 +0800
committerGitHub <noreply@github.com>2022-06-06 16:01:49 +0800
commit26095115f4ae90e3fdc6ab695978efd16e317f75 (patch)
tree92ec1c7ff54e0a65f4f0662baa8c0244dd9f324b /modules
parentebeb6e7c71a0c763b52153f4eb427e7c5b89a95e (diff)
downloadgitea-26095115f4ae90e3fdc6ab695978efd16e317f75.tar.gz
gitea-26095115f4ae90e3fdc6ab695978efd16e317f75.zip
Move some repository related code into sub package (#19711)
* Move some repository related code into sub package * Move more repository functions out of models * Fix lint * Some performance optimization for webhooks and others * some refactors * Fix lint * Fix * Update modules/repository/delete.go Co-authored-by: delvh <dev.lh@web.de> * Fix test * Merge * Fix test * Fix test * Fix test * Fix test Co-authored-by: delvh <dev.lh@web.de>
Diffstat (limited to 'modules')
-rw-r--r--modules/context/repo.go5
-rw-r--r--modules/indexer/issues/indexer.go4
-rw-r--r--modules/repository/create.go115
-rw-r--r--modules/repository/create_test.go21
-rw-r--r--modules/repository/delete.go33
-rw-r--r--modules/repository/fork.go31
-rw-r--r--modules/repository/generate.go65
-rw-r--r--modules/repository/generate_test.go57
-rw-r--r--modules/repository/init.go2
-rw-r--r--modules/repository/repo.go25
10 files changed, 338 insertions, 20 deletions
diff --git a/modules/context/repo.go b/modules/context/repo.go
index df3fe4e74d..5f4af114ff 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -26,6 +26,7 @@ import (
code_indexer "code.gitea.io/gitea/modules/indexer/code"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/markdown"
+ repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -551,14 +552,14 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
- canSignedUserFork, err := models.CanUserForkRepo(ctx.Doer, ctx.Repo.Repository)
+ canSignedUserFork, err := repo_module.CanUserForkRepo(ctx.Doer, ctx.Repo.Repository)
if err != nil {
ctx.ServerError("CanUserForkRepo", err)
return
}
ctx.Data["CanSignedUserFork"] = canSignedUserFork
- userAndOrgForks, err := models.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository)
+ userAndOrgForks, err := repo_model.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository)
if err != nil {
ctx.ServerError("GetForksByUserAndOrgs", err)
return
diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go
index 7adc938dcc..85de4c75b3 100644
--- a/modules/indexer/issues/indexer.go
+++ b/modules/indexer/issues/indexer.go
@@ -291,8 +291,8 @@ func populateIssueIndexer(ctx context.Context) {
return
default:
}
- repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{
- ListOptions: db.ListOptions{Page: page, PageSize: models.RepositoryListDefaultPageSize},
+ repos, _, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
+ ListOptions: db.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize},
OrderBy: db.SearchOrderByID,
Private: true,
Collaborate: util.OptionalBoolFalse,
diff --git a/modules/repository/create.go b/modules/repository/create.go
index 21d45c896e..95bb825403 100644
--- a/modules/repository/create.go
+++ b/modules/repository/create.go
@@ -7,15 +7,20 @@ package repository
import (
"context"
"fmt"
+ "os"
+ "path"
"strings"
+ "unicode/utf8"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
+ access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)
@@ -108,7 +113,7 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (
}
}
- if err := models.CheckDaemonExportOK(ctx, repo); err != nil {
+ if err := CheckDaemonExportOK(ctx, repo); err != nil {
return fmt.Errorf("checkDaemonExportOK: %v", err)
}
@@ -133,3 +138,111 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (
return repo, nil
}
+
+// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize
+func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error {
+ size, err := util.GetDirectorySize(repo.RepoPath())
+ if err != nil {
+ return fmt.Errorf("updateSize: %v", err)
+ }
+
+ lfsSize, err := models.GetRepoLFSSize(ctx, repo.ID)
+ if err != nil {
+ return fmt.Errorf("updateSize: GetLFSMetaObjects: %v", err)
+ }
+
+ return repo_model.UpdateRepoSize(ctx, repo.ID, size+lfsSize)
+}
+
+// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon...
+func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error {
+ if err := repo.GetOwner(ctx); err != nil {
+ return err
+ }
+
+ // Create/Remove git-daemon-export-ok for git-daemon...
+ daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`)
+
+ isExist, err := util.IsExist(daemonExportFile)
+ if err != nil {
+ log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err)
+ return err
+ }
+
+ isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic
+ if !isPublic && isExist {
+ if err = util.Remove(daemonExportFile); err != nil {
+ log.Error("Failed to remove %s: %v", daemonExportFile, err)
+ }
+ } else if isPublic && !isExist {
+ if f, err := os.Create(daemonExportFile); err != nil {
+ log.Error("Failed to create %s: %v", daemonExportFile, err)
+ } else {
+ f.Close()
+ }
+ }
+
+ return nil
+}
+
+// UpdateRepository updates a repository with db context
+func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
+ repo.LowerName = strings.ToLower(repo.Name)
+
+ if utf8.RuneCountInString(repo.Description) > 255 {
+ repo.Description = string([]rune(repo.Description)[:255])
+ }
+ if utf8.RuneCountInString(repo.Website) > 255 {
+ repo.Website = string([]rune(repo.Website)[:255])
+ }
+
+ e := db.GetEngine(ctx)
+
+ if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
+ return fmt.Errorf("update: %v", err)
+ }
+
+ if err = UpdateRepoSize(ctx, repo); err != nil {
+ log.Error("Failed to update size for repository: %v", err)
+ }
+
+ if visibilityChanged {
+ if err = repo.GetOwner(ctx); err != nil {
+ return fmt.Errorf("getOwner: %v", err)
+ }
+ if repo.Owner.IsOrganization() {
+ // Organization repository need to recalculate access table when visibility is changed.
+ if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
+ return fmt.Errorf("recalculateTeamAccesses: %v", err)
+ }
+ }
+
+ // If repo has become private, we need to set its actions to private.
+ if repo.IsPrivate {
+ _, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&models.Action{
+ IsPrivate: true,
+ })
+ if err != nil {
+ return err
+ }
+ }
+
+ // Create/Remove git-daemon-export-ok for git-daemon...
+ if err := CheckDaemonExportOK(db.WithEngine(ctx, e), repo); err != nil {
+ return err
+ }
+
+ forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
+ if err != nil {
+ return fmt.Errorf("getRepositoriesByForkID: %v", err)
+ }
+ for i := range forkRepos {
+ forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate
+ if err = UpdateRepository(ctx, forkRepos[i], true); err != nil {
+ return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err)
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go
index b6a89a7ed6..2a47e93631 100644
--- a/modules/repository/create_test.go
+++ b/modules/repository/create_test.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
+ repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
@@ -147,3 +148,23 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
}
assert.NoError(t, organization.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization")
}
+
+func TestUpdateRepositoryVisibilityChanged(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ // Get sample repo and change visibility
+ repo, err := repo_model.GetRepositoryByID(9)
+ assert.NoError(t, err)
+ repo.IsPrivate = true
+
+ // Update it
+ err = UpdateRepository(db.DefaultContext, repo, true)
+ assert.NoError(t, err)
+
+ // Check visibility of action has become private
+ act := models.Action{}
+ _, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act)
+
+ assert.NoError(t, err)
+ assert.True(t, act.IsPrivate)
+}
diff --git a/modules/repository/delete.go b/modules/repository/delete.go
new file mode 100644
index 0000000000..25fb15e300
--- /dev/null
+++ b/modules/repository/delete.go
@@ -0,0 +1,33 @@
+// Copyright 2022 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 (
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/organization"
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
+)
+
+// CanUserDelete returns true if user could delete the repository
+func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) {
+ if user.IsAdmin || user.ID == repo.OwnerID {
+ return true, nil
+ }
+
+ if err := repo.GetOwner(db.DefaultContext); err != nil {
+ return false, err
+ }
+
+ if repo.Owner.IsOrganization() {
+ isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID)
+ if err != nil {
+ return false, err
+ }
+ return isOwner, nil
+ }
+
+ return false, nil
+}
diff --git a/modules/repository/fork.go b/modules/repository/fork.go
new file mode 100644
index 0000000000..c967d3b741
--- /dev/null
+++ b/modules/repository/fork.go
@@ -0,0 +1,31 @@
+// Copyright 2019 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 (
+ "code.gitea.io/gitea/models/organization"
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
+)
+
+// CanUserForkRepo returns true if specified user can fork repository.
+func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) {
+ if user == nil {
+ return false, nil
+ }
+ if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) {
+ return true, nil
+ }
+ ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID)
+ if err != nil {
+ return false, err
+ }
+ for _, org := range ownedOrgs {
+ if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) {
+ return true, nil
+ }
+ }
+ return false, nil
+}
diff --git a/modules/repository/generate.go b/modules/repository/generate.go
index b3ce809173..94bb6e6429 100644
--- a/modules/repository/generate.go
+++ b/modules/repository/generate.go
@@ -5,6 +5,8 @@
package repository
import (
+ "bufio"
+ "bytes"
"context"
"fmt"
"os"
@@ -20,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
+ "github.com/gobwas/glob"
"github.com/huandu/xstrings"
)
@@ -78,7 +81,38 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi
})
}
-func checkGiteaTemplate(tmpDir string) (*models.GiteaTemplate, error) {
+// GiteaTemplate holds information about a .gitea/template file
+type GiteaTemplate struct {
+ Path string
+ Content []byte
+
+ globs []glob.Glob
+}
+
+// Globs parses the .gitea/template globs or returns them if they were already parsed
+func (gt GiteaTemplate) Globs() []glob.Glob {
+ if gt.globs != nil {
+ return gt.globs
+ }
+
+ gt.globs = make([]glob.Glob, 0)
+ scanner := bufio.NewScanner(bytes.NewReader(gt.Content))
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ g, err := glob.Compile(line, '/')
+ if err != nil {
+ log.Info("Invalid glob expression '%s' (skipped): %v", line, err)
+ continue
+ }
+ gt.globs = append(gt.globs, g)
+ }
+ return gt.globs
+}
+
+func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) {
gtPath := filepath.Join(tmpDir, ".gitea", "template")
if _, err := os.Stat(gtPath); os.IsNotExist(err) {
return nil, nil
@@ -91,7 +125,7 @@ func checkGiteaTemplate(tmpDir string) (*models.GiteaTemplate, error) {
return nil, err
}
- gt := &models.GiteaTemplate{
+ gt := &GiteaTemplate{
Path: gtPath,
Content: content,
}
@@ -227,7 +261,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r
if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
return fmt.Errorf("setDefaultBranch: %v", err)
}
- if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil {
+ if err = UpdateRepository(ctx, repo, false); err != nil {
return fmt.Errorf("updateRepository: %v", err)
}
@@ -240,7 +274,7 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo
return err
}
- if err := models.UpdateRepoSize(ctx, generateRepo); err != nil {
+ if err := UpdateRepoSize(ctx, generateRepo); err != nil {
return fmt.Errorf("failed to update size for repository: %v", err)
}
@@ -250,8 +284,27 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo
return nil
}
+// GenerateRepoOptions contains the template units to generate
+type GenerateRepoOptions struct {
+ Name string
+ DefaultBranch string
+ Description string
+ Private bool
+ GitContent bool
+ Topics bool
+ GitHooks bool
+ Webhooks bool
+ Avatar bool
+ IssueLabels bool
+}
+
+// IsValid checks whether at least one option is chosen for generation
+func (gro GenerateRepoOptions) IsValid() bool {
+ return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added
+}
+
// GenerateRepository generates a repository from a template
-func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts models.GenerateRepoOptions) (_ *repo_model.Repository, err error) {
+func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) {
generateRepo := &repo_model.Repository{
OwnerID: owner.ID,
Owner: owner,
@@ -288,7 +341,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
return generateRepo, err
}
- if err = models.CheckDaemonExportOK(ctx, generateRepo); err != nil {
+ if err = CheckDaemonExportOK(ctx, generateRepo); err != nil {
return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err)
}
diff --git a/modules/repository/generate_test.go b/modules/repository/generate_test.go
new file mode 100644
index 0000000000..139fa4c918
--- /dev/null
+++ b/modules/repository/generate_test.go
@@ -0,0 +1,57 @@
+// Copyright 2019 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 (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+var giteaTemplate = []byte(`
+# Header
+
+# All .go files
+**.go
+
+# All text files in /text/
+text/*.txt
+
+# All files in modules folders
+**/modules/*
+`)
+
+func TestGiteaTemplate(t *testing.T) {
+ gt := GiteaTemplate{Content: giteaTemplate}
+ assert.Len(t, gt.Globs(), 3)
+
+ tt := []struct {
+ Path string
+ Match bool
+ }{
+ {Path: "main.go", Match: true},
+ {Path: "a/b/c/d/e.go", Match: true},
+ {Path: "main.txt", Match: false},
+ {Path: "a/b.txt", Match: false},
+ {Path: "text/a.txt", Match: true},
+ {Path: "text/b.txt", Match: true},
+ {Path: "text/c.json", Match: false},
+ {Path: "a/b/c/modules/README.md", Match: true},
+ {Path: "a/b/c/modules/d/README.md", Match: false},
+ }
+
+ for _, tc := range tt {
+ t.Run(tc.Path, func(t *testing.T) {
+ match := false
+ for _, g := range gt.Globs() {
+ if g.Match(tc.Path) {
+ match = true
+ break
+ }
+ }
+ assert.Equal(t, tc.Match, match)
+ })
+ }
+}
diff --git a/modules/repository/init.go b/modules/repository/init.go
index 845a61ed0a..f8c7a89552 100644
--- a/modules/repository/init.go
+++ b/modules/repository/init.go
@@ -444,7 +444,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re
}
}
- if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil {
+ if err = UpdateRepository(ctx, repo, false); err != nil {
return fmt.Errorf("updateRepository: %v", err)
}
diff --git a/modules/repository/repo.go b/modules/repository/repo.go
index 30ca6fdff8..281999a1eb 100644
--- a/modules/repository/repo.go
+++ b/modules/repository/repo.go
@@ -116,7 +116,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
repo.Owner = u
}
- if err = models.CheckDaemonExportOK(ctx, repo); err != nil {
+ if err = CheckDaemonExportOK(ctx, repo); err != nil {
return repo, fmt.Errorf("checkDaemonExportOK: %v", err)
}
@@ -168,9 +168,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
}
- if err = models.UpdateRepoSize(ctx, repo); err != nil {
- log.Error("Failed to update size for repository: %v", err)
+ ctx, committer, err := db.TxContext()
+ if err != nil {
+ return nil, err
}
+ defer committer.Close()
if opts.Mirror {
mirrorModel := repo_model.Mirror{
@@ -203,17 +205,24 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
}
- if err = repo_model.InsertMirror(&mirrorModel); err != nil {
+ if err = repo_model.InsertMirror(ctx, &mirrorModel); err != nil {
return repo, fmt.Errorf("InsertOne: %v", err)
}
repo.IsMirror = true
- err = models.UpdateRepository(repo, false)
+ if err = UpdateRepository(ctx, repo, false); err != nil {
+ return nil, err
+ }
} else {
- repo, err = CleanUpMigrateInfo(ctx, repo)
+ if err = UpdateRepoSize(ctx, repo); err != nil {
+ log.Error("Failed to update size for repository: %v", err)
+ }
+ if repo, err = CleanUpMigrateInfo(ctx, repo); err != nil {
+ return nil, err
+ }
}
- return repo, err
+ return repo, committer.Commit()
}
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
@@ -253,7 +262,7 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo
}
}
- return repo, models.UpdateRepository(repo, false)
+ return repo, UpdateRepository(ctx, repo, false)
}
// SyncReleasesWithTags synchronizes release table with repository tags